Tento článek popisuje případovou studii léčení jednoho napadeného webu na levném hostingu a může posloužit jako rámcový návod, co je třeba prohlédnout, kde hledat škodlivý kód a jak Drupal web “odvšivit”, když máte k dispozici jen FTP přístup.
 
Můj klient byl vlastník webu, kterého firma zajišťující hosting informovala, že jeho web je pravděpodobně napaden a používán pro DDOS útoky, jelikož jejich sytémy detekují velkou frekvenci odchozích spojení, což je pro web nezvyklé.
 
Vyžádal jsem si FTP přístupy a heslo pro administrátora webu s tím, že tato hesla budou bezprostředně po ukončení léčení webu klientem změněna. Domluvili jsme se základních pravidlech důvěry, mlčenlivosti a předpokládané ceny.
 

Kontrola verze Drupalu

Nejprve jsem se přihlásil na web jako Admin a zkontroloval verzi Drupal jádra. Našel jsem verzi 7.53, která je z 7. prosince 2016. Vzhledem k tomu, že od té doby Drupal vydal několik oprav zabezpečení na kritické chyby umožňující spuštění vzdáleného kódu, bylo zřejmé, že web bude obsahovat škodlivý kód a upozornění hostingové společnosti nebude falešný poplach.
 

Škodlivý kód

Jak funguje napadení webu? Útočník využije neopravené zranitelnosti Drupalu k tomu, aby do souborového systému webu nahrál nějaký program, který mu umožňuje získat nad webovým prostorem plnou kontrolu, něco jako otevřená zadní vrátka, kterými může kdykoliv vstoupit, tzv. backdoor.
 
Zde je třeba pochopit, že útočníkovi nejčastěji vůbec nejde o to, aby napadený web zničil, poškodil, či z něj získal nějaká data. Nejčastěji mu jde o to, využít výpočetní výkon serveru ke svým účelům, zejména připravit si poslušného robota do tzv. Botnetu, který společně s dalšími tisíci roboty z napadených webů zaútočí v jeden okamžik na server oběti a zahltí ho požadavky. Případně může využít napadený server k těžbě Bitcoinů, rozesílání spamů, luštění hesel z MD5 otisků apod. Napadený web a útočníkovy programy žijí pokojně vedle sebe a spíš je cílem nechat web nadále fungovat a nevzbudit žádné podezření. 
 

Hledání škodlivého kódu

Škodlivý kód může být schovaný na různých místech. Motivací útočníka je, aby je měl na více místech a pokud možno tak, aby si jich nikdo nevšiml. Hledání napadení probíhá v několika krocích. V prvé řadě se rozhlížím v adresářové struktuře Drupalu a hledám soubory, které tam nepatří.
 
Nejprve jsem se podíval do hlavního adresáře Drupalu a hned jsem viděl soubory, které vypadají na první pohled podezřele, jako např: 4z8fvw0xxl.php, oznnumt360.php, uc583wnl.php, ale i takové s normálním názvem, jako např.: company.php, country.php, stats.php, které však k Drupalu nepatří. Pro ověření, zda se jedná o škodlivý kód, se stačí podívat na obsah souboru. Útočníkův kód bývá nejčastěji generovaný speciálními nástroji a vypadá tak, aby nebylo snadné z kódu zjistit, co daný program dělá. Zde je pár příkladů:
 
 
 
Nákaza je tímto potvrzena. Útočník je schopen nahrávat do prostoru webu vlastní kód, který mu umožňuje procházení adresářové struktury, nahrávání a stahování souborů, přístup k databázi a plno dalších věcí, ke kterým má napadený webserver oprávnění. Spuštěním škodlivého kódu přes web totiž útočník získává stejná práva k souborům, jako má web samotný. Může tedy např. načítat data i z prostoru mimo adresář webu, např. z /etc/passwd, ale také může zapisovat pouze tam, kam může zapisovat web, tedy ve většině případů pouze do prostoru adresáře domény. 
 
Co všechno takový backdoor umí, je pro mnoho neznalých šokujícím překvapením a pokud bude zájem, mohu udělat demonstraci na některém z budoucích Drupal akcí, nebo o tom napíšu další článek.
 
Pro úsporu času lze vynechat další hledání škodlivého kódu v souborech starého jádra Drupalu, protože ty budou přehrány novým Drupalem. Aby byly všechny útočníkovy programy v prostoru Drupal jádra opravdu odstraněny, nestačí soubory přehrát, ale je nutné všechny soubory Drupal jádra smazat (mimo .htaccess z rootu - ten může být pro každý webhosting upravený, proto je nutné si ho schovat do zálohy) a pak na server nahrát poslední verzi Drupal jádra. Vlastně se jedná o všechny soubory ve všech adresářích mimo adresář /sites, ale může se to lišit, protože ne každý web má obrázky v sites/default/files, tak je třeba u toho přemýšlet.
 
