Incident report · Hidden ELF backdoor

Incident report: the hidden ELF backdoor on a 261-account WHM server

A Scotland-based client called after one of their WooCommerce shops was listed as malicious on VirusTotal. Wordfence reported 283 infected files. ImunifyAV agreed at the file level. The database export was completely clean — no injected rows, no hidden administrator, no obfuscated code. All three results were accurate, and none of them found the backdoor: a packed x86-64 ELF binary sitting outside the web root entirely, in a hidden configuration folder inside the hosting account’s home directory.

Environment
WHM/cPanel server, 261 cPanel accounts (Scotland)
Trigger
A WooCommerce shop listed as malicious on VirusTotal
Scanner result
Wordfence: 283 infected files · backdoor: not flagged
Found by
WordPress-layer audit plus root SSH filesystem review

Start here · plain English

Every scan was clean about its own layer. The backdoor was in none of them.

The client operates a single WHM server carrying 261 cPanel accounts — WordPress sites plus several high-volume WooCommerce shops. The engagement began when one of those shops started appearing as malicious in VirusTotal results, which is a revenue problem long before it is a technical one.

The first round of evidence looked conclusive. Wordfence reported 283 infected files on the affected site, spread across several plugin files and the active theme. ImunifyAV, running on the cPanel side, produced a comparable file-level picture. A full SQL export of the site database was searched for injected markup, encoded values, unknown administrators, and modified options — and came back clean.

That combination is the finding. A pure file-modification infection, with no database persistence, no rogue administrator, and no obfuscated PHP loader, means the attacker never needed WordPress-level persistence — because something outside WordPress already had permission to rewrite those files whenever it wanted.

It did. A 1,388,544-byte packed x86-64 ELF executable was staged in the cPanel account’s home directory at ~/.config/htop/defunct — outside public_html, in a hidden folder that belongs to a legitimate Linux process viewer. No WordPress scanner reads that path, and no database export contains it.

261 cPanel accounts

One WHM server hosting a Scotland-based client’s WordPress sites and several large WooCommerce shops under one hosting boundary.

283 infected files

Wordfence correctly flagged injected plugin and theme files on the shop whose listing triggered the call.

Zero database findings

The full SQL export contained no injected content, no hidden administrator, and no obfuscated code — and that was the clue, not the reassurance.

One hidden ELF binary

Found only by reviewing the filesystem with root SSH access: ~/.config/htop/defunct, owner-only mode 0700, created 23 August 2026.

How the incident surfaced

The customer was told by VirusTotal, not by a scanner alert

Nobody on the estate received a security alert first. The shop owner discovered the problem the way most owners do: a public reputation service flagged the domain, and the consequences — browser warnings, ad-platform rejections, nervous customers — arrived immediately.

The natural request at that point is “clean the 283 files so the listing clears.” On a single-site install that is sometimes the whole job. On a WHM server with 261 accounts, an infection that rewrote files inside several plugins and the active theme raises a different question, and it is the only question worth answering first: not which files were changed, but what had the ability to change them.

  1. 01

    A shop was flagged publicly

    A WooCommerce store on the estate began showing as malicious in VirusTotal results — a reputational and revenue event that set the response clock, not a technical alert.

  2. 02

    Wordfence scan

    283 files flagged on the affected site across several plugins and the active theme: widespread modification of legitimate files, not one isolated dropper.

  3. 03

    ImunifyAV account scan

    The cPanel-side scanner returned a comparable file-level picture. Nothing in what the client saw pointed above the document root.

  4. 04

    Database review

    A complete SQL export was searched for injected markup, base64 blobs, unknown administrators, unexpected autoloaded options, and scheduled events. It was clean.

  5. 05

    Scope widened to the server

    With a shared WHM boundary, several revenue-critical stores, and a file-write capability nobody could account for, the engagement moved from site cleanup to server incident response.

Three clean results, one compromise

Each tool answered its own question correctly — and the answers did not add up

