Windows 组策略(Group Policy Object)机制的漏洞分析 - 嘶吼 RoarTalk – 网络安全行业综合服务平台,4hou.com

Windows 组策略(Group Policy Object)机制的漏洞分析

lucywang 资讯 2020-07-27 10:40:00
466634
收藏

导语:组策略的体系结构很复杂,Windows支持许多传统代码和自定义选项,包括不同的GPOLink类型,尽管在几乎所有代码路径中都有许多对线程模拟API的调用,但仍然缺少它。

James-Bond-Hacker-1-scaled.webp.jpg

Windows 组策略(Group Policy Object)机制的漏洞类大约有60个,专门针对策略更新步骤,允许域环境中的标准用户执行文件系统攻击,进而使恶意用户可以逃避反恶意软件解决方案,绕过安全性强化并可能导致对Windows 2000的严重攻击。组织的网络。这些漏洞会影响任何Windows计算机(2008或更高版本),并在域环境中提升其特权。

如果你对这项研究的其他发现感兴趣,请查阅详细信息(第1部分第2部分)。

GPSVC使所有加入域的Windows计算机暴露给一个特权升级(EoP)漏洞,通过运行gpudate.exe,你可以通过文件操作攻击升级为特权用户。如果你了解Windows的组策略,你就会知道系统在用户登录时会重新同步并应用当前已修改的组策略,但此时我们修改过的策略很可能会被覆盖掉。虽然我们可以通过将“SYSTEM”从构造注册表键值的ACL中移除来避免这种情况,但是Windows组策略客户端-GpSvc将会检测到这种操作,并在用户登录时修复ACL以便获取到写入权限,然后重写组策略。

通过分析GpSvc对这种ACL的处理过程,我发现当GpSvc在检测到注册表中的组策略键值时,会调用内部函数ForceRegCreateKeyEx,这个函数会尝试利用写入权限来打开我们的组策略键值,如果失败,则会调用AddPolicyPermissionOnKey来获取该注册表项的相应权限,以恢复“SYSTEM”在该表项上的写入权限,并重新打开它然后覆盖组策略。

Windows的组策略机制已经存在了很长时间,这是在域环境中(从打印机到备份设备)传播设置的一种相对安全的方法,即随便命名。因此,它需要与许多组件进行交互。许多交互可以造成许多潜在的漏洞,这就是我们要谈论的。

以下是该漏洞的工作原理:

96124-GPO-Vulnerability-InfographicV6-scaled.webp.jpg

背景

组策略或GPO对象最初是在Windows 2000的环境中使用的。虽然已经有一段时间了,它们有所变化,但是本质上还是相同的。管理员使用GPO在整个托管环境中实施其策略,并且功能非常强大。从禁用Windows Defender和防火墙到安装软件和打印机,管理员基本上可以使用GPO做任何他们想做的事情。

在Windows中,每个用户都有一组可由本地管理员修改的本地组策略,这使他们可以为本地计算机设置规则。在加入了域环境的计算机上,域管理员常常对适用于你的计算机的GPO感到一头雾水。

遵循最小特权原则是一种众所周知的安全最佳实践,该原则基于将用户的特权级别限制为最低限度。在这种情况下,这意味着不允许域用户成为本地管理员组的一部分。原因是本地管理员可以覆盖域管理员所应用的每个组策略,从而使GPO成为在公司网络上强制设置的一种非常无效的方法。

有趣的是,本地非特权用户可以手动请求组策略更新。因此,如果你在组策略更新过程中发现了一个漏洞,你可以在任何你想要的时候触发它,使潜在的攻击变得更容易。管理员不必等待90分钟(域环境中推送组策略更新的默认时间间隔为30分钟),而是在域环境上推送组策略更新的默认时间,管理员可以立即强制执行。

我们的兴趣在于名为gpsvc的本地组策略服务。该服务需要特权才能执行,因此它在NT AUTHORITY \ SYSTEM上下文环境中运行。这个环境很重要,因为如果我们设法找到它所执行的不安全文件操作,则大概可以使用文件操作攻击将其解析为另一个文件。

毫不奇怪,gpsvc托管在Svchost.exe中,并且通常在具有类似名称的DLL中实现-C:\ Windows \ System32 \ gpsvc.dll。这个DLL有一个RPC接口,我使用James Forshaw创建的这个很棒的工具将其反编译为C#。如下所示,我们有几种有趣的方法可以由本地用户调用。

