Free website migrationGet started
TopSyde
Abstract streams of light spiralling into a dark centre, ringed by small networks of connected points

The WordPress Implant That Rebuilt Itself From a Browser Tab

A teardown of SC, a self-healing WordPress implant we've removed from client sites since July 2026: drop-in persistence, a daemon that outlives PHP restarts, Ethereum-hosted C2, cloaked admins, captured passwords, and how to get rid of it for good.

Colton Joseph

Colton Joseph

Founder & Lead Developer

··17 min read

Last updated: October 16, 2026

Since July 2026 we have been removing the same piece of WordPress malware from client sites, over and over, as it changed under us. It calls itself "SC" in its own markers. We've seen versions 4.0.3, 4.5.3, 4.5.7 and, this morning, 5.1.0. Every version is built around one idea: a cleanup should fail. It keeps copies of itself in a dozen places, puts back whatever you delete, hides the administrator accounts it creates, writes down every password typed into the login form, and takes its orders from an Ethereum smart contract, so there is no server to take down.

This is everything we've learned, written for the people who have to clean it up: what it plants, how it hides, the three ways it came back after we thought it was gone, and the order of operations that finally made it stay gone. The indicators at the end are free to use. No client is named, and nothing here would identify one.

How it gets in

In every case where the logs reached back far enough, SC arrived through the front door. Someone logged into wp-admin as a real administrator and uploaded a plugin ZIP through Plugins → Add New → Upload. The plugin names are random and plausible: "Vapor Booster Pad", "Datum Router Pad", "Pulse Interface Dot", "Bright Generator". The ZIP carries a loader plugin, and the loader does the rest within a second of activation.

How the first administrator password was obtained, we can't say for every site. Several ran badly outdated plugins before they came to us, and the earliest access logs had already rotated away. What we can say is how the later ones were obtained, because SC wrote them down itself. More on that below.

What it plants

A full SC install touches far more of WordPress than most malware does. On a single site running 4.5.7 we removed 41 files and 63 database rows and cron entries. The layers, roughly in the order WordPress loads them:

LayerWhereWhy it matters
Auto-prepend.user.ini in the webroot and wp-content/, auto_prepend_file pointing at a hex-named PHP filePHP runs it before WordPress loads, on every request. Reinstalling core, plugins or the theme doesn't touch it.
Drop-inswp-content/db.php, object-cache.php, advanced-cache.phpWordPress loads these before any plugin or mu-plugin. SC also pins define('WP_CACHE', true); /* SC_WC */ into wp-config.php so advanced-cache.php always loads.
mu-plugin and pluginmu-plugins/<slug>.php plus a full plugin copyThe visible half. Removing it alone achieves nothing.
Theme blockAn SC_TH block appended to the active (child) theme's functions.phpUsually hundreds of lines added after the site's real code. One theme file went from 23 KB to 252 KB.
Replica directorywp-content/.sc_<8 hex>/Dot-prefixed, so a casual ls skips it.
Self-heal kitsZIPs named <8 hex>.zip in wp-content/, a theme folder and uploads/YYYY/MM/Up to three copies. WordPress's -1, -2 filename suffixes on repeated uploads give the loop away.
Database rowssc_* options and 12-character hex option namesHold the full implant source (140 KB to 731 KB), JavaScript payloads, C2 addresses, staged admin names and captured logins.
CronRandom-looking hook names, some one letter followed by noiseRe-fetch and re-heal on a schedule.

Most files are timestomped. Every re-dropped copy gets the same modification time, often weeks before the real install, so find -mtime -7 misses all of it. The ctime (inode change time) can't be set from PHP and tells the truth. Sort by ctime across the infection window and the whole install lines up within a minute or two.

The database half survives on its own

The hex-named rows are encrypted with a one-byte key: base64-decode the value, and the first byte is the XOR key for everything after it. Decoded, they are serialized PHP strings. One holds the entire implant. Others hold names like administrator_3f9a1c (an admin account it intends to create), a 24-character token, and arrays of login => password pairs.

Because a small key keeps most bytes printable, these rows don't look like the high-entropy blobs scanners are tuned to spot. We found sites where a file cleanup months earlier had left the database half behind. It sat dormant, then came back to life the moment anything executed its loader again. One site arrived from another host with only its database migrated and still carried 49 SC rows, including a 731 KB copy of the implant and three captured logins.

