// HackTheBox  ·  writeup

RouteCause

HackTheBox Easy tsharkWiresharksha256sumunzip
DFIR

Scenario

MediCare Pvt. Ltd. runs its public website on a single internet-facing server. On the night of 30 July 2026 their monitoring flagged a burst of requests from an unknown address, followed by a long interactive session. Nobody looked at the alert until the next morning. By then the server had already been rebuilt. No logs, no disk image, nothing except a packet capture from the perimeter. Work out how the attacker got in and what they left behind

Executive Summary

One external host scanned a WordPress site with a WPScan-style tool, then switched to a purpose-built exploit that abused the REST batch route to bypass authentication and spawn a temporary administrator. That account uploaded a plugin that gave command execution, followed by a second plugin whose only job was to create a hidden persistent admin and which fired minutes later. With a shell, the attacker planted a deliberately vulnerable plugin so they could upload files without credentials, published a page to reach it, and used it to drop a loader into the must-use plugin directory where other users would not see it. They finished by wiping the site’s backup directory. The whole intrusion is recoverable from the HTTP traffic in a single perimeter capture.

Artifacts

Timestamp note: The capture’s local timezone is +1000. Every answer uses UTC, which is what HTB accepted, so convert before submitting.

Reconnaissance

Q1 — What is the IP address of the attacker's machine?

Start with the conversation and endpoint statistics. One external address owns all of the HTTP attack traffic against the web server, so it is the attacker. Every later pivot in this case is a filter on that source.

tshark -r capture.pcap -q -z endpoints,ip
Click flag to reveal 176.107.185.250
Q2 — Prior to exploiting a CVE, the attacker enumerated the site with an automated tool. What custom User-Agent string did that tool present?

Dump every HTTP request from the attacker IP to a TSV with time, URI, method and User-Agent, then count requests per UA. One legacy Firefox 11 string on Linux i686 sends 178 requests in about six seconds, hitting plugin and theme paths in the pattern of a WPScan-style scanner. A real browser never produces that rate or that path list.

tshark -r capture.pcap -Y 'ip.src==176.107.185.250 && http.request' -T fields -e frame.time_utc -e http.request.method -e http.request.uri -e http.user_agent > work/http.tsv
cut -f4 work/http.tsv | sort | uniq -c | sort -rn

Tip: The format mask in the task is the shape of the string itself, which is a quick sanity check against the top UA in the count.

Click to reveal answer Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.16) Gecko/20120421 Gecko Firefox/11.0
Q3 — When did the attacker's enumeration activity begin?

Take the first request carrying the Q2 User-Agent. Use UTC output (frame.time_utc) rather than local time, since the capture sensor ran at +1000.

grep 'Firefox/11.0' work/http.tsv | head -1
Click flag to reveal 2026-07-30 19:09:44

Initial Access

Q4 — Immediately after the enumeration activity, a purpose-built tool took over. What User-Agent did it use?

The scanner goes quiet at 19:09:50 and a new UA appears from the same IP at 19:11:01. Its name is the tool’s own, short and not browser-shaped, which marks it as the exploit client.

awk -F'\t' '{print $4}' work/http.tsv | uniq -c
Click to reveal answer wp2shell
Q5 — Which server-side API endpoint did that tool repeatedly abuse to obtain unauthenticated access?

Filter requests from the Q4 UA. The tool sends repeated POSTs to /?rest_route=/batch/v1, the REST batch route, which lets it bundle sub-requests into one unauthenticated call.

tshark -r capture.pcap -Y 'http.user_agent=="wp2shell" && http.request.method=="POST"' -T fields -e frame.time_utc -e http.request.uri
Click flag to reveal /batch/v1
Q6 — Identify the CVE IDs that the attacker exploited.

