BdThemesin API-hyökkäys: näin tarkistat WordPress-sivustosi
BdThemesin lisäosien toimitusketjuhyökkäys ei muuttanut yhtäkään tiedostoa WordPress.org:n SVN-repositoriossa. Hyökkääjä myrkytti lisäosien hallintanäkymässä hakeman JSON-syötteen, jolloin haittakoodi suoritettiin kirjautuneen ylläpitäjän selaimessa jokaisella wp-admin-sivulatauksella. Se riitti luomaan vääriä ylläpitäjätunnuksia, asentamaan webshellin ja jättämään sivustolle pysyviä takaportteja.
Jos sivustollasi on yksikin tässä artikkelissa luetelluista BdThemes-lisäosista, tarkista kompromissin indikaattorit välittömästi. Pelkkä lisäosatiedostojen eheystarkistus ei riitä, koska hyökkäys toimi etä-API:n kautta eikä vaatinut tiedostomuutoksia palvelimella.
Toimi heti
Kaikki seitsemän vaikutuksen piirissä olevaa lisäosaa suljettiin väliaikaisesti WordPressin lisäosahakemistosta 7.8.2026 tarkistusta ja tutkintaa varten. Haavoittuvuus on luokiteltu korjaamattomaksi.
Mitä hyökkäyksessä tapahtui?
Toimitusketjuhyökkäys tarkoittaa hyökkäystä luotettuun ohjelmiston, päivityksen tai ulkoisen datan toimitusreittiin. Tässä tapauksessa kohteena oli BdThemesin Biggopti-komponentti, joka noutaa mainosbannereita toimittajan API:sta ja näyttää ne WordPressin hallintapaneelissa.
API ei ollut dynaaminen sovelluspalvelin, vaan Cloudflaren suojaaman DigitalOcean Spaces -objektitallennuksen tarjoama staattinen JSON-tiedosto. Hyökkääjä sai kirjoitusoikeuden tallennustilaan ja korvasi aidot JSON-vastaukset muokatuilla vastauksilla. Tämä viittaa vakavaan murtoon BdThemesin pilvitallennuksen tunnuksissa tai sisäisessä infrastruktuurissa.
Hyökkäys hyödynsi Biggoptin XSS-haavoittuvuutta. XSS eli cross-site scripting tarkoittaa, että hyökkääjä saa selaimen suorittamaan omaa JavaScriptiään luotetulla sivustolla. Koska skripti suoritettiin valmiiksi kirjautuneen ylläpitäjän istunnossa, sillä oli ylläpitäjän oikeuksien puitteissa pääsy WordPressin toimintoihin.
Haavoittuvuus Biggopti-kirjastossa
Biggopti-kirjaston eri versioissa on display_id-kenttään liittyvä XSS-haavoittuvuus Sigmative API:ssa. Sen CVSS-arvo on 5,4 / 10 (keskitaso), ja korjausta ei ollut saatavilla. Hyökkääjä, joka pystyy murtautumaan Sigmative API -palveluun, voi lisätä sivuille mielivaltaista JavaScriptiä, joka suoritetaan, kun käyttäjä avaa saastuneen sivun.
Jokainen Biggoptia käyttävä BdThemes-lisäosa rekisteröi client-side JavaScript -tiedoston admin_init-hookissa. Siksi selain lataa ja suorittaa skriptin ehdoitta jokaisella wp-admin-sivulla. Skripti noutaa bannerit API-endpointista ja kokoaa niiden HTML-rakenteen DOM:iin.
Ongelma syntyy, kun koodi sijoittaa etä-JSON:n display_id-arvon suoraan HTML:n id-attribuuttiin ilman selaimessa tehtävää merkistömuunnosta. Haavoittuvan logiikan pelkistetty muoto on seuraava:
// display_id tulee etäisestä JSON-vastauksesta eikä sitä muunnettu turvalliseksi.
var displayId = item.display_id || item.id || "default";
var elementId = "bdt-admin-biggopti-api-biggopti-" + displayId;
var attributes = 'id="' + elementId + '"';Samassa koodissa data-display-id-attribuutti muunnettiin HTML-turvalliseen muotoon korvaamalla &, <, >, ja lainausmerkit entiteeteillä. Rakenne oli tosin monimutkainen, todennäköisesti minifioinnin tai bundlauksen seurauksena. id-attribuutin kohdalla vastaava muunnos kuitenkin puuttui.
function escapeHtml(value) {
return (value || "")
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """);
}SVN-historia osoittaa, että haavoittuva attribuutin lisäys tuli Prime Sliderin (bdthemes-prime-slider-lite) versioon 4.1.9 1.3.2026, minkä jälkeen se päätyi muihin lisäosiin. Myöhemmissä julkaisuissa bannerin content-kentälle lisättiin DOMParser-pohjainen puhdistus, joka poistaa vaarallisia HTML-elementtejä ja inline-event handlereita. Se ei kuitenkaan suojannut id-attribuuttia.
Myrkytetty display_id katkaisi id-attribuutin ja lisäsi onanimationstart-event handlerin. CSS-animaatio laukaisi sen noin 10 millisekunnissa, joten haittakoodi käynnistyi äänettömästi, kun ylläpitäjä avasi minkä tahansa hallintapaneelin sivun. Saastuneessa API-vastauksessa oli esimerkiksi SAFE" onanimationstart=... style=animation:wrapperSlideInTop .01s ease-out both -alkuinen display_id, jonka merkkikoodattu JavaScript nouti seuraavan vaiheen skriptin ulkoiselta palvelimelta.
Vaikutuksen piirissä olevat lisäosat
Seuraavat lisäosat käyttivät haavoittuvaa Biggopti-komponenttia ja kuuluvat kompromissin piiriin:
- Element Pack Addons for Elementor –
bdthemes-element-pack-lite - Prime Slider Addons for Elementor –
bdthemes-prime-slider-lite - Pixel Gallery Addons for Elementor –
pixel-gallery - Ultimate Post Kit Addons for Elementor –
ultimate-post-kit - Ultimate Store Kit – Addon For WooCommerce, EDD and Elementor –
ultimate-store-kit - Live Copy Paste for Elementor –
live-copy-paste - Smart Admin Assistant –
smart-admin-assistant
Hyökkäyksen kaksi toimituspolkua
Hyökkäyksessä käytettiin useaa vaihetta ja kahta eri payloadia. Ensisijainen w2.js toimitettiin lisäosille, jotka käyttivät api-data-all-records-endpointia. Toissijainen x.js oli suoraan BdThemesin infrastruktuurissa ja toimitettiin lisäosille, jotka käyttivät api-data-records-endpointia.
Ensisijainen payload: w2.js
w2.js suoritettiin kirjautuneen ylläpitäjän istunnossa. Se eteni seuraavasti:
- Varmisti C2-yhteyden. Skripti lähetti kohdesivuston originin C2-palvelimelle
ia-cdn[.]com/fz/cja pyysi kohdistusohjeita. Jos vastaus oliskiptaidone, skripti keskeytti toimintansa. - Loi väärän ylläpitäjätilin. Skripti käytti aktiivisesta istunnosta löytyvää
X-WP-Nonce-arvoa ja loi ylläpitäjän WordPress REST API:n kautta. Jos se ei onnistunut, skripti käytti tavallisia lomakepyyntöjä. - Asensi webshellin. Skripti latasi C2-palvelimelta väärennetyn lisäosan ZIP-paketin ja asensi sen WordPressin normaalin lisäosan latauslomakkeen kautta. Lisäosa naamioitiin esimerkiksi slugilla
wp-smart-thumbnailstai muulla neutraalin kuuloisella slugilla. Paketissa oli URL-osoitteella suoraan kutsuttavaemer-run.php-webshell. - Asensi MU-lisäosien takaportit.
emer-run.phpasensi kaksi pysyvyyttä ylläpitävää moduulia Must-Use plugins -hakemistoon. Tutkituissa näytteissä kummankin aikaleima oli muutettu syyskuuhun 2025, jotta tiedostot sulautuisivat normaaleihin tiedostojärjestelmäaikaleimoihin. Tiedostonimet voivat vaihtua tartuntojen välillä. Ensimmäinen moduuli mahdollisti todennuksettoman ylläpitäjäkirjautumisen URL-parametrilla?_wplogin=<token>ja kohdisti toiminnon sivuston pisimpään rekisteröityneeseen ylläpitäjään. Toinen moduuli piilotti luodut tilit ylläpidon käyttäjälistasta WordPressin tietokantakyselyihin kytkeytymällä sekä pienensi käyttäjien kokonaismäärää vastaavasti. - Vuoti tulokset. Skripti lähetti suoritusvaiheiden tulokset C2-palvelimelle
navigator.sendBeacon-rajapinnalla.
Toissijainen payload: x.js
x.js laski ylläpitäjätunnuksen ja salasanan kohdesivuston hostname-arvosta. Se muodosti hostnimestä 32-bittisen hashin, muunsi sen base36-muotoon ja otti kuusi ensimmäistä merkkiä. Käyttäjänimi oli bd_ ja kuusimerkkinen hash, kun taas salasana oli Bd@26!, sama hash ja pääte x. Tilille annettiin @wordpress.org-loppuinen sähköpostiosoite.
Tunnukset ovat deterministisiä eli sama hostname tuottaa aina samat tunnukset. Hyökkääjien ei siksi tarvitse ylläpitää keskitettyä listaa murretuista sivustoista. Myös incident response -tiimi voi laskea epäillyn domainin tarkat tunnukset ja etsiä niitä.
// Havainnollistaa tunnusten ennustettavuuden. Älä käytä tätä tuotantokoodissa.
function makeCreds(host) {
let hash = 0;
for (let i = 0; i < host.length; i++) {
hash = ((hash << 5) - hash + host.charCodeAt(i)) | 0;
}
const suffix = Math.abs(hash).toString(36).slice(0, 6);
return { user: "bd_" + suffix, pass: "Bd@26!" + suffix + "x" };
}Skripti haki ensin /wp-admin/user-new.php-sivun, poimi sieltä nonce-arvon ja logout-URL:n, ja lähetti sitten lomakepyynnön uuden käyttäjän luomiseksi administrator-roolilla. Se ilmoitti C2-palvelimelle tilan, käyttäjänimen, salasanan, sivuston originin, logout-URL:n ja nykyisen sivun URL:n. Ilmoitus käytti ensin navigator.sendBeacon-rajapintaa ja tarvittaessa fetch-pyyntöä no-cors-tilassa. Selain tallensi onnistuneen yrityksen merkinnän localStorageen, jos tallennustila oli käytettävissä.
Kompromissin indikaattorit
Tarkista tiedostojärjestelmä, tietokanta ja käyttäjätilit seuraavien indikaattorien varalta. Ulkoiset Sigmative-endpointit olivat puhdistuneet 8.8.2026 mennessä, mutta aiempi sivustokompromissi voi jäädä palvelimelle API-vastausten puhdistamisesta huolimatta.
Ulkoiset palvelut
- Ensisijainen payload:
ia-cdn[.]com/fz/w2.js - C2 beacon -endpoint:
ia-cdn[.]com/fz/c - Myrkytetty API-endpoint, sittemmin puhdistettu:
api[.]sigmative[.]io/prod/store/api/biggopti/api-data-all-records - Myrkytetty API-endpoint, sittemmin puhdistettu:
api[.]sigmative[.]io/prod/store/api/biggopti/api-data-records - Toissijainen payload, sittemmin puhdistettu:
api[.]sigmative[.]io/prod/store/api/biggopti/x.js
Tiedostot, tietokanta ja käyttäjät
- Webshell:
emer-run.php; MD5:1024732009983dd5e54b4cf5593f04d4. - MU-lisäosan magic-login-takaportti:
class-wp-token-validate.php; MD5:7719cd98a35ffad2771f26d1ceab7d27. - MU-lisäosan piiloutumismoduuli:
class-wp-query-9d127ff3.phptai vastaavaclass-wp-query-*.php; MD5:9aadc3e5c5242b273bd17c5bdc358845. - MU-lisäosan health check -moduuli:
wp-cache-optimizer.php; MD5:e450ae5bc4bfc0d960dded06a76bb8e9. - Tietokantaoptio
fz_emer_login_tokens, joka tallentaa magic-login-tokenit. - Tietokantaoptio
fz_emer_done_v1, joka merkitsee kompromissin valmistuneeksi. - Käyttäjätilit, joiden sähköpostiosoite päättyy
@wordpress.orgtai@developer.wordpress.org. - Käyttäjänimet, jotka vastaavat muotoa
bd_ja kuusi aakkosnumeerista merkkiä.
Tarkistuslista epäillylle sivustolle
Aloita tarkistus ennen kuin luotat siihen, että lisäosan poistaminen tai API-vastauksen puhdistuminen ratkaisee tilanteen. Hyökkäys saattoi luoda pysyviä ylläpitäjätunnuksia ja MU-lisäosia, jotka jäävät käyttöön alkuperäisen lisäosan jälkeenkin.
- Selvitä, onko sivustolla nyt tai aiemmin ollut jokin seitsemästä vaikutuksen piirissä olevasta BdThemes-lisäosasta.
- Tarkista WordPressin käyttäjälista ja tietokanta epäilyttävien
bd_-alkuisten tunnusten sekä@wordpress.org– ja@developer.wordpress.org-osoitteiden varalta. Huomaa, että piiloutumismoduuli voi peittää tilit hallintanäkymästä ja muuttaa käyttäjien kokonaismäärää. - Tarkista lisäosahakemisto, Must-Use plugins -hakemisto sekä palvelimen muut tiedostot
emer-run.php-,class-wp-token-validate.php-,class-wp-query-*.php– jawp-cache-optimizer.php-tiedostojen varalta. Vertaile löydösten MD5-tiivisteitä annettuihin arvoihin. - Etsi tietokannan optiotaulusta arvot
fz_emer_login_tokensjafz_emer_done_v1. - Tarkista palvelin-, DNS-, proxy- ja sovelluslokit yhteyksien varalta domaineihin
ia-cdn[.]comjaapi[.]sigmative[.]iosekä edellä lueteltuihin polkuihin. - Vaihda ylläpitäjätilien salasanat ja istunnot, jos löydät indikaattoreita. Tutki sivusto incident response -prosessissa, koska hyökkääjä on voinut saada etäkoodin suoritusmahdollisuuden.
- Ota käyttöön korjattu versio vasta, kun sellainen on saatavilla ja lisäosa on jälleen tarkistettuna saatavilla. Älä oleta tiedostopohjaisen eheystarkistuksen yksin havaitsevan tätä hyökkäystä.
Aikajana
- 1.3.2026: Biggoptin API-JavaScript lisättiin Prime Sliderin versioon 4.1.9 SVN-revisiossa
r3471891.display_idsijoitettiin ilman merkistömuunnostaid-attribuuttiin, ja käytössä oliapi-data-records-endpoint. - 10.5.2026: Endpoint vaihtui muotoon
api-data-all-records.content-kentälle lisättiin DOMParser-puhdistus, muttaid-attribuutti jäi haavoittuvaksi. - 23.6.2026: Myrkytetyn API-kampanjan
start_date-arvo oli Summer Sale -ilmoituksessa. Tämä on aikaisin mahdollinen päivä, jolloin XSS on voinut olla aktiivinen. - 6.8.2026 klo 22.40 UTC: Myrkytetyn
api-data-records-vastauksen Last-Modified-aika. - 7.8.2026 klo 09.11 UTC: Myrkytetyn
api-data-all-records-vastauksen Last-Modified-aika. - 7.8.2026: Hyökkäys havaittiin käytännössä, ja tietoturvatiimi sai ilmoituksen siitä.
- 7.8.2026: Vaikutuksen piirissä olevat lisäosat suljettiin WordPressin lisäosahakemistosta tarkistusta varten.
- 7.8.2026 klo 16.56 UTC: Tutkinnan artefaktit tallennettiin.
- 8.8.2026: Molemmat API-endpointit palauttivat jälleen puhdasta JSON-dataa.
Miksi tämä hyökkäys on poikkeuksellinen?
Hyökkääjät eivät tarvinneet pääsyä yksittäisille WordPress-sivustoille eivätkä muuttaneet lisäosien source codea. He muuttivat toimittajan luotettuna pidetyn etädatan, ja puutteellinen renderöintikoodi teki mainosbannerista haittaohjelman toimituskanavan.
Tiedostopohjainen integrity scanner ei näe hyökkäystä silloin, kun lisäosatiedostot säilyvät muuttumattomina. Myös WAF voi havaita tilanteen heikosti, koska haitallinen JavaScript tulee selaimeen luotetun toimittaja-API:n vastauksena ja toimii jo todennetun ylläpitäjän selaimessa. Hyökkäyksen ensisijainen tavoite oli laajamittainen, huomaamaton ylläpitäjäpysyvyys ja etäkoodin suoritus WordPress-ympäristöissä.
Wordfence Premium-, Care- ja Response-asiakkaat sekä maksullisen Wordfence CLI:n asiakkaat saivat hyökkäyksen tunnistavat haittaohjelmatunnisteet ja WAF-säännöt 7.8.2026. Maksuttomat Wordfence- ja Wordfence CLI -käyttäjät saavat samat tunnisteet ja säännöt normaalin 30 päivän viiveen jälkeen.
Seuraava toimenpide
Tee ensin indikaattoritarkistus kaikille sivustoille, joilla käytät tai olet käyttänyt kyseisiä BdThemes-lisäosia. Jos löydät yksikin epäilyttävän tilin, MU-lisäosan, tietokantaoption tai C2-yhteyden, käsittele sivusto kokonaan kompromettoituneena: eristä se, säilytä lokit ja artefaktit tutkintaa varten sekä poista hyökkääjän pysyvyys ennen palautusta.
Hannah Turing
WordPress-kehittäjä ja tekninen kirjoittaja HelloWP:llä. Autan kehittäjiä rakentamaan parempia verkkosivustoja moderneilla työkaluilla kuten Laravel, Tailwind CSS ja WordPress-ekosysteemi. Intohimona puhdas koodi ja kehittäjäkokemus.
Kaikki julkaisutLisää käyttäjältä Hannah Turing
Joost de Valk vetäytyy FAIR-hankkeesta – mitä se kertoo WordPressin riippuvuuksista ja ohjelmistoketjun turvallisuudesta
WPvivid Backup & Migration -lisäosasta löytyi kriittinen tiedostonlataushaavoittuvuus (CVE-2026-1357): näin tarkistat riskin ja paikkaat oikein
GPT-5.3-Codex: Codex laajenee koodista koko tietokoneen ammattilaisagentiksi