From https://fbesnard.com/2018/04/13/HITB-XCTF-Quals-2018-babypwn/
Challenge description
nc 47.75.182.113 9999
Challenge resolution
Introducing ourselves
Using netcat to connect to the challenge, we are greeted with the following message :
|
|
Very talkative server, I appreciate that…
Maybe we should introduce ourselves :
|
|
So, it seems that the server is sending our input back to us (or is called Florent as well, which is likely not the case…).
At this point, one of the possible vulnerabilities that comes to our mind is a format string vulnerability :
|
|
By sending %p to the server, it replies to us with an address to which a pointer refers.
Unfortunately for us, we don’t have access to the binary or its source code.
But here we are : a blind format string vulnerability !
Further knowing the server (or getting our hands dirty)
Now it’s time to find a way to grab the flag.
I’ve already played with format strings vulnerabilities but never blindly.
While looking on the net for information on how I could efficiently leak usable addresses from the binary, I came across a challenge from the 33c3 CTF entitled Eat, Sleep Pwn, Repeat or ESPR (which is also the name of the German team which organized the 33c3 CTF).
The situation is pretty much the same and I started looking at write-ups of the challenge.
I stumbled across these 2 excellent ressources that I encourage you to take a look at :
In order to solve the challenge, I used the script from @jay_f0xtr0t (available here) that I adapted a little bit.
Below is the explanation of what the different parts of the code do :
First, we connect to the challenge (obviously) and set the architecture accordingly.
The challenge is a 64-bit binary : our %p inputs reveal addresses like 0x7f2a8a02f780 which start with 0x7f and are 6 bytes long.
|
|
The exec_payload function is the function that exploits the format string vulnerability strictly speaking.
We prepend an arbitrary value (_EOF in this case but it could have been something else…) to our payload and the function will parse the server’s response until it reaches our value.
We ignore \n because if the server is using the gets function (or similar) for reading our input, the fact that there is a newline character will cause a weird behaviour : the function will replace \n with \x00 (null byte) and we will get the output twice.
|
|
The find_elf function attempts to find an address that might be in the ELF binary.
To do so, it looks for an address starting with 0x400 (because 0x400000 is the default base address for binaries).
The address that we find will be useful later when we will use the DynELF function from PwnTools.
|
|
The find_leak_point function attempts to find the correct offset so that our input refers to itself and is sent back to us.
|
|
The leak function leaks data from the address given as argument.
Some workarounds were made by the initial creator to handle the case of the special \n that we previously mentionned.
|
|
Now using DynELF from PwnTools, we can find the addresses of the printf and systemfunctions.
The idea behind this is to overwrite the printf address from the Global Offset Table (GOT) with the one from system.
By doing so, when the server will attempt to reply to our request, it will use the system function instead of the printf function and thus execute the payload we send.
|
|
The find_plt_got function attempts to find the address of the GOT inside the Procedure Linkage Table (PLT).
Indeed, the addresses for the printf and system functions we found before are in reality jumps to other addresses.
So if we find the GOT, we will be able to have the real address of the printffunction from the GOT.
If you don’t get this point, you may want to take a look at this video from @LiveOverflow.
|
|
The forge_exploit function generates the final payload to be send to the server, replacing the value at the given address by the one we choose.
|
|
Below is the full exploit code :
|
|
Revealing its secret
It’s now time to run our exploit :
|
|