The pcap carries no CVE identifiers, so this one comes from advisories. The behaviour is an unauthenticated SQL injection in WordPress core reachable through the batch route, and a Patchstack write-up on the core fix (https://www.patchstack.com/articles/unauthenticated-sql-injection-in-wordpress-core-fixed-in-7-0-2/) lists the two CVE IDs. This was matched from reference material, not read from an artifact.

Gotcha: The platform accepts the two IDs only in one order, lowest number first. The reverse order is rejected.

Click to reveal answer CVE-2026-60137, CVE-2026-63030
Q7 — Exploitation produced a temporary administrative account. What are its credentials?

Right after the batch exploit, the tool logs in over wp-login.php. Decode the POST body: the log and URL-encoded pwd fields hold the generated admin account. Run the password through a URL decode so %21 and similar become literal characters.

tshark -r capture.pcap -Y 'http.request.method=="POST" && http.request.uri contains "wp-login.php"' -T fields -e urlencoded-form.key -e urlencoded-form.value
Click flag to reveal wp2_bb9ed300485b:Wp2!88_r0dvCRWzTvoGK9Cbz

Execution

Q8 — Using the new account, the exploit uploaded a file that facilitated command execution. What is the name of the file that was uploaded by the exploit?

Plugin installs go through update.php?action=upload-plugin as multipart POSTs. Export the HTTP objects and pull the multipart filename from the first upload after the login. It is a zip containing a PHP file of the same stem, which is the webshell wrapper.

tshark -r capture.pcap --export-objects http,work/obj -q
unzip -l work/up/*.zip

Gotcha: The question asks for the uploaded file, which is the .zip named in the multipart header, not the .php file inside it.

Click to reveal answer wp2shell_602a13ff.zip

Persistence

Q9 — The attacker installed a backdoor component whose sole purpose was persistence on the server. What is the hash of the file that was used to create backdoor access?

A second plugin upload follows the webshell, carried in frame 18285. Carve the multipart body out of that frame, unzip it, and hash the PHP file wp-insights-collector.php. The hash is of the PHP file, not the zip.

sha256sum work/up/b/wp-insights-collector.php
Click flag to reveal AE29E0ACF2071277F3DBCA178895F2602C4D06E42727225AA6A610803393ABE4
Q10 — What are the credentials of the backdoor account configured for persistent access?

Read the carved plugin source from Q9. It calls wp_create_user with a hard-coded username and password, gated behind a trigger condition.

grep -n 'wp_create_user' -B3 -A3 work/up/b/wp-insights-collector.php
Click to reveal answer wp_insights_user:insightsuser@!123
Q11 — When was the backdoor component triggered?

The plugin source from Q9 fires on a request to /?collect=go. Find the GET carrying that parameter; it sits in frame 19072. Read its timestamp in UTC.

tshark -r capture.pcap -Y 'http.request.uri contains "collect=go"' -T fields -e frame.number -e frame.time_utc
Click flag to reveal 2026-07-30 19:18:29
Q12 — What is the CVE ID of the flaw that the attacker deliberately introduced on the server to allow for unattended file upload capability?

A third upload-plugin POST, frame 20447, installs career-section.1.7.zip. That plugin version carries an unauthenticated arbitrary file upload, documented in Wordfence’s entry for Career Section 1.7 (https://www.wordfence.com/threat-intel/vulnerabilities/wordpress-plugins/career-section/career-section-17-unauthenticated-arbitrary-file-upload). The CVE ID comes from that advisory, matched to the plugin name and version seen in the capture.

tshark -r capture.pcap -Y 'frame.number==20447' -T fields -e http.file_data | head -c 300
Click to reveal answer CVE-2026-6271
Q13 — To reach the vulnerable upload feature, the attacker had to publish a page. What is its title?

The Career Section upload form is rendered through a shortcode on a public page, so the attacker had to create one. Look at the post creation in the capture for the title of the new post (post 27) carrying the csection shortcode.

tshark -r capture.pcap -Y 'http.request.method=="POST" && http.request.uri contains "post.php"' -T fields -e urlencoded-form.key -e urlencoded-form.value
Click flag to reveal Health Care Assistant Needed

Defense Evasion

Q14 — A file was uploaded through the public page form and was eventually moved to a path where it could hide certain components from other users. What is the full path of the file after it was moved?

Follow the webshell traffic after the page goes live. The command channel shows the upload landing as 1785439610_hider.php, then a mv that relocates it to ../../mu-plugins/hider.php. Must-use plugins do not appear in the normal plugin list, which is the hiding. Resolve the relative path against the web root of the site.

tshark -r capture.pcap -Y 'http.request.uri contains "mu-plugins" || http.file_data contains "hider"' -T fields -e frame.number -e http.request.uri
Click to reveal answer /var/www/html/wp-content/mu-plugins/hider.php

Impact

Q15 — The attacker destroyed the server's recovery capability. When did this occur?

The last meaningful webshell command removes the backup archives: rm -rf backup* inside wp-content/updraft, the UpdraftPlus backup directory. Take the timestamp of that request in UTC.

tshark -r capture.pcap -Y 'http.request.uri contains "updraft" || http.file_data contains "rm -rf"' -T fields -e frame.time_utc -e http.request.uri
Click flag to reveal 2026-07-30 19:31:37

Attack Summary

PhaseAction
ReconnaissanceWPScan-style enumeration with a spoofed legacy Firefox User-Agent
Initial Accesswp2shell exploit abuses the REST batch route for unauthenticated access
Initial AccessTemporary administrator account created and used to log in
ExecutionPlugin zip uploaded that gives command execution
PersistenceSecond plugin uploaded that creates a hidden backdoor admin when triggered
PersistenceBackdoor triggered with a collect=go request
PersistenceVulnerable Career Section plugin installed and a public page published to expose its upload form
Defense EvasionUploaded loader moved into mu-plugins to hide it from the plugin list
ImpactBackup directory wiped with rm -rf

Forensic Timeline

Timestamp (UTC)Event
2026-07-30 19:09:44Enumeration begins with the Firefox 11 User-Agent
2026-07-30 19:09:50Enumeration ends after 178 requests
2026-07-30 19:11:01wp2shell User-Agent first appears
2026-07-30 19:18:29Backdoor plugin triggered via /?collect=go
2026-07-30 19:31:37Backups deleted from wp-content/updraft

IOCs

TypeValue
IP176.107.185[.]250
User-Agent (scanner)Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.16) Gecko/20120421 Gecko Firefox/11.0
User-Agent (exploit)wp2shell
Account (temporary admin)wp2_bb9ed300485b
Account (backdoor)wp_insights_user
Filewp2shell_602a13ff.zip
Filewp-insights-collector.php
SHA-256ae29e0acf2071277f3dbca178895f2602c4d06e42727225aa6a610803393abe4
Path/var/www/html/wp-content/mu-plugins/hider.php
Plugincareer-section 1.7

MITRE ATT&CK

TechniqueIDDescription
Active Scanning: Wordlist ScanningT1595.002WPScan-style plugin and theme enumeration
Exploit Public-Facing ApplicationT1190Batch route authentication bypass in WordPress core
Valid Accounts: Local AccountsT1078.003Login with the account the exploit generated
Server Software Component: Web ShellT1505.003Uploaded plugin giving command execution
Create Account: Local AccountT1136.001wp_insights_user backdoor admin
Event Triggered ExecutionT1546Backdoor plugin fires on a crafted request
Indicator Removal: File DeletionT1070.004Loader tucked into mu-plugins and backups removed
Data DestructionT1485Backup directory wiped

Defender Takeaways

An unauthenticated core route needs to be patched fast and fronted by a WAF. The batch endpoint gave the attacker admin without any credential. Patch cadence for WordPress core and a rule limiting rest_route=/batch/v1 from the internet would have closed the door.

Scanner traffic is the early warning. 178 requests in six seconds under a fake legacy browser string is a trivially alertable burst. The exploit followed about a minute later, so a block at the scan stage would have cost the attacker the foothold.

Plugin uploads by new administrators should page someone. Three upload-plugin calls in one session, two shortly after an admin appeared, is an unmistakable pattern. Disable file modification in the dashboard (DISALLOW_FILE_MODS) so plugin installs through the web UI fail outright.

Watch mu-plugins and the user table. Must-use plugins load silently and never show in the plugin list. Monitor that directory for new files, and alert on new administrator accounts created outside a change window.

Keep backups off the web host. The attacker only had to run rm -rf on a local directory to remove recovery. Offsite, immutable backups would have survived, and a perimeter capture should not be the only evidence left, so ship web logs off the box.

Conclusion

The attacker went from a scanner to a hidden persistent administrator and deleted the backups in about twenty minutes, all over plain HTTP. The packet capture was the only record left because the server was rebuilt, which is the argument for shipping web logs and backups off the host.