{"id":251,"date":"2026-08-09T10:46:15","date_gmt":"2026-08-09T08:46:15","guid":{"rendered":"https:\/\/helloblog.io\/hr\/bdthemes-api-napad-xss-kompromitacija-wordpressa\/"},"modified":"2026-08-09T10:46:15","modified_gmt":"2026-08-09T08:46:15","slug":"bdthemes-api-napad-xss-kompromitacija-wordpressa","status":"publish","type":"post","link":"https:\/\/helloblog.io\/hr\/bdthemes-api-napad-xss-kompromitacija-wordpressa\/","title":{"rendered":"BdThemes API napad: XSS u banneru kompromitirao je WordPress administratore"},"content":{"rendered":"\n<p>Napada\u010di su kompromitirali opskrbni lanac dodataka tvrtke BdThemes bez izmjene ijedne datoteke u slu\u017ebenom WordPress.org repozitoriju. Umjesto toga, izmijenili su udaljeni JSON odgovor koji dodaci dohva\u0107aju za promotivne obavijesti u administraciji, a XSS propust pretvorili su u potpuno preuzimanje WordPress stranice.<\/p>\n\n\n\n<p>WordPress Plugins tim privremeno je zatvorio sve pogo\u0111ene dodatke dok traje pregled i istraga. Ako ih imate na stranici, nemojte se zadr\u017eati samo na a\u017euriranju: pregledajte korisnike, direktorije dodataka i tablicu opcija u bazi podataka.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">\u0160to je pogo\u0111eno i za\u0161to ovo nije obi\u010dan napad na dodatak<\/h2>\n\n\n\n<p>Pogo\u0111eni dodaci koriste internu komponentu <em>Biggopti<\/em>. Ona na svakom u\u010ditavanju administracije dohva\u0107a promotivne bannere s API-ja dobavlja\u010da i prikazuje ih u WordPress nadzornoj plo\u010di. API ne pokre\u0107e aplikacijski poslu\u017eitelj, nego poslu\u017euje stati\u010dne JSON datoteke iz DigitalOcean Spaces bucketa za\u0161ti\u0107enog Cloudflareom.<\/p>\n\n\n\n<p>Napada\u010di su o\u010dito dobili pravo pisanja u taj bucket ili pristup infrastrukturi BdThemesa. Zamijenili su legitimne JSON odgovore posebno oblikovanim sadr\u017eajem. Zato \u017ertva nije morala instalirati novu verziju dodatka, a datoteke dodatka na hostingu ostale su nepromijenjene: napad se izvr\u0161avao isklju\u010divo preko API odgovora, \u0161to ga \u010dini te\u0161ko vidljivim alatima koji provjeravaju integritet datoteka i uglavnom neupadljivim za web aplikacijske vatrozide.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Pogo\u0111eni dodaci<\/h3>\n\n\n\n<p>Ranjivost zahva\u0107a biblioteku Biggopti u razli\u010ditim verzijama. Ima CVSS ocjenu <strong>5,4 (srednja razina)<\/strong> i u trenutku incidenta nije postojala zakrpa.<\/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\">XSS u polju <code>display_id<\/code> izvr\u0161avao se svakom administratoru<\/h2>\n\n\n\n<p>Svaki BdThemes dodatak koji koristi Biggopti na hooku <code>admin_init<\/code> dodaje JavaScript u preglednik. Skripta se zato bezuvjetno izvr\u0161ava pri svakom u\u010ditavanju bilo koje stranice unutar <code>wp-admin<\/code> su\u010delja, dohva\u0107a podatke bannera i sastavlja HTML obavijest u DOM-u.<\/p>\n\n\n\n<p>Problem je nastao jer kod uzima <code>display_id<\/code> iz udaljenog JSON-a i bez izlaznog escapinga spaja ga u HTML atribut <code>id<\/code>. Dovoljno je da napada\u010d zatvori navodnik u vrijednosti atributa kako bi umetnuo vlastiti HTML atribut i JavaScript doga\u0111aj.<\/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>\/\/ Neescapirana vrijednost iz udaljenog JSON odgovora\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\">\/\/ Neescapirana vrijednost iz udaljenog JSON odgovora<\/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>U istom se kodu <code>data-display-id<\/code> ispravno escapira funkcijom koja mijenja <code>&amp;<\/code>, <code>&lt;<\/code>, <code>&gt;<\/code>, i <code>&quot;<\/code> u HTML entitete. To pokazuje da se autor koda pobrinuo za jedan atribut, ali ne i za <code>id<\/code>; struktura funkcije upu\u0107uje na minificirani ili bundlani kod.<\/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 escapeAttribute(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\"> escapeAttribute<\/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>Neescapirani unos uveden je 1. o\u017eujka 2026. u Prime Slider 4.1.9, u SVN reviziji <code>r3471891<\/code>, a zatim je prenesen u druge dodatke. Kasnija izdanja dodala su sanitizer temeljen na <code>DOMParser<\/code>u za polje sadr\u017eaja bannera, koji uklanja opasne HTML oznake i inline handlere, ali <code>id<\/code> atribut ostao je ranjiv.<\/p>\n\n\n\n<p>Zlonamjerni <code>display_id<\/code> iz kompromitiranog odgovora prekida atribut <code>id<\/code> te dodaje <code>onanimationstart<\/code>. CSS animacija aktivira taj handler za pribli\u017eno 10 milisekundi, bez vidljive interakcije, \u010dim prijavljeni administrator otvori bilo koju stranicu nadzorne plo\u010de. Uo\u010deni odgovor sadr\u017eavao je niz <code>SAFE&quot; onanimationstart=eval(String.fromCharCode(...)) style=animation:wrapperSlideInTop .01s ease-out both<\/code>, koji je dekodirao i dohva\u0107ao vanjsku skriptu.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Dva payload puta vode do trajne kompromitacije<\/h2>\n\n\n\n<p>Umetnuti event handler bira vanjske skripte prema dostupnosti infrastrukture napada\u010da. Primarni <code>w2.js<\/code> dolazio je dodatcima koji koriste endpoint <code>api-data-all-records<\/code>, dok je alternativni <code>x.js<\/code> bio izravno smje\u0161ten u infrastrukturi BdThemesa i poslu\u017eivao se dodacima s endpointom <code>api-data-records<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Primarni payload <code>w2.js<\/code><\/h3>\n\n\n\n<p>Kad se <code>w2.js<\/code> pokrene u sesiji prijavljenog administratora, prvo kontaktira C2 endpoint <code>ia-cdn[.]com\/fz\/c<\/code> i \u0161alje origin \u017ertvine stranice. Ako C2 vrati status <code>skip<\/code> ili <code>done<\/code>, skripta prekida rad; ina\u010de prima upute za ciljanje.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n\n<li>Iskori\u0161tava <code>X-WP-Nonce<\/code> iz aktivne administratorske sesije i preko WordPress REST API-ja stvara novog administratora. Ako taj put ne uspije, poku\u0161ava poslati standardni administratorski obrazac.<\/li>\n\n\n<li>S C2 poslu\u017eitelja preuzima ZIP koji se predstavlja kao dodatak te ga instalira kroz standardni obrazac za prijenos dodataka. La\u017eni dodatak koristi slug <code>wp-smart-thumbnails<\/code> ili sli\u010dan neutralan naziv, a sadr\u017ei webshell <code>emer-run.php<\/code> koji se poziva izravno URL-om.<\/li>\n\n\n<li>Poziv <code>emer-run.php<\/code> instalira dva modula za trajnost u direktorij Must-Use dodataka. U oba prona\u0111ena uzorka vremenske oznake vra\u0107ene su na rujan 2025. kako bi se uklopile me\u0111u legitimne datoteke; nazivi se mogu razlikovati me\u0111u infekcijama.<\/li>\n\n\n<li>Prvi MU dodatak daje magic-login backdoor: neprijavljeni napada\u010d mo\u017ee administratorski pristupiti najdulje registriranom administratoru stranice preko parametra <code>?_wplogin=&lt;token&gt;<\/code>.<\/li>\n\n\n<li>Drugi MU dodatak skriva novostvorene la\u017ene ra\u010dune: hooka upite WordPressove baze, uklanja ra\u010dune s administrativnog popisa korisnika i odgovaraju\u0107e smanjuje ukupan broj korisnika.<\/li>\n\n\n<li>Skripta \u0161alje rezultate svake faze na C2 preko <code>navigator.sendBeacon<\/code>.<\/li>\n\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\">Alternativni payload <code>x.js<\/code><\/h3>\n\n\n\n<p><code>x.js<\/code> ra\u010duna administratorske vjerodajnice iz hostnamea \u017ertvine stranice. Algoritam prolazi kroz znakove hostnamea, gradi 32-bitni hash, uzima apsolutnu vrijednost, pretvara je u base36 i zadr\u017eava prvih \u0161est znakova. Time dobiva korisni\u010dko ime oblika <code>bd_<\/code> + \u0161esteroznakovni hash te lozinku <code>Bd@26!<\/code> + hash + <code>x<\/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>function makeCreds(host) {\n  var hash = 0;\n  for (var i = 0; i &lt; host.length; i++) {\n    hash = ((hash &lt;&lt; 5) - hash + host.charCodeAt(i)) | 0;\n  }\n  var n = Math.abs(hash).toString(36).slice(0, 6);\n  return {\n    user: &quot;bd_&quot; + n,\n    pass: &quot;Bd@26!&quot; + n + &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 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 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\">  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\"> n,<\/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\"> n <\/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>Payload novom ra\u010dunu dodjeljuje adresu <code>@wordpress.org<\/code>, dohva\u0107a obrazac <code>\/wp-admin\/user-new.php<\/code>, iz njega izvla\u010di nonce i URL za odjavu te POST zahtjevom izra\u0111uje administratora. Rezultat, korisni\u010dko ime, lozinku, origin, URL stranice i URL za odjavu \u0161alje C2-u preko <code>sendBeacon<\/code>; ako to ne uspije, koristi <code>fetch<\/code> s <code>no-cors<\/code>, <code>keepalive<\/code> i bez vjerodajnica. U preglednikov <code>localStorage<\/code> sprema zastavicu dovr\u0161etka kad je dostupan.<\/p>\n\n\n\n<p>Vjerodajnice su deterministi\u010dke pa napada\u010di ne moraju centralno \u010duvati popis kompromitiranih stranica. S druge strane, incident response tim mo\u017ee za sumnjivu domenu izra\u010dunati to\u010dan ra\u010dun i lozinku koje treba tra\u017eiti.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Indikatori kompromitacije<\/h2>\n\n\n\n<p>Pregledajte poslu\u017eitelj i bazu prema sljede\u0107im indikatorima. Pogo\u0111eni API endpointi u me\u0111uvremenu vra\u0107aju \u010disti JSON, ali to ne uklanja ve\u0107 stvorene ra\u010dune, webshellove i MU backdoorove.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Mre\u017eni indikatori<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n\n<li>Primarni 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>Kompromitirani API endpoint, sada o\u010di\u0161\u0107en: <code>api[.]sigmative[.]io\/prod\/store\/api\/biggopti\/api-data-all-records<\/code><\/li>\n\n\n<li>Kompromitirani API endpoint, sada o\u010di\u0161\u0107en: <code>api[.]sigmative[.]io\/prod\/store\/api\/biggopti\/api-data-records<\/code><\/li>\n\n\n<li>Alternativni payload na infrastrukturi dobavlja\u010da: <code>api[.]sigmative[.]io\/prod\/store\/api\/biggopti\/x.js<\/code><\/li>\n\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Datoteke, opcije i ra\u010duni<\/h3>\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>MU magic-login backdoor <code>class-wp-token-validate.php<\/code>, MD5: <code>7719cd98a35ffad2771f26d1ceab7d27<\/code>.<\/li>\n\n\n<li>MU stealth modul <code>class-wp-query-9d127ff3.php<\/code> ili sli\u010dan naziv prema obrascu <code>class-wp-query-*.php<\/code>, MD5 poznatog uzorka: <code>9aadc3e5c5242b273bd17c5bdc358845<\/code>.<\/li>\n\n\n<li>MU modul koji se predstavlja kao health check, <code>wp-cache-optimizer.php<\/code>, MD5: <code>e450ae5bc4bfc0d960dded06a76bb8e9<\/code>.<\/li>\n\n\n<li>Opcija baze <code>fz_emer_login_tokens<\/code>, koja \u010duva magic-login tokene.<\/li>\n\n\n<li>Opcija baze <code>fz_emer_done_v1<\/code>, koja ozna\u010dava dovr\u0161enu kompromitaciju.<\/li>\n\n\n<li>Ra\u010duni s e-adresom na domeni <code>@wordpress.org<\/code> ili <code>@developer.wordpress.org<\/code>.<\/li>\n\n\n<li>Korisni\u010dka imena koja odgovaraju obrascu <code>bd_<\/code> iza kojeg slijedi \u0161est alfanumeri\u010dkih znakova.<\/li>\n\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Kronologija incidenta<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n\n<li><strong>1. o\u017eujka 2026.<\/strong> \u2013 Biggopti API JavaScript dodan je u Prime Slider 4.1.9 (SVN <code>r3471891<\/code>). <code>display_id<\/code> ulazi neescapiran u <code>id<\/code> atribut, a koristi se endpoint <code>api-data-records<\/code>.<\/li>\n\n\n<li><strong>10. svibnja 2026.<\/strong> \u2013 endpoint se mijenja u <code>api-data-all-records<\/code>. Dodan je <code>DOMParser<\/code> sanitizer za polje sadr\u017eaja, ali <code>id<\/code> atribut ostaje neescapiran.<\/li>\n\n\n<li><strong>23. lipnja 2026.<\/strong> \u2013 <code>start_date<\/code> kampanje u kompromitiranom API-ju nosi promotivnu obavijest \u201eSummer Sale\u201d. To je najraniji mogu\u0107i datum aktivnog XSS-a.<\/li>\n\n\n<li><strong>6. kolovoza 2026. u 22:40 UTC<\/strong> \u2013 posljednja izmjena kompromitiranog <code>api-data-records<\/code> odgovora.<\/li>\n\n\n<li><strong>7. kolovoza 2026. u 09:11 UTC<\/strong> \u2013 posljednja izmjena kompromitiranog <code>api-data-all-records<\/code> odgovora.<\/li>\n\n\n<li><strong>7. kolovoza 2026.<\/strong> \u2013 napad je uo\u010den u stvarnim napadima i prijavljen sigurnosnom timu; WordPress direktorij zatvara dodatke do pregleda.<\/li>\n\n\n<li><strong>7. kolovoza 2026. u 16:56 UTC<\/strong> \u2013 prikupljeni su artefakti istrage.<\/li>\n\n\n<li><strong>8. kolovoza 2026.<\/strong> \u2013 oba API endpointa vra\u0107aju \u010disti JSON.<\/li>\n\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">\u0160to trebate u\u010diniti odmah<\/h2>\n\n\n\n<p>Ako va\u0161a stranica koristi bilo koji navedeni BdThemes dodatak, pretpostavite da je administrator mo\u017eda u\u010ditao kompromitiranu administracijsku stranicu izme\u0111u najranijeg mogu\u0107eg datuma napada i \u010di\u0161\u0107enja API-ja. Pregledajte popis korisnika, osobito ra\u010dune <code>bd_******<\/code> i e-adrese s navedenih domena, zatim provjerite direktorije standardnih i Must-Use dodataka za navedene datoteke te pretra\u017eite tablicu opcija za <code>fz_emer_login_tokens<\/code> i <code>fz_emer_done_v1<\/code>.<\/p>\n\n\n\n<p>Samo uklanjanje dodatka ili provjera izmjena u datotekama nije dovoljna jer je napad stvarao administratore i trajne backdoorove bez izmjene postoje\u0107ih datoteka dodatka. Uklonite prona\u0111ene indikatore, opozovite sumnjive administratorske ra\u010dune i provjerite cijelu instalaciju prije nego \u0161to joj ponovno povjerite produkcijski promet.<\/p>\n\n\n\n<p>Wordfence Premium, Care, Response i pla\u0107eni korisnici Wordfence CLI-ja dobili su potpise zlonamjernog softvera i WAF pravila za ovaj incident 7. kolovoza 2026. Besplatni korisnici Wordfencea i besplatnog Wordfence CLI-ja dobit \u0107e iste potpise i pravila nakon uobi\u010dajenog odgode od 30 dana.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Zaklju\u010dak<\/h2>\n\n\n\n<p>Ovaj incident pokazuje da pouzdana udaljena promotivna poruka mo\u017ee postati vektor napada jednako opasan kao kompromitirano izdanje dodatka. Obranu zato ne smijete graditi samo na provjeri promjena u WordPress datotekama: kod koji renderira udaljeni sadr\u017eaj mora escapirati svaki kontekst, a incident response mora obuhvatiti ra\u010dune, bazu, MU dodatke, mre\u017ene zahtjeve i mehanizme trajnosti.<\/p>\n\n\n<div class=\"references-section\">\n                <h2>Reference \/ Izvori<\/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>Napada\u010di nisu morali izmijeniti nijednu datoteku dodatka: kompromitirani JSON banner u `wp-admin` su\u010delju bio je dovoljan da stvore skrivene administratore i instaliraju backdoorove.<\/p>\n","protected":false},"author":42,"featured_media":250,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[9],"tags":[137,33,136,10,125],"class_list":["post-251","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-sigurnost","tag-bdthemes","tag-sigurnost","tag-supply-chain","tag-wordpress","tag-xss"],"_links":{"self":[{"href":"https:\/\/helloblog.io\/hr\/wp-json\/wp\/v2\/posts\/251","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/helloblog.io\/hr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/helloblog.io\/hr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/helloblog.io\/hr\/wp-json\/wp\/v2\/users\/42"}],"replies":[{"embeddable":true,"href":"https:\/\/helloblog.io\/hr\/wp-json\/wp\/v2\/comments?post=251"}],"version-history":[{"count":0,"href":"https:\/\/helloblog.io\/hr\/wp-json\/wp\/v2\/posts\/251\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/helloblog.io\/hr\/wp-json\/wp\/v2\/media\/250"}],"wp:attachment":[{"href":"https:\/\/helloblog.io\/hr\/wp-json\/wp\/v2\/media?parent=251"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/helloblog.io\/hr\/wp-json\/wp\/v2\/categories?post=251"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/helloblog.io\/hr\/wp-json\/wp\/v2\/tags?post=251"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}