Brandon T. Elliott

home

Proving Grounds Play Walkthrough: "SunsetMidnight"

Proving Grounds Play

PG Play is a hands-on learning platform by OffSec with machines ranging in difficulty from Easy to Hard.

The Machine

SunsetMidnight is an intermediate rated machine that’s also rated as intermediate by the community.

Enumeration

First, I will export the IP of the machine to the $IP environment variable for ease of use within commands.

Nmap

Since all we’re given is an IP, nmap is the first thing we need to run:

nmap

We see ports 22/ssh, 80/http, and 3306/mysql are open.

The most interesting service here is mysql, because it isn’t normal for the port to be exposed remotely.

However, before enumerating mysql, we can first take an initial look at the http site.

Sunset-Midnight

Navigating to the http site in our browser, we are met with a redirect to sunset-midnight, therefore we will first add the machine IP and hostname to our /etc/hosts file.

After doing so, we can now browse to the site, which is quite clearly a wordpress site:

wordpress

Manual Inspection

Manual inspection of the site does not give us much, however, we do see that the default user admin is the author of the default Hello World post:

hello-world

Feroxbuster

We can go ahead and start a file/directory scan using feroxbuster while we continue our initial enumeration…

However, this didn’t end up returning anything of use to us, as only the default directories and files that are normally present in wordpress sites were returned.

Robots.txt

We can also look at robots.txt:

User-agent: *
Disallow: /wp-admin/
Allow: /wp-admin/admin-ajax.php

However, this appears to be a default robots.txt from wordpress, so nothing to see here…

WPScan

Next we will run wpscan, which is a good enumeration tool for wordpress sites:

wpscan

This gives us some intriguing info, such as xmlrpc being enabled, the wordpress version being 5.4.2, a plugin called simply-poll-master being present with version 1.5, as well as directory listing being enabled for the uploads directory, among other things…

Searchsploit

Using searchsploit to look for PoCs for the wordpress version as well as the plugin, however, leads to nothing, as well as nothing of interest being present in the uploads directory.

User Enumeration

Running wpscan again, but with --enumerate u to look for additional users, also leads to nothing, as it only returns the admin user that we already knew of.

With nothing else to go off of, it’s possible that this machine requires us to brute-force the admin user.

However, first, we will turn our attention to the open mysql port.

Mysql

We can first use searchsploit to look for potential PoCs for the version of mysql present which is 5.5.5-10.3.22-MariaDB-0+deb10u1, but this results in nothing of interest.

Hydra - Mysql Login

We can try to brute-force the mysql login using hydra.

Since the default user for mysql is root, we will first try with this user:

hydra -l root -P /usr/share/wordlists/rockyou.txt $IP mysql -t 4

After less than a minute, this returns a valid username and password!

login: root password: robert

We can now login to the mysql service by running:

mysql -h $IP -u root -p

and inputting robert as the password.

We will first list the databases present with show databases; which results in:

+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| wordpress_db       |
+--------------------+

We will then look at the wordpress_db database to try to extract the wordpress credentials:

use wordpress_db;
show tables;

+------------------------+
| Tables_in_wordpress_db |
+------------------------+
| wp_commentmeta         |
| wp_comments            |
| wp_links               |
| wp_options             |
| wp_postmeta            |
| wp_posts               |
| wp_sp_polls            |
| wp_term_relationships  |
| wp_term_taxonomy       |
| wp_termmeta            |
| wp_terms               |
| wp_usermeta            |
| wp_users               |
+------------------------+
select * from wp_users;

+----+------------+------------------------------------+---------------+---------------------+------------------------+---------------------+---------------------+-------------+--------------+
| ID | user_login | user_pass                          | user_nicename | user_email          | user_url               | user_registered     | user_activation_key | user_status | display_name |
+----+------------+------------------------------------+---------------+---------------------+------------------------+---------------------+---------------------+-------------+--------------+
|  1 | admin      | $P$BaWk4oeAmrdn453hR6O6BvDqoF9yy6/ | admin         | example@example.com | http://sunset-midnight | 2020-07-16 19:10:47 |                     |           0 | admin        |
+----+------------+------------------------------------+---------------+---------------------+------------------------+---------------------+---------------------+-------------+--------------+
1 row in set (0.043 sec)

