BypassUAC
本篇主要介紹如何以ICMLuaUtil方式BypassUAC,主要內容如下:
- 過掉
UAC提示框的方法總結 UACME項目- 什么類型的
COM interface可以利用? - 如何快速找到系統中的所有可利用的
COM組件? - 定位
ICMLuaUtil的虛函數表vftable - 如何調用
ICMLuaUtil.ShellExec執行命令?- C++ version
- CSharp version
- 兩個注意點
DLL形式- C++ dll導出函數方式
- C# dll導出函數方式
- 一個坑
- 值得研究的
C2推薦
過掉UAC提示框的方法總結
這里主要說的是dll的形式,通過上面的實操,可以發現有兩種方法:
- 基於白名單程序繞過
UAC - 偽裝進程
PEB繞過UAC - 無文件技術
偽裝進程的方式其實也可以算做借助了白名單,但是沒有直接調用白名單進程,所以單獨列出來了。
基於白名單程序繞過UAC
有些系統程序是直接獲取管理員權限,而不會觸發UAC彈框,這類程序稱為白名單程序,例如:slui.exe、wusa.exe、taskmgr.exe、msra.exe、eudcedit.exe、eventvwr.exe、CompMgmtLauncher.exe,rundll32.exe,explorer.exe等等。
常見的利用方式有:
DLL注入(RDI技術),一般注入到常駐內存的可信進程,如:explorerDLL劫持,常和注冊表配合使用達到劫持目的
偽裝進程PEB繞過UAC
上面在利用COM接口的ShellExec執行命令的時候,因為執行該操作的進程身份是不可信的,所以會觸發UAC彈窗。為了能夠迷惑系統,通過修改PEB結構,讓系統誤認為這是一個可信進程,偽裝的可信進程可以是calc.exe、rundll32.exe、explorer.exe等。

利用火絨劍查看進程信息,可以看到已經識別為可信進程了:

關於PEB的結構,可以參照這里。
無文件技術
“無文件攻擊”是一種攻擊策略,其出發點就是避免將惡意文件放在磁盤上,以逃避安全檢測。無文件四種攻擊形式:
-
惡意文檔
比如:在
word中加入惡意的宏代碼實現命令執行,又或者郵件中。 -
惡意腳本
常用的腳本引擎:powershell.exe,cscript.exe,cmd.exe 和 mshta.exe,同樣不生成惡意二進制文件。
-
惡意本地程序交互
例如:
rundll32.exe、wmi等,詳細參考這里。 -
惡意內存代碼
直接生成純
shellcode,通過其他方式加載到內存執行。
UACME項目
項目總結了50多種繞過UAC的方式,並且列出具備auto-elevate能力的UAC白名單程序或接口。
利用方式主要可以分為兩大類:
- 各類
UAC白名單程序的DLL劫持(Dll Hijack) - 各類提升權限的
COM接口利用(Elevated COM interface)
項目的主程序為Akagi,其中包含了所有的method,使用vs2019本地編譯后可以使用akagi32 41或者akagi64 41啟動程序,41這個指的是README中描述的方法索引,運行后可以直接得到管理員權限的cmd窗口。
項目的Source目錄存儲的是所有子項目的源碼,其中Source/Shared存放的是被所有子項目共同引用的一些函數,本篇主要利用Akagi和Yuubari這兩個Project來探究一下如何利用COM接口提升權限。
什么類型的COM interface可以利用?
以項目中索引為41的方法為例:
Author: Oddvar Moe
Type: Elevated COM interface
Method: ICMLuaUtil
Target(s): Attacker defined
Component(s): Attacker defined
Implementation: ucmCMLuaUtilShellExecMethod
Works from: Windows 7 (7600)
Fixed in: unfixed 🙈
How: -
該方法的目標接口是ICMLuaUtil,對應Akagi項目中具體實現函數為ucmCMLuaUtilShellExecMethod,在項目中的methods/api0cradle.c文件中可以找到該方法的定義:

觀察發現這里利用的是CMSTPLUA組件的ICMLuaUtil接口。
我的測試系統Windows 10 (1909),使用OleViewDotNet工具可以查看系統中的COM接口屬性信息,注意需要以管理員權限運行。
打開CLSIDs窗口搜索cmstplua,可以快速定位該組件:

右鍵查看CMSTPLUA組件的Elevation屬性:

