BSides 2020 — snappaste (1) explained

Ilyar
3 min readDec 28, 2020

This is the first challange of two (pwn challanges) named snappate.
They can be found at https://github.com/bsidestlv/ctf20-public/tree/master/dockerfiles/snappaste (you’ll need docker in order run them locally, or to compile the snappase.c file with it’s dependencies)

I won’t explain the idea behind the vulnerability because Omer (1byte)did it very well. You can find his write here. I’ll add a bit more information to his writeup because I think it’s necessary.

We start with our primitive: a Write-What-Where vulnerability. Because we can overflow num_bytes variable, paste_received_ptr offset can be controled by the user. Before that, let’s look at the PASTE_RECEIVED struct:

We can do two things: write to where Data ptr points to and we can later also write to where Metadata points to. This allows us to Write (Backdoor addr) Where(Metadata) What(Our own file name). In short, we want to write our file name (stored in *header*->metadata we send. Don’t confuse it with paste_recived->metadata) to the backdoor address, which we will supply to the paste_received->metadata pointer with paste_received->data pointer.

Let’s first look at the simple case and then make a general conclusion. We want to write 16 bytes of the desired filename, thus header->metadata will contain 16 bytes of chars. We also want to write the backdoor leaked addr into the header->data_compressed. This will allow us the overwrite paste_received->metadata pointer with the backdoor address. Here we have a slight problem, however. We will need to padd the leaked backdoor pointer based on the num_bytes value, in order to successfuly override the paste_recived->metadata pointer. Here is why:

alloc starts at 0x0 for simplisity

This case is the perfect, where we don’t need to padd because if we choose the right number for the num_bytes, data_ptr will point straight to the start of metadata pointer. That happens when paste_received offset is alloc.get() + 8 as we can see above. For that case, we will need to choose 0xFFFFFFF8 for the header->data_decompressed_size, because 16 + 0xFFFFFFF8 = 8.

However, if we want to go to the extreme, where num_bytes equal to 15 (the maximum), we will need to padd with 7 bytes before the leaked backdoor addr:

In that case, you can see that because paste_received->data pointer to 16 (it points to alloc.get() + metadata_size), it’s in the start of the debug padding, therefore we need to fill 7 more bytes until we reach the next address which is the metadata_ptr we want to overflow.

At the end, we can choose data_decompressed_size to be between 0xFFFFFFF8–0xFFFFFFFF in order to succeed. Don’t forget to paste your page before override backdoor with it.

The full exploit can be find in 1Byte’s writeup.

Happy hacking!

--

--