Windows Server 2008 R2-2009 NetMan DLL劫持漏洞分析
2020-04-24 10:09:42 Author: www.4hou.com(查看原文) 阅读量:315 收藏

导语:​从2008R2至2019年所有Windows Server版本都存在一个DLL劫持漏洞,受影响的NT AUTHORITY\SYSTEM服务与该DLL加载可以由普通用户触发,不需要重新启动,需要发现某些%PATH%目录配置了弱权限,这可能是我所知道的最直接的权限提升最直接的一种方法。

从2008R2至2019年所有Windows Server版本都存在一个DLL劫持漏洞,受影响的NT AUTHORITY\SYSTEM服务与该DLL加载可以由普通用户触发,不需要重新启动,需要发现某些%PATH%目录配置了弱权限,这可能是我所知道的最直接的权限提升最直接的一种方法。目前似乎没有公开资料介绍过这一点,我将在本文中与大家分享我的发现。

0x01 分析概述

首先,Microsoft不认为DLL劫持是一个漏洞。我倾向于同意这一说法,因为默认情况下,即使通过具有更高特权的进程运行的目录从目录中加载了DLL ,普通用户也无法利用此行为。尽管在实践中,尤其是在公司环境中,常见的情况是看到使用弱文件夹权限配置的第三方应用程序。此外,如果他们将自己添加到系统的,则整个系统将面临风险,我对此的个人看法是,Microsoft应该防止这些不受控制的行为。%PATH%``%PATH%DLL加载目录尽可能大一些,以防止影响单个应用程序的配置问题成为更大影响的特权升级攻击媒介。

 https://msrc-blog.microsoft.com/2018/04/04/triaging-a-dll-planting-vulnerability/

0x02 使用Procmon搜索DLL劫持

这个发现是我在Windows 2008 R2上进行的一些研究的意外结果。尽管微软已经不再支持该系统,但它仍在公司网络中广泛使用,我一直在寻找通过CVE-2020-0668漏洞利用的最简方法。在过去的几个月中,我对Windows 10 Worsktation进行了大量研究,而在Windows 7/2008 R2上进行工作需要我忘记我学到的一些技术,并从头开始。我最初的问题是:如何轻松利用Windows 2008 R2上写入的任意文件?

 https://itm4n.github.io/cve-2020-0668-windows-service-tracing-eop/

我的第一个直觉是从IKEEXT服务开始。在Windows 2008 R2的默认安装中,此服务是停止的,并且每当启动wlbsctrl.dll时它将尝试加载缺少的库。普通用户只需尝试启动虚拟VPN连接即可轻松触发此服务。但是,仅启动一次会影响其启动模式。因此,在这种情况下利用此服务将需要重新启动计算机,因此,我不得不寻找其他方式。我也考虑了不同的DLL劫持的机会,但它们要么不容易触发,要么随机出现。

我决定从启动Process Monitor并检查由于 NAME NOT FOUND 错误而失败的DLL加载事件开始我的研究。在任意文件写入漏洞的情况下,研究不必局限于%PATH%文件夹,因此可以产生很多结果!因此,为了完善研究,我添加了一个约束。我想过滤掉尝试从该C:\Windows\System32\文件夹加载DLL ,然后在另一个Windows文件夹中找到它的进程,尤其是在需要它们正常运行的情况下,目的是尽可能避免拒绝服务。

我考虑了3个DLL劫持案例:

· 程序加载不存在的DLL中C:\Windows\System32\ ,但存在于另一个Windows目录,C:\Windows\System\例如。由于C:\Windows\System32\文件夹的优先级较高,因此这可能是有效的候选者。

· 程序加载了不存在的DLL,但使用了安全的DLL搜索顺序。因此,它仅尝试从C:\Windows\System32\例如文件夹中加载它。

· 程序将加载不存在的DLL,并使用不受限制的DLL搜索顺序。