這里的Enabled和Auto Approval值都是True表示這個組件可以用來繞過UAC認證,這是第一點。
第二點是目標接口ICMLuaUtil需要有一個可以執行命令的地方,通過在CISIDs窗口鼠標懸浮在ICMLuaUtil上,可以看到該接口對應的二進制文件為cmlua.dll:

虛函數偏移為cmlua.dll+0x6360,通過IDA打開該系統文件(c:\windows\system32\cmlua.dll),跳到虛函數表的位置,可以看到ICMLuaUtil接口的虛函數表:

摘出來看接口函數如下:
01 QueryInterface(_GUID const &,void * *)
02 AddRef(void)
03 Release(void)
04 SetRasCredentials(ushort const *,ushort const *,ushort const *,int)
05 SetRasEntryProperties(ushort const *,ushort const *,ushort * *,ulong)
06 DeleteRasEntry(ushort const *,ushort const *)
07 LaunchInfSection(ushort const *,ushort const *,ushort const *,int)
08 LaunchInfSectionEx(ushort const *,ushort const *,ulong)
09 CreateLayerDirectory(ushort const *)
10 ShellExec(ushort const *,ushort const *,ushort const *,ulong,ulong)
11 SetRegistryStringValue(int,ushort const *,ushort const *,ushort const *)
12 DeleteRegistryStringValue(int,ushort const *,ushort const *)
13 DeleteRegKeysWithoutSubKeys(int,ushort const *,int)
14 DeleteRegTree(int,ushort const *)
15 ExitWindowsFunc(void)
16 AllowAccessToTheWorld(ushort const *)
17 CreateFileAndClose(ushort const *,ulong,ulong,ulong,ulong)
18 DeleteHiddenCmProfileFiles(ushort const *)
19 CallCustomActionDll(ushort const *,ushort const *,ushort const *,ushort const *,ulong *)
20 RunCustomActionExe(ushort const *,ushort const *,ushort * *)
21 SetRasSubEntryProperties(ushort const *,ushort const *,ulong,ushort * *,ulong)
22 DeleteRasSubEntry(ushort const *,ushort const *,ulong)
23 SetCustomAuthData(ushort const *,ushort const *,ushort const *,ulong)
其中第10個函數ShellExec從IDA中看到該函數調用了ShellExecuteEx這個Windows API實現了命令執行:

通過對ICMLuaUtil接口的分析,可以看出可以用來BypassUAC執行命令的COM組件需要有兩個特點:
elevation屬性啟用,且開啟Auto Approval;COM組件中的接口存在可以命令執行的地方,例如ICMLuaUtil的ShellExec;
如何快速找到系統中的所有可利用的COM組件?
除了通過上面的方式在OleView中手動去找,還可以通過UACMe項目提供的Yuubari工具快速查看系統UAC設定信息以及所有可以利用的程序和COM組件,使用方法如下:
使用VS2019加載Yuubari,生成后會得到二進制文件UacInfo64.exe,運行后在同目錄生成一個log文件記錄所有輸出結果:

從這里面可以找到所有的Autoelevated COM objects,包括CMSTPLUA組件的信息:

定位ICMLuaUtil的虛函數表vftable
通過分析UACMe中的ucmCMLuaUtilShellExecMethod實現可以知道想要利用COM接口,需要知道這幾個東西:
- 標識
COM組件的GUID,即CLSID - 標識
interface的GUID,即IID - 該接口的虛函數表,主要用來找到
ShellExec的函數偏移
前兩個可以很容易找到,虛函數表可以通過OleView提示的虛函數表位置偏移找到,這里再說一種通用的方法,完全利用IDA。
第一步,用IDA打開cmlua.dll;
第二步,在左側函數列表中搜索destructor或者constructor,雙擊后跳轉后,上下找找可以看到調用vftable的地方:

雙擊跳轉到變量定義位置,就可以找到虛函數表!

如何調用ICMLuaUtil.ShellExec執行命令?
c++ version
代碼是從UACMe中摘出來的,放在了github上。
代碼地址:BypassUAC
如果直接把ucmCMLuaUtilShellExecMethod這個函數直接摘出來,會發現還是會彈UAC的窗:

在vs2019中可以對Akagi項目調試,項目屬性中設置命令參數為41:

直接在函數ucmCMLuaUtilShellExecMethod的地方下斷:

