Atak na BdThemes: zatrute API JSON przejmuje WordPressa
Atak na ekosystem BdThemes nie wymagał podmiany plików wtyczki ani instalacji aktualizacji przez ofiarę. Wystarczyło przejąć zdalny strumień JSON, który wyświetlał bannery promocyjne w panelu WordPressa, aby uruchomić JavaScript w przeglądarce każdego zalogowanego administratora.
Dotknięte wtyczki są tymczasowo zamknięte w oficjalnym katalogu WordPressa na czas pełnej kontroli i trwającego dochodzenia zespołu WordPress Plugins. Problem ma CVSS 5.4 (średni), nie ma poprawki, a osoba, która go zgłosiła, pozostaje nieznana.
Pełne przejęcie witryny bez aktualizacji wtyczki
Jeśli używasz choć jednej z wymienionych dalej wtyczek BdThemes, potraktuj instalację jako potencjalnie przejętą. Atak mógł tworzyć konto administratora, instalować webshell i zapisywać trwałe backdoory, nie zmieniając plików oryginalnej wtyczki.
Jak doszło do kompromitacji łańcucha dostaw
Wtyczki BdThemes zawierają wewnętrzny komponent Biggopti. Pobiera on bannery promocyjne z API dostawcy i renderuje je w kokpicie administracyjnym WordPressa. API korzystało ze statycznych plików JSON w bucketcie DigitalOcean Spaces, chronionym przez Cloudflare, a nie z dynamicznego serwera aplikacyjnego.
Autorzy wtyczek wprowadzili podatność Cross-Site Scripting (XSS), czyli możliwość uruchomienia obcego JavaScriptu w kontekście zaufanej strony. Następnie nieuprawniony podmiot uzyskał zapis do bucketa i podmienił prawidłowe odpowiedzi JSON na spreparowane dane. Żaden plik kodu źródłowego w oficjalnym repozytorium WordPress.org nie został przy tym zmieniony.
Biggopti dodaje asset JavaScript po hooku admin_init, więc działa bezwarunkowo przy każdym załadowaniu dowolnej strony wp-admin. Skrypt pobiera dane bannera, a potem wstawia pole display_id z odpowiedzi JSON bez escapowania bezpośrednio do atrybutu HTML id.
// JavaScript - fragment podatnego składania atrybutu HTML
var f = t.display_id || t.id || "default";
var m = "bdt-admin-biggopti-api-biggopti-" + f;
A = 'id="' + m + '"';W tym samym kodzie data-display-id był już escapowany przez funkcję zamieniającą znaki &, <, > i " na encje HTML. Konstrukcja tej funkcji była zawiła, prawdopodobnie na skutek minifikacji lub bundlowania, ale nie chroniła osobnego atrybutu id.
// JavaScript - funkcja użyta dla innego atrybutu
function p(t) {
return (t || "")
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """);
}Historia commitów SVN wskazuje, że nieescapowane wstawianie do atrybutu pojawiło się 1 marca 2026 roku w Prime Sliderze 4.1.9 (bdthemes-prime-slider-lite, rewizja r3471891), a później trafiło do pozostałych wtyczek. Późniejsze wydania dodały oparty na DOMParser sanitizer dla pola treści bannera, który usuwał niebezpieczne tagi HTML i inline handlery, lecz nie naprawiły id.
Złośliwy display_id zamykał atrybut id i dopisywał handler zdarzenia onanimationstart. Animacja CSS uruchamiała go w ciągu 10 ms, po cichu, gdy administrator otwierał stronę kokpitu. W przechwyconej odpowiedzi API znajdował się rekord typu adminDashboard, z tytułem bannera „Build more. Pay less. This Summer”, którego display_id ładował zewnętrzny skrypt przez zakodowane wywołanie fetch.
Atak był sterowany wyłącznie przez API: ofiara nie musiała aktualizować wtyczki, a pliki na dysku pozostawały niezmienione. Dlatego skanery integralności oparte na plikach nie widzą tego mechanizmu, a firewall aplikacji webowej ma ograniczoną widoczność ataku wykonywanego w przeglądarce zalogowanego administratora.
Dwa warianty złośliwego payloadu
Handler zdarzenia rozpoczynał wieloetapową kompromitację i dobierał zewnętrzny skrypt zależnie od dostępności infrastruktury atakującego. Główny payload w2.js trafiał do wtyczek korzystających z endpointu api-data-all-records.
Po uruchomieniu w sesji zalogowanego administratora w2.js kontaktował się z serwerem C2 ia-cdn[.]com/fz/c, przekazując origin witryny i pobierając instrukcje targetowania. Jeśli C2 zwracał status skip albo done, skrypt kończył pracę.
Następnie wykorzystywał X-WP-Nonce obecny w aktywnej sesji administratora, by utworzyć przez WordPress REST API nowe konto z rolą administratora. Gdy ta droga zawodziła, przechodził na zwykłe wysyłanie formularzy WordPressa.
Kolejny etap pobierał z C2 fałszywe archiwum ZIP wtyczki i instalował je przez standardowy formularz uploadu wtyczek. Fałszywa wtyczka ukrywała się pod slugiem wp-smart-thumbnails albo podobną, neutralnie brzmiącą nazwą, zawierała webshell emer-run.php, a atakujący wywoływał ten plik bezpośrednio po URL.
Wywołanie emer-run.php instalowało w katalogu Must-Use plugins dwa moduły zapewniające trwałość. Obie przechwycone próbki miały timestamp cofnięty do września 2025 roku, aby wtopić się w legalne daty systemu plików; nazwy plików mogą różnić się między infekcjami.
Pierwszy moduł był backdoorem magic login: pozwalał wejść do panelu administratora bez uwierzytelnienia przez parametr URL ?_wplogin=<token> i kierował atak na najdłużej zarejestrowane konto administratora. Drugi moduł utrudniał analizę – podpinał się do zapytań bazy danych WordPressa, ukrywał utworzone konta na liście użytkowników administracyjnych i odpowiednio zmniejszał łączną liczbę użytkowników. Wyniki każdego etapu skrypt wysyłał do C2 przez navigator.sendBeacon.
Drugi skrypt, x.js, hostowano bezpośrednio w infrastrukturze BdThemes i podawano ofiarom korzystającym z endpointu api-data-records. Wyliczał on deterministyczne dane administratora na podstawie nazwy hosta witryny: obliczał hash, zamieniał jego wartość bezwzględną na base36 i brał pierwsze sześć znaków.
// JavaScript - schemat deterministycznych danych konta
var n = Math.abs(hash).toString(36).slice(0, 6);
var user = "bd_" + n;
var pass = "Bd@26!" + n + "x";Powstawała nazwa użytkownika bd_ z sześcioma znakami hash base36 oraz hasło z prefiksem Bd@26!, tym samym hashem i końcowym x. Skrypt łączył te dane z adresem e-mail w domenie @wordpress.org, tworzył konto administratora przez /wp-admin/user-new.php, raportował rezultat do C2 i – jeśli przeglądarka udostępniała localStorage – zapisywał flagę wykonania lokalnie.
Deterministyczny algorytm zwalniał atakujących z utrzymywania centralnej listy przejętych stron. Zespół reagujący na incydent może za to obliczyć dokładną nazwę i hasło, których trzeba szukać dla podejrzanej domeny.
Zakres i powiązania kampanii
Domena C2 jest powiązana z tą samą grupą, która stała za atakami łańcucha dostaw na Advanced Responsive Video Embedder oraz OptinMonster w ciągu poprzednich dwóch miesięcy.
Celem kampanii było masowe, ciche utrzymanie uprawnień administracyjnych i zdalne wykonanie kodu w milionach środowisk WordPressa. Atakujący nie potrzebowali dostępu do konkretnych witryn: wystarczyło zatruć zaufany feed promocyjny i wykorzystać błąd w kodzie, który go wyświetlał.
Obecność złośliwych rekordów JSON oraz drugiego payloadu x.js bezpośrednio w bucketcie dostawcy wskazuje na poważne przejęcie poświadczeń do magazynu chmurowego BdThemes albo jego infrastruktury wewnętrznej.
Dotknięte wtyczki
Podatność Biggopti przez parametr display_id z API Sigmative dotyczy następujących wtyczek:
- Element Pack Addons for Elementor – Elementor Widgets, Elementor Templates, Elementor Addons –
bdthemes-element-pack-lite - Live Copy Paste for Elementor – Cross Domain Copy Paste & Page Duplicator –
live-copy-paste - Pixel Gallery Addons for Elementor – Easy Grid, Creative Gallery, Drag and Drop Grid, Custom Grid Layout, Portfolio Gallery –
pixel-gallery - Prime Slider Addons for Elementor – Widgets, Templates & Elementor Addons –
bdthemes-prime-slider-lite - Smart Admin Assistant – Dashboard and Site Enhancements –
smart-admin-assistant - Ultimate Post Kit Addons for Elementor –
ultimate-post-kit - Ultimate Store Kit – Addon For WooCommerce, EDD and Elementor –
ultimate-store-kit
Pełny opis podatności znajduje się w bazie Wordfence Intelligence.
Wskaźniki kompromitacji
Sprawdź zasoby zewnętrzne, pliki, opcje bazy danych oraz konta użytkowników. Endpointy API dostawcy wymienione niżej zostały już oczyszczone, ale ich wcześniejsze użycie stanowi ważny ślad analityczny.
- Główny payload:
ia-cdn[.]com/fz/w2.js. - Endpoint beacon C2:
ia-cdn[.]com/fz/c. - Zatruty endpoint dostawcy:
api[.]sigmative[.]io/prod/store/api/biggopti/api-data-all-records. - Zatruty endpoint dostawcy:
api[.]sigmative[.]io/prod/store/api/biggopti/api-data-records. - Zasób drugiego payloadu:
api[.]sigmative[.]io/prod/store/api/biggopti/x.js.
- Webshell
emer-run.php, MD5:1024732009983dd5e54b4cf5593f04d4. - Backdoor magic login MU-plugin:
class-wp-token-validate.php, MD5:7719cd98a35ffad2771f26d1ceab7d27. - Moduł ukrywania MU-plugin:
class-wp-query-9d127ff3.phplub podobny plik pasujący doclass-wp-query-*.php, MD5 próbki:9aadc3e5c5242b273bd17c5bdc358845. - Moduł „Health Check” MU-plugin:
wp-cache-optimizer.php, MD5:e450ae5bc4bfc0d960dded06a76bb8e9. - Opcja bazy danych
fz_emer_login_tokens, która przechowuje tokeny magic login. - Opcja bazy danych
fz_emer_done_v1, która oznacza zakończoną kompromitację. - Konta używające domen
@wordpress.orgalbo@developer.wordpress.org. - Nazwy użytkowników pasujące do wzorca
bd_oraz sześć znaków alfanumerycznych.
Oś czasu
- 1 marca 2026 – JavaScript API Biggopti trafia do Prime Slidera 4.1.9 w rewizji SVN
r3471891.display_idnie jest escapowany w atrybucieid, a wtyczka korzysta z endpointuapi-data-records. - 10 maja 2026 – endpoint zmienia się na
api-data-all-records. Dodano sanitizerDOMParserdla pola treści, aleidnadal pozostaje nieescapowany. - 23 czerwca 2026 –
start_datekampanii z zatrutym API dla komunikatu „Summer Sale”; to najwcześniejsza możliwa data aktywności XSS. - 6 sierpnia 2026, 22:40 UTC – czas Last-Modified zatrutego
api-data-records. - 7 sierpnia 2026, 09:11 UTC – czas Last-Modified zatrutego
api-data-all-records. - 7 sierpnia 2026 – zespół Threat Intelligence otrzymuje zgłoszenie i obserwuje atak w środowiskach produkcyjnych.
- 7 sierpnia 2026 – wtyczki zostają zamknięte w katalogu WordPressa do czasu kontroli.
- 7 sierpnia 2026, 16:56 UTC – przechwycono artefakty dochodzenia.
- 8 sierpnia 2026 – oba endpointy API ponownie zwracają czysty JSON.
Co sprawdzić teraz
Przejrzyj listę użytkowników w bazie danych, katalogi wtyczek – w tym Must-Use plugins – oraz tabelę opcji pod kątem wszystkich wskaźników z tej listy. Nie ograniczaj się do kontroli integralności plików: ten atak tworzył trwałe elementy poza oryginalnymi plikami wtyczek.
Sygnatury malware i reguły WAF wykrywające tę kompromitację otrzymali 7 sierpnia 2026 użytkownicy Wordfence Premium, Care, Response oraz płatnego Wordfence CLI. Użytkownicy bezpłatnego Wordfence i bezpłatnego Wordfence CLI dostaną je po standardowym 30-dniowym opóźnieniu.
Odniesienia / Źródła
- PSA: Supply Chain Compromise in BdThemes Ecosystem via Poisoned API Response
- Biggopti Library (Various Versions) – Cross-Site Scripting via display_id from Sigmative API
- Wordfence Prism Detected Backdoored WordPress Plugin Within Two Hours of it Being Introduced
- Security Incident: Tampered Script Served via OptinMonster and TrustPulse
Katarzyna Nowak
Redaktor naczelna zespołu polskiego, architekt enterprise Java i mikroserwisów. Projektowanie i optymalizacja systemów wielkoskalowych to moja specjalność.
Wszystkie wpisy