Rolodex Walk-through (DefCon WarGamez CTF 2007)
Service Details
The Rolodex service took commands from the network, including the ability to read ":"-separated files and report back information from them. more detailed disassembly info coming soon...
After comparing the various "read" and "memcpy" sizes to the stack and "calloc" allocation sizes, we discovered that the "LOAD" command did some rather inappropriate math when copying file contents into the newly allocated buffer. Additionally, no path sanitization was performed, meaning one could issue commands like "LOAD /etc/passwd" or "LOAD /tmp/".
While examining the caller's use of the resulting allocated buffer, it was clear it was a 0x28c byte buffer, where the last two 4-byte chunks were being used in a linked list. Without an overflow, these two pointers ("next" and "prev", as we'll see) were intended to be NULL.
Linked list management
After reconstructing the actions taken against the buffer, we see the following actions during the normal course of running the "LOAD" command.
The program starts with a NULL global "ulist" pointer:
The file opened during the "LOAD" command is read one line at a time into newly allocated and cleared memory regions. The first line's allocated buffer is shown as region "A", with its contents being filled from the first line of the file. Note that the "next" and "prev" pointers are NULL due to the entire region being calloc'd:
Now the region is inked into the global linked list. For the first node of the list, only "ulist" it updated to point at it:
For the next line of the file, a new region ("B") is allocated (and cleared), and its contents filled from disk:
Then it is linked into the global linked list. In this case, the first node ("A") has its "next" pointer set to point at the second node ("B"), and the second node ("B") has its "prev" pointer set to point back at node "A":
For the third line of the file, another region ("C") is allocated (and cleared), and its contents filled from disk:
Finally, we link it into the list, as with the other nodes, updating the new node's "prev" pointer, and the prior node's "next" pointer:
Linked list abuse
Since the function handling the newly allocated memory regions gets its math wrong, it is possible to write over the "next" and "prev" pointers if there are too many characters between ":"s in the input file. What does this get us? This means we can sneak a node into the linked list.
By overflowing the "next" pointer, we can force the list to suddenly have an extra node after our first node is linked to "ulist". This means we control where region "B" is located in memory:
As a result, when the next line is read in from the file (which will populate the contents of region "C" in this diagram), node "B" will have its "next" pointer updated but only if "next" was NULL:
Results: we can change a value of 0x00000000 located anywhere in system memory to a point to a newly allocated region of memory that contains bytes under our control. How is this useful? As it turns out, the libc "dtors" contains a NULL-terminated list of exit handlers that get called during program shutdown. All we need to do load region "C" with our shellcode (line 2 of the file), and aim 0x284 bytes above the "dtors" in the overflowed contents of region "A" (line 1 of the file).
By SSHing into a target machine, we could generate a "corrupt" data file with two lines: the first containing an overflowed "next" pointer to the dtors, and the second containing the shellcode. Then we connect to the Rolodex service, issue a "LOAD" for the file, and then "QUIT". During shutdown, the dtors would run, executing our shellcode (which contained a shell command to overwrite the key file with our team's overwrite token).
As a quick aside, it seems that while we abused the linking option, sk3wlmaster used the UNlink operation, which didn't have the same limitation of only ovewriting an already-NULL address.
example code coming soon...

CTF 2007