【COM】通过COM组件IFileOperation越权复制文件

概述:本文是基于伪装PEB进行越权复制文件相关学习研究进行的拓展文章,主要记录通过COM组件越权复制文件。

[toc]

本篇博客参考的文章较多,主要描述和记录一下伪装PEB进行越权复制的操作。

伪装PEB进行越权复制

伪装PEB

主要操作就是修改当前进程的 ImagePathName CommandLineFullDllNameBaseDllName 这几个变量,通过修改成为与系统可信的进程一样的内容进而实现越权操作。3gstudent 提供了Demo,可以去Github看下相关逻辑,这里不做过多解释。

  • _RTL_USER_PROCESS_PARAMETERS.ImagePathName

  • _RTL_USER_PROCESS_PARAMETERS.CommandLine(可选)

  • _LDR_DATA_TABLE_ENTRY.FullDllName

  • _LDR_DATA_TABLE_ENTRY.BaseDllName

源代码路径:https://github.com/3gstudent/Use-COM-objects-to-bypass-UAC/blob/master/MasqueradePEB.cpp

原理:COM组件通过 Process Status API (PSAPI) 读取进程PEB结构中的Commandline来识别它们正在运行的进程。如果将进程的 Path 改成可信文件(如explorer.exe),就能够欺骗PSAPI,调用COM组件IFileOperation实现越权复制

PSAPI:进程状态API,主要提供用于检索一下信息的函数集:

COM调用堆栈如下所示

如下所示为启动一个uac进程到该进程发起rpc的调用堆栈,须知当前进程的提权是通过 RPC 调用到 Appinfo 服务的。流程如下:

  1. uac 通过 RPC 请求到 AppInfo 服务
  2. APPInfo 通过 AiLaunchProcess 接口创建 consent.exe 进程,调用时会传入一个结构体地址,调用命令行为 consent.exe ppid 结构体长度 结构体地址
  3. consent.exe 会根据用户操作将结果写入结构体中。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
