// HackTheBox  ·  writeup

Ultimatum

HackTheBox Easy grepCatscalePython
DFIRLinux

Scenario

Ultimatum is an easy Sherlock where you are tasked with analysing a compromised Linux server running a vulnerable WordPress plugin.

Executive Summary

An attacker fingerprinted a WordPress blog with a WordPress scanner, then abused a privilege escalation flaw in the Ultimate Member plugin through its public registration form to create an administrator account. They came back from a second address, logged in and browsed wp-admin by hand. From the theme editor they dropped a PHP reverse shell into a theme file, which gave them a shell as the web server user and a callback to an external host. They then staged a well-known Linux enumeration script in shared memory to look for privilege escalation paths. The Apache logs, a Catscale triage collection and its process and socket listings cover the whole chain.

Artifacts

Timestamp note: The archive extracts with unreadable permissions. Fix them on a working copy (chmod -R u+rwX) and leave the original untouched.

Reconnaissance

Q1 — Which security scanning tool was utilized by the attacker to fingerprint the blog website?

Start with the Apache access.log and count requests by user agent. One address sends 1895 POSTs to xmlrpc.php with a user agent that names its own tool and version, the signature of a WordPress user and password enumeration run. The question asks for name/version, so take both straight from the user agent string.

awk -F'"' '{print $6}' access.log | sort | uniq -c | sort -rn | head
Click flag to reveal WPScan/3.8.24

Initial Access

Q2 — Which CVE was exploited by the attacker?

Follow the scanner IP past the xmlrpc noise. It requests the Ultimate Member plugin’s readme.txt to read the version, then sends a POST to /index.php/register/ that returns a 302. A registration POST right after a version check on this plugin points to the Ultimate Member privilege escalation through registration. This one was reasoned from the request pattern and the plugin identity rather than read from an artifact, because nothing in the logs names the CVE.

grep 23.106.60.163 access.log | grep -E 'ultimate-member|/register/'
Click to reveal answer CVE-2023-3460
Q3 — What was the IP Address utilized by the attacker to exploit the CVE?

The registration POST from Q2 comes from the same address as the scanner. It is a public cloud address, which matters for Q5.

grep 'POST /index.php/register/' access.log
Click flag to reveal 23.106.60.163

Persistence

Q4 — What is the name of the backdoor user added to the blog as part of the exploitation process?

Ultimate Member serves a profile page per user. Immediately after the registration POST, the same IP requests a /index.php/user/<name>/ page, which is the newly created account being checked. The format mask (seven masked characters then n) fits the name.

grep 23.106.60.163 access.log | grep '/index.php/user/'
Click to reveal answer secragon
Q5 — After the exploit, the SOC team observed that the attacker's IP address changed and from the logs, it seems that the attacker manually explored the website after logging in. The SOC team believes that the previous IP seen during exploitation was a public cloud IP. What is the IP Address the attacker used after logging in to the site?

Look for the login POST that follows the registration. It arrives at 08:37:28 from a different address, and the requests after it are the irregular, page-by-page browsing of wp-admin that a person produces, unlike the scanner’s machine-paced traffic.

grep -E 'POST /wp-login.php|/wp-admin/' access.log | grep -v 23.106.60.163
Click flag to reveal 198.16.74.45

Execution

Q6 — The SOC team has suspicions that the attacker added a web shell for persistent access. Confirm the full path of the web shell on the server.

Theme-editor requests from the manual session point at a theme file. In the Catscale full-timeline.csv, one PHP file under the active theme was modified at 08:58:02, right after that activity, and its content is a stock PHP reverse shell. The filename is built to look like part of the block theme.

grep -i 'twentytwentythree' full-timeline.csv | grep '08:58'
Click to reveal answer /var/www/html/wp-content/themes/twentytwentythree/patterns/hidden-comments.php
Q7 — What was the value of the $shell variable in the web shell?

Read the file from Q6. It is the common PHP reverse shell, which sets $shell near the top. The same line also appears in the Misc list of known web shell content, which gives a quick way to match the file to a public tool.

grep -n '\$shell' hidden-comments.php

Gotcha: The format hint says “full variable”, but the accepted answer is only the quoted value followed by the semicolon, not the $shell = assignment.

Click flag to reveal 'uname -a; w; id; /bin/bash -i';
Q8 — What is the size of the webshell in bytes?

