Tuesday, October 9, 2012

Exploit Harvesting at DefCon 20 CTF


The setting for this scenario was DefCon 20 “Capture The Flag” in Las Vegas.  Each server was set up with a spanning port so that each team could see traffic for their server, and we had a notification system set up so that if we saw one of our secret keys going off the wire, our packet capture system would dump the last minute of traffic into a PCAP file for analysis.  We will focus on an exploit that was detected against a service named “coney”.

Once the exploit was seen on the wire, the packet captures revealed the following:


(The red is sent from the attacker and the blue is the server response.)  The key is the 32-byte ASCII sequence on the 5th from the bottom line, which is what triggered the notification system that the service was being exploited.  So, analyzing the packet capture, there is a question response system:
ATTACKER: “I’m internet famous!\n” (authentication)
SERVER: 16-byte key
SERVER: “enter ip:”
ATTACKER: “dc20:c7f:2012:f:0:0:0:22” (attacker’s IP for the server to connect back to)
SERVER: “knock knock!”
ATTACKER: 32-byte key (authentication)
ATTACKER: (exploit)
SERVER: key + adjacent RAM

The first problem to overcome is that the server gives the client a 16-byte key, but expects a 32 byte one in order to reach the vulnerable code-path.  Upon observation, the keys change every connection, governed by /dev/urandom.  Running this shows that the server is kind enough to send 2 UDP packets 24 bytes long to the IPv6 address specified by the attacker.  Each UDP packet has the same 16-byte key that was in the original connection, but appended is another 8 bytes.  Concatenated together {original 16 byte key} + {8 byte key from UDP1} + {8 byte key from UDP2} == 32-byte key to get to the exploitable code.  Unfortunately, the UDP packets sent to the attacker are sent to random addresses.  The potential for guessing the ports is one pathway to pursue to solve this problem, but the easy (and most quickly implemented) is to listen on all UDP ports 1-65535.  We now know how to reach the exploitable code path and can go about dis-assembling the exploit!


From just a cursory look, the exploit is sandwiched in-between a NOP sled and a bunch of return addresses.  The many 0xBA’s result in 5-byte instructions “0xBA 0xBABABABA”, in assembly: mov dx, 0xBABABABA.  We can assume this is a sled for EIP to hit once the overflow happens, and the 0x16ce9595’s at the end are the part of an overflow that overwrites a return address and causes execution to land in the sled.

Note, the theme of the contest is “everything sheep”, and so the creators of the exploit paid homage to the contest organizers with their “BA BA” sled.

The next step is to extract the exploit and analyze it.  Sometimes this is not the simplest process, as most exploits rely on weird little tricks to compensate for the lack of knowledge about where they are in memory space.  Here is a sample disassembly in IDA: 
and since I don't have a big monitor and it chopped the bottom:


Without looking those far jumps and calls, we can assume the following:
1.     Since the exploit has its strings imbedded in it, it needs to get a reference to the stack so it can use them for function calls.  The string at 0x03e4 -> 0x03f7 could be such a string.
2.     The exploit has to either get references to the import table so that it can call functions that the program uses, or it has to call absolute addresses to do things.  In this case, it looks like it is using an absolute reference to the programs function table.
3.     From the packet capture, the key is printed out, and then some RAM.  This could be two things: the key has been read into memory adjacent to the exploit’s reference to the key file or the key file has been referenced by the program and the exploit is just using a reference to the string to call a read.  We will assume the former, and not the latter (for the moment).

The first jump is most likely a call to a reference giving instruction inside of the programs TEXT segment to get the address of the stack.  The next two calls we can determine by the following criteria: The exploit does not have another string of bytes inside of it (indicating it doesn’t overwrite our key), so we can assume the exploits goal is to print out the key file in the current working directory, and the key is 32-bytes long (0x20 hex).  It then needs to print out this key on the current socket.  So, the following calls are needed:
1.     file_handle = OPEN(“/home/coney/key”, “r”)
2.     storage_area = READ(file_handle, 32 bytes)
3.     WRITE(socket_handle, &storage_area)
4.     Exit / crash

Near the bottom of the exploit listing, there are 3 interesting adds: 0x4f474542 + 0x4f444549 + 0x81534f41.  The potential exists that, despite IDA saying that those instructions are valid, it is actually a string.  Pulling the last 32 bytes and brute force xor’ing them revealed that following about the last 15 bytes: “^EBEGO^EIEDOS^EAOS” xor 0x2a == “/home/coney/key”.  That would be the string needed for the OPEN call.

Re-analyzing the program in light of this in IDA reveals the following:

With this understanding, we can see that the program jumps down to the bottom (0x000003e4) to get a reference to the stack, then back to the decryption section in the middle of the program, the decryption section xors the encrypted “/home/coney/key” string, then jumps to the OPEN call (0x000003a4), which then follows on to the read call (0x00003ac), then to the WRITE(socket, data) call (0x00003c5).

Now that the exploit is fully understood, re-using it is trivial.  Since the exploit is kind enough to re-use the socket file handle and write the key back onto it, there is no need to alter it in order to immediately start exploiting other team’s servers!  Overwriting their keys or gaining a shell is the next step, and since we know where code execution begins within the exploit, all we have to do is substitute the existing shell code with our own, making sure to respect the correct offsets and space requirements.

1 comment:

  1. As a farmer with livestock, I rely on tractors for tasks like feeding and managing manure. The john deere 4440 stands out as a compelling option, but I’m also looking at the john deere 5020 for more intensive fieldwork. For tillage, the john deere 4640 appears to be an excellent fit, whereas the kubota b7100 might be suitable for everyday tasks. Finally, I’m weighing whether the john deere 1010 would offer the best value for multi-purpose use on my farm. Which one do you recommend I get?

    ReplyDelete