[0x0]   RPCRT4!LRPC_BASE_CCALL::DoAsyncSend+0x21c   0xbddbc4   0x76538061   
[0x1] RPCRT4!LRPC_CCALL::AsyncSend+0x61 0xbddc48 0x7653796e
[0x2] RPCRT4!I_RpcSend+0x7e 0xbddc64 0x75dda34a
[0x3] combase!CAsyncCall::RpcSendRequest+0xaf 0xbddc8c 0x75e59faa
[0x4] combase!ThreadSendReceive+0xa4f 0xbdddd0 0x75dd77f8
[0x5] combase!CSyncClientCall::SwitchAptAndDispatchCall+0xadb 0xbdddd0 0x75dd77f8
[0x6] combase!CSyncClientCall::SendReceive2+0xbca 0xbdddd0 0x75dd77f8
[0x7] combase!SyncClientCallRetryContext::SendReceiveWithRetry+0x29 0xbddfa8 0x75e5c0a7
[0x8] combase!CSyncClientCall::SendReceiveInRetryContext+0x29 0xbddfa8 0x75e5c0a7
[0x9] combase!ClassicSTAThreadSendReceive+0x98 0xbddfa8 0x75e5c0a7
[0xa] combase!CSyncClientCall::SendReceive+0x2a7 0xbde06c 0x75de0468
[0xb] combase!CClientChannel::SendReceive+0x79 0xbde258 0x76516b23
[0xc] combase!NdrExtpProxySendReceive+0xc8 0xbde258 0x76516b23
[0xd] RPCRT4!NdrClientCall2+0x9e3 0xbde280 0x75eaeaa0
[0xe] combase!ObjectStublessClient+0x70 0xbde6d0 0x75ea6a3f
[0xf] combase!ObjectStubless+0xf 0xbde6f0 0x75e113f5
[0x10] combase!CRpcResolver::DelegateActivationToSCM+0x30e 0xbde700 0x75e8c69c
[0x11] combase!CRpcResolver::CreateInstance+0x14 0xbde80c 0x75e12d54
[0x12] combase!CClientContextActivator::CreateInstance+0x144 0xbde828 0x75e124d4
[0x13] combase!ActivationPropertiesIn::DelegateCreateInstance+0xc4 0xbdea88 0x75e3a762
[0x14] combase!ICoCreateInstanceEx+0xc12 0xbdead4 0x75e399d1
[0x15] combase!CComActivator::DoCreateInstance+0x231 0xbdedd8 0x75f4bec1
[0x16] combase!CComActivator::StandardCreateInstance+0x81 0xbdeecc 0x75ba8686
[0x17] ole32!CLUAMoniker::CreateInstance+0x126 0xbdf73c 0x63e8f20f
[0x18] comsvcs!CNewMoniker::BindToObject+0x12f 0xbdf77c 0x75b869cd
[0x19] ole32!CCompositeMoniker::BindToObject+0x19d 0xbdf7f8 0x75b84f9e
[0x1a] ole32!CoGetObject+0xbe 0xbdf82c 0x74e70e88
[0x1b] windows_storage!CoCreateInstanceAsAdmin+0xb2 0xbdf878 0x74e7e364
[0x1c] windows_storage!CFileOperation::_CreateElevatedCopyengine+0x43 0xbdfb80 0x74e8293a
[0x1d] windows_storage!CFileOperation::_RunElevatedOperation+0x4d 0xbdfbf4 0x74ce1761
[0x1e] windows_storage!CFileOperation::_ProcessLUAOperations+0x118056 0xbdfc28 0x74bc878a
[0x1f] windows_storage!CFileOperation::PrepareAndDoOperations+0x238 0xbdfc7c 0x74bc2274
[0x20] windows_storage!CFileOperation::PerformOperations+0xd4 0xbdfcec 0xa03f55
[0x21] MasqueradePEBtoCopyfile!wmain+0x365 0xbdfd1c 0xa047fe
[0x22] MasqueradePEBtoCopyfile!__scrt_wide_environment_policy::initialize_environment+0x2e 0xbdfe80 0xa04667
[0x23] MasqueradePEBtoCopyfile!__crt_char_traits<wchar_t>::tcscpy_s<wchar_t * &,unsigned int,wchar_t const * const &>+0x1d7 0xbdfe94 0xa044fd
[0x24] MasqueradePEBtoCopyfile!__crt_char_traits<wchar_t>::tcscpy_s<wchar_t * &,unsigned int,wchar_t const * const &>+0x6d 0xbdfef0 0xa04878
[0x25] MasqueradePEBtoCopyfile!wmainCRTStartup+0x8 0xbdfef8 0x76cdfcc9
[0x26] KERNEL32!BaseThreadInitThunk+0x19 0xbdff00 0x77607c6e
[0x27] ntdll!__RtlUserThreadStart+0x2f 0xbdff10 0x77607c3e
[0x28] ntdll!_RtlUserThreadStart+0x1b 0xbdff6c 0x0

CoGetObject 的创建管理员对象

image-20231205182252389

到达 AppInfo 后, 调用堆栈如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[0x0]   ntdll!NtCreateUserProcess   0xdf231fc698   0x7ff9da72b473   
[0x1] KERNELBASE!CreateProcessInternalW+0xfe3 0xdf231fc6a0 0x7ff9da728a03
[0x2] KERNELBASE!CreateProcessAsUserW+0x63 0xdf231fdc70 0x7ff9daa4de30
[0x3] KERNEL32!CreateProcessAsUserWStub+0x60 0xdf231fdce0 0x7ff9d4a4526b
[0x4] appinfo!AiLaunchProcess+0x8eb 0xdf231fdd50 0x7ff9d4a4789d
[0x5] appinfo!AiLaunchConsentUI+0x51d 0xdf231fec40 0x7ff9d4a471e3
[0x6] appinfo!AiCheckLUA+0x343 0xdf231fee60 0x7ff9d4a62ff1
[0x7] appinfo!AipGetTokenForService+0x245 0xdf231ff040 0x7ff9d4a639b6
[0x8] appinfo!RAiGetTokenForCOM+0x206 0xdf231ff160 0x7ff9db4ab4b3
[0x9] RPCRT4!Invoke+0x73 0xdf231ff220 0x7ff9db50c5ea
[0xa] RPCRT4!Ndr64AsyncServerWorker+0x39a 0xdf231ff2d0 0x7ff9db489188
[0xb] RPCRT4!DispatchToStubInCNoAvrf+0x18 0xdf231ff3e0 0x7ff9db46a3a6
[0xc] RPCRT4!RPC_INTERFACE::DispatchToStubWorker+0x1a6 0xdf231ff430 0x7ff9db469fd6
[0xd] RPCRT4!RPC_INTERFACE::DispatchToStubWithObject+0x186 0xdf231ff510 0x7ff9db47730f
[0xe] RPCRT4!LRPC_SCALL::DispatchRequest+0x16f 0xdf231ff5b0 0x7ff9db4768c8
[0xf] RPCRT4!LRPC_SCALL::HandleRequest+0x7f8 0xdf231ff680 0x7ff9db475eb1
[0x10] RPCRT4!LRPC_ADDRESS::HandleRequest+0x341 0xdf231ff790 0x7ff9db47591e
[0x11] RPCRT4!LRPC_ADDRESS::ProcessIO+0x89e 0xdf231ff830 0x7ff9db47a032
[0x12] RPCRT4!LrpcIoComplete+0xc2 0xdf231ff970 0x7ff9dc990330
[0x13] ntdll!TppAlpcpExecuteCallback+0x260 0xdf231ffa10 0x7ff9dc9c2f86
[0x14] ntdll!TppWorkerThread+0x456 0xdf231ffa90 0x7ff9daa47344
[0x15] KERNEL32!BaseThreadInitThunk+0x14 0xdf231ffd90 0x7ff9dc9c26b1
[0x16] ntdll!RtlUserThreadStart+0x21 0xdf231ffdc0 0x0

