Home Blog About GitHub

pwnthem0le is a Turin-based, hacking students group born out of CyberChallenge 2018. Read more about us!

23 December 2018

X-MAS CTF 2018 - Forbidden Documents

by madt1m

Fun things happen in the CTF wild landscape. Like approaching a PWN challenge with no access to the binary object of the process we are supposed to pwn :)

This has been a fun challenge. Follow my brain while he was trying to get this flag!

Binary Exploitation Starter Pack: Getting the Binary

The only thing we can do, for starters, is to interact with the service to find something weird – or better, of good use.

With a few tries, we quickly understand that the program works like some sort of file retriever:


The first thing I asked myself concerns that “offset” option. Why did they leave me this to decide?

(EDIT: No, wait - the first thing I asked myself was “Can i get the flag just asking politely to the service?” and no, I couldn’t.)

The answer is quite simple: we cannot retrieve much more than 1200-1300 bytes at once from this binary – which is something that I did not stop analyzing, since we have that cute offset thing which allows us to retrieve a file chunk after chunk.

Long story short, I used this same service to retrieve the binary file loaded in its heart (kinda meta-phylo-physics, uh?) – here, briefly, the process:


Goal! We have a name! …which gives us a good lead to follow in order to retrieve both the binary AND the object featured in the target machine - which quite always comes handy to fellow pwners :)

NOTE! </br> Retrieving both the object files proved to be not that straightforward. In fact, two main things stole me a certain amount of time:

What follows is the script I used to retrieve the file, with the given fixes as in before:

File Retriever

So, with a quick and excited - no, kidding, it took tens of tries - pair of commands:

python random_exe_name 1000

python /lib/x86_64-linux-gnu/ 1000

I had finally access to both binary and libc.

It’s Beginning to look a lot like Pwn

All excited and thrilled for the new hunt, we analyze the binary:


And look for some easy buffer overflow:


Bingo! The fread() function delegated to read the file chunk into the stack just happily takes whatever we tell here to fill through the size variable, which is assigned with the “How much should we read” question. This means that, reading a file big enough with a proper size input, we can overflow the saved EIP in stack, gaining control of program execution.

info functions @plt command in peda confirms us that we have the puts() in plt. The 2-stage attack becomes clearer and cleared in our pwning minds:




If something in this process doesn’t seem clear here, I’d suggest you to ask a search engine about Leaking GOT :)



Where obviously, "/bin/sh" and system() addresses in libc are de-randomized using leak.

Ok then, everything works here, but…how can we control the content of the buffer to be overflown?

The hint to solve this came straight from the binary, precisely:


The check for flag is obvious, but…what about STDIN?

Yes, you got it right. Opening stdin basically means that the fread() function would write our arbitrary input to the buffer, so that we can realize our best dreams of pwn4g3.

“There are other ways to do this too”

As in before, the hint comes from the binary itself. In Linux, there are quite a few ways to access I/O as files.

After some study, we came out with "/proc/self/fd/0" as a valid alias for STDIN, which worked. I had full access to the buffer :)

A bit of context now:

I had to go out for a dinner. I was sitting in front of my laptop, the clock showed 8:00 PM. I still had 30 minutes to get ready and prepare for the night, and I managed to successfully pwn the exploit locally. Finally relieved, I change offsets and address in the exploit, and launch it. Nothing. EOF.

The reason behind this brief, little, sad story takes a name sadly famous: Bad characters.

It seems that the connection on the remote side is dropping some bytes in the fopen, including the \x12, and the thing is, the main address of the first stage happens to contain one of those bytes.

But we do not lose hope and courage: there’s a return address to main stored in stack, just one word after the location where we stored the main address :)

Therefore, we slightly modify the 1st stage ROP chain to:


The exploit, complete:



tags: pwn  file_leak  bad_characters  got_leak  rop_chain