2.png

当你运行gpupdate命令时,为了查看gpsvc服务中调用的是哪个方法,我弹出windb .exe并在每个暴露的RPC例程上设置一个断点,输入:

3.png

第一个函数是运行GPUpdate.exe时对我们重要的函数;它将调用Server_ProcessRefresh(),这将启动更新过程。但是,在此之前,让我们注意到这种行为(客户机通过RPC从服务请求服务)是麻烦的来源和许多漏洞的根源。不幸的是,Windows是基于不同组件之间的RPC通信的,没有这种机制就不能正常工作。Server_ProcessRefresh()向域控制器请求GPO对象,“给我我的组策略,以便我可以更新它们”,在获得结果后,它会为每个组策略调用ProcessGPOList()。

该方法具有超过600行的反编译代码,以及COM对象的使用。如果我们看一看它的签名,就能猜到它是做什么的:

4.png

并非所有的参数都被正式记录了,幸运的是,_GROUP_POLICY_OBJECTW被记录了,并且在C ++中创建GPO对象的开发人员可以创建它:

5.png

我们可以看到_GROUP_POLICY_OBJECTW是一个包含许多对象的链表结构。 * pPrev和* PNext两个对象是指向_GROUP_POLICY_OBJECTW的指针,这提供了一种遍历链表的简便方法。现在,本地服务遍历该列表并相应地继续执行指针,以确定该对象是否填充了相同类型的GPO对象。因此,ProcessGPOList()将对每个组策略调用。

让我们看一下GPOLink和szGPOName, GPOLink参数可以设置为五个参数:

GPLinkUnknown:没有可用的链接信息;

GPLinkMachine :GPO链接到计算机(本地或远程);

GPLinkSite :GPO链接到一个网站;

GPLinkDomain:GPO被链接到一个域;

GPLinkOrganizationalUnit:GPO链接到一个组织机构;

事实证明,此参数的值确定本地服务将其写入组策略的位置。如果将GPO链接到计算机,它将具有值C:\ProgramData\Microsoft\Group Policy\History\{GUID}\Machine\Preferernces\Applied-Object\Applied-Object.xml。

但是,如果GPOLink的值为GPLinkOrganizationalUnit,则它将应用于域中的每个用户和计算机,GPSVC会将策略复制到本地用户可以访问的路径中。 Windows使用%localappdata%路径执行任务:

C:\Users\eran\AppData\Local\Microsoft\Group Policy\History{szGPOName}\USER-SID\Preferences\Applied-Object\Applied-Object.xml. The Applied-Object\Applied-Object.xml is replaced by the object the group policy applies. For instance, a policy on printers would be translated to Printers\Printers.xml

我在上面提到过,gpsvc可以将所有文件系统操作都作为NT AUTHORITY \ SYSTEM,这意味着,如果服务没有模拟本地用户(在这里就是这种情况),我们可以进行符号链接攻击,以利用允许的目录ACL。当我们尝试执行文件操作攻击时,我们需要检查特权组件是否引用了模仿本地用户的API,该API可以是:

RpcImpersonateClient
ImpersonateLoggedOnUser
CoImpersonateClient

这些API大约有12种不同的调用,不包括对SetTokenInformation的调用。由此可以推断出开发人员了解模拟的重要性。但是,每个代码路径都需要正确地进行模拟,这就是麻烦所在。在本文的示例中,漏洞存在于模块gpprefcl.dll中,它将组策略写到磁盘上,该磁盘被加载到ProcessGPOList例程中。

如果查看gpprefcl.dll的导出表(部分副本),我们可以得到提示:

