We again get their libc version. It gives us a leak, but this time it begins with 0x56
, so likely something in the binary. If we step through in a debugger again, we find the program actually gives us the address of main. This lets us calculate the binary base.
We're going to need to use the libc somehow, so we can use the PLT and the GOT to leak a libc address.
Because the GOT is inside of the binary itself and is a table of libc addresses, if we can read the GOT we can read a libc address.
Meanwhile, the PLT is also inside of the binary. The PLT has a bunch of stubs, allowing us to call a libc function without it's address.
printf is called before we input. So it's GOT entry will contain it's libc address.
Thus, we can call printf on printf in got to leak printf's address, subtract appropriately to get the libc base, and then do what we did last time. in 64-bit, arguments are in rdi, then rsi, then rdx, etc. We need a pop rdi gadget in order to call system("/bin/sh")
. The gadget would essentially be a piece of code within the binary that does "pop rdi ; ret"
, popping the next value off the stack into rdi and then returning to the next return address.
So our exploit must:
Use address of main to get binary base and address of gadgets and GOT and PLT
call printf on printf in got to leak it's address (and call vuln afterwards so we get another input)
Use this to calculate libc base and address of other things we want
On second input, do padding + pop rdi + address of /bin/sh + address of system
After looking around in the file (raw) i noticed there wasn't an IDAT header and instead found an EASY header so i just renamed it. however, only half of the image was complete so i looked down to around where the image breaks (took some time) and found another EASY header and did the same thing. i suspected it was replace so i control + f for EASY and replaced them all with IDAT.
It gives us some sort of address, but what address? it Begins with 0xf7
, so likely an address in libc. We can step through in pwndbg and find that it's actually printing the address of system in libc. Since the challenge gives us their libc version, we can calcualate the libc base given the address of system and therefore the address of /bin/sh
.
This means we can make the program go to the address of system, with /bin/sh
as an argument(arguments are stored on the stack, just after the return address in 32-bit)
So, our exploit must:
Collect system address
Calculate libc version and address of /bin/sh
Use this to call system("/bin/sh")
The program reads the flag from a file called flag.txt, and prints it out one character at a time. But it always gets killed! Looking at the c code included in the directory, only a few sections seem relevant
The process forks
The process checks if it is the original, if so enters 'hare mode', otherwise enters tortoise mode
In hare mode the process waits a while and then kills itself
In tortoise mode the process reads a file one char at a time
So if we kill the process in hare mode before it kills itself along with the process in tortoise mode, we will get the flag!
Open 2 ssh sessions, in one start the binary, and in the other run ps aux. Kill the process with the larger PID, check in the other window, and the flag will be printed!
Flag: forgot lol
Simple buffer overflow. There is a function win_func that calls system on a global variable. We can read this global variable and find it's value is /bin/sh
- it pops a shell for us.
In the function vuln, it reads 0x32
bytes into a buffer at rbp-0x20
. This allows us to overwrite the return address with the address of winfunc.
So our exploit is 0x28 bytes of junk + address of win_func
.