越权原理

基于以上描述,我们大概了解了启动一个UAC进程的流程和过程。那么,到底是在哪一步判断中进程的UAC鉴权操作。

处理逻辑:AIS(appinfo.dll) 服务:处理提升请求

主要看一下 AipGetTokenForService 函数。以下 2 种情况可能不会弹 UAC 对话框,会自动提升至管理员权限(越权也是基于白名单):

UAC 流程

简单说明一下UAC的请求流程。

  1. 程序配置为自动提升

如果程序中配置了 autoElevate 为 true,会尝试自动提升

​ 1. 先判断是否限制自动提权策略

自动提权策略

​ 2. 判断是否设置了 autoElevate

判断autoElevate
  1. 白名单

判断要执行的程序是否属于白名单,在白名单之内就调用 AipIsValidAutoApprovalEXE 函数检查程序签名等信息,如果不在就基本结束这个函数了

白名单列表

依靠上述两个判断还是不够的,在 appinfo 中还有如下所示的几个列表。

  1. g_lpExcludedWindowsDirs

    g_lpExcludedWindowsDirs
  2. g_lpIncludedWindowsDirs

    g_lpIncludedWindowsDirs
  3. g_lpIncludedSystemDirs

    g_lpIncludedSystemDirs
  4. g_lpIncludedPFDirs

    g_lpIncludedPFDirs

consent进程执行逻辑

在进行上述判断之后会创建 consent 进程,传递父进程id以及内存地址

  1. 写入consent进程参数
consent.exe 命令行
  1. 拉起consent进程
启动 Consent进程

Buffer 就是 consent 进程的 commandline。

consent进程
  1. 继续分析 consent 进程的执行逻辑。调用后,首先对命令行进行了解析。
consent 参数解析
  1. 随后读取了传入的结构体
读取 _CONSENTUI_PARAM_HREADER 结构体
  1. 提权操作结束后,将用户操作结果写回给 appinfo 进程直接中。
返回操作结果

弹窗逻辑

但是中间弹窗的过程被省略了,这里可以调试分析一下。主要就是通过查看COM组件有没有自提升权限进而判断是否需要弹窗,查看 CuiIsCOMClassAutoApprovable 即可。

越权逻辑

越权主要还是基于以下两点,流程上和 consent.exe 是不涉及的。

  1. 各类UAC白名单程序的DLL劫持(Dll Hijack)

  2. 各类提升权限的COM接口利用(Elevated COM interface)

    可利用的COM接口有哪些,可以在 HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\UAC\\COMAutoApprovalList 注册表下查看值为 键值项为1 的项为可以自提升的。

本文伪装PEB所示的代码就是通过白名单 g_lpIncludedSystemDirs 实现的。检查的堆栈为:

appinfo!RAiGetTokenForCOM -> appinfo!AipGetTokenForService -> appinfo!AiCheckSecureApplicationDirectory -> appinfo!AipCheckSecureWindowsDirectory 或者 AipCheckSecurePFDirectory(取决于传递的路径)

AipGetTokenForService

