1.1 - format string vulnerability.
We have a format string vulnerability we can confirm this by running the binary:
1 | $ ./32_new |
A there it is, we leaked an address from the stack, analysing the binary again we can see we already have a cool function that calls system('cat flag.txt')
so we don’t have to actually leak libc addresses and go through all that trouble:
1.2 - flag function.
This one is really simple:
1 | 1 - Calculate the offset of the address we put in the stack using %p. |
Before going into an explanation I’ll show you some modifiers from printf
man page this will be useful since we want to override a certain number of bytes and this length modifiers will help us on that.
1 | An optional length modifier, that specifies the size of the argument. |
For example if we want to override an address like this 0x0804870b
this a 32 bit address so if we need to change all the bits we would use %ln
which is a long and it’s 32 bits or we could even use %lln
would work too since is 64 bit (long long).
Usually we want to use %hn
so we can override 2 bytes(16 bits) at each if we get greedy and try to override it as long when the binary prints the string output it will take a lot of time since it needs 0x0804870b
spaces to be printed, this is why we prefer to use %hn the address but this time we need to do it in two operations instead of one.
1 | 0804 -> '%11hn' |
Stack address offset calculation
We can do this by printing a bunch of addresses from the stack using %x
or %p
, we can insert some ‘AAAA’ in the beginning and the a bunch of %x
and check on which location the ‘AAAA’ are positioned in the stack.
1 | def getConn(): |
We can see our 41414141
will appear in the position 10th, we now know where its located in the stack when we put some strings in the beginning:
1 | $ python 32_new.py |
To access its position we can do like this:
1 | '%10$hn' |
Override exit function
Now we need to calculate how much characters we need to add into our format expression, for example if we needed 100 we could do it like this:
1 | '%100%10$hn' |
Now starting the exploit we can easily get the exit GOT
address with pwntools
and the flag function we can get it from radare2 you can check it at the picture 1.2 above.
One nice trick is to clear the existing EXIT
function address with %10$lln
of course since we are adding some characters at the begining of the string the address won’t be converted to 0 in this case it actually turned into 0x0000004e
, 0x4e is 78 in decimal and that’s why I’m subtracting in the 78! And there is another thing that is very cleaver, is to split the address in half using some bit operations with this we know exactly how many characters to add (of course you still need to do some debugging in gdb
).
1 | EXIT_GOT = binary.got['exit'] |
The full exploit:
1 | from pwn import * |