第一种情况可能会导致拒绝服务,因此我将其放在一边。第二种情况很有趣,但是在Procmon返回的所有结果中可能很难发现。第三种情况无疑是最有趣的一种,如果该DLL不存在,则可以减少劫持该DLL时导致拒绝服务的风险,而且在Procmon中也很容易发现。

为此,我没有在Process Monitor中添加新的过滤器。相反,我只是添加了一条规则,突出显示了包含的所有路径 WindowsPowerShell。有人可能会问为什么要使用这个特定关键字。在Windows的所有(现代)版本上,C:\Windows\System32\WindowsPowerShell\v1.0\都是默认%PATH%文件夹的一部分。因此,每您看到某个程序试图从该文件夹中加载DLL时,很可能意味着该程序易于发生DLL Hijacking。

然后,我尝试启动/停止每个服务或计划的任务。而且,在花了几个小时盯着Procmon的输出之后,终于看到了:

我的第一个想法是:“如果wlanhlp.dll是可劫持的 DLL,我应该早就知道了,我可能在某个地方犯了一个错误,或者我安装了引起此问题的第三方应用程序”。但是后来我明白了,首先,在专用VM中使用Windows Server 2008 R2的全新安装。唯一的第三方应用程序是“ VMware Tools”。其次,到目前为止,我所做的所有研究主要针对Windows的Worstation版本,因为通常更方便。

幸运的是,我还安装了另一个装有Windows 7的VM,因此我迅速进行了检查。原来,此DLL在工作站版本上存在!

如果wlanhlp.dll确实与Wlan功能相关,这就可以解释了,Wlan API默认仅在Workstation版本上可用,并且必须作为Server版本上的其他组件安装。

0x03 NetMan和Missing Wlan API

从Procmon中查看事件属性,了解有关该服务的更多信息。

该进程运行为NT AUTHORITY\SYSTEM,这对我们来说是个好消息。它具有PID 972,因此在任务管理器中检查相应的服务。

在此过程中运行三个服务。查看Procmon中事件的堆栈跟踪,能够确定试图加载此DLL的名称。

我们可以看到出现了netman.dll,因此相应的服务必须是NetMan(又名Network Connections)。如果仔细查看此堆栈跟踪,还会发现几行包含对RPCRT4.dll或ole32.dll的引用。这意味着此事件很可能是通过RPC / COM触发的。如果是这样,我们也有机会可以以几行代码作为普通用户触发此事件。

DLL劫持的机会是由于以下事实:Windows 6.1(7/2008 R2)的服务器版本上默认未安装Wlan API。问题是:同一原理是否适用于其他版本的Windows?

幸运的是,我在研究中使用了大量虚拟机,并且已经设置了Windows Server 2012 R2和2019实例,因此验证时间并不长。

在Windows Server 2012 R2上,wlanhlp.dll不会在Procmon中显示,但是wlanapi.dll正好相反。查看事件的详细信息,事实证明它是相同的,这意味着Windows 6.3(8.1 / 2012 R2)也受到“影响”。

此版本的Windows现在已经很旧了,Windows 2019是否不会受到同一问题的影响?让我们来看看...

Windows Server 2019上也会发生完全相同的行为!我最终检查了从2008年到2019年所有可能版本的Windows Server。对此我不再赘述,所有版本都容易发生DLL劫持。我无法彻底测试的唯一服务器是Server 2008,我无法在此服务器上重现该问题。

0x04 触发DLL劫持事件

让我们总结一下情况。在Windows Server的所有版本中运行的NT AUTHORITY\SYSTEM,尝试加载 wlanhlp.dll 或 wlanapi.dll DLL不使用安全DLL搜索顺序。因此,最终尝试从系统环境 %PATH% 变量中列出的目录中加载此DLL。

下一步是弄清楚我们是否可以以普通用户身份触发此事件。我已经提到此行为是由于某些RPC / COM事件引起的,但这并不一定意味着我们可以触发它。此事件也可能是两个服务通过RPC相互通信的结果。

再次检查堆栈跟踪,但是这次,使用Procmon实例配置为使用Microsoft提供的公共符号,为此,我切换到用于安全研究的Windows 10 VM。