We now have multiple choices to continue here, we can try to crack the hash $P$BaWk4oeAmrdn453hR6O6BvDqoF9yy6/ of the admin user, or we can simply generate our own password hash and update it.

I am going to opt to try to crack the hash first, because:

  1. The password may be re-used elsewhere.
  2. It is less intrusive to use the current password than to change it (if possible).

However, after saving the hash to a file called hash and trying to crack it with john using john --wordlist=/usr/share/wordlists/rockyou.txt hash, it wasn’t able to be cracked with that wordlist.

So, moving on, we can generate our own wordpress hash using an online tool. A password of admin results in the hash $P$BDAZikbiusGcI7G1VRlHry7NrqzPKh/

To modify the password within the mysql database with our new hash, we can use the following sql query:

UPDATE `wp_users` SET `user_pass` = '$P$BDAZikbiusGcI7G1VRlHry7NrqzPKh/' WHERE user_login = 'admin';

Now, we can navigate back to the wordpress site to login with the credentials admin:admin.

Wordpress

Once we’re logged in, we can use the tried and true method of replacing 404.php in the Theme Editor with a php reverse shell to our IP address.

We will modify the theme Twenty Nineteen since modifying the current theme results in an error.

theme-editor

With this in place, we can now set the current theme of the blog to Twenty Nineteen.

Then, we will start up the listener on our machine with nc -nlvp 9999.

With this running, we can now navigate to a page of the blog that does not exist in order to trigger the 404.php page to be loaded.

This gives us a shell as the www-data user:

www-data

Stabilized Shell

Using python, we can stabilize our shell, which will make our lives a lot easier:

stabilize-shell

User

Running ls -l /home shows us that the box has one regular user jose and also that we have read access to this directory.

Inside the home directory of jose we see local.txt and user.txt.

local

We have read permissions to local.txt so we can go ahead and cat the contents of it and submit it for our first flag.

To gain access to user.txt however, we will have to escalate to the jose user.

Generally, when you have access as www-data, a good place to look for other credentials is in config files used by the website which normally have hardcoded credentials in them in order to access the database.

In this case, we can see in /var/www/html/wordpress that there is a wp-config.php file, which is standard for wordpress.

www-dir

Inside, we find hardcoded database credentials, which are potentially credentials re-used on the machine by jose:

config

After copying the password, we can now try to switch users to jose:

jose

And now that we are jose, we can again navigate to our home directory and cat the user.txt that we couldn’t access before:

user

However, this isn’t anything. Cool.

Next, we will need to escalate our privileges to root.

Root

Normally, the first thing I try to run is sudo -l, however, in this case, this gave us nothing.

Next, we can search for SUID files on the machine:

suids

All of these look to be standard, except for /usr/bin/status

However, searching for this on GTFOBins, there doesn’t appear to be anything documented for it. Possibly it’s a custom binary?

Let’s see what happens when we run it…

status-binary

Using the strings binary, we might be able to do a bit of basic analysis on what it’s doing:

status

The primary thing that stands out is the service ssh status string.

It seems that it may be calling the /usr/sbin/service binary but it’s not specifying the full path to it, therefore the $PATH environment variable will be used in order to locate it.

Therefore, we should be able to create our own service executable (which will just start a /bin/bash shell), modify the $PATH to place the path to our newly created service file (which will be in jose’s home directory) at the beginning of the $PATH so that it looks for it there first, and finally, execute the /usr/bin/status binary which will be ran with root permissions due to the SUID flag being set on it.

path

And…

root

Success!

Now we can change directories to /root and cat proof.txt to submit our final flag.