7     4 0002E450 GenerateGroupPolicyApplications
  8     5 0002EE10 GenerateGroupPolicyDataSources
  9     6 0002F080 GenerateGroupPolicyDevices
  10    7 0002D820 GenerateGroupPolicyDrives
  11    8 0002D5B0 GenerateGroupPolicyEnviron
  12    9 0002DD00 GenerateGroupPolicyFiles
  13    A 0002F2F0 GenerateGroupPolicyFolderOptions
  14    B 0002DA90 GenerateGroupPolicyFolders
  15    C 0002DF70 GenerateGroupPolicyIniFile
  21   12 0002E6C0 GenerateGroupPolicyPrinters
  22   13 0002FCB0 GenerateGroupPolicyRegionOptions
  29   1A 0002EED0 ProcessGroupPolicyDataSources
  30   1B 0002F140 ProcessGroupPolicyDevices
  31   1C 0002D8E0 ProcessGroupPolicyDrives
  32   1D 0002D670 ProcessGroupPolicyEnviron
  33   1E 0002E5E0 ProcessGroupPolicyExApplications
  34   1F 0002EFA0 ProcessGroupPolicyExDataSources
  35   20 0002F210 ProcessGroupPolicyExDevices
  36   21 0002D9B0 ProcessGroupPolicyExDrives
  38   23 0002DE90 ProcessGroupPolicyExFiles
  39   24 0002F480 ProcessGroupPolicyExFolderOptions
  40   25 0002DC20 ProcessGroupPolicyExFolders
  41   26 0002E100 ProcessGroupPolicyExIniFile
  42   27 0002EAC0 ProcessGroupPolicyExInternet
  43   28 0002F6F0 ProcessGroupPolicyExLocUsAndGroups
  54   33 0002DDC0 ProcessGroupPolicyFiles
  55   34 0002F3B0 ProcessGroupPolicyFolderOptions
  56   35 0002DB50 ProcessGroupPolicyFolders
  59   38 0002F620 ProcessGroupPolicyLocUsAndGroups
  1    39 000407E0 ProcessGroupPolicyMitigationOptions
  60   3A 00030730 ProcessGroupPolicyNetShares
  61   3B 0002F890 ProcessGroupPolicyNetworkOptions
  62   3C 0002FB00 ProcessGroupPolicyPowerOptions
  63   3D 0002E780 ProcessGroupPolicyPrinters
  2    3E 00040AC0 ProcessGroupPolicyProcessMitigationOptions
  67   42 00030250 ProcessGroupPolicyServices
  68   43 0002EC60 ProcessGroupPolicyShortcuts
  69   44 000304C0 ProcessGroupPolicyStartMenu

每个导出的函数的行为都相同,每个例程都会返回apmCse::PolicyMain

return apmCse::PolicyMain(
a1,
        (__int64)&`GetCseVersionPrinters'::`2'::s_wVersion,
        (__int64)L"GenerateGroupPolicyPrinters",
        (__int64)L"Group Policy Printers");

常规PolicyMain()的工作是实际应用GPO,每个不同的“应用对象”都有不同的行为,该行为基于该方法的第三个参数。稍后将在内部的动态调用中使用它,gpprefcl.dll中有66个导出方法,几乎所有方法都是以这种方式实现的,唯一的区别是第三个和第四个参数。

除此之外,我们在PolicyMain()中有多个调用。其中,有一个调用以初始化主要对象apmCSE,该对象已用25个不同的参数初始化。

之后,我们调用了apmCse :: StartClient

!silent; x gpprefcl!apm*; !igrep "DeleteFile|WriteFile|textfile"

结果:

