{"id":235,"date":"2026-08-09T10:46:12","date_gmt":"2026-08-09T08:46:12","guid":{"rendered":"https:\/\/helloblog.io\/pl\/atak-bdthemes-zatrute-api-json\/"},"modified":"2026-08-09T10:46:12","modified_gmt":"2026-08-09T08:46:12","slug":"atak-bdthemes-zatrute-api-json","status":"publish","type":"post","link":"https:\/\/helloblog.io\/pl\/atak-bdthemes-zatrute-api-json\/","title":{"rendered":"Atak na BdThemes: zatrute API JSON przejmuje WordPressa"},"content":{"rendered":"\n<p>Atak na ekosystem BdThemes nie wymaga\u0142 podmiany plik\u00f3w wtyczki ani instalacji aktualizacji przez ofiar\u0119. Wystarczy\u0142o przej\u0105\u0107 zdalny strumie\u0144 JSON, kt\u00f3ry wy\u015bwietla\u0142 bannery promocyjne w panelu WordPressa, aby uruchomi\u0107 JavaScript w przegl\u0105darce ka\u017cdego zalogowanego administratora.<\/p>\n\n\n\n<p>Dotkni\u0119te wtyczki s\u0105 tymczasowo zamkni\u0119te w oficjalnym katalogu WordPressa na czas pe\u0142nej kontroli i trwaj\u0105cego dochodzenia zespo\u0142u WordPress Plugins. Problem ma CVSS 5.4 (\u015bredni), nie ma poprawki, a osoba, kt\u00f3ra go zg\u0142osi\u0142a, pozostaje nieznana.<\/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\">Pe\u0142ne przej\u0119cie witryny bez aktualizacji wtyczki<\/h4>\n\n\n<p>Je\u015bli u\u017cywasz cho\u0107 jednej z wymienionych dalej wtyczek BdThemes, potraktuj instalacj\u0119 jako potencjalnie przej\u0119t\u0105. Atak m\u00f3g\u0142 tworzy\u0107 konto administratora, instalowa\u0107 webshell i zapisywa\u0107 trwa\u0142e backdoory, nie zmieniaj\u0105c plik\u00f3w oryginalnej wtyczki.<\/p>\n\n<\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Jak dosz\u0142o do kompromitacji \u0142a\u0144cucha dostaw<\/h2>\n\n\n\n<p>Wtyczki BdThemes zawieraj\u0105 wewn\u0119trzny komponent <em>Biggopti<\/em>. Pobiera on bannery promocyjne z API dostawcy i renderuje je w kokpicie administracyjnym WordPressa. API korzysta\u0142o ze statycznych plik\u00f3w JSON w bucketcie DigitalOcean Spaces, chronionym przez Cloudflare, a nie z dynamicznego serwera aplikacyjnego.<\/p>\n\n\n\n<p>Autorzy wtyczek wprowadzili podatno\u015b\u0107 Cross-Site Scripting (XSS), czyli mo\u017cliwo\u015b\u0107 uruchomienia obcego JavaScriptu w kontek\u015bcie zaufanej strony. Nast\u0119pnie nieuprawniony podmiot uzyska\u0142 zapis do bucketa i podmieni\u0142 prawid\u0142owe odpowiedzi JSON na spreparowane dane. \u017baden plik kodu \u017ar\u00f3d\u0142owego w oficjalnym repozytorium WordPress.org nie zosta\u0142 przy tym zmieniony.<\/p>\n\n\n\n<p>Biggopti dodaje asset JavaScript po hooku <code>admin_init<\/code>, wi\u0119c dzia\u0142a bezwarunkowo przy ka\u017cdym za\u0142adowaniu dowolnej strony <code>wp-admin<\/code>. Skrypt pobiera dane bannera, a potem wstawia pole <code>display_id<\/code> z odpowiedzi JSON bez escapowania bezpo\u015brednio do atrybutu HTML <code>id<\/code>.<\/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>\/\/ JavaScript - fragment podatnego sk\u0142adania atrybutu HTML\nvar f = t.display_id || t.id || &quot;default&quot;;\nvar m = &quot;bdt-admin-biggopti-api-biggopti-&quot; + f;\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\">\/\/ JavaScript - fragment podatnego sk\u0142adania atrybutu HTML<\/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 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>W tym samym kodzie <code>data-display-id<\/code> by\u0142 ju\u017c escapowany przez funkcj\u0119 zamieniaj\u0105c\u0105 znaki <code>&amp;<\/code>, <code>&lt;<\/code>, <code>&gt;<\/code> i <code>&quot;<\/code> na encje HTML. Konstrukcja tej funkcji by\u0142a zawi\u0142a, prawdopodobnie na skutek minifikacji lub bundlowania, ale nie chroni\u0142a osobnego atrybutu <code>id<\/code>.<\/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>\/\/ JavaScript - funkcja u\u017cyta dla innego atrybutu\nfunction p(t) {\n  return (t || &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:#6A737D\">\/\/ JavaScript - funkcja u\u017cyta dla innego atrybutu<\/span><\/span>\n<span class=\"line\"><span style=\"color:#F97583\">function<\/span><span style=\"color:#B392F0\"> p<\/span><span style=\"color:#E1E4E8\">(<\/span><span style=\"color:#FFAB70\">t<\/span><span style=\"color:#E1E4E8\">) {<\/span><\/span>\n<span class=\"line\"><span style=\"color:#F97583\">  return<\/span><span style=\"color:#E1E4E8\"> (t <\/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>Historia commit\u00f3w SVN wskazuje, \u017ce nieescapowane wstawianie do atrybutu pojawi\u0142o si\u0119 1 marca 2026 roku w Prime Sliderze 4.1.9 (<code>bdthemes-prime-slider-lite<\/code>, rewizja <code>r3471891<\/code>), a p\u00f3\u017aniej trafi\u0142o do pozosta\u0142ych wtyczek. P\u00f3\u017aniejsze wydania doda\u0142y oparty na <code>DOMParser<\/code> sanitizer dla pola tre\u015bci bannera, kt\u00f3ry usuwa\u0142 niebezpieczne tagi HTML i inline handlery, lecz nie naprawi\u0142y <code>id<\/code>.<\/p>\n\n\n\n<p>Z\u0142o\u015bliwy <code>display_id<\/code> zamyka\u0142 atrybut <code>id<\/code> i dopisywa\u0142 handler zdarzenia <code>onanimationstart<\/code>. Animacja CSS uruchamia\u0142a go w ci\u0105gu 10 ms, po cichu, gdy administrator otwiera\u0142 stron\u0119 kokpitu. W przechwyconej odpowiedzi API znajdowa\u0142 si\u0119 rekord typu <code>adminDashboard<\/code>, z tytu\u0142em bannera \u201eBuild more. Pay less. This Summer\u201d, kt\u00f3rego <code>display_id<\/code> \u0142adowa\u0142 zewn\u0119trzny skrypt przez zakodowane wywo\u0142anie <code>fetch<\/code>.<\/p>\n\n\n\n<p>Atak by\u0142 sterowany wy\u0142\u0105cznie przez API: ofiara nie musia\u0142a aktualizowa\u0107 wtyczki, a pliki na dysku pozostawa\u0142y niezmienione. Dlatego skanery integralno\u015bci oparte na plikach nie widz\u0105 tego mechanizmu, a firewall aplikacji webowej ma ograniczon\u0105 widoczno\u015b\u0107 ataku wykonywanego w przegl\u0105darce zalogowanego administratora.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Dwa warianty z\u0142o\u015bliwego payloadu<\/h2>\n\n\n\n<p>Handler zdarzenia rozpoczyna\u0142 wieloetapow\u0105 kompromitacj\u0119 i dobiera\u0142 zewn\u0119trzny skrypt zale\u017cnie od dost\u0119pno\u015bci infrastruktury atakuj\u0105cego. G\u0142\u00f3wny payload <code>w2.js<\/code> trafia\u0142 do wtyczek korzystaj\u0105cych z endpointu <code>api-data-all-records<\/code>.<\/p>\n\n\n\n<p>Po uruchomieniu w sesji zalogowanego administratora <code>w2.js<\/code> kontaktowa\u0142 si\u0119 z serwerem C2 <code>ia-cdn[.]com\/fz\/c<\/code>, przekazuj\u0105c origin witryny i pobieraj\u0105c instrukcje targetowania. Je\u015bli C2 zwraca\u0142 status <code>skip<\/code> albo <code>done<\/code>, skrypt ko\u0144czy\u0142 prac\u0119.<\/p>\n\n\n\n<p>Nast\u0119pnie wykorzystywa\u0142 <code>X-WP-Nonce<\/code> obecny w aktywnej sesji administratora, by utworzy\u0107 przez WordPress REST API nowe konto z rol\u0105 administratora. Gdy ta droga zawodzi\u0142a, przechodzi\u0142 na zwyk\u0142e wysy\u0142anie formularzy WordPressa.<\/p>\n\n\n\n<p>Kolejny etap pobiera\u0142 z C2 fa\u0142szywe archiwum ZIP wtyczki i instalowa\u0142 je przez standardowy formularz uploadu wtyczek. Fa\u0142szywa wtyczka ukrywa\u0142a si\u0119 pod slugiem <code>wp-smart-thumbnails<\/code> albo podobn\u0105, neutralnie brzmi\u0105c\u0105 nazw\u0105, zawiera\u0142a webshell <code>emer-run.php<\/code>, a atakuj\u0105cy wywo\u0142ywa\u0142 ten plik bezpo\u015brednio po URL.<\/p>\n\n\n\n<p>Wywo\u0142anie <code>emer-run.php<\/code> instalowa\u0142o w katalogu Must-Use plugins dwa modu\u0142y zapewniaj\u0105ce trwa\u0142o\u015b\u0107. Obie przechwycone pr\u00f3bki mia\u0142y timestamp cofni\u0119ty do wrze\u015bnia 2025 roku, aby wtopi\u0107 si\u0119 w legalne daty systemu plik\u00f3w; nazwy plik\u00f3w mog\u0105 r\u00f3\u017cni\u0107 si\u0119 mi\u0119dzy infekcjami.<\/p>\n\n\n\n<p>Pierwszy modu\u0142 by\u0142 backdoorem magic login: pozwala\u0142 wej\u015b\u0107 do panelu administratora bez uwierzytelnienia przez parametr URL <code>?_wplogin=&lt;token&gt;<\/code> i kierowa\u0142 atak na najd\u0142u\u017cej zarejestrowane konto administratora. Drugi modu\u0142 utrudnia\u0142 analiz\u0119 \u2013 podpina\u0142 si\u0119 do zapyta\u0144 bazy danych WordPressa, ukrywa\u0142 utworzone konta na li\u015bcie u\u017cytkownik\u00f3w administracyjnych i odpowiednio zmniejsza\u0142 \u0142\u0105czn\u0105 liczb\u0119 u\u017cytkownik\u00f3w. Wyniki ka\u017cdego etapu skrypt wysy\u0142a\u0142 do C2 przez <code>navigator.sendBeacon<\/code>.<\/p>\n\n\n\n<p>Drugi skrypt, <code>x.js<\/code>, hostowano bezpo\u015brednio w infrastrukturze BdThemes i podawano ofiarom korzystaj\u0105cym z endpointu <code>api-data-records<\/code>. Wylicza\u0142 on deterministyczne dane administratora na podstawie nazwy hosta witryny: oblicza\u0142 hash, zamienia\u0142 jego warto\u015b\u0107 bezwzgl\u0119dn\u0105 na base36 i bra\u0142 pierwsze sze\u015b\u0107 znak\u00f3w.<\/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>\/\/ JavaScript - schemat deterministycznych danych konta\nvar n = Math.abs(hash).toString(36).slice(0, 6);\nvar user = &quot;bd_&quot; + n;\nvar pass = &quot;Bd@26!&quot; + n + &quot;x&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\">\/\/ JavaScript - schemat deterministycznych danych konta<\/span><\/span>\n<span class=\"line\"><span style=\"color:#F97583\">var<\/span><span style=\"color:#E1E4E8\"> n <\/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 style=\"color:#F97583\">var<\/span><span style=\"color:#E1E4E8\"> user <\/span><span style=\"color:#F97583\">=<\/span><span style=\"color:#9ECBFF\"> \"bd_\"<\/span><span style=\"color:#F97583\"> +<\/span><span style=\"color:#E1E4E8\"> n;<\/span><\/span>\n<span class=\"line\"><span style=\"color:#F97583\">var<\/span><span style=\"color:#E1E4E8\"> pass <\/span><span style=\"color:#F97583\">=<\/span><span style=\"color:#9ECBFF\"> \"Bd@26!\"<\/span><span style=\"color:#F97583\"> +<\/span><span style=\"color:#E1E4E8\"> n <\/span><span style=\"color:#F97583\">+<\/span><span style=\"color:#9ECBFF\"> \"x\"<\/span><span style=\"color:#E1E4E8\">;<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>Powstawa\u0142a nazwa u\u017cytkownika <code>bd_<\/code> z sze\u015bcioma znakami hash base36 oraz has\u0142o z prefiksem <code>Bd@26!<\/code>, tym samym hashem i ko\u0144cowym <code>x<\/code>. Skrypt \u0142\u0105czy\u0142 te dane z adresem e-mail w domenie <code>@wordpress.org<\/code>, tworzy\u0142 konto administratora przez <code>\/wp-admin\/user-new.php<\/code>, raportowa\u0142 rezultat do C2 i \u2013 je\u015bli przegl\u0105darka udost\u0119pnia\u0142a <code>localStorage<\/code> \u2013 zapisywa\u0142 flag\u0119 wykonania lokalnie.<\/p>\n\n\n\n<p>Deterministyczny algorytm zwalnia\u0142 atakuj\u0105cych z utrzymywania centralnej listy przej\u0119tych stron. Zesp\u00f3\u0142 reaguj\u0105cy na incydent mo\u017ce za to obliczy\u0107 dok\u0142adn\u0105 nazw\u0119 i has\u0142o, kt\u00f3rych trzeba szuka\u0107 dla podejrzanej domeny.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Zakres i powi\u0105zania kampanii<\/h2>\n\n\n\n<p>Domena C2 jest powi\u0105zana z t\u0105 sam\u0105 grup\u0105, kt\u00f3ra sta\u0142a za atakami \u0142a\u0144cucha dostaw 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> oraz <a href=\"https:\/\/optinmonster.com\/security-incident-tampered-script-served-via-optinmonster-and-trustpulse\/#what-to-check-and-do\">OptinMonster<\/a> w ci\u0105gu poprzednich dw\u00f3ch miesi\u0119cy.<\/p>\n\n\n\n<p>Celem kampanii by\u0142o masowe, ciche utrzymanie uprawnie\u0144 administracyjnych i zdalne wykonanie kodu w milionach \u015brodowisk WordPressa. Atakuj\u0105cy nie potrzebowali dost\u0119pu do konkretnych witryn: wystarczy\u0142o zatru\u0107 zaufany feed promocyjny i wykorzysta\u0107 b\u0142\u0105d w kodzie, kt\u00f3ry go wy\u015bwietla\u0142.<\/p>\n\n\n\n<p>Obecno\u015b\u0107 z\u0142o\u015bliwych rekord\u00f3w JSON oraz drugiego payloadu <code>x.js<\/code> bezpo\u015brednio w bucketcie dostawcy wskazuje na powa\u017cne przej\u0119cie po\u015bwiadcze\u0144 do magazynu chmurowego BdThemes albo jego infrastruktury wewn\u0119trznej.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Dotkni\u0119te wtyczki<\/h2>\n\n\n\n<p>Podatno\u015b\u0107 Biggopti przez parametr <code>display_id<\/code> z API Sigmative dotyczy nast\u0119puj\u0105cych wtyczek:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n\n<li><a href=\"https:\/\/www.wordfence.com\/threat-intel\/vulnerabilities\/wordpress-plugins\/bdthemes-element-pack-lite\">Element Pack Addons for Elementor \u2013 Elementor Widgets, Elementor Templates, Elementor Addons<\/a> \u2013 <code>bdthemes-element-pack-lite<\/code><\/li>\n\n\n<li><a href=\"https:\/\/www.wordfence.com\/threat-intel\/vulnerabilities\/wordpress-plugins\/live-copy-paste\">Live Copy Paste for Elementor \u2013 Cross Domain Copy Paste &#038; Page Duplicator<\/a> \u2013 <code>live-copy-paste<\/code><\/li>\n\n\n<li><a href=\"https:\/\/www.wordfence.com\/threat-intel\/vulnerabilities\/wordpress-plugins\/pixel-gallery\">Pixel Gallery Addons for Elementor \u2013 Easy Grid, Creative Gallery, Drag and Drop Grid, Custom Grid Layout, Portfolio Gallery<\/a> \u2013 <code>pixel-gallery<\/code><\/li>\n\n\n<li><a href=\"https:\/\/www.wordfence.com\/threat-intel\/vulnerabilities\/wordpress-plugins\/bdthemes-prime-slider-lite\">Prime Slider Addons for Elementor \u2013 Widgets, Templates &#038; Elementor Addons<\/a> \u2013 <code>bdthemes-prime-slider-lite<\/code><\/li>\n\n\n<li><a href=\"https:\/\/www.wordfence.com\/threat-intel\/vulnerabilities\/wordpress-plugins\/smart-admin-assistant\">Smart Admin Assistant \u2013 Dashboard and Site Enhancements<\/a> \u2013 <code>smart-admin-assistant<\/code><\/li>\n\n\n<li><a href=\"https:\/\/www.wordfence.com\/threat-intel\/vulnerabilities\/wordpress-plugins\/ultimate-post-kit\">Ultimate Post Kit Addons for Elementor<\/a> \u2013 <code>ultimate-post-kit<\/code><\/li>\n\n\n<li><a href=\"https:\/\/www.wordfence.com\/threat-intel\/vulnerabilities\/wordpress-plugins\/ultimate-store-kit\">Ultimate Store Kit \u2013 Addon For WooCommerce, EDD and Elementor<\/a> \u2013 <code>ultimate-store-kit<\/code><\/li>\n\n<\/ul>\n\n\n\n<p>Pe\u0142ny opis podatno\u015bci znajduje si\u0119 w <a href=\"https:\/\/www.wordfence.com\/threat-intel\/vulnerabilities\/id\/7bf1d6f9-afe2-41c2-968b-20dbc474cd73\">bazie Wordfence Intelligence<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Wska\u017aniki kompromitacji<\/h2>\n\n\n\n<p>Sprawd\u017a zasoby zewn\u0119trzne, pliki, opcje bazy danych oraz konta u\u017cytkownik\u00f3w. Endpointy API dostawcy wymienione ni\u017cej zosta\u0142y ju\u017c oczyszczone, ale ich wcze\u015bniejsze u\u017cycie stanowi wa\u017cny \u015blad analityczny.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n\n<li>G\u0142\u00f3wny payload: <code>ia-cdn[.]com\/fz\/w2.js<\/code>.<\/li>\n\n\n<li>Endpoint beacon C2: <code>ia-cdn[.]com\/fz\/c<\/code>.<\/li>\n\n\n<li>Zatruty endpoint dostawcy: <code>api[.]sigmative[.]io\/prod\/store\/api\/biggopti\/api-data-all-records<\/code>.<\/li>\n\n\n<li>Zatruty endpoint dostawcy: <code>api[.]sigmative[.]io\/prod\/store\/api\/biggopti\/api-data-records<\/code>.<\/li>\n\n\n<li>Zas\u00f3b drugiego payloadu: <code>api[.]sigmative[.]io\/prod\/store\/api\/biggopti\/x.js<\/code>.<\/li>\n\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n\n<li>Webshell <code>emer-run.php<\/code>, MD5: <code>1024732009983dd5e54b4cf5593f04d4<\/code>.<\/li>\n\n\n<li>Backdoor magic login MU-plugin: <code>class-wp-token-validate.php<\/code>, MD5: <code>7719cd98a35ffad2771f26d1ceab7d27<\/code>.<\/li>\n\n\n<li>Modu\u0142 ukrywania MU-plugin: <code>class-wp-query-9d127ff3.php<\/code> lub podobny plik pasuj\u0105cy do <code>class-wp-query-*.php<\/code>, MD5 pr\u00f3bki: <code>9aadc3e5c5242b273bd17c5bdc358845<\/code>.<\/li>\n\n\n<li>Modu\u0142 \u201eHealth Check\u201d MU-plugin: <code>wp-cache-optimizer.php<\/code>, MD5: <code>e450ae5bc4bfc0d960dded06a76bb8e9<\/code>.<\/li>\n\n\n<li>Opcja bazy danych <code>fz_emer_login_tokens<\/code>, kt\u00f3ra przechowuje tokeny magic login.<\/li>\n\n\n<li>Opcja bazy danych <code>fz_emer_done_v1<\/code>, kt\u00f3ra oznacza zako\u0144czon\u0105 kompromitacj\u0119.<\/li>\n\n\n<li>Konta u\u017cywaj\u0105ce domen <code>@wordpress.org<\/code> albo <code>@developer.wordpress.org<\/code>.<\/li>\n\n\n<li>Nazwy u\u017cytkownik\u00f3w pasuj\u0105ce do wzorca <code>bd_<\/code> oraz sze\u015b\u0107 znak\u00f3w alfanumerycznych.<\/li>\n\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">O\u015b czasu<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n\n<li><strong>1 marca 2026<\/strong> \u2013 JavaScript API Biggopti trafia do Prime Slidera 4.1.9 w rewizji SVN <code>r3471891<\/code>. <code>display_id<\/code> nie jest escapowany w atrybucie <code>id<\/code>, a wtyczka korzysta z endpointu <code>api-data-records<\/code>.<\/li>\n\n\n<li><strong>10 maja 2026<\/strong> \u2013 endpoint zmienia si\u0119 na <code>api-data-all-records<\/code>. Dodano sanitizer <code>DOMParser<\/code> dla pola tre\u015bci, ale <code>id<\/code> nadal pozostaje nieescapowany.<\/li>\n\n\n<li><strong>23 czerwca 2026<\/strong> \u2013 <code>start_date<\/code> kampanii z zatrutym API dla komunikatu \u201eSummer Sale\u201d; to najwcze\u015bniejsza mo\u017cliwa data aktywno\u015bci XSS.<\/li>\n\n\n<li><strong>6 sierpnia 2026, 22:40 UTC<\/strong> \u2013 czas Last-Modified zatrutego <code>api-data-records<\/code>.<\/li>\n\n\n<li><strong>7 sierpnia 2026, 09:11 UTC<\/strong> \u2013 czas Last-Modified zatrutego <code>api-data-all-records<\/code>.<\/li>\n\n\n<li><strong>7 sierpnia 2026<\/strong> \u2013 zesp\u00f3\u0142 Threat Intelligence otrzymuje zg\u0142oszenie i obserwuje atak w \u015brodowiskach produkcyjnych.<\/li>\n\n\n<li><strong>7 sierpnia 2026<\/strong> \u2013 wtyczki zostaj\u0105 zamkni\u0119te w katalogu WordPressa do czasu kontroli.<\/li>\n\n\n<li><strong>7 sierpnia 2026, 16:56 UTC<\/strong> \u2013 przechwycono artefakty dochodzenia.<\/li>\n\n\n<li><strong>8 sierpnia 2026<\/strong> \u2013 oba endpointy API ponownie zwracaj\u0105 czysty JSON.<\/li>\n\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Co sprawdzi\u0107 teraz<\/h2>\n\n\n\n<p>Przejrzyj list\u0119 u\u017cytkownik\u00f3w w bazie danych, katalogi wtyczek \u2013 w tym Must-Use plugins \u2013 oraz tabel\u0119 opcji pod k\u0105tem wszystkich wska\u017anik\u00f3w z tej listy. Nie ograniczaj si\u0119 do kontroli integralno\u015bci plik\u00f3w: ten atak tworzy\u0142 trwa\u0142e elementy poza oryginalnymi plikami wtyczek.<\/p>\n\n\n\n<p>Sygnatury malware i regu\u0142y WAF wykrywaj\u0105ce t\u0119 kompromitacj\u0119 otrzymali 7 sierpnia 2026 u\u017cytkownicy Wordfence Premium, Care, Response oraz p\u0142atnego Wordfence CLI. U\u017cytkownicy bezp\u0142atnego Wordfence i bezp\u0142atnego Wordfence CLI dostan\u0105 je po standardowym 30-dniowym op\u00f3\u017anieniu.<\/p>\n\n\n<div class=\"references-section\">\n                <h2>Odniesienia \/ \u0179r\u00f3d\u0142a<\/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><li><a href=\"https:\/\/www.wordfence.com\/threat-intel\/vulnerabilities\/id\/7bf1d6f9-afe2-41c2-968b-20dbc474cd73\" target=\"_blank\" rel=\"noopener noreferrer\">Biggopti Library (Various Versions) &#8211; Cross-Site Scripting via display_id from Sigmative API<\/a><\/li><li><a href=\"https:\/\/www.wordfence.com\/blog\/2026\/07\/wordfence-prism-detected-backdoored-wordpress-plugin-within-two-hours-of-it-being-introduced\/\" target=\"_blank\" rel=\"noopener noreferrer\">Wordfence Prism Detected Backdoored WordPress Plugin Within Two Hours of it Being Introduced<\/a><\/li><li><a href=\"https:\/\/optinmonster.com\/security-incident-tampered-script-served-via-optinmonster-and-trustpulse\/#what-to-check-and-do\" target=\"_blank\" rel=\"noopener noreferrer\">Security Incident: Tampered Script Served via OptinMonster and TrustPulse<\/a><\/li><\/ul>\n            <\/div>","protected":false},"excerpt":{"rendered":"<p>Zatruty banner JSON w panelu WordPressa wystarczy\u0142, by atakuj\u0105cy przej\u0119li sesje administrator\u00f3w wtyczek BdThemes. Sprawd\u017a konta, MU-plugins i opcje bazy, bo pliki \u017ar\u00f3d\u0142owe mog\u0142y pozosta\u0107 nietkni\u0119te.<\/p>\n","protected":false},"author":24,"featured_media":234,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[9],"tags":[140,35,139,10,130],"class_list":["post-235","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-bezpieczenstwo","tag-bdthemes","tag-bezpieczenstwo","tag-lancuch-dostaw","tag-wordpress","tag-xss"],"_links":{"self":[{"href":"https:\/\/helloblog.io\/pl\/wp-json\/wp\/v2\/posts\/235","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/helloblog.io\/pl\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/helloblog.io\/pl\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/helloblog.io\/pl\/wp-json\/wp\/v2\/users\/24"}],"replies":[{"embeddable":true,"href":"https:\/\/helloblog.io\/pl\/wp-json\/wp\/v2\/comments?post=235"}],"version-history":[{"count":0,"href":"https:\/\/helloblog.io\/pl\/wp-json\/wp\/v2\/posts\/235\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/helloblog.io\/pl\/wp-json\/wp\/v2\/media\/234"}],"wp:attachment":[{"href":"https:\/\/helloblog.io\/pl\/wp-json\/wp\/v2\/media?parent=235"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/helloblog.io\/pl\/wp-json\/wp\/v2\/categories?post=235"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/helloblog.io\/pl\/wp-json\/wp\/v2\/tags?post=235"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}