This weekend, I took part in Tokyo Westerns CTF 2020. I only managed a few hours on Sunday night, but I was able to solve 2 (warmup) challengs. The writeups are below, for future reference:
Nothing More to Say
This challenge was presented as a 64-bit Linux ELF file and corresponding source code. You can download this here. The challenge text describes it as a format string vulnerabiilty.
Initial inspection shows that the challenge is reasonably simple, but established some constraints:
- The input is constrained to 0x100 characters. Minus 3*8 characters (for offsets), then minus 3*7 (for “%..$hhn”) means we have an absolute maximum of 0xd3 characters.
- read() is the input mechanism, so null bytes are OK
- Input is passed to printf directly.
- We have unlimited attempts to exploit
- execstack is enabled – maybe this is an avenue
Initially, I leaked the remote libc by printing the GOT. Using an online libc database, we quickly find this is an Ubuntu libc, with three magic ROP gadgets – unfortunately, overwriting printf with these doesn’t seem to work (constraints not satisfied?)
Unfortunately, on this version of libc, system’s address ends with 0xe0, placing this out of reach of our format string – but on reversing the libc file, we note that system simply proxies the call to 0x4EF50:
While 0xEF is out of reach of our format string, libc base randomisation might cause an overflow to the next byte (depending on where libc is loaded at). Therefore, we can hope the second and third least significant bytes on the offset of libc+0x4ef50 are lower than 0xd3, allowing us to overwrite printf in a single go.
A few tries later, and success:
The resulting script is here. Life is made significantly easier by the fact that null bytes are accepted – we can simply stash our %n pointers at the end of our input, and reference them using static / known indexes (they’re always 33/34/35 – we can pad the input’s length to put them there.
It’s been so long since I’ve seen a format string exploit, it’s good to practice this again, even if it’s a bit unrealistic.
Reversing iS Amazing
This challenge was presented as a Linux binary, which you can download here. Initial reverse engineering shows that this uses the OpenSSL Public Key API to sign the user’s input, then compares the signed input to a static block:
The simplest approach (IMO) is to extract the key and static block from the binary during execution (breaking at BIO_new_mem_buf and memcmp), save it to file and
We can use gdb’s “dump” command to extract memory:
A little reading of the OpenSSL man pages later, and we have a stub executable that can read the private key and signed block from memory, and use RSA_public_decrypt to recover the message digest into readable form:
I also attempted the web “urlcheck” challenge for fun, but wasn’t able to solve it in the time allocated.
Thankyou to the Tokyo Westerns team for putting together another great CTF, I look forward to playing again next year.