If you clean only files, you have cleaned half an infection. It's the same trap behind most of the reinfection cycles we're asked to break.

How it hides

Administrator accounts. SC creates admins named adm_, admin_, administrator_ or backup_ followed by hex characters, then hooks pre_user_query, rest_user_query and views_users so they vanish from the Users screen, the REST API and the role counts. wp user list lies too, because the implant loads as a drop-in before WP-CLI's --skip-plugins has any say. The only reliable count is the database itself:

SELECT u.user_login, u.user_registered
FROM wp_users u
JOIN wp_usermeta m ON m.user_id = u.ID
WHERE m.meta_key = 'wp_capabilities'
  AND m.meta_value LIKE '%administrator%';

If that returns more rows than the Users screen shows, you have found the cloak. On one site SQL counted more administrators than wp-admin did, and the extra accounts only appeared in WordPress after the implant was gone.

Itself. It filters all_plugins and show_advanced_plugins to drop off the Plugins screen, edits the update transient so its slug never shows an update, and strips itself from Site Health's debug information.

Its code. Each file uses its own monoalphabetic substitution: two 90-odd character alphabets and a string table, decoded character by character at runtime. There is no eval(base64_decode( for a signature to catch. Newer versions also write identifiers as \x and octal escapes inside ordinary strings, such as "f\x75n\x63"."ts".

The process that outlives a restart

This is the part that turned a routine cleanup into a week of work.

Versions from 4.5.3 on start a PHP process from the command line, not from PHP-FPM. It runs a file named .gr_<32 hex>.php with the flags --sc-cli --sc-succ, detaches, and reparents to PID 1. Every so often it writes a new generation of itself, executes it, and deletes the file. On one site we found it holding 25 deleted generations open, each 261,440 bytes, all recoverable from /proc/<pid>/fd/. It also keeps its plugin payloads in SysV shared memory, tagged SCSHM1:<length>:<sha256>, so it can rebuild with nothing left on disk.

Restarting PHP-FPM doesn't touch it, because it was never an FPM worker. So the sequence on the worst site went like this: the cleanup finished at 13:26, the daemon re-dropped its markers at 13:29:49, and two seconds later it minted a fresh cloaked administrator. No login. No upload. It just put itself back.

Two things have to happen in the same pass:

  1. Kill the daemon and its whole process group (kill -9 -<pgid>), not just the PID.
  2. Move every execution root out of the webroot: drop-ins, auto-prepend targets, the mu-plugin, the replica directory, the self-heal ZIPs.

Kill it without moving the roots, and the next page view through db.php starts it again. Move the roots without killing it, and the live daemon puts them back within seconds. Afterwards, watch the site with real traffic for at least a minute before calling it done.

Orders from a smart contract

SC gets its instructions through a technique researchers call EtherHiding. Instead of calling a command server, it makes a read-only eth_call (function selector 0x3bc5de30, a getString() getter) to one of three Ethereum contracts, through any of about twenty public RPC endpoints, and records which endpoint worked in an option called sc_last_rpc. Reading a contract is free, leaves no transaction behind, and can't be taken down by a registrar or a hosting provider. Changing the payload for every infected site costs the operator one transaction.

Some versions also carry ordinary HTTP endpoints as a fallback, all ending in the same path, /SGct2K. They're listed below.

What it does once it's in

The implant source we decoded (it calls itself "Lumen Orchestrator Fix", v3.1.0, inside a 140 KB row) goes well past SEO spam:

  • Captures logins. It hooks authenticate and stores every username and plaintext password typed into the login form, then sends admin details and session cookies out.
  • Steals keys. It reads wp-config.php, .env files and WooCommerce settings for Stripe, Braintree and Authorize.net credentials and AWS keys, and looks for git tokens.
  • Copies recent orders. On WooCommerce sites, roughly the last ten days of orders.
  • Spreads. It looks for sibling WordPress installs under the same account and tries to infect them. One site's status row read spread: no_roots, meaning it looked and found none.
  • Leaves a way back in. It registers file-manager AJAX endpoints (mk_file_folder_manager, connector, fs_connector) with no file-manager plugin installed.

If SC ran on a store, treat every key in wp-config.php and every payment gateway credential as exposed and roll them.

Three ways it came back

We got this wrong before we got it right. Each mistake taught us something, so here they are.

1. Drop-ins with legitimate names

Our first cleanups removed the mu-plugin, the payload files, the database rows and the rogue admin, and the site was reinfected by the next page view. The execution root was db.php, a file name WordPress reserves for database drop-ins and that tools like Query Monitor legitimately use. Plenty of scanners, ours included at the time, trusted those three file names. A legitimate file name is not a legitimate file. Read the content of every drop-in, every time.

2. A browser tab

The strangest one. After a full cleanup, a site kept reinstalling the plugin through wp-admin's upload form, from the IP address of a real administrator, in their real browser session. It looked exactly like a compromised workstation, and we nearly told a client their computer was infected.

It wasn't. An admin had a tab open on the site from the days it was infected. The implant's JavaScript was still running in that tab, polling /?sc_<hex>=1 every 60 seconds and waiting for a logged-in admin session. The moment one appeared, it uploaded the loader again. It carried the 59 KB ZIP in the page's memory, so deleting every copy on the server made no difference. The tell in the access log: requests to a PHP path that returns 404 (the page talking to malware the server no longer has), interleaved with normal admin activity from the same session. We proved it by closing the tabs. The polling stopped within one interval and never came back.

After any SC cleanup, everyone who had the site open during the infection should close every tab on it and restart the browser.

3. A password it wrote down a month earlier

This morning, 16 October 2026, a site we had cleaned in September was reinfected with version 5.1.0. Three IP addresses we had never seen tried the login form. The fourth attempt logged in as a real administrator, and eight seconds later a new loader plugin was uploaded and activated.

The password was one SC had captured on that site in September. We had found the captured-login row, deleted it, and recorded which accounts were in it. The site owner's password was never reset, and the attacker came back for it. The reinfection announced itself with a crash: two of 5.1.0's files declared the same junk function, so every uncached request died with a PHP fatal error, which is how we heard about it within the hour.

Turning on two-factor login for every administrator would have stopped that login cold. We've since changed our cleanup so that every account named in a captured-login row gets a forced password reset and an emailed link in the same pass. We also reset every administrator who could have signed in while an implant was live on their site, captured row or not, because the hook sees every login, whether or not a stored copy survives.

How to remove it so it stays removed

If you're cleaning SC yourself, this order is what held for us. It's SC-specific; our general hacked WordPress cleanup checklist covers the rest.

  1. Snapshot first. Copy files and the database somewhere outside the webroot. You will want the evidence.
  2. Find the process. ps -eo pid,ppid,pgid,cmd | grep -E 'sc-cli|\.gr_'. Check ipcs -m for shared memory segments owned by the site user.
  3. Kill the group and move the roots together, in one script: the process group, the three drop-ins (if they contain SC markers), every .user.ini with an auto_prepend_file, its target, the mu-plugin and plugin copies, .sc_* directories, and every <8 hex>.zip under wp-content/, including uploads.
  4. Strip the theme block surgically. The site's real code comes first in functions.php; SC appends after it. Don't delete the file.
  5. Remove the /* SC_WC */ line from wp-config.php, or WP_CACHE stays forced on. Don't leave the marker in a comment, or it will trip every scan forever after.
  6. Delete database rows by exact name. List sc_* options and 12-character hex option names, decode the hex ones (base64, first byte is the XOR key), and delete only the ones that decode to SC content. Never delete by prefix: premium plugin updaters also park data under md5-style names.
  7. Unschedule its cron hooks and remove the cloaked admins you found by SQL.
  8. Reset every password for every account that could have logged in while it was live. Rotate the salts in wp-config.php so every session dies. Roll payment gateway and cloud keys on any store.
  9. Sweep by ctime across the whole infection window. Leftovers like small throttle files and integrity stamps only stand out once the big pieces are gone.
  10. Watch it. Load the site with real traffic for a minute or two, re-check the process list, count admins by SQL again, and run a full scan.
  11. Restart the browsers of everyone who had the site open.

Indicators of compromise

Free to use in your own detection. Hex values in angle brackets vary per site.

Markers in files: SC_DB, SC_ADV, SCOCV, SC_TH, SC_WC, SC_CORE_BOOTSTRAPPED, SCV:, __SC_BOOT, SCSHM1:

Paths: wp-content/.sc_<8 hex>/, .gr_<32 hex>.php, wp-content/<8 hex>.php (auto-prepend target), wp-content/cache/<8 hex>.php, <8 hex>.zip in wp-content/, theme folders and uploads/, .wp-object-cache-<8 hex>.dat and .lkg, empty marker files starting .kk_, .gk_, .pv_, .sd_, .bt_

Process: php ... .gr_<32 hex>.php --sc-cli --sc-succ with parent PID 1

Options: sc_payload_persistent, sc_persist_manifest, sc_initialized, sc_last_fetch_ts, sc_last_rpc, sc_last_heal_ts, sc_c2_cache, sc_own_manifest, sc_reins_oc, plus 12-character hex option names whose base64 value XOR-decodes to serialized PHP

Admin logins: adm_, admin_, administrator_, backup_ followed by 6 to 10 hex characters

Plugin slugs seen: vapor-booster-pad, datum-router-pad, pulse-interface-dot, bright-generator (each with a -loader companion)

Ethereum contracts (EtherHiding C2): 0x9A4752cAA1C15868487A0ACb691F81bfA901E063, 0x839d1cE5c3F259e8d3D17114d7186EDabdbeA94b, 0x6d2c5435EF70196740a48904B69377935D50abBB

HTTP C2 (path /SGct2K): correspondabb.com, rehearsal-b.com, chordapple.com, stand-medal.com

RPC endpoint recorded in sc_last_rpc: https://0xrpc.io/eth (a public endpoint, abused, not malicious itself)

How we handle it now

Every site we host gets a nightly Sentinel scan with a dedicated SC check that reads drop-ins by content, counts administrators by SQL, decodes the hex option rows and looks for the daemon. When it finds SC, the cleanup runs the sequence above as one operation, resets the exposed logins and emails the owners their reset links. Every variant shape that has refused to clean so far became a test case before the fix shipped, which is why 5.1.0 was gone within half an hour of the crash that announced it.

If your WordPress site keeps getting reinfected and nobody can find the way back in, run our free malware scanner for an outside view, or read how WordPress malware removal works when it's done properly. If you'd rather hand it to someone who has met this exact family, every TopSyde plan includes malware removal at no extra charge. Plans and prices are on our pricing page.

Frequently asked questions

How do I know if my WordPress site has the SC malware?

Look for files or comments containing SC_DB, SC_ADV, SCOCV or SC_WC in wp-content/db.php, object-cache.php, advanced-cache.php and wp-config.php, a dot-folder named .sc_ plus eight hex characters in wp-content, and options starting sc_ in the database. Then count administrators with SQL and compare the number with the Users screen. A mismatch means accounts are being hidden.

Why does my site get reinfected right after I clean it?

With SC, usually one of four things survived: a drop-in file, a .user.ini auto-prepend, the database rows that hold the implant's source, or a detached PHP process that rebuilds everything from memory. A fifth cause is outside the server entirely: a browser tab that was open on the infected site and reinstalls the plugin when an admin logs in.

Does restarting PHP or the server remove it?

Restarting PHP-FPM doesn't, because the resident process was started from the command line and isn't an FPM worker. Killing the process alone doesn't either, because the drop-ins start it again on the next request. You have to kill the process group and remove the files that launch it in the same pass.

Do I need to change passwords after cleaning SC?

Yes, for every account that logged in while it was live. SC hooks the login form and stores usernames with plaintext passwords. We've seen an attacker use a captured password a month later to reinstall it. Rotate the salts in wp-config.php as well, and roll any payment or cloud API keys stored on the site.

Can a security plugin stop SC?

A security plugin runs inside WordPress, and SC loads before plugins do, from drop-ins and an auto-prepend file. It also hides its admin accounts and itself from the screens a plugin reports on. Detection that works has to look from outside WordPress: file contents, raw SQL, the process list and file ctimes.

Colton Joseph
Colton Joseph

Founder & Lead Developer

20+ years full-stack development, WordPress, AI tools & agents

Colton is the founder of TopSyde with 20+ years of full-stack development experience spanning WordPress, cloud infrastructure, and AI-powered tooling. He specializes in performance optimization, server architecture, and building AI agents for automated site management.

Related Articles

View all →

Free malware scanner

Check your site for signs of malware.

Paste your URL to check for injected scripts, suspicious redirects and cloaked content. See your results without signing up or entering an email. This checks public pages; it cannot rule out backdoors in your server files or database.

Free public-page scan. No signup; results on screen and by email.