A clean database export is usually reported as good news. In this case it was the strongest indicator that the investigation was not finished. Most commodity WordPress infections leave something behind in the database, because that is how they survive a file cleanup: an injected script in the options table, an extra administrator, a scheduled event that rewrites the dropper. None of that was present.

The absence of an obfuscated PHP loader pointed the same way. Injected PHP is how an attacker regains file-write access through the web application. If files are being rewritten and no such loader exists, the write capability is arriving from somewhere else — a compromised system account, stolen SSH or SFTP credentials, or a process running as the account user.

So the correct reading of “Wordfence: 283 files, ImunifyAV: same, database: clean” was never “almost clean.” It was “we have found the damage and none of the mechanism.”

Evidence sourceWhat it reportedWhat that actually provesWhat it cannot prove
Wordfence scan283 modified or injected files across plugins and the active theme.Application files were rewritten after they were installed.Which process wrote them, or whether that process still has access.
ImunifyAV (cPanel)File-level detections consistent with Wordfence; nothing server-level surfaced to the client.The infected files matched known malicious patterns.That the account home directory above the document root is clean.
SQL database exportNo injected rows, no unknown administrator, no encoded option values, no rogue scheduled events.The attacker did not need WordPress-level persistence.That no persistence exists elsewhere in the account or on the server.
Lockora Security AuditWordPress core integrity, hardening state, component exposure, and user and capability review.Which application-level controls were missing, drifting, or already sound.Anything above the WordPress installation directory.
Filesystem review over root SSHOne hidden, recently created, non-standard ELF binary in the account home directory.An executable backdoor artifact was staged inside the hosting account.When it last ran, or what it did while it was running.

How the backdoor was found

The plugin-level audit narrowed the question. Root SSH answered it.

Lockora Security Audit was used to get a fast, consistent posture and integrity picture across the WordPress installations — core file integrity, hardening state, component exposure, and a full user and capability review. Lockora is our own plugin, published in the WordPress.org directory; it is used in engagements like this one because it produces the same structured output on every site in an estate, which makes the outliers obvious.

What that audit produced was not the backdoor. It produced the elimination. Once core integrity, configuration, users, roles, and the database were all accounted for, the remaining explanation for repeatedly rewritten plugin and theme files was no longer inside WordPress. It was underneath it.

The rest of the work was a filesystem review from root SSH on the WHM server: enumerate what exists, bound the search by the time window the infected files provide, and look specifically for things that have no business being in a hosting account.

  1. 01

    Establish a trusted vantage point

    Work from root SSH on the WHM server rather than from inside a single cPanel account, so the review is not limited by the permissions — or the visibility — of a user that may already be compromised.

  2. 02

    Bound the time window

    Use the modification timestamps of the infected plugin and theme files to define a search window instead of scanning 261 accounts blindly. Everything written inside that window is a candidate.

  3. 03

    Enumerate outside the document root

    Review the account home directory itself: dot-directories such as .config, .cache, .local, and .ssh, plus temporary and mail paths. These are the locations a WordPress scanner never reads and an owner never opens.

  4. 04

    Look for executables where none belong

    A hosting account serving WordPress has no legitimate reason to contain a user-owned, multi-megabyte compiled binary. File type, size, permission bits, and creation date are enough to isolate it — no reverse engineering required.

  5. 05

    Record before touching

    Capture the full path, ownership, permission mode, size, timestamps, and SHA-256 hash, and preserve a copy of the file, before any removal decision is taken. Deleting the only evidence turns the rest of the investigation into guesswork.

  6. 06

    Classify with a second opinion

    Submit the artifact for targeted scanning and compare its path and characteristics against published research, rather than trusting a single signature match in either direction.

The artifact

What the hidden file actually was

The file was not PHP, not a script, and not part of any installed application. It was a compiled Linux executable, deliberately placed in a directory that belongs to htop — a legitimate interactive process viewer whose configuration lives in ~/.config/htop on a normal system — and named to resemble a dead process entry in a listing.

The properties below are the complete set of observations retained from the review. The hash and path are published on purpose: they are indicators other administrators can check against their own servers.