修改为 C:\windows\explorer.exe 之后,其相当于从白名单启动的进程,因此可以绕过consent,直接获取权限。

文件启动路径

获取程序运行路径的堆栈

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
[0x0]   combase!<lambda_7438a189e512c84b56128b16ff6946f3>::operator()+0x9d   0x71d5d8   0x75070f45   
[0x1] combase!CRpcResolver::GetConnection+0x70 0x71db48 0x75051915
[0x2] combase!CoInitializeSecurity+0xe5 0x71db78 0x750ed384
[0x3] combase!InitializeSecurity+0x4f 0x71ddec 0x7509196b
[0x4] combase!CComApartment::InitRemoting+0x8d 0x71de20 0x750b1ce2
[0x5] combase!CComApartment::StartServer+0x60 0x71de64 0x7506dd3d
[0x6] combase!InitChannelIfNecessary+0xb2 0x71de64 0x7506dd3d
[0x7] combase!CGIPTable::RegisterInterfaceInGlobalHlp+0x4d 0x71de80 0x7506dce5
[0x8] combase!CGIPTable::RegisterInterfaceInGlobal+0x15 0x71dec0 0x7453b91b
[0x9] windows_storage!CFreeThreadedItemContainer::Initialize+0x8b 0x71ded8 0x7453b1b0
[0xa] windows_storage!CFSPropertyStoreFactory_CreateInstance+0x360 0x71df0c 0x7451ab6b
[0xb] windows_storage!CFSFolder::_BindToChild+0x10e 0x71e15c 0x7454e000
[0xc] windows_storage!CFSFolder::_Bind+0xa10 0x71e928 0x7454d279
[0xd] windows_storage!CFSFolder::BindToObject+0x4c9 0x71ec3c 0x74562745
[0xe] windows_storage!CShellItem::BindToHandler+0x525 0x71ef1c 0x7455e92e
[0xf] windows_storage!CShellItem::_GetPropertyStoreWorker+0x2ee 0x71f1ec 0x7457313d
[0x10] windows_storage!CShellItem::GetPropertyStoreForKeys+0x11d 0x71f260 0x745a1977
[0x11] windows_storage!CShellItem::GetString+0x57 0x71f4e8 0x745a18e3
[0x12] windows_storage!IShellItem_GetFileName+0x5b 0x71f530 0x745a0934
[0x13] windows_storage!CPendingOperation::AddToTree+0x114 0x71f55c 0x745a07fb
[0x14] windows_storage!CCopyTree::InitializeFromPendingList+0x9a 0x71f7b0 0x7459224f
[0x15] windows_storage!CFileOperation::PerformOperations+0xaf 0x71f7d4 0x543f55
[0x16] MasqueradePEBtoCopyfile!wmain+0x365 0x71f818 0x5447fe
[0x17] MasqueradePEBtoCopyfile!__scrt_wide_environment_policy::initialize_environment+0x2e 0x71f97c 0x544667
[0x18] MasqueradePEBtoCopyfile!__crt_char_traits<wchar_t>::tcscpy_s<wchar_t * &,unsigned int,wchar_t const * const &>+0x1d7 0x71f990 0x5444fd
[0x19] MasqueradePEBtoCopyfile!__crt_char_traits<wchar_t>::tcscpy_s<wchar_t * &,unsigned int,wchar_t const * const &>+0x6d 0x71f9ec 0x544878
[0x1a] MasqueradePEBtoCopyfile!wmainCRTStartup+0x8 0x71f9f4 0x7612fcc9
[0x1b] KERNEL32!BaseThreadInitThunk+0x19 0x71f9fc 0x76fd7c6e
[0x1c] ntdll!__RtlUserThreadStart+0x2f 0x71fa0c 0x76fd7c3e
[0x1d] ntdll!_RtlUserThreadStart+0x1b 0x71fa68 0x0
image-20231205173634633

获取dll的堆栈

1
2
[0x0]   ntdll!LdrGetDllFullName   0x71d974   0x76de5a56   
[0x1] KERNELBASE!GetModuleFileNameW+0x46 0x71d978 0x750ff6ee

【COM】通过COM组件IFileOperation越权复制文件
https://hodlyounger.github.io/A_OS/Windows/COM/【COM】通过COM组件IFileOperation越权复制文件/
作者
mingming
发布于
2023年11月21日
许可协议