rapid7 / metasploit-payloads

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

Add Windows Memory Search support using regex #686

Closed sjanusz-r7 closed 10 months ago

sjanusz-r7 commented 12 months ago

This PR adds in the ability to search Windows process memory for needles. These needles are searched for using regex, provided by the tiny-regex-c library. This library has been modified to match an arbitrary length of bytes (null-bytes included). This was necessary so that we do not treat null-bytes as the end of a string/buffer, and continue trying to match the regular expression.

Example Usage

I went through the following steps:

  1. Compile the project using Visual Studio in a Windows 10 x64 VM as an x64 project in Debug mode.
  2. Mount the Framework data directory into the VM as a share with write permissions.
  3. On the VM, execute: cp -rf ./output/* /z/meterpreter && ~/Desktop/met.exe to copy the debug dll files to Framework. met.exe is a symlink to a Framework-generated Meterpreter payload.
  4. In Framework, setg MeterpreterDebugBuild true
  5. Get a session
  6. sessions -i -1
  7. irb

Now we can define our memory search function that we will use for testing:

require 'rex/post/meterpreter/extensions/stdapi/tlv'
require 'rex/post/meterpreter/extensions/stdapi/command_ids'
require 'rex/post/meterpreter/extensions/stdapi/sys/process_subsystem/memory'

def mem_search(pid, needles, min_search_len = 5, match_len = 255)
  stdapi = ::Rex::Post::Meterpreter::Extensions::Stdapi
  request = ::Rex::Post::Meterpreter::Packet.create_request(stdapi::COMMAND_ID_STDAPI_SYS_PROCESS_MEMORY_SEARCH)

  request.add_tlv(stdapi::TLV_TYPE_PID, pid)

  needles.each do | needle |
    request.add_tlv(stdapi::TLV_TYPE_MEMORY_SEARCH_NEEDLE, needle)
  end
  request.add_tlv(stdapi::TLV_TYPE_MEMORY_SEARCH_MATCH_LEN, match_len)  
  request.add_tlv(::Rex::Post::Meterpreter::TLV_TYPE_UINT, min_search_len)

  self.send_request(request)
end

Then we can use regex to search for needles:

response = mem_search(pid, ['my_needle.*'], 5, 255)
response.tlvs[2].tlvs[0].value

When searching for multiple needles, call:

response = mem_search(pid, ['needle_one', "some_needle"], 5, 255)

The changes in the tiny-regex-c library allow us to match null-bytes as well, meaning we can match wide characters:

wide_needle = "e\x00x\x00a\x00m\x00p\x00l\x00e\x00.*"
response = mem_search(pid, [wide_needle], 5, 255)

To make sure the command is stable, you can run the following in irb for a single needle:

100.times { response = mem_search(10840, ['some_needle'], 5, 255) }

or with multiple needles:

100.times { response = mem_search(10840, ['needle_one', 'needle_two.*', 'needle_three'], 5, 255) }

This should result in no memory usage increases for Meterpreter and the session should remain stable.

Debugging

When wanting to debug the new re.c file, we can first:

#include <windows.h>

This will also typedef CHAR which initially conflicted with the enum CHAR; this has been renamed to CHAR_RE. Then define a buffer, format it using sprintf and call OutputDebugStringA, mimicking what dprintf was doing.

char buffer[1024];
unsigned long long example_llu = 42;
sprintf(buffer, "Example output: %llu", example_llu);
OutputDebugStringA(buffer);

You will need to use the DebugView program to view debug logs.

Dr. Memory

I also ran the generated executable with Dr. Memory using drmemory -- ~/Desktop/met.exe:

``` Dr. Memory version 2.6.19621 build 0 built on Sep 23 2023 02:25:01 Windows version: WinVer=105;Rel=2009;Build=19045;Edition=Professional Dr. Memory results for pid 5632: "met.exe" Application cmdline: "./met.exe" Recorded 124 suppression(s) from default C:\Users\win10\scoop\apps\drmemory\current\bin64\suppress-default.txt ERROR: Failed to find "main" for limiting memory dump WARNING: application is missing line number information. Error #1: UNINITIALIZED READ: reading register eax # 0 WS2_32.dll!WSALookupServiceNextW +0x23f1 (0x00007ffa23ffded1 ) # 1 WS2_32.dll!WSALookupServiceNextW +0x2ffd (0x00007ffa23ffeade ) # 2 WS2_32.dll!WSAStartup +0x33c (0x00007ffa23ffee4d ) # 3 met.exe!? +0x0 (0x000000014000411b ) # 4 KERNEL32.dll!BaseThreadInitThunk Note: @0:00:00.609 in thread 10020 Note: instruction: cmp %eax %r12d Error #2: UNINITIALIZED READ: reading register eflags # 0 WS2_32.dll!WSALookupServiceNextW +0x240f (0x00007ffa23ffdeef ) # 1 WS2_32.dll!WSALookupServiceNextW +0x2ffd (0x00007ffa23ffeade ) # 2 WS2_32.dll!WSAStartup +0x33c (0x00007ffa23ffee4d ) # 3 met.exe!? +0x0 (0x000000014000411b ) # 4 KERNEL32.dll!BaseThreadInitThunk Note: @0:00:00.609 in thread 10020 Note: instruction: cmovo %r13 -> %rax Error #3: UNINITIALIZED READ: reading 0x000000000014fbc0-0x000000000014fbc4 4 byte(s) within 0x000000000014fbc0-0x000000000014fbc8 # 0 replace_memset [D:\a\drmemory\drmemory\drmemory\replace.c:194] # 1 WS2_32.dll!WSALookupServiceNextW +0x2448 (0x00007ffa23ffdf29 ) # 2 WS2_32.dll!WSALookupServiceNextW +0x2ffd (0x00007ffa23ffeade ) # 3 WS2_32.dll!WSAStartup +0x33c (0x00007ffa23ffee4d ) # 4 met.exe!? +0x0 (0x000000014000411b ) # 5 KERNEL32.dll!BaseThreadInitThunk Note: @0:00:00.656 in thread 10020 Note: instruction: cmp 0x30(%rsp) $0x0000000000000003 Error #4: UNINITIALIZED READ: reading 0x000000000014fb9c-0x000000000014fba0 4 byte(s) within 0x000000000014fb88-0x000000000014fba0 # 0 system call NtDeviceIoControlFile AFD_RECV_INFO # 1 MSWSOCK.dll!NSPStartup +0x55d (0x00007ffa2240c5fe ) # 2 WS2_32.dll!recv +0xc0 (0x00007ffa24001e51 ) # 3 met.exe!? +0x0 (0x0000000140004179 ) # 4 met.exe!? +0x0 (0x000000014000400a ) # 5 KERNEL32.dll!BaseThreadInitThunk Note: @0:00:01.000 in thread 10020 Error #5: UNINITIALIZED READ: reading 0x000000000014fc7c-0x000000000014fc80 4 byte(s) within 0x000000000014fc78-0x000000000014fc88 # 0 system call NtDeviceIoControlFile AFD_RECV_INFO.BufferArray # 1 MSWSOCK.dll!NSPStartup +0x55d (0x00007ffa2240c5fe ) # 2 WS2_32.dll!recv +0xc0 (0x00007ffa24001e51 ) # 3 met.exe!? +0x0 (0x0000000140004179 ) # 4 met.exe!? +0x0 (0x000000014000400a ) # 5 KERNEL32.dll!BaseThreadInitThunk Note: @0:00:01.000 in thread 10020 Error #6: UNINITIALIZED READ: reading 0x000000000014fb84-0x000000000014fb88 4 byte(s) within 0x000000000014fb70-0x000000000014fb88 # 0 system call NtDeviceIoControlFile AFD_RECV_INFO # 1 MSWSOCK.dll!NSPStartup +0x55d (0x00007ffa2240c5fe ) # 2 WS2_32.dll!recv +0xc0 (0x00007ffa24001e51 ) # 3 met.exe!? +0x0 (0x00000001400041b3 ) # 4 met.exe!? +0x0 (0x000000014000400a ) # 5 KERNEL32.dll!BaseThreadInitThunk Note: @0:00:01.125 in thread 10020 Error #7: UNINITIALIZED READ: reading 0x000000000014fc64-0x000000000014fc68 4 byte(s) within 0x000000000014fc60-0x000000000014fc70 # 0 system call NtDeviceIoControlFile AFD_RECV_INFO.BufferArray # 1 MSWSOCK.dll!NSPStartup +0x55d (0x00007ffa2240c5fe ) # 2 WS2_32.dll!recv +0xc0 (0x00007ffa24001e51 ) # 3 met.exe!? +0x0 (0x00000001400041b3 ) # 4 met.exe!? +0x0 (0x000000014000400a ) # 5 KERNEL32.dll!BaseThreadInitThunk Note: @0:00:01.125 in thread 10020 Error #8: UNINITIALIZED READ: reading register rsi # 0 met.exe!? +0x0 (0x00000001400041b9 ) # 1 met.exe!? +0x0 (0x000000014000400a ) # 2 KERNEL32.dll!BaseThreadInitThunk Note: @0:00:01.140 in thread 10020 Note: instruction: test %rsi %rsi Error #9: UNINITIALIZED READ: reading 0x000000000014f3e0-0x000000000014f3e1 1 byte(s) # 0 (0x0000000001047196) # 1 met.exe!? +0x0 (0x000000014000400a ) # 2 met.exe!? +0x0 (0x000000014000400a ) # 3 KERNEL32.dll!BaseThreadInitThunk Note: @0:00:02.780 in thread 10020 Note: instruction: cmp (%rax,%rcx) $0x00 Error #10: UNINITIALIZED READ: reading register eflags # 0 (0x000000000103d447) # 1 met.exe!? +0x0 (0x000000014000400a ) # 2 met.exe!? +0x0 (0x000000014000400a ) # 3 KERNEL32.dll!BaseThreadInitThunk Note: @0:00:02.937 in thread 10020 Note: instruction: jz $0x000000000103d431 Error #11: UNINITIALIZED READ: reading 0x000000000013f5dc-0x000000000013f5e0 4 byte(s) within 0x000000000013f5c8-0x000000000013f5e0 # 0 system call NtDeviceIoControlFile AFD_RECV_INFO # 1 MSWSOCK.dll!NSPStartup +0x55d (0x00007ffa2240c5fe ) # 2 WS2_32.dll!recv +0xc0 (0x00007ffa24001e51 ) # 3 KERNEL32.dll!BaseThreadInitThunk Note: @0:00:04.108 in thread 10020 Error #12: UNINITIALIZED READ: reading 0x000000000013f6bc-0x000000000013f6c0 4 byte(s) within 0x000000000013f6b8-0x000000000013f6c8 # 0 system call NtDeviceIoControlFile AFD_RECV_INFO.BufferArray # 1 MSWSOCK.dll!NSPStartup +0x55d (0x00007ffa2240c5fe ) # 2 WS2_32.dll!recv +0xc0 (0x00007ffa24001e51 ) # 3 KERNEL32.dll!BaseThreadInitThunk Note: @0:00:04.108 in thread 10020 Error #13: UNINITIALIZED READ: reading 0x0000000001bbfc84-0x0000000001bbfc88 4 byte(s) within 0x0000000001bbfc70-0x0000000001bbfc88 # 0 system call NtDeviceIoControlFile AFD_SEND_INFO # 1 MSWSOCK.dll!? +0x0 (0x00007ffa224093bf ) # 2 WS2_32.dll!send +0x16a (0x00007ffa23ff248b ) # 3 KERNEL32.dll!BaseThreadInitThunk Note: @0:00:08.357 in thread 6604 Error #14: UNINITIALIZED READ: reading 0x0000000001bbfd4c-0x0000000001bbfd50 4 byte(s) within 0x0000000001bbfd48-0x0000000001bbfd58 # 0 system call NtDeviceIoControlFile AFD_SEND_INFO.BufferArray # 1 MSWSOCK.dll!? +0x0 (0x00007ffa224093bf ) # 2 WS2_32.dll!send +0x16a (0x00007ffa23ff248b ) # 3 KERNEL32.dll!BaseThreadInitThunk Note: @0:00:08.373 in thread 6604 Error #15: UNADDRESSABLE ACCESS beyond heap bounds: reading 0x00000000009baed5-0x00000000009baed8 3 byte(s) within 0x00000000009baed0-0x00000000009baed8 # 0 (0x000000000103d431) # 1 KERNEL32.dll!BaseThreadInitThunk Note: @0:00:28.788 in thread 12136 Note: next higher malloc: 0x00000000009baf00-0x00000000009bb3a8 Note: refers to 0 byte(s) beyond last valid byte in prior malloc Note: prev lower malloc: 0x00000000009baea0-0x00000000009baed5 Note: instruction: mov (%rax) -> %rdx Error #16: UNADDRESSABLE ACCESS beyond heap bounds: reading 0x00000000009baed5-0x00000000009baed8 3 byte(s) within 0x00000000009baed0-0x00000000009baed8 # 0 (0x000000000103d449) # 1 KERNEL32.dll!BaseThreadInitThunk Note: @0:00:28.788 in thread 12136 Note: next higher malloc: 0x00000000009baf00-0x00000000009bb3a8 Note: refers to 0 byte(s) beyond last valid byte in prior malloc Note: prev lower malloc: 0x00000000009baea0-0x00000000009baed5 Note: instruction: mov 0xfffffff8(%rax) -> %rdx Error #17: UNADDRESSABLE ACCESS beyond heap bounds: reading 0x00000000009ccef0-0x00000000009ccf00 16 byte(s) within 0x00000000009ccee0-0x00000000009ccf00 # 0 (0x0000000003883136) # 1 KERNEL32.dll!BaseThreadInitThunk Note: @0:00:31.008 in thread 13436 Note: next higher malloc: 0x00000000009ccf10-0x00000000009ccf16 Note: refers to 0 byte(s) beyond last valid byte in prior malloc Note: prev lower malloc: 0x00000000009ccee0-0x00000000009ccef0 Note: instruction: vpcmpeqb %ymm2 (%rcx) -> %ymm1 Error #18: UNINITIALIZED READ: reading 0x0000000000a98f50-0x0000000000a98f54 4 byte(s) # 0 IPHLPAPI.DLL!ConvertInterfaceNameToLuidW +0x464 (0x00007ffa220f58b4 ) # 1 IPHLPAPI.DLL!GetAdaptersAddresses +0x55 (0x00007ffa220f43d6 ) # 2 KERNEL32.dll!BaseThreadInitThunk Note: @0:00:39.504 in thread 7392 Note: instruction: cmp (%rcx,%rax) %r12d Error #19: UNINITIALIZED READ: reading register eax # 0 IPHLPAPI.DLL!ConvertInterfaceNameToLuidW +0x519 (0x00007ffa220f5969 ) # 1 IPHLPAPI.DLL!GetAdaptersAddresses +0x55 (0x00007ffa220f43d6 ) # 2 KERNEL32.dll!BaseThreadInitThunk Note: @0:00:39.723 in thread 7392 Note: instruction: cmp %eax $0x00000100 Error #20: UNINITIALIZED READ: reading register eax # 0 IPHLPAPI.DLL!ConvertInterfaceNameToLuidW +0x53a (0x00007ffa220f598a ) # 1 IPHLPAPI.DLL!GetAdaptersAddresses +0x55 (0x00007ffa220f43d6 ) # 2 KERNEL32.dll!BaseThreadInitThunk Note: @0:00:39.723 in thread 7392 Note: instruction: cmp %eax $0x00000100 Error #21: UNINITIALIZED READ: reading 0x0000000000a98f66-0x0000000000a98f68 2 byte(s) # 0 IPHLPAPI.DLL!ConvertInterfaceNameToLuidW +0x563 (0x00007ffa220f59b3 ) # 1 IPHLPAPI.DLL!GetAdaptersAddresses +0x55 (0x00007ffa220f43d6 ) # 2 KERNEL32.dll!BaseThreadInitThunk Note: @0:00:39.723 in thread 7392 Note: instruction: data16 cmp 0x16(%rcx,%rax,2) %r12w Error #22: UNINITIALIZED READ: reading 0x0000000000a9fb16-0x0000000000a9fb18 2 byte(s) # 0 IPHLPAPI.DLL!ConvertInterfaceNameToLuidW +0x593 (0x00007ffa220f59e3 ) # 1 IPHLPAPI.DLL!GetAdaptersAddresses +0x55 (0x00007ffa220f43d6 ) # 2 KERNEL32.dll!BaseThreadInitThunk Note: @0:00:40.082 in thread 7392 Note: instruction: data16 cmp 0x06(%rcx,%rax,2) %r12w Error #23: UNINITIALIZED READ: reading 0x0000000001bbfa18-0x0000000001bbfa19 1 byte(s) # 0 IPHLPAPI.DLL!ConvertInterfaceNameToLuidW +0x5b9 (0x00007ffa220f5a09 ) # 1 IPHLPAPI.DLL!GetAdaptersAddresses +0x55 (0x00007ffa220f43d6 ) # 2 KERNEL32.dll!BaseThreadInitThunk Note: @0:00:40.613 in thread 7392 Note: instruction: cmp (%rax,%rbx) %r12l Error #24: UNINITIALIZED READ: reading register ecx # 0 IPHLPAPI.DLL!ConvertInterfaceNameToLuidW +0x83c (0x00007ffa220f5c8c ) # 1 IPHLPAPI.DLL!GetAdaptersAddresses +0x55 (0x00007ffa220f43d6 ) # 2 KERNEL32.dll!BaseThreadInitThunk Note: @0:00:40.676 in thread 7392 Note: instruction: cmp %ecx $0x00000008 Error #25: UNINITIALIZED READ: reading 0x0000000000a9fd20-0x0000000000a9fd24 4 byte(s) # 0 IPHLPAPI.DLL!ConvertInterfaceNameToLuidW +0x86a (0x00007ffa220f5cba ) # 1 IPHLPAPI.DLL!GetAdaptersAddresses +0x55 (0x00007ffa220f43d6 ) # 2 KERNEL32.dll!BaseThreadInitThunk Note: @0:00:40.676 in thread 7392 Note: instruction: cmp 0x00000210(%rdi,%rax) $0x00000002 Error #26: UNINITIALIZED READ: reading 0x0000000000a9fd1c-0x0000000000a9fd20 4 byte(s) # 0 IPHLPAPI.DLL!ConvertInterfaceNameToLuidW +0x88b (0x00007ffa220f5cdb ) # 1 IPHLPAPI.DLL!GetAdaptersAddresses +0x55 (0x00007ffa220f43d6 ) # 2 KERNEL32.dll!BaseThreadInitThunk Note: @0:00:40.691 in thread 7392 Note: instruction: cmp 0x0000020c(%rdi,%rax) $0x00000004 Error #27: UNINITIALIZED READ: reading register r8d # 0 IPHLPAPI.DLL!ConvertInterfaceNameToLuidW +0x942 (0x00007ffa220f5d92 ) # 1 IPHLPAPI.DLL!GetAdaptersAddresses +0x55 (0x00007ffa220f43d6 ) # 2 KERNEL32.dll!BaseThreadInitThunk Note: @0:00:40.691 in thread 7392 Note: instruction: cmp %r8d $0x00000005 Error #28: UNINITIALIZED READ: reading 0x00000000009d5250-0x00000000009d5258 8 byte(s) # 0 IPHLPAPI.DLL!ConvertInterfaceNameToLuidW +0x95d (0x00007ffa220f5dad ) # 1 IPHLPAPI.DLL!GetAdaptersAddresses +0x55 (0x00007ffa220f43d6 ) # 2 KERNEL32.dll!BaseThreadInitThunk Note: @0:00:40.707 in thread 7392 Note: instruction: cmp (%r9,%rcx,8) %r10 Error #29: UNINITIALIZED READ: reading 0x00000000009df010-0x00000000009df018 8 byte(s) # 0 IPHLPAPI.DLL!ConvertInterfaceNameToLuidW +0x97d (0x00007ffa220f5dcd ) # 1 IPHLPAPI.DLL!GetAdaptersAddresses +0x55 (0x00007ffa220f43d6 ) # 2 KERNEL32.dll!BaseThreadInitThunk Note: @0:00:40.754 in thread 7392 Note: instruction: cmp (%r9,%rcx,8) %r10 Error #30: UNINITIALIZED READ: reading 0x00000000009deef8-0x00000000009deefc 4 byte(s) # 0 IPHLPAPI.DLL!ConvertInterfaceNameToLuidW +0xd1b (0x00007ffa220f616b ) # 1 IPHLPAPI.DLL!GetAdaptersAddresses +0x55 (0x00007ffa220f43d6 ) # 2 KERNEL32.dll!BaseThreadInitThunk Note: @0:01:04.572 in thread 7392 Note: instruction: cmp 0x08(%rcx) $0x0000000e Error #31: UNINITIALIZED READ: reading 0x00000000009df538-0x00000000009df53c 4 byte(s) # 0 IPHLPAPI.DLL!ConvertInterfaceNameToLuidW +0xd93 (0x00007ffa220f61e3 ) # 1 IPHLPAPI.DLL!GetAdaptersAddresses +0x55 (0x00007ffa220f43d6 ) # 2 KERNEL32.dll!BaseThreadInitThunk Note: @0:01:04.588 in thread 7392 Note: instruction: cmp 0x08(%rcx) $0x0000000e Error #32: UNINITIALIZED READ: reading 0x0000000000aaaad4-0x0000000000aaaad6 2 byte(s) within 0x0000000000aaaad4-0x0000000000aaaad8 # 0 IPHLPAPI.DLL!GetAdaptersAddresses +0x4ea (0x00007ffa220f486a ) # 1 KERNEL32.dll!BaseThreadInitThunk Note: @0:01:25.459 in thread 7392 Note: instruction: cmp 0x64(%rbx) $0x00000083 ```

This points at issues not related to the added memory search functionality and occurred before the memory search function was called.

Diagram

To help future travellers or potentially myself, below is a diagram of the memory search buffer implementation: image

adfoster-r7 commented 12 months ago

Looks like there's multiple warnings/errors on the mingw build