PropertyObserved value
Path~/.config/htop/defunct — inside the cPanel account home, outside the document root
File typeMalformed / packed x86-64 ELF executable
Size1,388,544 bytes (approximately 1.36 MB)
SHA-256745fc2346e9ad0fdd00104c6d8732ecf7759cb053bd61c296c7b26e9ddb98d50
Permissions0700 — readable, writable, and executable only by the owning user
OwnershipThe site’s own cPanel user; not root, not a system account
Created23 August 2026
Targeted scan resultImunify heuristic classification SMW-HEUR-ELF
Runtime state at discoveryNot running; not open by any process
Persistence referencesNo cron entry, shell profile, or startup reference found
Paired key fileThe commonly associated defunct.dat was absent

Assessment · high confidence

The path and the profile match a Global Socket (gsocket) backdoor

The ~/.config/htop/defunct path is highly distinctive, and it is chosen for exactly the reasons that make it effective: htop is a legitimate tool, ~/.config is a legitimate hidden configuration directory, and “defunct” reads as a dead process entry to anyone skimming a listing. Nothing about the location looks like malware until you ask why a shared hosting account contains a compiled binary at all.

That path, combined with a packed x86-64 ELF of roughly this size in a hosting account, matches the Global Socket (gsocket) deployment pattern documented in Sansec’s malware research and in independent handler reports. On that basis the artifact is assessed with high confidence as a gsocket covert backdoor component.

gsocket itself is legitimate open-source software from The Hacker’s Choice. It establishes an end-to-end encrypted TCP session between two endpoints through a public relay network, addressed by a shared secret instead of an IP address and port. For an attacker holding a hosting account, that is close to ideal: no inbound port has to be opened, NAT and firewall rules are bypassed by design, and the traffic is encrypted and outbound, so a perimeter built around inbound rules never sees it.

Two observations argue against a fully activated channel at the moment of discovery. There was no defunct.dat — the paired file that commonly holds the shared secret — and no cron entry, shell profile, or startup reference invoking the binary. The plausible readings are that the capability was staged but not yet activated, that the launcher and key file were removed by an earlier partial cleanup or by the operator, or that activation used a route not preserved in the retained evidence. The available evidence does not settle which.

Confidence: high (artifact class)

The path, file characteristics, permissions, and account context match a documented gsocket deployment pattern.

Confidence: undetermined (execution)

Nothing in the retained evidence proved the binary ever ran on this server, and it was not running or open by any process when found.

Why attackers choose gsocket

No inbound port, NAT and firewall traversal through a public relay, end-to-end encryption, and a binary that can masquerade as an ordinary process.

Why the missing key file matters

gsocket deployments commonly store the shared secret beside the binary. Its absence moves the assessment from “active channel” toward “staged capability” — without proving either.

Identifying the tool is not attribution

gsocket is public software used by many unrelated actors. Naming the toolkit says nothing about who deployed it here.

Handled as live regardless

A staged remote-access capability inside an account on a 261-site server is treated as an active compromise until access is rotated and the estate is verified.

Why the scanners missed it

This was a scope boundary, not a scanner failure

It is tempting to conclude that Wordfence and ImunifyAV underperformed. They did not. They answered the questions they are built to answer, and the backdoor sat outside those questions.

Wordfence is a WordPress plugin. It runs inside the WordPress installation, and its file scanning is oriented around WordPress core, plugins, themes, and PHP content in the document root. A compiled binary in the account home directory is not in scope, contains no PHP for pattern matching to match, and is not reachable over the web at all.