通過分析函數調用鏈,發現ucmMain在調用對應方法之前先調用了supMasquradeProcess這個函數。

該函數負責進行PEB的偽裝,將自己的進程信息偽裝成為c:\windows\explorer.exe這個系統的可信進程,這樣才能繞過UAC認證窗口,所以在使用COM組件提權之前需要先偽裝一下進程才可以:

這種方式,因為修改的是自己的進程信息,並不是修改其他進程,所以一般殺軟、AV是不會攔的。
CSharp version
代碼摘自Moriarty2016和p0wnedShell。
代碼地址:BypassUAC_csharp
兩個注意點
C#版本的代碼中需要注意ICMLuaUtil接口的定義,其繼承自IUnKnown,該接口定義函數如下:
IUnknown::AddRef
IUnknown::QueryInterface
IUnknown::QueryInterface
所以在定義ICMLuaUtil的時候,有以下兩點需要注意:
- 指明繼承自
IUnKnown接口; - 繼承的函數不需要加上,
C#會自動添加;

關於C#接口的知識,可以從這里了解更多。
DLL 形式
如何使用?
dll可以使用系統可信進程rundll32.exe進行加載,這樣也不需要調用MarquradePEB。
C++ dll導出函數的方式
代碼地址:BypassUAC_Dll
導出的函數為BypassUAC,導出方式直接新建一個def文件,格式參考這里,內容如下:
LIBRARY BypassUAC
EXPORTS
BypassUAC
生成之后通過CFF Explorer查看導出表:

利用rundll32.exe .\BypassUAC_Dll.dll,BypassUAC命令測試后,bypass成功!
C# 導出dll函數的方式
代碼地址:BypassUAC_Dll_csharp
C#導出dll函數的方式有兩種:
- 使用
DllExport這個NuGet包 - 通過
IL反編譯的方式
DllExport
默認C#導入其他庫函數,可以使用[DllImport],但是不支持[DllExport],通過NuGet包管理器安裝DllExport這個包可以實現這個功能。
在vs中可以對指定項目安裝這個包:

安裝之后,直接使用[DllExport]導出BypassUAC函數即可:

重新生成dll文件,在CFF中查看,已經導出成功:

IL 反編譯
如果了解Java的,java文件首先編譯成class,然后交給JVM去解釋成機器碼。.net為了跨平台,這里類似,同樣有一個中間語言的文件,但不是class了,而是IL。
通過修改IL文件,也可以導出dll函數。
首先去除[DllExport]后將dll代碼編譯,編譯后的dll文件是看不到Export Directory的。

然后ildasm把dll文件反編譯成il文件,命令如下:
ildasm BypassUAC_Dll_csharp.dll /out=BypassUAC_Dll_csharp.il
打開生成的BypassUAC_Dll_csharp.il文件,找到需要導出的目標函數BypassUAC,在函數開頭處添加如下代碼:
.export [1]

保存后,需要使用ilasm再把il編譯成dll文件,這里遇到一個坑,如果按照如下命令進行編譯:
ilasm BypassUAC_Dll_csharp.il /dll /out=BypassUAC_Dll_csharp_exp.dll
發現使用rundll32.exe .\BypassUAC_Dll_csharp_exp.dll,BypassUAC運行后沒有任何反應。
在BypassUAC函數開頭處添加一個MessageBox彈窗,再次運行彈框之后,附加到windbg調試,讓程序再次跑起來,運行結束后在windbg中可以看到:

進程加載的cmlua.dll文件並不是system32目錄,而是SysWOW64的,SysWOW64放的是32位系統文件,程序為什么去加載的是32位的,使用CFF看一下生成的dll文件類型:

問題的根源就是這里,利用IL轉之前的dll是64位的,轉之后變成了32位的,解決方法很簡單,使用ilasm的時候添加一個/X64參數就可以了:
ilasm BypassUAC_Dll_csharp.il /dll /X64 /out=BypassUAC_Dll_csharp_exp.dll
這樣就可以成功的BypassUAC了。

值得研究的C2推薦
-
Python
- Empire,官方已經不維護了不推薦用,但是值得研究借鑒
- Pupy,很適合玩Python的研究
- SILENTTRINITY,利用的
.net DLR方式實現,動態加載不落地 - PoshC2
-
.NET
- Covenant,網頁版的C2