可以看到在CLanConnection::GetProperties()这里调用了该方法。在其他情况下,将CLanConnection::GetPropertiesEx()改为调用该方法,看看是否可以通过使用OleViewDotNet检查NetMan公开的COM对象来找到这些方法。

LAN Connection Class似乎是一个不错的候选者,因此,我创建了此类的实例并检查了INetConnection接口的详细信息。

我们可以看到该CLanConnection::GetProperties()方法。

首先,我看到了我从未见过的DLL劫持。然后,它是由RPC / COM事件触发的。最后,使用OleViewDotNet进行查找很简单。但是,现在只能出现一个问题:对COM对象的限制权限。

COM对象也是安全的,并且它们具有ACL,这些ACL定义了允许谁使用它们。因此,我们需要先进行检查,然后再进行下一步。

当我第一次看到Administrators和NT AUTHORITY\...时,我想了一下,只能由特权高的帐户触发。然后我看到了NT AUTHORITY\INTERACTIVE。

这实际上意味着,只有通过交互式会话进行身份验证的普通用户才能使用此COM对象。更具体地说,需要在服务器上本地登录。事实证明,当通过RDP(包括VDI)进行连接时,也会获得一个交互式会话,因此在这种情况下,普通用户可以使用此COM对象。否则,如果尝试在WinRM会话中使用它,则会收到“访问被拒绝”错误。这不像我最初预期的那样好,但这仍然是一个看似有趣的触发因素。

以下截图显示了在Windows Server 2019的RDP会话中打开的命令提示符。

至此,研究部分结束了,编写一些代码!幸运的是,该INetConnection接口已记录在此处,这使事情变得容易得多。其次,在搜索如何枚举INetConnection->EnumConnections()网络接口时,我偶然发现了Simon Mourier此处 发布的一个有趣的解决方案。

 https://docs.microsoft.com/en-us/windows/win32/api/netcon/nn-netcon-inetconnection
 
 https://stackoverflow.com/questions/5917304/how-do-i-detect-a-disabled-network-interface-connection-from-a-windows-applicati/5942359#5942359

这是我最终的PoC代码:

 // https://stackoverflow.com/questions/5917304/how-do-i-detect-a-disabled-network-interface-connection-from-a-windows-applicati/5942359#5942359
 
 #include  #include  #include  
 int main()
 {
     HRESULT hResult;
 
     typedef void(__stdcall* LPNcFreeNetconProperties)(NETCON_PROPERTIES* pProps);
     HMODULE hModule = LoadLibrary(L"netshell.dll");
     if (hModule == NULL) { return 1; }
     LPNcFreeNetconProperties NcFreeNetconProperties = (LPNcFreeNetconProperties)GetProcAddress(hModule, "NcFreeNetconProperties");
 
     hResult = CoInitializeEx(0, COINIT_MULTITHREADED);
     if (SUCCEEDED(hResult))
     {
         INetConnectionManager* pConnectionManager = 0;
         hResult = CoCreateInstance(CLSID_ConnectionManager, 0, CLSCTX_ALL, __uuidof(INetConnectionManager), (void**)&pConnectionManager);
         if (SUCCEEDED(hResult))
         {
             IEnumNetConnection* pEnumConnection = 0;
             hResult = pConnectionManager->EnumConnections(NCME_DEFAULT, &pEnumConnection);
             if (SUCCEEDED(hResult))
             {
                 INetConnection* pConnection = 0;
                 ULONG count;
                 while (pEnumConnection->Next(1, &pConnection, &count) == S_OK)
                 {
                     NETCON_PROPERTIES* pConnectionProperties = 0;
                     hResult = pConnection->GetProperties(&pConnectionProperties);
                     if (SUCCEEDED(hResult))
                     {
                         wprintf(L"Interface: %ls\n", pConnectionProperties->pszwName);
                         NcFreeNetconProperties(pConnectionProperties);
                     }
                     else
                     {
                         wprintf(L"[-] INetConnection::GetProperties() failed. Error code = 0x%08X (%ls)\n", hResult, _com_error(hResult).ErrorMessage());
                     }
                     pConnection->Release();
                 }
                 pEnumConnection->Release();
             }
             else
             {
                 wprintf(L"[-] IEnumNetConnection::EnumConnections() failed. Error code = 0x%08X (%ls)\n", hResult, _com_error(hResult).ErrorMessage());
             }
             pConnectionManager->Release();
         }
         else
         {
             wprintf(L"[-] CoCreateInstance() failed. Error code = 0x%08X (%ls)\n", hResult, _com_error(hResult).ErrorMessage());
         }
         CoUninitialize();
     }
     else
     {
         wprintf(L"[-] CoInitializeEx() failed. Error code = 0x%08X (%ls)\n", hResult, _com_error(hResult).ErrorMessage());
     }
     FreeLibrary(hModule);
     wprintf(L"Done\n");
 }