Místo, které je dobré pečlivě prohlédnout je adresář /sites/all a také sites/default/files, kde jsou obrázky. Zkušený hacker ví, že jádro umí updatovat skoro každý, tak schovává kód někam, kde soubory zůstávají i po updatu jádra, ale nebývá to pravidlem.
 
V mém případě se přímo v adresáři sites nacházel index.php, který načítal soubor 
modules/help/.20ae99b9.ico
 
Zde je dobré se zastavit a uvědomit si, že útočníkovy soubory se škodlivým kódem nemusejí mít vždy příponu “php”. Soubor typu PHP může vypadat na první pohled neškodně, jako výše uvedený, ale slouží k tomu, aby načetl škodlivý kód ze souboru, kde byste nic škodlivého nečekali, např. soubor s ikonou.
 
Cesta k souboru může být různě zakódovaná, jak např. zde v dalším souboru index.php:
Obě cesty vedou ke stejnému souboru, ale znaky jsou různými způsoby zakódované a rozkódované vypadají takto: /data/web/virtuals/26981/virtual/www/modules/help/.20ae99b9.ico
 
Jelikož modul Help je součástí jádra Drupalu, přijde přehrát a zde je důvod mé poznámky o tom, že je třeba nejprve všechny soubory jádra smazat. Jelikož soubor .20ae99b9.ico je v modulu navíc, v případě pouhého přehrání souborů by zůstal na místě.
 
Abych nemusel ručně kontrolovat všechny moduly, používám modul Hacked!, který porovná obsah všech souborů všech modulů na webu s jejich originály na oficiálním úložišti na Drupal.org. Jeho výstupem je pak report, jaký soubor je kde navíc, změněný, nebo chybí. Ušetří se tím mnoho času. Modul Hacked! mě upozornil na modifikovaný soubor redirect.api.php v modulu Redirect. Z jeho obsahu je vidět, že útočník vložil svůj kód do existujícího korektního souboru. Škodlivý kód je vložený do jedné řádky za několik stovek mezer, takže když soubor soubor otevřete v editoru, nevidíte na první pohled nic divného. Vy ho vidíte v ukázce po smazání mezer.
 
 
Další škodlivý kód se nacházel v souboru sites/all/themes/.work.ppp
 

Obrázky

Zbývalo poslední místo, kde by mohly být nějaké soubory se škodlivým kódem, a to adresář s obrázky. Možná si řeknete, že tam je zbytečné hledat, protože obrázek je obrázek a nemůže nic špatného udělat a soubor typu PHP nepůjde spustit, protože to si Drupal hlídá přes .htaccess. To je sice pravda, ale jak si ukážeme na tomto případu, i kód převlečený za obrázek lze v Drupalu spustit, a to i po přehrátí Drupal jádra novými a zdravými soubory.
 
Mezi obrázky napadeného webu jsem našel dva soubory, které obsahovaly PHP kód. První byl lib.php.suspected:
Podle kódu to byl file uploader (formulář pro nahrávání souborů), ale deaktivovaný patrně zásahem hostingové společnosti, protože původně se jmenoval lib.php a došlo k jeho přejmenování na “suspected - podezřelý”. 
 
Zajímavější soubor byl a.jpg, který vypadal takto:
Zajímavé na něm bylo to, že to nebyl obrázek a to, že nejprve spustil soubor jádra Drupalu session.inc a potom vykonával škodlivý kód. Nebylo mi jasné, jakým způsobem se tento kód spouští, ale měl jsem silné tušení, že vzhledem k volání session.inc se bude vykonávat při každém zobrazení stránky. Soubor jsem smazal a reakce na sebe nenechala dlouho čekat. Web okamžitě přestal fungovat a odměnil mě hláškou:
Warning: require_once(sites/default/files/a.jpg): failed to open stream: No such file or directory ve funkci drupal_bootstrap() (řádek: 2537 v souboru includes/bootstrap.inc).”
 
Bootstrap.inc byl v té době již z poslední verze Drupalu, což ve mně vzbudilo opravdu velkou touhu zjistit, jak je to možné, že zdravý Drupal chce volat nějaký škodlivý kód. Našel jsem si zmíněný kus kódu:
 
case DRUPAL_BOOTSTRAP_SESSION:
  require_once DRUPAL_ROOT . '/' . variable_get('session_inc', 'includes/session.inc');
  drupal_session_initialize();
  break; 
 
Zde Drupal standardně načítá soubor 'includes/session.inc', avšak pouze pokud neexistuje Drupal proměnná s názvem 'session_inc'. Pokud existuje, pak načte kód ze souboru, který je uvedený v této proměnné. V databázi napadeného webu tedy útočník nechal proměnnou 'session_inc', které měla obsah: "sites/default/files/a.jpg", což byl ten způsob, jak načíst PHP kód z obrázku. Tímto způsobem si útočník zajistil, že jeho script se vykoná i po dalších aktualizacích jádra.
 