The timeline CSV carries a size column for every file. Filter it for the Q6 path and read the size.

grep 'hidden-comments.php' full-timeline.csv
Click to reveal answer 2592

Command and Control

Q9 — The SOC team believes that the attacker utilized the webshell to get RCE on the server. Can you confirm the C2 IP and Port?

The reverse shell sets $ip and $port at the top of the file. The collected socket listing confirms it: an established connection to that address owned by apache2, sh and bash.

grep -E '^\$(ip|port)' hidden-comments.php
grep ESTAB ss-anepo.txt
Click flag to reveal 43.204.24.76:6969
Q10 — What is the process ID of the process which enabled the Threat Actor (TA) to gain hands-on access to the server?

In the process listing, the Apache worker (apache2, 234471) spawned sh (234517), which spawned an interactive bash -i running as www-data (234521). The interactive shell is the process the attacker is typing into.

grep -E 'www-data.*(sh|bash)' ps.txt

Gotcha: The parent apache2 PID and the intermediate sh PID are both on the chain, but the question wants the process that gave the hands-on shell, which is bash -i.

Click to reveal answer 234521

Discovery

Q11 — What is the name of the script/tool utilized as part of internal enumeration and finding privilege escalation paths on the server?

Writable world locations are where a www-data shell can drop tools. The collected listing of /dev/shm shows an enumeration script staged there.

grep -E '/dev/shm|/tmp' dev-dir-files.txt
Click flag to reveal LinEnum.sh

Attack Summary

PhaseAction
ReconnaissanceWPScan fingerprints the blog and hammers xmlrpc.php from a cloud IP
Initial AccessVersion check on Ultimate Member, then a registration POST abusing CVE-2023-3460
PersistenceBackdoor admin account secragon created and its profile page checked
Initial AccessLogin from a second IP at 08:37:28, followed by manual wp-admin browsing
PersistenceTheme editor used to write a PHP reverse shell into the active theme, modified 08:58:02
Command and ControlWeb shell is triggered, apache2 spawns sh and bash -i, connecting to the C2
DiscoveryLinEnum.sh staged in /dev/shm to look for privilege escalation paths

IOCs

TypeValue
IP (scanner and exploit)23.106.60[.]163
IP (manual session)198.16.74[.]45
IP:port (C2)43.204.24[.]76:6969
User agentWPScan/3.8.24
Account (backdoor)secragon
File (web shell)/var/www/html/wp-content/themes/twentytwentythree/patterns/hidden-comments.php (2592 bytes)
File (enumeration)/dev/shm/LinEnum.sh

MITRE ATT&CK

TechniqueIDDescription
Active Scanning: Vulnerability ScanningT1595.002WPScan fingerprinting and xmlrpc enumeration
Exploit Public-Facing ApplicationT1190Ultimate Member registration flaw, CVE-2023-3460
Create Account: Local AccountT1136.001Backdoor administrator secragon on the blog
Server Software Component: Web ShellT1505.003PHP reverse shell written into a theme pattern file
Command and Scripting Interpreter: Unix ShellT1059.004bash -i spawned by the web server process
System Information DiscoveryT1082LinEnum.sh run for local enumeration

Defender Takeaways

An outdated plugin on a public WordPress site is the whole attack surface. The exploit was a single POST to the registration page. Patch Ultimate Member, disable open registration if it isn’t needed, and alert on a new administrator appearing seconds after a registration request.

Scanner user agents are free detections. WPScan announced itself by name and version and sent thousands of xmlrpc.php POSTs. Block or rate-limit xmlrpc.php, and alert on that user agent.

Disable the theme and plugin editor. DISALLOW_FILE_EDIT would have removed the path the attacker used to write PHP into the theme. File integrity monitoring on the theme directory would have flagged the modified file as well.

A web server process that spawns a shell is abnormal. The apache2 to sh to bash -i chain and an established outbound connection from www-data are easy to detect with process lineage rules and egress filtering. A web server has little reason to reach an arbitrary external port.

Conclusion

The attacker went from a plugin flaw to an interactive shell on the web server using a single registration request and the built-in theme editor. Every step left a plain trace in the Apache logs and the process and socket listings, but the exposure that mattered was that the site was both unpatched and allowed code edits from the admin panel.