Before diving into exploit and vulnerabilities, I’ll take a little time to introduce the core concepts behind the challenge. The same key concepts which made this challenge so much fun, frustrating, and wait, did I say frustrating?
The binary, twitter, was basically an emulator to ROMs from the past which the challenge provided us…Pong, Space Invaders and such, you know :)
A good run of reversing with IDA and some googling made me discover a whole world of passionate programmers of this language, Chip-8, emerged from the 70’ to provide old devs and young devs a worthy way of spending a free night, and a couple beers.
And twitter is just that, a Chip-8 interpreter written in c++ written by some passionate nerd :)
So, to properly follow and reproduce the writeup, I’d encourage you to go and take a quick read of the Chip-8 Instruction Set – I’ll refer to that in what follows.
Moreover, to successfully write my custom ROM and exploit the vulnerability I used chipper.
The binary is NX, so we need to use some ROP technique to exploit it. With PIE option, dynamic linking, and ASLR, not a single address in memory will be loaded in a deterministic fashion. We will definitely need some leak.
Chip-8 accesses its RAM through a dedicated register named Index Register, or I.
An 8-bit register wouldn’t be enough to address the whole content of its memory, which is historically (and modern interpreters follow the same convention) large 4K, so that the Index is large 16-bit – with 4K, only 12 of which are used.
My bet was that, in our given interpreter binary, the check to avoid that Index register didn’t address anything larger than 4K was faulty; so I could write custom instructions to read and write from areas of memory used by the interpreter, out of the dedicated environment. A quick run with a Proof-Of-Concept ROM confirmed the vulnerability.
option binary align off ld I, #FFF ld v0, #42 ld v1, #4F ld v2, #4F ld v3, #42 ld v4, #10 (add I, v4 ld [I], v3)*a lot of times
Standing to the Chip8 Instruction Set, what I’m doing here is:
./chipper overflow.rom overflow.asm
We basically have a buffer overflow here, where the buffer is represented by the 4KB allocated to the environment. Moreover, we can issue read and write operations from arbitrary areas of memory up to 2^16 bytes starting from the buffer.
Again, we need a leak. But really, when you have the chance to write and read an arbitrary number of times to/from memory, you will pretty much always find something to make good use of.
My strategy here was:
__libc_csu_init. I have my leaks. With these, I can compute relative addresses to ROPgadgets and libc functions, thus pwning the binary.
The exploit works as follows:
POPRSI | 1337 | POPRDI | 1337 | SETREUID | POPRDI | /bin/sh ADDRESS | SYSTEM | EXIT
All of this has to be written in Chip-8 instructions. The steps above have been adapted to reflect architectural limits such as number of GP registers :)
Lots of fun to be had with challenges like these. All in all, the attack was quite basic:
But nevertheless, finding and exploiting the vulnerability on such a nerdy architecture proved to be extremely rewarding – 800 pts :)
You can inspect the final asm code HERE!