下面的截图显示了Windows Server 2008 R2上的最终结果。如我们所见,可以简单地通过枚举机器的以太网接口来触发DLL加载,机器必须至少具有一个以太网接口,否则该技术将无法正常工作。

下面的截图显示了尝试运行与通过Windows Server 2019上的远程PowerShell会话连接的普通用户相同的可执行文件。

0x05 处理INTERACTIVE限制

@ splinter_code开发了RunasCs工具,该工具实现了一种生成交互过程的通用方法。此技巧涉及Windows内部的一些细微之处,这些细微之处通常并不为人所知。我不会在这里详细介绍该技术,因为它需要专门的文章才能清楚地解释所有内容,但我将尝试给出一个高级解释。

 https://github.com/antonioCoco/RunasCs

简而言之,可以调用CreateProcessWithLogon()以创建一个交互过程。此函数需要目标用户的名称和密码。问题是,如果尝试从会话0(大多数服务所在的地方)中运行的进程中执行此操作,则子进程将立即kill。一个典型的例子是当通过WinRM进行远程连接时。所有命令都通过一个子进程执行,该子进程以你的身份运行在会话0中。

为什么会出问题呢?事实是,交互式过程之所以称为这种方式,是因为它与桌面交互,而桌面是Windows世界中一个特定的安全对象。但是,如果我们的WinRM进程在会话0中运行,则不允许与此桌面进行交互。

如在下面的截图中看到的那样,使用此技巧,我们可以生成一个交互式进程,因此NetManTrigger.exe就像在本地登录一样运行。

0x06 分析结论

经过分析,我可以说NetMan服务可能是我所知道的DLL劫持最有用的目标。但是还有另一种有趣的情况,如果破坏了另一个以LOCAL SERVICEor 身份运行的服务NETWORK SERVICE,那么仍然可以触发NetMan服务以将特权提升为SYSTEM。

最后但并非最不重要的一点是,我将其集成到了Windows特权升级检查脚本-PrivescCheck中。根据Windows的版本,该Invoke-HijackableDllsCheck函数将告诉可能通过%PATH%目录劫持了哪个DLL 。

 https://github.com/itm4n/PrivescCheck

0x07 参考资源

· Microsoft安全响应中心(MSRC)-DLL植入漏洞 https://msrc-blog.microsoft.com/2018/04/04/triaging-a-dll-planting-vulnerability/

· CVE-2020-0668-Windows服务跟踪中的一个普通特权升级漏洞 https://itm4n.github.io/cve-2020-0668-windows-service-tracing-eop/

· Windows的一些植入0-day漏洞 https://www.reddit.com/r/hacking/comments/b0lr05/a_few_binary_plating_0days_for_windows/

· RunasCs-如何得到交互式shellhttps://github.com/antonioCoco/RunasCs

本文翻译自:https://itm4n.github.io/windows-server-netman-dll-hijacking/如若转载,请注明原文地址:


文章来源: https://www.4hou.com/posts/lDY6
如有侵权请联系:admin#unsafe.sh