本篇主要介绍如何以ICMLuaUtil方式BypassUAC,主要内容如下:
UAC提示框的方法总结UACME项目COM interface可以利用?COM组件?ICMLuaUtil的虚函数表vftableICMLuaUtil.ShellExec执行命令? DLL形式 C2推荐UAC提示框的方法总结这里主要说的是dll的形式,通过上面的实操,可以发现有两种方法:
UACPEB绕过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中加入恶意的宏代码实现命令执行,又或者邮件中。
rundll32.exe、wmi等,详细参考这里。
shellcode,通过其他方式加载到内存执行。
项目总结了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,即CLSIDinterface的GUID,即IIDShellExec的函数偏移前两个可以很容易找到,虚函数表可以通过OleView提示的虚函数表位置偏移找到,这里再说一种通用的方法,完全利用IDA。
第一步,用IDA打开cmlua.dll;
第二步,在左侧函数列表中搜索destructor或者constructor,双击后跳转后,上下找找可以看到调用vftable的地方:

双击跳转到变量定义位置,就可以找到虚函数表!

ICMLuaUtil.ShellExec执行命令?代码是从UACMe中摘出来的,放在了github上。
代码地址:BypassUAC
如果直接把ucmCMLuaUtilShellExecMethod这个函数直接摘出来,会发现还是会弹UAC的窗:

在vs2019中可以对Akagi项目调试,项目属性中设置命令参数为41:

直接在函数ucmCMLuaUtilShellExecMethod的地方下断:

通过分析函数调用链,发现ucmMain在调用对应方法之前先调用了supMasquradeProcess这个函数。

该函数负责进行PEB的伪装,将自己的进程信息伪装成为c:\windows\explorer.exe这个系统的可信进程,这样才能绕过UAC认证窗口,所以在使用COM组件提权之前需要先伪装一下进程才可以:

这种方式,因为修改的是自己的进程信息,并不是修改其他进程,所以一般杀软、AV是不会拦的。
代码摘自Moriarty2016和p0wnedShell。
代码地址:BypassUAC_csharp
C#版本的代码中需要注意ICMLuaUtil接口的定义,其继承自IUnKnown,该接口定义函数如下:
IUnknown::AddRef
IUnknown::QueryInterface
IUnknown::QueryInterface所以在定义ICMLuaUtil的时候,有以下两点需要注意:
IUnKnown接口;C#会自动添加;
关于C#接口的知识,可以从这里了解更多。
dll可以使用系统可信进程rundll32.exe进行加载,这样也不需要调用MarquradePEB。
代码地址:BypassUAC_Dll
导出的函数为BypassUAC,导出方式直接新建一个def文件,格式参考这里,内容如下:
LIBRARY BypassUAC
EXPORTS
BypassUAC生成之后通过CFF Explorer查看导出表:

利用rundll32.exe .\BypassUAC_Dll.dll,BypassUAC命令测试后,bypass成功!
代码地址:BypassUAC_Dll_csharp
C#导出dll函数的方式有两种:
DllExport这个NuGet包IL反编译的方式默认C#导入其他库函数,可以使用[DllImport],但是不支持[DllExport],通过NuGet包管理器安装DllExport这个包可以实现这个功能。
在vs中可以对指定项目安装这个包:

安装之后,直接使用[DllExport]导出BypassUAC函数即可:

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

如果了解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了。

.net DLR方式实现,动态加载不落地