{"id":212,"date":"2026-08-09T10:45:23","date_gmt":"2026-08-09T08:45:23","guid":{"rendered":"https:\/\/helloblog.io\/cs\/bdthemes-xss-kompromitovane-api\/"},"modified":"2026-08-09T10:45:23","modified_gmt":"2026-08-09T08:45:23","slug":"bdthemes-xss-kompromitovane-api","status":"publish","type":"post","link":"https:\/\/helloblog.io\/cs\/bdthemes-xss-kompromitovane-api\/","title":{"rendered":"BdThemes: kompromitovan\u00e9 API spou\u0161t\u011blo XSS v administraci WordPressu"},"content":{"rendered":"\n<p>\u00dato\u010dn\u00edci kompromitovali ekosyst\u00e9m plugin\u016f BdThemes, ani\u017e by zm\u011bnili jedin\u00fd soubor v ofici\u00e1ln\u00edm repozit\u00e1\u0159i WordPressu. Sta\u010dilo jim upravit vzd\u00e1len\u00fd JSON feed s propaga\u010dn\u00edmi bannery, kter\u00fd pluginy na\u010d\u00edtaly do ka\u017ed\u00e9 str\u00e1nky administrace, a zneu\u017e\u00edt neescapovan\u00fd atribut HTML.<\/p>\n\n\n\n<p>D\u016fsledek je kritick\u00fd: \u0161kodliv\u00fd JavaScript b\u011b\u017e\u00ed v prohl\u00ed\u017ee\u010di p\u0159ihl\u00e1\u0161en\u00e9ho administr\u00e1tora. M\u016f\u017ee vytvo\u0159it ciz\u00ed \u00fa\u010det spr\u00e1vce, nahr\u00e1t plugin s webshellu, nainstalovat perzistentn\u00ed zadn\u00ed vr\u00e1tka a odeslat v\u00fdsledky na C2 server. Napaden\u00fd web p\u0159itom nepot\u0159eboval aktualizaci pluginu a soubory pluginu na disku z\u016fstaly beze zm\u011bny.<\/p>\n\n\n\n<div class=\"wp-block-group callout callout-danger is-style-danger is-layout-flow wp-block-group-is-layout-flow\" style=\"border-width:1px;border-radius:8px;padding-top:1rem;padding-right:1.5rem;padding-bottom:1rem;padding-left:1.5rem\">\n\n<h4 class=\"wp-block-heading callout-title\">Co ud\u011blat hned<\/h4>\n\n\n<p>Pou\u017e\u00edv\u00e1\u0161-li n\u011bkter\u00fd z dot\u010den\u00fdch plugin\u016f, okam\u017eit\u011b prov\u011b\u0159 seznam u\u017eivatel\u016f, adres\u00e1\u0159e plugin\u016f v\u010detn\u011b <code>mu-plugins<\/code> a tabulku <code>wp_options<\/code> na uveden\u00e9 indik\u00e1tory kompromitace. Pouh\u00e1 kontrola integrity soubor\u016f tento \u00fatok nemus\u00ed odhalit.<\/p>\n\n<\/div>\n\n\n\n<p>Pluginy byly 7. srpna 2026 v adres\u00e1\u0159i WordPressu do\u010dasn\u011b uzav\u0159eny, zat\u00edmco pokra\u010dovala jejich kontrola. K 8. srpnu ob\u011b kompromitovan\u00e1 API vracela \u010dist\u00fd JSON. Nelze ale p\u0159edpokl\u00e1dat, \u017ee t\u00edm automaticky zmizely \u00fa\u010dty, webshell nebo MU-pluginy, kter\u00e9 \u00fatok mohl na web u\u017e ulo\u017eit.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Jak \u00fatok fungoval<\/h2>\n\n\n\n<p>Dot\u010den\u00e9 pluginy obsahuj\u00ed intern\u00ed komponentu <em>Biggopti<\/em>. Ta p\u0159i na\u010dten\u00ed administrace z\u00edsk\u00e1v\u00e1 propaga\u010dn\u00ed bannery z API a vykresluje je v <code>wp-admin<\/code>. Zdroj dat netvo\u0159il dynamick\u00fd aplika\u010dn\u00ed server: \u0161lo o statick\u00e9 JSON soubory v DigitalOcean Spaces, kter\u00e9 chr\u00e1nil Cloudflare.<\/p>\n\n\n\n<p>JavaScript Biggopti se registruje na hook <code>admin_init<\/code>, tak\u017ee se spust\u00ed bezpodm\u00edne\u010dn\u011b p\u0159i ka\u017ed\u00e9m na\u010dten\u00ed libovoln\u00e9 str\u00e1nky <code>wp-admin<\/code>. Z odpov\u011bdi API p\u0159evezme hodnotu <code>display_id<\/code> a bez escapov\u00e1n\u00ed ji vlo\u017e\u00ed do HTML atributu <code>id<\/code>. Pr\u00e1v\u011b tady vznik\u00e1 XSS (cross-site scripting): \u00fato\u010dn\u00edk m\u016f\u017ee do hodnoty vlo\u017eit vlastn\u00ed HTML atribut nebo JavaScript, kter\u00fd prohl\u00ed\u017ee\u010d administr\u00e1tora spust\u00ed.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#24292e\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" style=\"color:#e1e4e8;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>\/\/ Hodnota z ned\u016fv\u011bryhodn\u00e9 vzd\u00e1len\u00e9 odpov\u011bdi\nvar f = t.display_id || t.id || &quot;default&quot;;\nvar m = &quot;bdt-admin-biggopti-api-biggopti-&quot; + f;\n\n\/\/ Chyb\u00ed escapov\u00e1n\u00ed f p\u0159ed vlo\u017een\u00edm do HTML\nA = 'id=&quot;' + m + '&quot;';\n<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#6A737D\">\/\/ Hodnota z ned\u016fv\u011bryhodn\u00e9 vzd\u00e1len\u00e9 odpov\u011bdi<\/span><\/span>\n<span class=\"line\"><span style=\"color:#F97583\">var<\/span><span style=\"color:#E1E4E8\"> f <\/span><span style=\"color:#F97583\">=<\/span><span style=\"color:#E1E4E8\"> t.display_id <\/span><span style=\"color:#F97583\">||<\/span><span style=\"color:#E1E4E8\"> t.id <\/span><span style=\"color:#F97583\">||<\/span><span style=\"color:#9ECBFF\"> \"default\"<\/span><span style=\"color:#E1E4E8\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color:#F97583\">var<\/span><span style=\"color:#E1E4E8\"> m <\/span><span style=\"color:#F97583\">=<\/span><span style=\"color:#9ECBFF\"> \"bdt-admin-biggopti-api-biggopti-\"<\/span><span style=\"color:#F97583\"> +<\/span><span style=\"color:#E1E4E8\"> f;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color:#6A737D\">\/\/ Chyb\u00ed escapov\u00e1n\u00ed f p\u0159ed vlo\u017een\u00edm do HTML<\/span><\/span>\n<span class=\"line\"><span style=\"color:#79B8FF\">A<\/span><span style=\"color:#F97583\"> =<\/span><span style=\"color:#9ECBFF\"> 'id=\"'<\/span><span style=\"color:#F97583\"> +<\/span><span style=\"color:#E1E4E8\"> m <\/span><span style=\"color:#F97583\">+<\/span><span style=\"color:#9ECBFF\"> '\"'<\/span><span style=\"color:#E1E4E8\">;<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>Ve stejn\u00e9m k\u00f3du se atribut <code>data-display-id<\/code> escapoval funkc\u00ed, kter\u00e1 nahrazuje <code>&amp;<\/code>, <code>&lt;<\/code>, <code>&gt;<\/code>, <code>&quot;<\/code> za HTML entity. Pro atribut <code>id<\/code> ale tato ochrana chyb\u011bla. Pozd\u011bj\u0161\u00ed verze doplnily sanitizaci obsahu banneru p\u0159es <code>DOMParser<\/code>, kter\u00e1 odstra\u0148uje nebezpe\u010dn\u00e9 HTML tagy a inline handlery; neescapovan\u00e9 <code>display_id<\/code> v <code>id<\/code> v\u0161ak z\u016fstalo.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#24292e\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" style=\"color:#e1e4e8;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>function escapeHtml(value) {\n  return (value || &quot;&quot;)\n    .replace(\/&amp;\/g, &quot;&amp;amp;&quot;)\n    .replace(\/&lt;\/g, &quot;&amp;lt;&quot;)\n    .replace(\/&gt;\/g, &quot;&amp;gt;&quot;)\n    .replace(\/&quot;\/g, &quot;&amp;quot;&quot;);\n}\n<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#F97583\">function<\/span><span style=\"color:#B392F0\"> escapeHtml<\/span><span style=\"color:#E1E4E8\">(<\/span><span style=\"color:#FFAB70\">value<\/span><span style=\"color:#E1E4E8\">) {<\/span><\/span>\n<span class=\"line\"><span style=\"color:#F97583\">  return<\/span><span style=\"color:#E1E4E8\"> (value <\/span><span style=\"color:#F97583\">||<\/span><span style=\"color:#9ECBFF\"> \"\"<\/span><span style=\"color:#E1E4E8\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">    .<\/span><span style=\"color:#B392F0\">replace<\/span><span style=\"color:#E1E4E8\">(<\/span><span style=\"color:#9ECBFF\">\/<\/span><span style=\"color:#DBEDFF\">&#x26;<\/span><span style=\"color:#9ECBFF\">\/<\/span><span style=\"color:#F97583\">g<\/span><span style=\"color:#E1E4E8\">, <\/span><span style=\"color:#9ECBFF\">\"&#x26;amp;\"<\/span><span style=\"color:#E1E4E8\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">    .<\/span><span style=\"color:#B392F0\">replace<\/span><span style=\"color:#E1E4E8\">(<\/span><span style=\"color:#9ECBFF\">\/<\/span><span style=\"color:#DBEDFF\">&#x3C;<\/span><span style=\"color:#9ECBFF\">\/<\/span><span style=\"color:#F97583\">g<\/span><span style=\"color:#E1E4E8\">, <\/span><span style=\"color:#9ECBFF\">\"&#x26;lt;\"<\/span><span style=\"color:#E1E4E8\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">    .<\/span><span style=\"color:#B392F0\">replace<\/span><span style=\"color:#E1E4E8\">(<\/span><span style=\"color:#9ECBFF\">\/<\/span><span style=\"color:#DBEDFF\">><\/span><span style=\"color:#9ECBFF\">\/<\/span><span style=\"color:#F97583\">g<\/span><span style=\"color:#E1E4E8\">, <\/span><span style=\"color:#9ECBFF\">\"&#x26;gt;\"<\/span><span style=\"color:#E1E4E8\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">    .<\/span><span style=\"color:#B392F0\">replace<\/span><span style=\"color:#E1E4E8\">(<\/span><span style=\"color:#9ECBFF\">\/<\/span><span style=\"color:#DBEDFF\">\"<\/span><span style=\"color:#9ECBFF\">\/<\/span><span style=\"color:#F97583\">g<\/span><span style=\"color:#E1E4E8\">, <\/span><span style=\"color:#9ECBFF\">\"&#x26;quot;\"<\/span><span style=\"color:#E1E4E8\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>Chyba se objevila 1. b\u0159ezna 2026 v Prime Slider 4.1.9, v SVN revizi <code>r3471891<\/code>, a n\u00e1sledn\u011b se roz\u0161\u00ed\u0159ila do dal\u0161\u00edch plugin\u016f. Neopr\u00e1vn\u011bn\u00e1 osoba z\u00edskala z\u00e1pis do \u00falo\u017ei\u0161t\u011b dodavatele a nahradila legitimn\u00ed JSON p\u0159ipraven\u00fdmi z\u00e1znamy. Hodnota <code>display_id<\/code> ukon\u010dila atribut <code>id<\/code>, p\u0159idala handler <code>onanimationstart<\/code> a CSS animaci; prohl\u00ed\u017ee\u010d tak spustil payload p\u0159ibli\u017en\u011b do 10 ms od na\u010dten\u00ed administra\u010dn\u00ed str\u00e1nky.<\/p>\n\n\n\n<p>\u00dato\u010dn\u00edk v <code>display_id<\/code> skr\u00fdval p\u0159es <code>String.fromCharCode()<\/code> vol\u00e1n\u00ed <code>fetch()<\/code> na extern\u00ed skript. Ve zneu\u017eit\u00e9 odpov\u011bdi se banner tv\u00e1\u0159il jako letn\u00ed nab\u00eddka \u201eBuild more. Pay less. This Summer\u201c, ale ve skute\u010dnosti se z n\u011bj stal spou\u0161t\u011b\u010d dal\u0161\u00ed f\u00e1ze infekce.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Dot\u010den\u00e9 pluginy a zranitelnost<\/h2>\n\n\n\n<p>Zranitelnost v knihovn\u011b Biggopti m\u00e1 <a href=\"https:\/\/www.wordfence.com\/threat-intel\/vulnerabilities\/id\/7bf1d6f9-afe2-41c2-968b-20dbc474cd73\">CVSS 5,4<\/a>, tedy st\u0159edn\u00ed z\u00e1va\u017enost, a v okam\u017eiku zve\u0159ejn\u011bn\u00ed nem\u011bla opravu. \u00dato\u010dn\u00edk v\u0161ak pot\u0159eboval kompromitovat server Sigmative API; za t\u00e9to podm\u00ednky mohl vlo\u017eit libovoln\u00fd skript do str\u00e1nek, kter\u00e9 otev\u0159e p\u0159ihl\u00e1\u0161en\u00fd u\u017eivatel.<\/p>\n\n\n\n<p>Riziko se t\u00fdk\u00e1 t\u011bchto plugin\u016f a slug\u016f:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n\n<li>Element Pack Addons for Elementor (<code>bdthemes-element-pack-lite<\/code>)<\/li>\n\n\n<li>Prime Slider Addons for Elementor (<code>bdthemes-prime-slider-lite<\/code>)<\/li>\n\n\n<li>Pixel Gallery Addons for Elementor (<code>pixel-gallery<\/code>)<\/li>\n\n\n<li>Ultimate Post Kit Addons for Elementor (<code>ultimate-post-kit<\/code>)<\/li>\n\n\n<li>Ultimate Store Kit \u2013 Addon For WooCommerce, EDD and Elementor (<code>ultimate-store-kit<\/code>)<\/li>\n\n\n<li>Live Copy Paste for Elementor (<code>live-copy-paste<\/code>)<\/li>\n\n\n<li>Smart Admin Assistant (<code>smart-admin-assistant<\/code>)<\/li>\n\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Prim\u00e1rn\u00ed payload: \u00fa\u010det spr\u00e1vce, webshell a perzistence<\/h2>\n\n\n\n<p>Pluginy, kter\u00e9 pou\u017e\u00edvaly endpoint <code>api-data-all-records<\/code>, na\u010d\u00edtaly prim\u00e1rn\u00ed payload <code>w2.js<\/code>. Skript nejd\u0159\u00edv kontaktoval C2 endpoint <code>ia-cdn[.]com\/fz\/c<\/code>, kter\u00e9mu p\u0159edal origin napaden\u00e9ho webu. Pokud server odpov\u011bd\u011bl stavem <code>skip<\/code> nebo <code>done<\/code>, skript akci ukon\u010dil; jinak dostal instrukce pro dal\u0161\u00ed postup.<\/p>\n\n\n\n<p>V aktivn\u00ed relaci administr\u00e1tora pak zneu\u017eil <code>X-WP-Nonce<\/code> a p\u0159es WordPress REST API zalo\u017eil nov\u00fd \u00fa\u010det s rol\u00ed administr\u00e1tora. Kdy\u017e REST API neusp\u011blo, p\u0159e\u0161el na klasick\u00e9 odesl\u00e1n\u00ed formul\u00e1\u0159e. N\u00e1sledn\u011b z C2 st\u00e1hl ZIP fale\u0161n\u00e9ho pluginu a nahr\u00e1l ho p\u0159es standardn\u00ed formul\u00e1\u0159 pro instalaci pluginu.<\/p>\n\n\n\n<p>Fale\u0161n\u00fd plugin pou\u017e\u00edval slug <code>wp-smart-thumbnails<\/code> nebo podobn\u011b neutr\u00e1ln\u011b zn\u011bj\u00edc\u00ed n\u00e1zev. Obsahoval webshell <code>emer-run.php<\/code>, kter\u00fd \u00fato\u010dn\u00edk volal p\u0159\u00edmo p\u0159es URL. Tento soubor d\u00e1le ukl\u00e1dal do adres\u00e1\u0159e Must-Use plugin\u016f dva moduly pro perzistenci; z\u00edskan\u00e9 vzorky m\u011bly \u010dasov\u00e9 \u00fadaje zp\u011btn\u011b nastaven\u00e9 na z\u00e1\u0159\u00ed 2025, aby l\u00e9pe splynuly s existuj\u00edc\u00edmi soubory. N\u00e1zvy soubor\u016f se mezi jednotliv\u00fdmi infekcemi mohou li\u0161it.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n\n<li>Prvn\u00ed MU-plugin vytv\u00e1\u0159\u00ed zadn\u00ed vr\u00e1tka pro magic login. Nep\u0159ihl\u00e1\u0161en\u00fd \u00fato\u010dn\u00edk se s tokenem v parametru <code>?_wplogin=&lt;token&gt;<\/code> dostane do administrace pod nejd\u00e9le registrovan\u00fdm administr\u00e1torsk\u00fdm \u00fa\u010dtem webu.<\/li>\n\n\n<li>Druh\u00fd MU-plugin zakr\u00fdv\u00e1 stopy. Hookuje datab\u00e1zov\u00e9 dotazy WordPressu, skryje vytvo\u0159en\u00e9 ciz\u00ed \u00fa\u010dty v seznamu u\u017eivatel\u016f administrace a odpov\u00eddaj\u00edc\u00edm zp\u016fsobem sn\u00ed\u017e\u00ed i celkov\u00fd po\u010det u\u017eivatel\u016f.<\/li>\n\n\n<li>Dal\u0161\u00ed zaznamenan\u00fd MU-plugin se vyd\u00e1v\u00e1 za modul \u201eHealth Check\u201c.<\/li>\n\n\n<li>V ka\u017ed\u00e9 f\u00e1zi skript odes\u00edl\u00e1 v\u00fdsledek na C2 p\u0159es <code>navigator.sendBeacon<\/code>.<\/li>\n\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Alternativn\u00ed payload: p\u0159edv\u00eddateln\u00e9 p\u0159ihla\u0161ovac\u00ed \u00fadaje<\/h2>\n\n\n\n<p>Druh\u00e1 v\u011btev \u00fatoku pou\u017e\u00edvala <code>x.js<\/code>, kter\u00fd le\u017eel p\u0159\u00edmo v infrastruktu\u0159e BdThemes a obsluhoval pluginy s endpointem <code>api-data-records<\/code>. Skript nevolil \u00fadaje n\u00e1hodn\u011b: vypo\u010d\u00edtal je deterministicky z hostname napaden\u00e9ho webu. \u00dato\u010dn\u00edk proto nemusel centr\u00e1ln\u011b uchov\u00e1vat seznam kompromitovan\u00fdch web\u016f &#8211; p\u0159ihla\u0161ovac\u00ed \u00fadaje pro konkr\u00e9tn\u00ed dom\u00e9nu si dok\u00e1zal kdykoli znovu odvodit.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#24292e\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" style=\"color:#e1e4e8;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>function makeCreds(host) {\n  var hash = 0;\n\n  for (var i = 0; i &lt; host.length; i++) {\n    hash = ((hash &lt;&lt; 5) - hash + host.charCodeAt(i)) | 0;\n  }\n\n  var suffix = Math.abs(hash).toString(36).slice(0, 6);\n\n  return {\n    user: &quot;bd_&quot; + suffix,\n    pass: &quot;Bd@26!&quot; + suffix + &quot;x&quot;\n  };\n}\n<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#F97583\">function<\/span><span style=\"color:#B392F0\"> makeCreds<\/span><span style=\"color:#E1E4E8\">(<\/span><span style=\"color:#FFAB70\">host<\/span><span style=\"color:#E1E4E8\">) {<\/span><\/span>\n<span class=\"line\"><span style=\"color:#F97583\">  var<\/span><span style=\"color:#E1E4E8\"> hash <\/span><span style=\"color:#F97583\">=<\/span><span style=\"color:#79B8FF\"> 0<\/span><span style=\"color:#E1E4E8\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color:#F97583\">  for<\/span><span style=\"color:#E1E4E8\"> (<\/span><span style=\"color:#F97583\">var<\/span><span style=\"color:#E1E4E8\"> i <\/span><span style=\"color:#F97583\">=<\/span><span style=\"color:#79B8FF\"> 0<\/span><span style=\"color:#E1E4E8\">; i <\/span><span style=\"color:#F97583\">&#x3C;<\/span><span style=\"color:#E1E4E8\"> host.<\/span><span style=\"color:#79B8FF\">length<\/span><span style=\"color:#E1E4E8\">; i<\/span><span style=\"color:#F97583\">++<\/span><span style=\"color:#E1E4E8\">) {<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">    hash <\/span><span style=\"color:#F97583\">=<\/span><span style=\"color:#E1E4E8\"> ((hash <\/span><span style=\"color:#F97583\">&#x3C;&#x3C;<\/span><span style=\"color:#79B8FF\"> 5<\/span><span style=\"color:#E1E4E8\">) <\/span><span style=\"color:#F97583\">-<\/span><span style=\"color:#E1E4E8\"> hash <\/span><span style=\"color:#F97583\">+<\/span><span style=\"color:#E1E4E8\"> host.<\/span><span style=\"color:#B392F0\">charCodeAt<\/span><span style=\"color:#E1E4E8\">(i)) <\/span><span style=\"color:#F97583\">|<\/span><span style=\"color:#79B8FF\"> 0<\/span><span style=\"color:#E1E4E8\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">  }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color:#F97583\">  var<\/span><span style=\"color:#E1E4E8\"> suffix <\/span><span style=\"color:#F97583\">=<\/span><span style=\"color:#E1E4E8\"> Math.<\/span><span style=\"color:#B392F0\">abs<\/span><span style=\"color:#E1E4E8\">(hash).<\/span><span style=\"color:#B392F0\">toString<\/span><span style=\"color:#E1E4E8\">(<\/span><span style=\"color:#79B8FF\">36<\/span><span style=\"color:#E1E4E8\">).<\/span><span style=\"color:#B392F0\">slice<\/span><span style=\"color:#E1E4E8\">(<\/span><span style=\"color:#79B8FF\">0<\/span><span style=\"color:#E1E4E8\">, <\/span><span style=\"color:#79B8FF\">6<\/span><span style=\"color:#E1E4E8\">);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color:#F97583\">  return<\/span><span style=\"color:#E1E4E8\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">    user: <\/span><span style=\"color:#9ECBFF\">\"bd_\"<\/span><span style=\"color:#F97583\"> +<\/span><span style=\"color:#E1E4E8\"> suffix,<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">    pass: <\/span><span style=\"color:#9ECBFF\">\"Bd@26!\"<\/span><span style=\"color:#F97583\"> +<\/span><span style=\"color:#E1E4E8\"> suffix <\/span><span style=\"color:#F97583\">+<\/span><span style=\"color:#9ECBFF\"> \"x\"<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">  };<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>Tak vznik\u00e1 u\u017eivatelsk\u00e9 jm\u00e9no <code>bd_<\/code> n\u00e1sledovan\u00e9 \u0161esti znaky base36 a heslo ve tvaru <code>Bd@26!<\/code> + stejn\u00fd suffix + <code>x<\/code>. Skript \u00fa\u010det spoj\u00ed s e-mailem na dom\u00e9n\u011b <code>@wordpress.org<\/code>, p\u0159\u00edpadn\u011b se p\u0159i vyhled\u00e1v\u00e1n\u00ed stop po\u010d\u00edt\u00e1 tak\u00e9 s <code>@developer.wordpress.org<\/code>. P\u0159es na\u010dten\u00ed <code>\/wp-admin\/user-new.php<\/code> z\u00edsk\u00e1 nonce a formul\u00e1\u0159em vytvo\u0159\u00ed administr\u00e1tora. V\u00fdsledek &#8211; v\u010detn\u011b u\u017eivatelsk\u00e9ho jm\u00e9na, hesla, originu webu, URL odhl\u00e1\u0161en\u00ed a aktu\u00e1ln\u00ed URL &#8211; po\u0161le na C2.<\/p>\n\n\n\n<p>Po pokusu o vytvo\u0159en\u00ed \u00fa\u010dtu si payload ukl\u00e1d\u00e1 p\u0159\u00edznak do <code>localStorage<\/code>, pokud je \u00falo\u017ei\u0161t\u011b prohl\u00ed\u017ee\u010de dostupn\u00e9. Pro odesl\u00e1n\u00ed dat preferuje <code>navigator.sendBeacon<\/code>; kdy\u017e nen\u00ed k dispozici, pou\u017e\u00edv\u00e1 <code>fetch()<\/code> s metodou POST, <code>keepalive<\/code>, re\u017eimem <code>no-cors<\/code> a bez cookies.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Indik\u00e1tory kompromitace<\/h2>\n\n\n\n<p>P\u0159i incident response hledej soubory, datab\u00e1zov\u00e9 volby i podez\u0159el\u00e9 \u00fa\u010dty. Kontroluj zejm\u00e9na n\u00e1sleduj\u00edc\u00ed hodnoty:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n\n<li>Prim\u00e1rn\u00ed payload: <code>ia-cdn[.]com\/fz\/w2.js<\/code><\/li>\n\n\n<li>C2 beacon endpoint: <code>ia-cdn[.]com\/fz\/c<\/code><\/li>\n\n\n<li>D\u0159\u00edve kompromitovan\u00e9 endpointy: <code>api[.]sigmative[.]io\/prod\/store\/api\/biggopti\/api-data-all-records<\/code>, <code>api[.]sigmative[.]io\/prod\/store\/api\/biggopti\/api-data-records<\/code> a <code>api[.]sigmative[.]io\/prod\/store\/api\/biggopti\/x.js<\/code><\/li>\n\n\n<li>Webshell <code>emer-run.php<\/code> s MD5 <code>1024732009983dd5e54b4cf5593f04d4<\/code><\/li>\n\n\n<li>MU-plugin pro magic login <code>class-wp-token-validate.php<\/code> s MD5 <code>7719cd98a35ffad2771f26d1ceab7d27<\/code><\/li>\n\n\n<li>MU-plugin pro skr\u00fdv\u00e1n\u00ed stop <code>class-wp-query-9d127ff3.php<\/code> nebo podobn\u00fd soubor podle vzoru <code>class-wp-query-*.php<\/code>; zachycen\u00fd vzorek m\u00e1 MD5 <code>9aadc3e5c5242b273bd17c5bdc358845<\/code><\/li>\n\n\n<li>MU-plugin maskovan\u00fd jako kontrola zdrav\u00ed <code>wp-cache-optimizer.php<\/code> s MD5 <code>e450ae5bc4bfc0d960dded06a76bb8e9<\/code><\/li>\n\n\n<li>Volba datab\u00e1ze <code>fz_emer_login_tokens<\/code>, kter\u00e1 ukl\u00e1d\u00e1 tokeny magic loginu<\/li>\n\n\n<li>Volba datab\u00e1ze <code>fz_emer_done_v1<\/code>, kter\u00e1 ozna\u010duje dokon\u010denou kompromitaci<\/li>\n\n\n<li>\u00da\u010dty s e-mailovou adresou na <code>@wordpress.org<\/code> nebo <code>@developer.wordpress.org<\/code><\/li>\n\n\n<li>U\u017eivatelsk\u00e1 jm\u00e9na odpov\u00eddaj\u00edc\u00ed vzoru <code>bd_<\/code> a \u0161esti alfanumerick\u00fdm znak\u016fm<\/li>\n\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">\u010casov\u00e1 osa<\/h2>\n\n\n\n<ol class=\"wp-block-list\">\n\n<li><strong>1. b\u0159ezna 2026:<\/strong> Prime Slider 4.1.9 dostal Biggopti API JavaScript. Revize SVN <code>r3471891<\/code> vlo\u017eila <code>display_id<\/code> bez escapov\u00e1n\u00ed do atributu <code>id<\/code>; plugin pou\u017e\u00edval endpoint <code>api-data-records<\/code>.<\/li>\n\n\n<li><strong>10. kv\u011btna 2026:<\/strong> endpoint se zm\u011bnil na <code>api-data-all-records<\/code>. Do obsahu banneru p\u0159ibyla sanitizace p\u0159es <code>DOMParser<\/code>, ale atribut <code>id<\/code> z\u016fstal zraniteln\u00fd.<\/li>\n\n\n<li><strong>23. \u010dervna 2026:<\/strong> v kompromitovan\u00e9 kampani za\u010d\u00ednalo datum banneru \u201eSummer Sale\u201c. Jde o nejd\u0159\u00edv\u011bj\u0161\u00ed mo\u017en\u00fd okam\u017eik aktivn\u00edho XSS.<\/li>\n\n\n<li><strong>6. srpna 2026, 22:40 UTC:<\/strong> kompromitovan\u00fd <code>api-data-records<\/code> m\u011bl posledn\u00ed zm\u011bnu.<\/li>\n\n\n<li><strong>7. srpna 2026, 09:11 UTC:<\/strong> kompromitovan\u00fd <code>api-data-all-records<\/code> m\u011bl posledn\u00ed zm\u011bnu.<\/li>\n\n\n<li><strong>7. srpna 2026:<\/strong> \u00fatok se objevil v provozu a dot\u010den\u00e9 pluginy se uzav\u0159ely v adres\u00e1\u0159i WordPressu.<\/li>\n\n\n<li><strong>7. srpna 2026, 16:56 UTC:<\/strong> vznikly forenzn\u00ed artefakty pro vy\u0161et\u0159ov\u00e1n\u00ed.<\/li>\n\n\n<li><strong>8. srpna 2026:<\/strong> oba API endpointy za\u010daly vracet \u010dist\u00fd JSON.<\/li>\n\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\">Pro\u010d je tento \u00fatok obt\u00ed\u017en\u00e9 zachytit<\/h2>\n\n\n\n<p>\u00dato\u010dn\u00edci nepozm\u011bnili zdrojov\u00e9 soubory v repozit\u00e1\u0159i WordPress.org ani soubory nainstalovan\u00e9ho pluginu. Zneu\u017eili d\u016fv\u011bru v datov\u00fd kan\u00e1l dodavatele a administr\u00e1torsk\u00fd prohl\u00ed\u017ee\u010d. Kontrola hash\u016f soubor\u016f proto p\u0159ed samotn\u00fdm spu\u0161t\u011bn\u00edm payloadu nem\u011bla co naj\u00edt a webov\u00fd aplika\u010dn\u00ed firewall \u00fatok obvykle vid\u011bl jen omezen\u011b.<\/p>\n\n\n\n<p>C2 infrastruktura souvis\u00ed tak\u00e9 s ned\u00e1vn\u00fdmi supply-chain \u00fatoky na <a href=\"https:\/\/www.wordfence.com\/blog\/2026\/07\/wordfence-prism-detected-backdoored-wordpress-plugin-within-two-hours-of-it-being-introduced\/\">Advanced Responsive Video Embedder<\/a> a <a href=\"https:\/\/optinmonster.com\/security-incident-tampered-script-served-via-optinmonster-and-trustpulse\/#what-to-check-and-do\">OptinMonster<\/a>. Nahr\u00e1n\u00ed \u0161kodliv\u00fdch JSON z\u00e1znam\u016f i <code>x.js<\/code> p\u0159\u00edmo do bucketu dodavatele ukazuje na kompromitovan\u00e9 p\u0159\u00edstupy ke cloudov\u00e9mu \u00falo\u017ei\u0161ti BdThemes nebo k jeho intern\u00ed infrastruktu\u0159e.<\/p>\n\n\n\n<p>Pokud na webu najde\u0161 by\u0165 jedin\u00fd indik\u00e1tor, ber ho jako incident s mo\u017en\u00fdm vzd\u00e1len\u00fdm spu\u0161t\u011bn\u00edm k\u00f3du. Zru\u0161 podez\u0159el\u00e9 \u00fa\u010dty, odstra\u0148 nalezen\u00e9 \u0161kodliv\u00e9 soubory a datab\u00e1zov\u00e9 volby, prov\u011b\u0159 v\u0161echny MU-pluginy, zm\u011b\u0148 p\u0159\u00edstupy administr\u00e1tor\u016f i hostingu a obnov d\u016fv\u011bryhodn\u00fd stav z ov\u011b\u0159en\u00e9 z\u00e1lohy. Signatury malwaru a pravidla WAF z\u00edskali 7. srpna 2026 u\u017eivatel\u00e9 Wordfence Premium, Care, Response a placen\u00e9ho Wordfence CLI; bezplatn\u00e9 varianty je dostanou po standardn\u00ed 30denn\u00ed prodlev\u011b.<\/p>\n\n\n<div class=\"references-section\">\n                <h2>Reference \/ Zdroje<\/h2>\n                <ul class=\"references-list\"><li><a href=\"https:\/\/www.wordfence.com\/blog\/2026\/08\/psa-supply-chain-compromise-in-bdthemes-ecosystem-via-poisoned-api-response\/\" target=\"_blank\" rel=\"noopener noreferrer\">PSA: Supply Chain Compromise in BdThemes Ecosystem via Poisoned API Response<\/a><\/li><\/ul>\n            <\/div>","protected":false},"excerpt":{"rendered":"<p>\u00datok na pluginy BdThemes obe\u0161el kontrolu soubor\u016f: \u0161kodliv\u00fd JSON banner spustil JavaScript p\u0159\u00edmo v administraci WordPressu. Zjisti, jak\u00e9 stopy po n\u011bm hledat d\u0159\u00edv, ne\u017e p\u0159evezme kontrolu nad webem.<\/p>\n","protected":false},"author":34,"featured_media":211,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[9],"tags":[37,62,126,10,129],"class_list":["post-212","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-bezpecnost","tag-bezpecnost","tag-pluginy","tag-supply-chain","tag-wordpress","tag-xss"],"_links":{"self":[{"href":"https:\/\/helloblog.io\/cs\/wp-json\/wp\/v2\/posts\/212","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/helloblog.io\/cs\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/helloblog.io\/cs\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/helloblog.io\/cs\/wp-json\/wp\/v2\/users\/34"}],"replies":[{"embeddable":true,"href":"https:\/\/helloblog.io\/cs\/wp-json\/wp\/v2\/comments?post=212"}],"version-history":[{"count":0,"href":"https:\/\/helloblog.io\/cs\/wp-json\/wp\/v2\/posts\/212\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/helloblog.io\/cs\/wp-json\/wp\/v2\/media\/211"}],"wp:attachment":[{"href":"https:\/\/helloblog.io\/cs\/wp-json\/wp\/v2\/media?parent=212"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/helloblog.io\/cs\/wp-json\/wp\/v2\/categories?post=212"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/helloblog.io\/cs\/wp-json\/wp\/v2\/tags?post=212"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}