Earlier this year, I completed a binary reverse engineering challenge from Atredis Partners. This was interesting, so I will present the writeup below, for posterity. The challenge began with a Slack message from a comrade, who mentioned there was a binary-style challenge available at arkos.atredis.com, port 4444.
Upon connecting, I was greeted with the prompt shown above. A bit of manual testing revealed that I could use the “help” and “read” commands – the “read” command would consistently produce a single byte from a specified location in memory:
Here, I built a memory dumping script which called read in a loop to give me an extract from memory. I extracted according to the memory map, until I hit contiguous blocks of zero (which I assumed to be the end of real data in a mapped section). Immediately, a few interesting tidbits jump out at me.
We can immediately note that in the PROM section starting at 0x4000, there is a reference to “write” and “call”, which appear to be commands:
At this point, I decided to try the “write” and “call” commands – the “write” command seems to allow a single byte to be written with the syntax “write <addr> <byte>”. I couldn’t make the “call” command do anything at this point, but it always printed “JSR <addr>”.
I did some Google, and I found that JSR could stand for Jump Subroutine, an assembly language thing for MOS 6502 microcontrollers. Cool!
With this, I could now fully disassemble the program at 0x8000 in IDA. After some learning about 6502 and some manual effort (the program took 16-bit addresses, which were loaded in two operations of single byte chunks, which was annoying to deal with), I was able to reconstruct some basic application logic flow:
- There are two points in the application which seem to seek a file from disk: displaying /etc/motd (0x8270), and displaying /var/mail/spool/atredis (0x82a2).
- Both called “fopen” at 0x8059, after loading a pointer to the filename at $95 and $96
- “fopen” is a strange loop – it sets an “id” in $99, then calls “disk_read_sector” at 0x8034. It then compares the filename to what was initially entered, and exits the loop if it’s what we’re looking for, or continues the loop if no match.
After a little experimentation, I found that RAM was executable, and I could write shellcode via the “write” command and “call” it successfully. I initially attempted to build a stub which called fopen with a controlled filename, but this didn’t work.
I then wondered if I could simply patch the program – it turns out I could. I then patched the byte at 0x8060, to modify the initial “fopen id”, and 0x8084, to pass the filename check at the end of fopen, and presto, the flag:
This was a fun challenge, and well thought out. Thanks to the Atredis folks for putting this together.