[bkpCTF-2015] braintree (tz) write-up

This is a write-up for braintree challenge, which is the last part of 3-chained pwnable challenge from Boston Key Party CTF last weekend. You can read about the other parts here: quincy-center, quincy-adams.

The binaries were packaged into a tar ball.

The MBTA wrote a cool system. It’s pretty bad though, sometimes the commands work, sometimes they don’t…
Exploit it. (tz flag) 8899

The goal is to get “tz” flag by exploiting the kernel space process.

If you haven’t read the previous write-up for quincy-adams, I strongly recommend you to read before continuing with this one as we will assume knowledge gained from it.


As it was mentioned previously, we will be using the same primitive: hypercall #92.

Therefore, we have an arbitrary-write-anywhere primitive. So, the question is “what can we overwrite in tz that will get us an arbitrary code execution?”

We started looking at each of the hypercall handlers in tz.


Then, we stumbled upon hypercall #85.

This function seemed like some sort of cleanup (we called it delete_op in our shellcode) function for an object used in tz.
(As I said previously, we didn’t do much of reversing on tz as we did for uspace and kspace)

It seems like the first argument (v3) is a word that represents id of some sort, but the important thing is that we can control its value. v2 is an offset to the tz data structure, and the value at tz_space + v2 (where v2 is 0) is 0.

Since NX is enabled on tz, we decided to overwrite the GOT entry to execute system. Since the addresses are randomized, we first need to leak an address to calculate the address of system. We are going to abuse the hypercall #92 to do 3 things:

  • Leak out libc address, so we can calculate the address of system.
  • Overwrite free (.got.plt in tz) with &system.
  • Overwrite contents in v4 + 8 (aka, tz_space + 8) with a pointer to our command buffer.

However, doing all of these comes with a price. The size limit (256 bytes) starts to become an issue here. We can either put another stager in the middle to allow us more space, or optimize our payload such that it fits under 256 bytes! We chose to do latter :P

At first, we were over ~10 bytes, but once we have “optimized” a little bit, we finally got our payload to be 254 bytes!

Note that we are not using the same shell.asm as before (our new payload is now called shell.asm). However, we can continue to use the same stage1.asm and the python script from kspace exploit. For convenience sake, it is also attached here.


We have abused the hypercall #92 (encrypt) to exploit both kspace and tz, but there may be another way to exploit kspace without going through the hypervisor.

Well, that’s it for the 3-parts pwnable challenge write-up =)

Thank you for reading, and happy hacking!


You may also like...

2 Responses

  1. Dan says:

    This was so much helpful. Thank you very much.

  2. acez says:

    Don’t know how I missed this for so long ! Great writeup :)

Leave a Reply

Your email address will not be published. Required fields are marked *