Bylo potřeba proměnnou smazat. Měl jsem k dispozici pouze FTP a přístup k databázi přes PhpMyAdmin, takže jsem smazal proměnnou jako databázový záznam v tabulce variables. To bohužel nestačilo, protože celý bootstrap proces je Drupalem kešován a aby se změna projevila, bylo třeba smazat keš. Přes administrační rozhraní to nešlo, protože web nefungoval, Drush nebyl k dispozici. Osvědčeným způsobem, jak smazat keš, je vyprázdnit kešovací tabulky v databázi. Pro mé účely stačilo vyprázdnit tabulku cache_bootstrap a web se opět rozjel.
 

Backdoor v databázi

Jak je vidět na výše uvedeném příkladu, jakmile má útočník možnost nahrát na web svůj program, nic mu nebrání získat přístup k databázi, protože přístupy k ní jsou standardně v souboru settings.php. Může tedy získat např. e-mailové adresy všech uživatelů a veškerý obsah webu, včetně např. osobních údajů zákazníků e-shopu s adresami a telefony.
 
V Drupalu lze schovat backdoor přímo do databáze, konkrétně do tabulky menu_router, kam si Drupal ukládá funkce, které má zavolat pokud dostane požadavek na zaobrazení určité stránky. Útočník do některého sloupce určeného pro tzv. callback zapíše PHP funkci, která provede určitý kód, nebo nahraje na server dodaný soubor.
 
Nejrychlejší způsob, jak celou tabulku menu_router zkontrolovat, je provést její export do textového souboru (například přes PhpMyAdmin) a v něm vyhledat výskyty funkcí “eval” a “file_put_content”. Pokud nějaký záznam obsahuje takovou funkci, je třeba záznam z tabulky smazat a vyčistit keš.
 

Poslední kontrola před spuštěním

Pro jistotu jsem ještě nechal ve všech souborech mimo Drupal jádro vyhledat výskyty řetězce “base64_decode”, “create_function” a “eval(”, abych objevil nějaké zapomenuté soubory, které jsem z nějakého důvodu přehlédl nebo je modul Hacked! nedetekoval. Žádné další podezřelé soubory jsem už nenašel, web jsem vyvedl z režimu údržby do ostrého provozu a klientovi jsem po pár hodinách předal web s aktualizovaným jádrem a pokud jsem něco nepřehlédl, tak i bez škodlivého kódu. 
 

Závěr

Jsem přesvědčen, že z tohoto příkladu je možné vzít si několik poučení:
  1. Drupal se vyplatí udržovat aktualizovaný, minimálně reagovat na všechna závažná bezpečnostní oznámení Drupal security týmu a pokud se daný problém týká vašeho Drupalu, co nejdříve aktualizovat a neopomenout ani žádné málo navštěvované weby, protože ty jsou často nejžádanější kořistí útočníka.
  2. Drupal pohání nejenom enterprise weby s hostingy za tisíce s SSH konzolí a Drushem, ale jsou u nás i weby nízkorozpočtových organizací a malých podnikatelů, které jsou hostovány na sdíleném hostingu, kde je k dispozici pouze přístup přes FTP/SFTP. Neměli bychom se na tyto “Drupalisty” vykašlat jen proto, že jsme profíci zvyklí na vysoký komfort drahých hostingů a virtuálních serverů. Každý provozovatel Drupal webu je součástí komunity a jednou může rozhodnout o nákupu drahého webu postaveného právě na Drupalu na základě pozitivních zkušeností.
  3. Občas je dobré se podívat mezi soubory vašeho webu, jestli se tam neobjevily nějaké podezřelé soubory s příponou PHP.
 
Tento článek není a ani nemůže být kompletním manuálem na všechny případy, ale poskytuje konkrétní vodítka a nápady, co dělat, je-li váš web napaden a jak se zbavit většiny nebo veškerého škodlivého kódu. Věřím, že zdatnější uživatelé si mohou tímto způsobem pomoci v nouzi sami.
 
Attribution: Icon Hacker #169076

Komentáře

To samé jsme řešil před cca 5 týdny na jednom vlastním webu – kovářovic kobyla. :(

Ze dne na den mi přibylo necelých 7 miliónů stránek v Google indexu. Naštěstí mě Google Search Console upozornila na vyřazení z vyhledávání, jinak bych to asi nezjistil.

Výsledek je, že po měsíci od opravy už Google vyhodil přes 6 000 000 stránek z indexu a pomalu se vracím na původní pozice v SERPu.

Mám tedy doplnění k tvému článku z vlastní zkušenosti:

  • "protože to si Drupal hlídá přes .htaccess." – v mém případě byl kompletně upravený i obsah .htaccess a robots.txt
  • Hodně mi pomohl GIT, díky tomu bylo lépe vidět co je a co není upravené, kromě samotných souborů ve složce .git!! (takže došlo za pár dní k re-hacku)
  • Určitě bych pro FTP doporučil GIT FTP (https://git-ftp.github.io/), není to tak pohodlné jako plný GIT, ale rozhodně se to vyplatí, nejen v případě hacku.
  • U modulu Hacked! je také nutné přemýšlet, dostal jsem od něj několik false positive reportů.