ImunifyAV runs server-side and can see the account home. When the file was scanned directly it did match — as SMW-HEUR-ELF. That classification is a broad heuristic meaning roughly “an ELF binary where one is not expected in a user home directory,” not a gsocket-specific signature. Heuristics of that class are well known for flagging legitimate binaries, which is precisely why they get triaged as noise, allowlisted wholesale, or switched off. What the retained evidence does not establish is which of those happened here — only that nothing in the client’s scan results led anyone to that file.

  • WordPress security plugins are scoped to the WordPress installation; the account home directory sits above it.
  • The ~/.config directory is hidden, so it does not appear in ordinary FTP or File Manager listings unless hidden files are shown.
  • htop is legitimate software, so a ~/.config/htop directory looks like normal user configuration to anyone glancing at the tree.
  • A compiled ELF binary contains no PHP, so PHP-oriented pattern matching has nothing to match on.
  • Heuristic ELF detections are noisy by nature and are frequently dismissed, allowlisted, or disabled after false positives.
  • The database is the wrong place to look for a backdoor that never needed WordPress in the first place.
  • A per-site scan result is evidence about one document root — never about the server the document root sits on.

MITRE ATT&CK mapping

Standard technique names for the observed and assessed behavior

The mapping below describes behavior in shared vocabulary. It does not identify a threat actor, and it separates what was observed on disk from what the tool class is capable of. Where a mapping rests on the assessed identification rather than on observed execution, that is stated in the confidence line.

T1036.005Defense evasion

Masquerading: Match Legitimate Name or Location

The binary was stored in ~/.config/htop — the configuration directory of a legitimate process viewer — under a filename that reads as a dead process entry.

T1564.001Defense evasion

Hide Artifacts: Hidden Files and Directories

Placement inside a dot-directory kept the artifact out of ordinary file listings, FTP clients, and control-panel file managers used by the site owner.

T1027.002Defense evasion

Obfuscated Files or Information: Software Packing

The executable was a malformed and packed x86-64 ELF, which frustrates static inspection and signature matching against the unpacked tool.

T1219Command and control

Remote Access Software

gsocket provides interactive remote shell access using legitimate, publicly available software. The capability was staged on the account; execution on this server was not established.

T1090Command and control

Proxy

gsocket reaches its operator through a public relay network rather than a direct inbound connection, which is what makes it effective behind NAT and inbound firewall rules. No relay traffic was recovered from this environment.

Scope and limitations

What this report establishes and what it does not

AreaEvidence consideredBoundary
The artifactPath, ownership, permissions, size, timestamps, SHA-256, targeted scan classification, and runtime state at discovery.The binary was not reverse-engineered. The identification rests on characteristics, location, and published research.
Execution historyProcess table, open file handles, cron entries, shell profiles, and startup locations at review time.The absence of a reference at review time does not prove the binary never ran earlier.
Initial accessFile timestamps, account layout, shared-service exposure, and the logs still available.No entry vector is claimed. Log retention on shared hosting is rarely sufficient to prove one after the fact.
Blast radius261 cPanel accounts on one WHM instance, several of them revenue-critical WooCommerce stores.Accounts not individually reviewed are not certified clean by this report.
Visitor and customer impactWebsite-side file modifications and the public reputation listing that followed.Customer data access, order manipulation, and payment exposure require their own evidence and were not established here.
Client identityRegion and estate size are described so the scale of the environment is understood.Client name, domains, cPanel usernames, IP addresses, log excerpts, and credentials are redacted.

Check your own server · IOC triage

What to look for on a WHM or cPanel server you are responsible for

Every check below is read-only. Run them from a trusted device with root access, and preserve what you find — path, owner, permission mode, size, timestamps, and hash, plus a copy of the file — before deleting anything. A deleted artifact cannot be classified, and an unclassified artifact leaves you guessing about how far the compromise reached.

A match is not automatically this backdoor. Legitimate binaries do live in home directories on some systems, and heuristic ELF detections produce false positives. The point of the table is to tell you which observations deserve an explanation, not to declare every one of them malicious.