00007ffd`ba4355f8 gpprefcl!apmDeleteFile(long __cdeclapmDeleteFile(unsigned short const *))
00007ffd`ba4333cc gpprefcl!apmWriteTextFile (long __cdecl apmWriteTextFile(class apmString const &,unsigned short const *,bool))
00007ffd`ba4332b8 gpprefcl!apmWriteFile (long __cdecl apmWriteFile(unsigned char *,unsigned long,unsigned short const *,bool))
00007ffd`ba407d74 gpprefcl!apmConfigFile::deleteFiles (private: long __cdecl apmConfigFile::deleteFiles(unsigned short const *,bool))
00007ffd`ba434008 gpprefcl!apmDeleteFileSystemItem (long __cdecl apmDeleteFileSystemItem(unsigned short const *,unsigned short const *,struct _WIN32_FIND_DATAW *,bool,bool,bool,bool))

在对结果进行过滤之后,由于在其中执行文件系统操作的可能性很高,因此可以在这些方法中设置断点,这可能会导致我们很容易发动文件系统攻击。

输出看起来很有希望,每个例程似乎都执行文件系统操作。除了在每个例程中放置一个断点之外,我们还可以检查是否有一个线程模拟api的调用。如果不是,我们就成功了。

事实证明,apmClientContext类具有用于impersonateLoggedOnUser()的封装函数,称为apmClientContext :: impersonate()。通过继续此路径,我们应该检查上述文件系统例程中是否有对apmClientContext :: impersonate()的引用。

现在,在许多情况下,应在gpprefcl.dll模块中按原样使用该模拟例程。但是,如果我们检查对该例程的外部参照,则看不到上述例程的引用。我们需要更进一步,例如检查gpprefcl!apmWriteFile()及其调用者gpprefcl!apmDeleteFile()的调用者例程:

apmClient::cseApplyGpoPolicies() → apmClient::UpdateGph() → gpprefcl!apmWriteFile()
apmClient::cseRemoveLastGpoPolicies()→ apmClient::PurgeGph() → gpprefcl!apmDeleteFile()

上面提到的两种方法都不会调用apmClientContext :: impersonate()。应用GPO的方法是apmClient :: cseApplyGpoPolicies()和apmClient :: cseRemoveLastGpoPolicies()。当Windbg到达gpprefcl!apmWriteFile()的断点时,我在查看调用堆栈后才意识到这一点:

00 000000dd`d27fc3a8 00007ffd`ba3f413f gpprefcl!apmWriteFile01
 000000dd`d27fc3b0 00007ffd`ba3f2867 gpprefcl!apmClient::UpdateGph+0x13702
 000000dd`d27fc490 00007ffd`ba3f54ee
 gpprefcl!apmClient::cseApplyGpoPolicies+0x2a703 000000dd`d27fc5a0
 00007ffd`ba3f3e3a gpprefcl!apmClient::processGpoLists+0x4ca04
 000000dd`d27fc710 00007ffd`ba41d49a gpprefcl!apmClient::Main+0x1a05
 000000dd`d27fc740 00007ffd`ba41d310
 gpprefcl!apmCse::StartClient+0xee06 000000dd`d27fdc00
 00007ffd`ba41e911 gpprefcl!apmCse::PolicyMain+0x25007
 000000dd`d27fdf40 00007ffd`c9c89ce2
 gpprefcl!ProcessGroupPolicyExPrinters+0xc108 000000dd`d27fe010
 00007ffd`c9c50b25 gpsvc!ProcessGPOList+0x88209 000000dd`d27fe3d0
 00007ffd`c9c5caf5 gpsvc!ProcessGPOs+0x227c5

剩下的唯一事情就是漏洞利用。

漏洞利用

过程如下:

1. 列出你在C:\Users\user\AppData\Local\Microsoft\Group Policy\History\中的组策略GUID;

2. 如果你有多个GUID,请检查最近更新的目录;

3. 进入该目录并进入子目录,即用户SID;

4. 查看最新的修改目录;这取决于你的环境。就我而言,这是打印机;

5. 删除打印机目录内的xml文件;

6. 创建一个指向\ RPC Control的NTFS挂载点和一个带有xml的对象管理器符号链接,该链接指向C:\Windows\System32\whatever.dll。

7. 打开你喜欢的终端并运行gpupdate;

在任意位置的任意创建,你还可以使用此漏洞删除和修改系统保护的文件。根据你的GPO对象(打印机,设备,驱动器),攻击利用会有很小的变化。

总结

组策略的体系结构很复杂,Windows支持许多传统代码和自定义选项,包括不同的GPOLink类型,尽管在几乎所有代码路径中都有许多对线程模拟API的调用,但仍然缺少它。当你将策略应用于组织单位时,服务将GPO写入磁盘时就是这种情况。

此漏洞机制的存在,意味着数百万的Windows计算机如果不更新可能会受到影响,但将来Microsoft可能会提供缓解措施,即需要管理员权限才能创建连接\挂载点,这将完全防止文件系统受到攻击。

本文翻译自:https://www.cyberark.com/resources/threat-research-blog/group-policies-going-rogue如若转载,请注明原文地址:
  • 分享至
取消

感谢您的支持,我会继续努力的!

扫码支持

打开微信扫一扫后点击右上角即可分享哟

发表评论

 
本站4hou.com,所使用的字体和图片文字等素材部分来源于原作者或互联网共享平台。如使用任何字体和图片文字有侵犯其版权所有方的,嘶吼将配合联系原作者核实,并做出删除处理。
©2022 北京嘶吼文化传媒有限公司 京ICP备16063439号-1 本站由 提供云计算服务