Incident ResponseClient under NDA

WordPress Breach Dated, Scoped and Contained

A forensic assessment of a SocGholish-style compromise: read-only evidence, offline analysis and a rebuild call argued from proof

By Lotfi Otmanine

Client
Professional services firm (anonymized)
Engagement
Fixed-scope forensic assessment (Phase 0), delivered; rebuild scoped as a separate phase
Stack
WordPressPHPMySQLSSHKali LinuxLUKSage encryptionSHA-256 manifestsWayback Machineurlscan.io

Key result

25,000+

files verified against server hashes

01

Context

A professional services firm's WordPress site was reported by an external scanner as carrying a SocGholish fake browser update injection, the delivery chain associated with the TA2726 traffic distribution operation. The hosting provider's own scan reported no infected files. Variants in this family hide from the plugin list, serve clean pages to logged-in administrators and automation, and use the site itself as the first hop, so neither the dashboard nor the owner's own view of the site could be trusted as evidence.

The engagement opened with a fixed-scope assessment: preserve the compromised state, inventory what was present, assess the exposure of personal data and stored credentials, and settle one question with evidence: clean in place, or rebuild. The rules were strict. No change of any kind without specific approval, all access from an isolated analysis machine, nothing served by the site downloaded or executed. The report had to stand up to third-party review, so every finding carries a stated confidence and its limits.

02

The Challenge

  • No historical web, host or login logs existed for the period of the compromise, and platform backups were retained for 30 days only.
  • File modification times on the implants were forged, and a platform migration had reset every file's change time, so the filesystem alone could not date anything that happened before it.
  • The site's contact form had stored personal data for years, and its exposure had to be assessed without reading a single submission.
  • The site was still live and serving the injected loader during evidence capture, and containment could not modify site code or disturb the evidence.

03

Scope and Approach

Isolated lab and rules of engagement

All work ran from an isolated Linux analysis VM, with case data in an encrypted container mounted without execute permission. Nothing the site served was downloaded for execution. WordPress was not started on the server and its admin screens were never used as evidence, because this malware family hides from them. Secrets were recorded by name and location only, never by value.

Read-only evidence capture

A full timestamp listing was taken before any file content was read. The file archive was streamed over SSH straight to the VM, with nothing written on the server, and verified file by file against hashes computed on the server: over 25,000 files, all matching. The database was dumped in a single transaction with its triggers. Each stage closed with a SHA-256 manifest, and later manifests re-verified the earlier ones.

Offline analysis of files and database

The offline copy was enumerated directly: plugin folders, must-use plugins, drop-ins, configuration, rewrite rules and database triggers. This surfaced about a dozen unauthorised plugins under disguised names, an obfuscated loader in the web root, more than five thousand spam posts with forged publication dates, several subscriber accounts of unestablished origin, and every credential readable from inside the site.

Passive history from public sources

With no logs to work from, the timeline was rebuilt from third-party records: web archive captures, crawl records, scan services and domain registry data. Archived homepages bracketed the first visible alteration, archived pages dated each injected script and same-site gateway as it appeared, and archived sitemaps measured the spam as it grew. No indicator domain was visited or resolved at any point.

Containment, report and handoff

A holding page was deployed after approval, tested first in a header-gated mode, then made live. DNS was then moved off the compromised environment, which stays preserved and unchanged. The report states every finding with a severity, a separate confidence level and its limits, and the evidence was handed over as one encrypted package with its own delivery manifest.

04

Architecture flow

Compromised site
live, serving injected loader
Read-only capture
streamed over SSH, hashed
Encrypted offline copy
isolated VM, no execute
Files, database, archives
implants, exposure, timeline
Containment
holding page, then DNS move
Clean baseline?
backups vs dwell time
no
Rebuild recommended
yes
Clean in place
Encrypted handoff
report + delivery manifest

05

Technical Deep Dive

Dating a breach when the timestamps lie

All the gateway plugins carried one identical modified time, copied from an early cloaking plugin. Two script injectors were stamped with the site's original build date, yet one hard-coded a domain registered years later, which proved the date forged. Change times began at a platform migration and could not date anything earlier. So file times served only to find candidates; the dates came from public archive captures, cross-checked against post-migration change times.

Accessible is not the same as accessed

Around two hundred contact-form submissions containing personal data were assessed from counts, dates and field names only. None was read. They were split into before, within and after the observed compromise window. Attacker code ran inside the site and could read the database, so the records were accessible. Whether any was actually read cannot be shown either way without logs, and the report says exactly that.

A published flaw traced by reading code

A published advisory for the installed form plugin described unauthenticated reading of stored submissions. Instead of testing it, its permission checks were traced line by line through the preserved code and configuration. On that configuration the submission-reading path was reachable without login. It was reported as a conclusion from static reading, with the dates it could and could not cover, and with exploitation neither tested nor claimed.

Containment that never touched site code

The holding page was one new file, placed where the platform loads code before WordPress on every request. No existing file changed, and rollback is deletion. A test mode served it only to requests carrying a secret header. Once live, 37 of 38 sampled addresses returned it. The cached homepage could not be purged at the host, so public traffic was moved away by DNS instead, and the switch was verified independently.

06

Engineering Decisions

Rebuild, argued from evidence

No backup predated the compromise, the entry path was not established, unauthorised components had been added on at least ten separate occasions, and forged dates meant no inventory could be proven complete. Cleaning in place would remove what was found without proving nothing was missed, so the recommendation was a rebuild from official sources, with content migrated only after review.

Findings and inference kept apart

Each finding carries a severity and a separate confidence: established, corroborated or informed inference. The most likely entry path, a compromised administrator login, is stated as inference, not as a finding. Low confidence never lowers a severity, and a working hypothesis that proved wrong was withdrawn in writing rather than quietly dropped.

Deviations recorded, not smoothed over

An interrupted archive transfer was discarded and re-run, and a single authorised command-line start of WordPress during a cache purge attempt was logged as an exception. Each deviation went into the custody record with its timing and effect, so a third party can see exactly how every piece of evidence was handled.

07

Results

  • Compromise dated to more than a year before detection, bracketed by public archive captures, with forged file dates identified and set aside.
  • About a dozen disguised plugins and an obfuscated loader inventoried and their persistence mapped; must-use plugins, drop-ins, configuration, rewrite rules and database triggers checked and found clean.
  • Over 25,000 files and a complete database captured read-only, every file verified against server-side hashes, and handed over as one encrypted package with its own manifest.
  • Exposure of around two hundred stored contact-form submissions assessed without reading one, and every stored credential inventoried by presence, with a rotation and revocation list.
  • Site taken out of public service without modifying any existing file, and a rebuild recommendation delivered with its rationale, approved as the final assessment deliverable.

Have a site that needs this kind of care?

Tell me what is breaking or what you need built. I will reply with how I would approach it and what I would check first.

Custom quote within 24 hours

Chat on WhatsApp