BypassUAC

December 17, 2023
测试
测试
测试
测试
11 分钟阅读

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.exewusa.exetaskmgr.exemsra.exeeudcedit.exeeventvwr.exeCompMgmtLauncher.exerundll32.exeexplorer.exe等等。

常见的利用方式有:

  • DLL注入(RDI技术),一般注入到常驻内存的可信进程,如:explorer
  • DLL劫持,常和注册表配合使用达到劫持目的

伪装进程PEB绕过UAC

上面在利用COM接口的ShellExec执行命令的时候,因为执行该操作的进程身份是不可信的,所以会触发UAC弹窗。为了能够迷惑系统,通过修改PEB结构,让系统误认为这是一个可信进程,伪装的可信进程可以是calc.exerundll32.exeexplorer.exe等。

利用火绒剑查看进程信息,可以看到已经识别为可信进程了:

关于PEB的结构,可以参照这里。

无文件技术

“无文件攻击”是一种攻击策略,其出发点就是避免将恶意文件放在磁盘上,以逃避安全检测。无文件四种攻击形式:

  1. 恶意文档 比如:在word中加入恶意的宏代码实现命令执行,又或者邮件中。
  2. 恶意脚本 常用的脚本引擎:powershell.exe,cscript.exe,cmd.exe 和 mshta.exe,同样不生成恶意二进制文件。
  3. 恶意本地程序交互 例如:rundll32.exewmi等,详细参考这里。
  4. 恶意内存代码 直接生成纯shellcode,通过其他方式加载到内存执行。

UACME项目

项目地址:https://github.com/hfiref0x/UACME

项目总结了50多种绕过UAC的方式,并且列出具备auto-elevate能力的UAC白名单程序或接口。

利用方式主要可以分为两大类:

  1. 各类UAC白名单程序的DLL劫持(Dll Hijack
  2. 各类提升权限的COM接口利用(Elevated COM interface

项目的主程序为Akagi,其中包含了所有的method,使用vs2019本地编译后可以使用akagi32 41或者akagi64 41启动程序,41这个指的是README中描述的方法索引,运行后可以直接得到管理员权限的cmd窗口。

项目的Source目录存储的是所有子项目的源码,其中Source/Shared存放的是被所有子项目共同引用的一些函数,本篇主要利用AkagiYuubari这两个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属性:

这里的EnabledAuto 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个函数ShellExecIDA中看到该函数调用了ShellExecuteEx这个Windows API实现了命令执行:

通过对ICMLuaUtil接口的分析,可以看出可以用来BypassUAC执行命令的COM组件需要有两个特点:

  1. elevation属性启用,且开启Auto Approval
  2. COM组件中的接口存在可以命令执行的地方,例如ICMLuaUtilShellExec

如何快速找到系统中的所有可利用的COM组件?

除了通过上面的方式在OleView中手动去找,还可以通过UACMe项目提供的Yuubari工具快速查看系统UAC设定信息以及所有可以利用的程序和COM组件,使用方法如下:

使用VS2019加载Yuubari,生成后会得到二进制文件UacInfo64.exe,运行后在同目录生成一个log文件记录所有输出结果:

从这里面可以找到所有的Autoelevated COM objects,包括CMSTPLUA组件的信息:

定位ICMLuaUtil的虚函数表vftable

通过分析UACMe中的ucmCMLuaUtilShellExecMethod实现可以知道想要利用COM接口,需要知道这几个东西:

  • 标识COM组件的GUID,即CLSID
  • 标识interfaceGUID,即IID
  • 该接口的虚函数表,主要用来找到ShellExec的函数偏移

前两个可以很容易找到,虚函数表可以通过OleView提示的虚函数表位置偏移找到,这里再说一种通用的方法,完全利用IDA

第一步,用IDA打开cmlua.dll; 第二步,在左侧函数列表中搜索destructor或者constructor,双击后跳转后,上下找找可以看到调用vftable的地方:

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

参考:Get interface definition of undocumented COM objects

如何调用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的时候,有以下两点需要注意:

  1. 指明继承自IUnKnown接口;
  2. 继承的函数不需要加上,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函数的方式有两种:

  1. 使用DllExport这个NuGet
  2. 通过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的。

然后ildasmdll文件反编译成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转之前的dll64位的,转之后变成了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

其他参考

  • T1088

继续阅读

更多来自我们博客的帖子

如何安装 BuddyPress
由 测试 December 17, 2023
经过差不多一年的开发,BuddyPress 这个基于 WordPress Mu 的 SNS 插件正式版终于发布了。BuddyPress...
阅读更多
Filter如何工作
由 测试 December 17, 2023
在 web.xml...
阅读更多
如何理解CGAffineTransform
由 测试 December 17, 2023
CGAffineTransform A structure for holding an affine transformation matrix. ...
阅读更多