This year’s Chaos Communication Congress featured an entry-level CTF contest alongside the original one. For everyone who don’t know what a CTF is or where to start, a talk followed:
I decided to publish my own solutions alongside description for educational purposes, though you’ll probably find other writeups on people’s blogs and repositories if you don’t find it clear.
We’ll start by cloning tasks from Github:
And proceed to the poet/distrib subdirectory. What we’ll find there is a binary, which on execution asks us to type some strings to stdin, and loops on incorrect answer:
That’s for the introduction. How did I exploit it?
Vector of attack – Buffer overflow
After checking if score depends of anything, what came to my mind was to try to overflow input buffer, typing enormous quantities of characters and checking what happens, if anything.
I pasted a big chunk of characters to the first one, for the poem’s content, but nothing happened.
I typed more characters than expected to the poem’s author buffer (not, that I knew how many characters it expected; again I just guessed that a possible vector of attack may be by overflowing) and eureka, score counter got unexpected, non zero value:
Next thing I did, was to find out exactly how many characters do I need to overflow. I just iterated over how many characters I typed, starting with aaa, then aaaa, then aaaaa, etc.
After a few tries I decided to try with 33 and 65 as it was a multiplicity-of-32 overflown by 1 and someone could set that multiplicity-of-32 value for memory alignment.
I found it, buffer size was 64; after typing 65 characters for the first time I got this score value changed:
So the next thing I checked: does the score change, depending on what character is the 65th character? I tried with zero:
So for the ‘a’ it’s 97 and for the zero it’s 48… Let’s have a look at the ASCII table:
Score matches value of the character I typed! Maybe I could use that to make score having value of 1 million, so it would print the flag for me?
Well, the last clue I needed was – when the value stops to change; how many characters proceeding after the 64 have an impact on the score. Spoiler: 4.
After that I deduced, that score must be stored in a 4 byte integer, and what I needed to figure out was… How do I write 1 million in binary. Then I needed to left pad it with zeroes to 32 bits, and write it down in 8-bit brackets, and check ASCII value of characters I just put into brackets. Here’s a drawing of what I did:
What I meant was “making it 1 million from decimal to binary”
So after figuring out that it was [aaa overflowing sequence] + [@] + [B] + [^O] (non printable character) I typed this into the program and got the flag:
Analysis having the source code, aka why overflowing buffer caused changing score value?
Afterwards, I looked at the source code of the poem binary. As you see, score field was declared just after the author buffer. Why does it matter? Because for the compiler, there’s no abstraction for structures. Under the hood, it looks as though someone allocated [1024 + 64 + 4] bytes of continuous memory when created an instance of this struct. It’s how humans interact with this structure, referring to certain bytes by aliases (text, author, score) makes it less intuitive to understand why the trick worked.
PS: The proper way to run these tasks is by Docker, since It may be handy to write some scripts that would automate buffer overflow since you could use sockets for communication.