[0ctf 2017] uploadcenter knote pwnable write-up

Categories CTF

0ctf is over for a week. We(NeSE) ranked 6th/908 at last. During the game, I looked at two pwnable challenges : knote and uploadcenter, I spent more than 16 hours on uploadcenter and 14 hours on knote. I found the info leak and race condition in knote and the info leak and mismatch in mmap/munmap size in uploadcenter. But I did not came up with the thread stack UAF exploit. So I wrote this article to write down what I thought most fun part of these challenges.

1. uploadcenter

a. file information

b. reverse engineering

  1. option1: allow you to input team name input the stack and then print it out. the interesting part is read() will not replace ‘\n’ with ‘\x00’ and the stack is not initialized, so printf might leak what is “left” on the stack by other functions. The delete function will leave a heap pointer on the stack which can be leaked by this function.

  2. option2:  the most complex function which accepts a zlib compressed png image, decompress and parse it, and add it to a linked list, the author uses zlib 1.2.8 which has several low or medium impact vulnerabilities described in this post. but as far as I know, these bugs are not exploitable in this challenge.

    note the mmap call, size equals height multiply the width of the png, which is under our control.
  3. option3 show file information, not interesting.
  4. option4 delete file, the related code is:

    although the unlink operation is not safe, I did not find any chances of a heap overflow or heap use-after-free in this program. This unsafe unlink is no more than a decoy set up by the author, but this is the reality of code review, you will keep hitting your head against thousands lines of complex pseudocode, finding nothing, until the bug got caught. I spent too much time looking for heap overflow: set up a png fuzzer and fuzz the png parse code, nothing found.

    Pay attention to munmap()’s size parameter, you will find there is a mismatch! munmap’s size is the whole png size while the mmap size is width*height. During the fuzzing of png header, I do found some mmap() allocated memory has been strangely unmapped, e.g. the temp buffer storing the user input is unmapped. But how to gain RCE using this vulnerability? This write-up by Dragon Sector describes it well. In short words, is creating a thread stack use-after-free by exploiting the mmap/munmap mismatch.
  5. option5 and option6 both create a thread but option 6 create a thread that will never return. because of the pthread_lock() and pthread_cond_wait() call, The thread is “frozen” until a new png is uploaded. the following is options6 code:


  1. upload an image A with 8MB mmap size and  8MB munmap size
  2. upload an image B with 8MB mmap size  and 16MB munmap size
  3. delete image B (which will unmap image A either )
  4. create a monitor thread(thread stack will be allocated the same place as image A’s position)
  5. delete image A( munmap the thread stack)
  6. upload image X with 8MB mmap size and 8MB munmap size (with crafted thread stack)
  7. ROP to execute execve(“bin/sh”,0,0)!


  1. A thread stack is allocated with mmap(size=0x801000), so we can prepare our png size carefully to mmap exactly the same as a thread stack.
  2. do not call system() directly because the thread cookie is overwritten. use magic gadget instead.
  3. A useful gadget learnt from HITCON’s writeup


TB continued.

No Comments

Leave a Reply