Late Writeup – flea_attack (Harekaze)

This weekend, me and 0x4a47 attempted the flea_attack challenge from Harekaze CTF, but we were unable to solve it in the time allocated. Still, this was a good lesson in modern heap exploitation, and therefore, I think it’s worth writing up.

At the end of this post, I will disclose the exploit-in-progress at the time the CTF ended, as well as two modified exploits, one of which “works” (but both prove the concept).

flea_attack

This challenge was presented as a 64-bit Linux binary, which you can download here: flea_attack. The flow of the application is as follows:

  • Open /home/flea_attack/flag, drop this into 0x204080
  • Read a comment, of 0x60 (via original_fgets: 95 characters) in length into 0x204000.
  • Present the user with a menu, allowing:
    • Adding a note (_malloc)
    • Removing a note (_free)

Based on the challenge title and the way the add and remove functions were structured as malloc and free primitives, we figured this would be a heap challenge.

My initial, naive approach was to attempt your standard unlink macro corruption, but inspecting memory, I noticed that this challenge required a different approach:

As you can see, there is no fd/bk pointer to overwrite to exploit unlink with, just a size. Furthermore, there’s not really any “overwrite” per se: while we entirely control a chunk, there’s no way provided for us to actually write outside an allocated chunk.

The madness of GLIBC

This is due to the glibc’s heap implementation, which is much, much more complicated than glibc. In glibc, memory allocations are stored in “bins”, in which memory blobs of a single size can be stored one chunk after another / as efficiently as possible by glibc. For example, if I request a malloc of 2 bytes, malloc is likely to return me a chunk of 16 bytes (the smallest chunk size), as part of a bin (as per the behaviour above).

Each chunk allocation looks like this:

When I free a chunk, two things happen:

  • Perform some sanity checking around the chunk I want to free – it’s structures must be valid. Look here for more information.
  • The chunk’s “fd” ptr is zeroed. This indicates the memory is ready for re-use.
  • The chunk address is added to a “freelist”, which operates like a FIFO stack. If I want to allocate 2 bytes, glibc will traverse it’s freelist, to determine if there’s a chunk of memory it can re-use. If not, it will allocate me a new chunk.

When I allocate memory to a previously freed chunk (from the freelist):

  • If the “fd” ptr is zeroed, return a pointer here and let the user write.
  • If the “fd” ptr is not zeroed, return a pointer here and let the user write, but next time you allocate memory, follow the pointer to get the next free chunk.

Note that none of this is magic: glibc malloc simply relies on some flimsy-ass local structures to determine if you’ve got a valid chunk and what that looks like so it’s entirely possible to forge heap allocations for yourself, which was my approach.

Forging a chunk

We can then forge two chunks with a single malloc call: if we allocate a large chunk of memory, we can write a smaller chunk header inside it, creating a second “fake allocation”. This second allocation can then be freed, writing it’s location to the free list.

Now, when we reallocate a chunk of the same size, glibc will fetch our fake block from the freelist – if the fd pointer happens to be written at this point, glibc will fuck up the next allocation, pointing it to whatever we filled fd with.

We can attempt this to overwrite the flag directly. Firstly, we forge a fake heap chunk:

Our fake heap chunk is at 0x7bb260 (with malloc returning 0x7bb270). Note that it’s size is 0x20 (the 1 is a flag, indicating the previous chunk is in use).

Now, we allocate memory of size < 20, and we should overwrite this with no error:

Note that 0x7bb270 is now replaced by our userdata. Where is our pointer, I wonder?

There it is! The error indicates that glibc tried to give us memory from that location, but it doesn’t have a valid header. Fair enough, it’s the flag, and there’s nothing before it: that’s not a valid header.