CheckWhere to lookWhat raises concernFirst safe action
The documented gsocket paths~/.config/htop/defunct and ~/.config/htop/defunct.dat in every account home, plus similar decoy locations under .ssh, .cache, and .local.Either file present. The .dat file holds the shared secret that lets whoever has it open a session to your server.Treat it as an active compromise: preserve the evidence, isolate the account, and start credential rotation immediately.
Known file hashFile hashes across all account home directories.A file matching SHA-256 745fc2346e9ad0fdd00104c6d8732ecf7759cb053bd61c296c7b26e9ddb98d50.Preserve the file, then treat that hosting account and every credential it holds as compromised.
Executables where none belongEvery /home account home, including hidden dot-directories, temporary paths, and mail directories.A user-owned executable file — commonly mode 0700 — in an account that should hold only web content, mail, and configuration.Record path, owner, mode, size, timestamps, and SHA-256; keep a preserved copy before any removal decision.
Processes with implausible namesThe running process list, including entries styled as kernel threads in square brackets.A process presenting as a kernel thread but owned by a hosting user, or a running process whose executable path has been deleted.Capture the process, its owner, its open file handles, and its network connections before terminating anything.
Unexplained outbound sessionsLong-lived outbound TCP connections originating from hosting user accounts.Persistent outbound sessions from a web hosting account to hosts unrelated to updates, mail, payments, or your CDN.Record endpoints and timing. Do not assume inbound firewall rules would have prevented the channel — they do not apply to it.
Account-level persistenceThe crontab of every hosting user, plus ~/.bashrc, ~/.bash_profile, ~/.profile, and any user service units.Entries invoking a binary from a dot-directory, or lines appended long after the account was created.Preserve the file, then compare it against a known-good account of similar age on the same server.
File-write correlationModification timestamps of the infected plugin, theme, and core files.Application files rewritten in a tight window with no matching deployment, update, or editor session to explain it.Use that window to bound the rest of the search across the account and the server, rather than scanning everything at once.
Cross-account repetitionThe other accounts on the same WHM server, especially those sharing an owner, a deployment routine, or a backup source.The same artifact, path, timestamp cluster, or infection pattern appearing in more than one account.Escalate to a server-level incident. Do not certify individual accounts clean while a shared cause is unexplained.

Containment and eradication

On a shared WHM server, per-site cleanup is the last step, not the first

01

Preserve

Copy the artifact, hashes, timestamps, and logs before anything is deleted.

02

Contain

Isolate the affected account and close the access the binary would have used.

03

Rotate

Change every credential the account and the server hold, from a trusted device.

04

Rebuild

Replace the infected application files from verified sources instead of editing them.

05

Verify

Re-check the estate after caches, cron, updates, and normal traffic have run again.

  1. 01

    Preserve the artifact and its context

    Keep the binary, its hash, its timestamps, its ownership, and the surrounding directory listing. This is the only material that can later answer how far the compromise reached.

  2. 02

    Isolate the affected account

    Restrict or suspend the account rather than the whole server where the business allows it, and remove the account user’s ability to execute binaries from its home directory.

  3. 03

    Treat the account user as compromised

    Everything that user could reach is in scope: its document roots, its cron, its SSH keys, its mail, its databases. Everything it wrote since the artifact’s creation date is untrusted until it is verified.

  4. 04

    Rotate credentials across the estate

    WHM and cPanel logins, SSH keys, FTP and SFTP accounts, database users, WordPress administrators and application passwords, API tokens, payment and shipping integrations, and deployment secrets — rotated from a device that is not part of the incident.

  5. 05

    Rebuild the infected application files

    Replace WordPress core, plugins, and themes from verified sources rather than stripping injected lines. 283 flagged files is a rebuild, not an edit — and hand-editing leaves the ones nobody flagged.

  6. 06

    Sweep every other account

    A backdoor in one account on a 261-account server is a server-level finding until the same method has been applied to the others. Shared owners, shared deployment routines, and shared backups are the priority order.

  7. 07

    Close the enabling condition

    Establish how the account user could write to plugin and theme files at all, how a binary could be dropped and executed from a home directory, and whether account isolation on the server actually holds under test.

  8. 08

    Re-check after normal operation resumes

    Verify after caches expire, cron runs, plugin updates apply, and traffic returns. That is the point at which an incomplete cleanup reveals itself — not the moment the homepage looks right.

Prevention for hosts and agencies

The controls that turn an invisible incident into an alert

Monitor above the web root

Alert on new executable files anywhere in account home directories — not only inside document roots, which is where every application scanner already looks.

Restrict execution from home directories

Where the hosting model permits it, prevent execution of user-written binaries from home, temporary, and upload paths. A backdoor that cannot execute is an artifact, not a channel.

Watch egress, not just ingress

A relay-based backdoor needs no inbound port, so inbound firewall rules never see it. Baseline what hosting accounts normally connect to and alert on the rest.

Keep accounts genuinely isolated

Separate system users, restricted shells, controlled cron, and least-privilege database users limit how far one compromised site can reach on a 261-account server.

Do not switch off heuristic ELF detection

It is noisy, and the right answer is an allowlist of known-good binaries with a triage routine — not disabling the only class of detection that would have flagged this file.

Review each layer independently

An application scanner, a server scanner, and a filesystem review answer three different questions. A clean result from one is never a clean result for the server.

Conclusion

The scan results were accurate. The conclusion drawn from them would have been wrong.

Wordfence found 283 infected files and was right. ImunifyAV agreed at the file level and was right. The database export was clean and that was true. A cleanup built on those three results would have removed the visible damage, restored the shop, and cleared the public listing — while leaving a remote-access capability inside a hosting account that had write permission over every file it had just rewritten.

The finding came from one deliberately unglamorous step: looking outside the application, with root access, at the directories a site owner never opens. That step is the difference between a site cleanup and a server incident response, and on an estate of 261 accounts sharing one boundary it is not optional.

Client identifiers, domains, account names, and log excerpts are withheld from this report. The file hash and the path are published on purpose — they cost an attacker nothing and they let another administrator check their own server tonight.

Common questions

Questions about this incident

Would Wordfence have caught this backdoor with different settings?

Not in the ordinary case. Wordfence runs inside the WordPress installation and is oriented toward WordPress core, plugins, themes, and PHP content in the document root. The binary sat in the hosting account’s home directory above that root, contained no PHP, and was never reachable over the web. It found the damage correctly — the mechanism was outside its scope.

Is a clean database export good news after a malware infection?

It is useful evidence, and it is often misread. Most commodity WordPress infections leave database persistence behind. When files are being rewritten and the database is clean, with no rogue administrator and no obfuscated loader, the likely explanation is that the attacker has write access from outside the application — which is a more serious situation, not a less serious one.

Can I just delete the file if I find it on my server?

Not as a first move. Preserve a copy along with its path, owner, permission mode, size, timestamps, and SHA-256 hash first. Deleting the artifact destroys the only material that can establish whether it ran, what it could reach, and whether another copy exists in a different account — and the account credentials still need rotating either way.

Does a missing defunct.dat mean the server was never actually accessed?

No. It means the shared secret was not sitting next to the binary at the time of review. The capability may have been staged and not yet activated, or the launcher and key file may have been removed earlier. On a server carrying 261 accounts, a staged remote-access binary is handled as an active compromise until access has been rotated and the estate verified.

Is gsocket itself malware?

No. gsocket is legitimate open-source networking software from The Hacker’s Choice, used lawfully for remote administration through NAT and firewalls. What makes this instance malicious is the context: an unexplained, packed, owner-only copy hidden in the configuration directory of a hosting account that has no legitimate use for it, on a site whose plugin and theme files were being rewritten by something nobody could account for.

We host WordPress for clients on WHM. Where do we start?

Start with a read-only sweep of every account home for the paths and hash in this report, then bound a wider search by the timestamps of any files you already know were modified. If anything turns up in more than one account, treat it as a server-level incident rather than a set of site cleanups — that distinction determines whether the cleanup holds.

Choose the response path

The containment plan should match the size of the incident.

One infected WordPress or WooCommerce site

Find the mechanism, not just the flagged files.

Best for an owner whose site is flagged, blocklisted, or reinfecting after a cleanup that removed everything the scanner reported.

A WHM server, host, or agency estate

Sweep the whole server before certifying any account clean.

Best when many cPanel accounts share one server, one owner, or one deployment routine — and a finding in one account has to be answered for all of them.