Our flag is stored at 0x204080, but we’re only able to write until 0x204060 (based on the original_fgets function). Still, if I’m able to allocate memory in the 0x204000 to 0x204060 range, this should be good enough: I can size this allocation to cover until the flag (by writing 95 bytes into the comment: normally, original_fgets will add 0x0a after your comment, but will fail at doing so if you write as many characters as it allows, giving us a clean fastbin length.

So, we modify our exploit as follows:

  • In the initial comment, forge a chunk at 0x204056 (by sending 94 “A”‘s followed by one character of length). Let the size of this chunk be X.
  • Make an allocation of size >X. Let this be allocation A
  • Within allocation A, forge a second chunk of size X. Let this be allocation B.
  • Free B (on the freelist)
  • Free A.
  • Make an allocation of size >X, re-using A. During this allocation, recreate B, with a fd pointer aiming at 0x204056.
  • Make an allocation of size X, re-using B, and storing B’s “fd” pointer as the next free chunk.
  • Make a second allocation of size B. This will allocate memory at 0x204066 (taking into account headers), letting is write and leak memory from there (by filling it with enough characters such that it reaches the flag at 0x204080).

While we did not finish this exercise in time, you can find the original script we arrived at at the conclusion of the CTF here.

A working script which demonstrates the concept above is here. Note when you make the second allocation of size <0x20, you get an address within the comment section, demonstrating the attack is possible. Tweak the field size to leak the flag. Here’s the script in action, allocating an address within the comment section:

I also followed someone else’ writeup, which talked about exploiting this through a double free. This is also doable, and the script for that is here. Note that when double freeing, you can’t free the same chunk twice in a row: thus the extraneous free operation.

If only there were more hours in the day…

Posted in Bards, Computers, Jesting | Leave a comment

Writeup – CBC-MAC / Web1 (Nullcon IM)

This weekend, I participated in the Nullcon IM and Harekaze CTF challenges. Due to my own general laziness, and spending far too long farming a Legiana Gem, I only managed to solve one challenge worth writing about. Without further ado:

CBC-MAC / Web1

This challenge indicated that it was donated by PentesterLabs. I don’t know if it was modified for this challenge, but if you’re going through PentesterLabs now, I recommend giving this writeup a miss if you don’t want spoilers.

This challenge was presented a a web challenge, which allowed any user to log in with the password “Password01”:

Once we log in, we are provided with two cookies: iv, which looks like an 8-byte initialization vector, and auth, which contains a username and what looks like a signature.

The challenge text indicates this has something to do with CBC-MAC. Going to Wikipedia, we learn that if we can control the IV, we are able to exert some limited influence over the first block of data: that is, if we flip a bit in the first block, and flip the corresponding bit in the IV, the signature should still be valid.

We can do this in Burp Suite. First, log in with “bdministrator”. Then, decode the “auth” cookie, modify the user name to “administrator” and re-encode the cookie:

Now, do exactly the same to the IV. Note that you must flip exactly the corresponding bits, and that to change 62 to 61, you need to flip two bits (xor 0b11). This should log you in, and get you the flag:

As always, thankyou to the organisers of both CTF’s this weekend. Well done in particular to Nullcon, for rocking the boat by introducing multiple architectures for reverse engineering / pwn. I am pleased to have the opportunity to participate in these events, and to have technical challenges to amuse myself with and improve myself upon.

See you in Technex CTF (if time permits – 12 hours!) and TAMUctf 18. In the meantime, a thousand projects await:

Posted in Bards, Computers, Jesting | Leave a comment

Writeup – BaskinRobins31 (Codegate)

This weekend, I participated briefly in the Codegate CTF (mostly during bits of SharifCTF downtime, as they overlapped heavily). I contributed to a solve for the BaskinRobins31 challenge, for which the writeup is below.

This was a joint effort between me and 0x4a47. The majority of the effort is not mine: when I got started, the exploit was mostly there and structurally functional.

BaskinRobins31

This challenge was presented as a 64-bit Linux binary, which you can download here.

This is somewhat similar to the “pwn1/vuln” challenge from SharifCTF, with the only significant difference being that it is 64-bit. In IDA:

We can clearly see a stack overflow. The read() function is used, which works to our benefit – we won’t need to worry about null bytes. Unfortunately, exploitation is a little more tricky – libc isn’t provided, so we’ll need to work out our own libc, and 64-bit’s calling conventions require arguments to be in registers, making life a little bit harder.

Fortunately, the “helper” function helpfully allows us to convert arguments onto the stack into arguments in registers.

Our first task is to leak the address of libc – we can do this by pointing helper to a write call, with the argument being somewhere in the GOT:

By writing two known addresses (so 16 bytes) out to ourselves, we can determine the version of libc in use:

We can match this with an online libc database to determine which libc we’re looking at (and thus, the base address of libc, and everything we need to drop a shell). We initially tried libcdb.com, with no success, but then 0x4a47 pointed me to this website, which had a more comprehensive database, with which we got a match (and the libc binary).

With our hands on a copy of libc, it is a trivial exercise to identify the location of system and the string “/bin/sh”. We continue the rop chain to “reset” the overflow, allowing us a second shot at the helper function, triggering a call to system(“/bin/sh”):

The final exploit we used is here.

Thanks to the Codegate organisers for yet another high-quality CTF: playing events like this are always a good ego check, and an indicator of which direction we should go next to improve ourselves.

 

Posted in Bards, Computers, Jesting | Leave a comment

Writeup – RunMe, pwn1/vuln, Skeleton Key (SharifCTF)

This weekend, I participated in the SharifCTF competition. I will present some writeups below.

RunMe1.exe

This challenge was presented as a Windows executable, which you can download here. The goal of the challenge is to modify the executable such that it executes for the flag. We can start our investigation with IDA, to identify roughly what the executable looks like:

Initially, this doesn’t run: the error message it gives in WinDbg talks about “Win32 error 0n129” – a bit of Google reveals that this is the error provided when you try to execute a driver as a normal executable.

We know that the executable headers can define which type of executable it is, via the Subsystem field in the Optional Header. We can modify this field to specify a Win32 GUI executable, and then run the application:

Hashing the file (md5sum) then gives us the flag:

pwn1/vuln

This challenge was presented as a Linux binary with a libc, which you can download here.

On inspection with IDA, we can identify what looks like your regular stack overflow, only complicated by the presence of ASLR and DEP / NX on the target system:

There’s not enough gadgets in the executable to build a rop chain with one file only, but our exploit is simple enough: we simply leak the address of a known something in libc, calculate libc’s base address, and then drop execl(“/bin/sh”) (or anything equivalent tbh). In diagram form:

A quick Python script later, and the flag is ours.

The Skeleton Key

This challenge was presented as an APK file, which you can download here.

We begin our analysis by extracting the file and converting classes.dex to a JAR file, to identify what’s happening. The amount of code in this executable is surprisingly small – it appears to simply load logo.svg and then do nothing:

At a glance, logo.svg appears to be an image of a stylized skull, but on inspecting the SVG closer, we note there are a large number of paths which do not appear to be rendered at all, with a blank style:

Furthermore, we can note that each of these paths is rendered on a tiny surface area: we’ll need to expand this (multiplying all the coordinates by 1000) if we want to see anything meaningful. A little bit of Python later, and we have progress:

We can see there are clearly characters in there, but they are superimposed on top of each other. We can easily fix this by changing the start position of each path, giving us the flag.

You can download the Python script used to expand the SVG’s hidden path elements here. Note that this needs a bit of wrangling of the original SVG to make it work: it expects path elements *only*, and isn’t aware of anything else.

Thanks to the Sharif organisers for putting together this event. It’s a shame that Sharif was impacted so heavily by downtime, and at a disadvantageous time of day (Saturday afternoon/night AEST) Still, it’s good to be CTF’ing again. Also, if I might leave one bit of feedback for the Sharif organisers: the point value for reversing and pwn, even the simpler challenges, shouldn’t be equal to non-blind SQLi with full error messages. These, to me, seem like a league apart in terms of difficulty and knowledge required.

See you all next week in nullcon IM and Harekaze CTF.

Posted in Bards, Computers, Jesting | Leave a comment

Never forget where all this started…

This weekend, I am favored with the good fortune to participate in both SharifCTF and the Codegate Qualifiers CTF. In times like this, we often get so engrossed in our efforts to wrangle that final rop chain gadget, that we simply forget to smell the roses, so to speak:

As our industry move towards ever increasing levels of cyber excellence, may we never forget what made all this so great in the first place.

Posted in Bards, Computers, Jesting | Leave a comment