Hurá, Nette už má první záznam v CVE! To znamená, že v něm byla objevena první vážná zranitelnost. Co se vlastně stalo?
Na konci prázdnin mi napsal vývojář Cyku Hong z malebného Taiwanu, že našel v Nette zranitelnost a v následujícím e-mailu vysvětlil princip možného zneužití. Ověřil jsem, že jde o uskutečnitelný útok. Dovoluje útočníkovi za určitých okolností na některých webech pomocí speciálně sestaveného URL spustit kód, tedy jde o zranitelnost Remote code execution (RCE). Cyku, díky!
Musím říct, že to bylo v 13leté historii frameworku Nette vlastně
poprvé, co někdo našel takto závažnou zranitelnost. Dříve byly
několikrát reportovány drobné záležitosti, např. letos v březnu Jan
Gocník odhalil možnou zranitelnost v případě, že by programátor
deserializoval a vypsal query proměnnou
echo unserialize($_GET['a'])
, což je samo o sobě principiálně
velmi nebezpečné, nicméně jeho nález jsem samozřejmě opravil. Také jsem
dostal řadu hlášení, které nebyly opodstatněné, například že
uploadovaný obrázek vyhovující testu isImage()
může v sobě
obsahovat PHP kód. Což samozřejmě může, například v metadatech, ale
není to bezpečnostní problém Nette.
Ale zpět k chybě, o které je tento článek. Bezprostředně po
nahlášení jsem ji opravil a vydal nové verze balíčků
nette/application
a nette/nette
.
Nejstarší zasaženou verzí bylo Nette 2.0, které už sice není 6 let udržované, ale protože Nette má bezpečnost jako jednu z priorit, vydal jsem nové verze také u všech nepodporovaných verzí. Což je ve světě opensource frameworků ojedinělý krok. Díky tomu mohou uživatelé snadno a bez prodlení aktualizovat nejen projekty udržované a běžící na současných verzích, ale i projekty s technologickým dluhem. Vlastně se teď dá říci, že každá řada Nette je nejen Long-Term Support Release (tedy podporovaná alespoň dva roky, viz tabulka), ale z pohledu bezpečnostních fixů i Forever-Term Supported 🙂
Druhým krokem bylo o chybě informovat. Samotné zveřejnění chyby na blogu by i bez podrobného popisu zneužití představovalo vodítko pro darebáky, kteří by se o chybě dozvěděli a mohli se pokusit ji zneužít. Proto mi připadalo fér nejprve informovat všechny podporovatele Nette, poté i další uživatele na které mám kontakt a teprve s určitým časovým odstupem publikovat oznámení veřejně na blogu, GitHubu a katalogu CVE. Prostě dát partnerům určitý čas zaktualizovat všechny weby dříve, než by se objevil první útočník. Původně jsem zamýšlel dát odstup týden, ale pak jsem na základě diskusí pochopil, že to je doslova šibeniční termín a vhodnější je dát alespoň 2–4 týdny.
Jak už jsem zmiňoval, šlo o mou první zkušenost s takovou situací, ale chtěl jsem ji zvládnout příkladně. Abych se nedopustil žádného přešlapu, napsat jsem Michalu Špačkovi, kterého považuji za nejlepšího odborníka v této oblasti, a všechno s ním konzultoval. Michal mi schválil postup, dal řadu užitečných rad, připomínkoval emaily atd. Michale, moc děkuji!
Ačkoliv žádný z mnou provozovaných webů nebyl tímto způsobem zranitelný, prohledal jsem jejich access logy za posledních 8 let (co díra existuje) a zjistil, že tento typ útoku na ně historicky nikdo nezkusil. Soudím, že na zranitelnost nikdo dříve nepřišel. Útočníci totiž obvykle zkouší testovat také přímo web nette.org.
Nechci zveřejňovat přesný postup zneužití chyby a doufám, že to ani nikdo jiný neudělá. Alespoň ne v dohledné době, protože by tím způsobil ostatním nepříjemnosti a zpronevěřil se duchu open source.
Aktualizujte prosím co nejdříve na nejnovější setinkové verze:
- nette/application 3.0.6 (případně 3.0.2.1, 3.1.0-RC2 nebo dev)
- nette/application 2.4.16
- nette/application 2.3.14
- nette/application 2.2.10
- nette/nette 2.1.13
- nette/nette 2.0.19
Nejrychlejší oprava
Michal připravil Linuxový skript a já obdobu v PHP, který automaticky aplikuje patch přímo do zdrojových kódů Nette na disku. Hodí se v případě, že udržujete velké množství projektů, které nemáte čas korektně aktualizovat pomocí Composeru.
Informaci o chybě rozeslal emailem svým klientům VSHosting, WEDOS nebo HostingBB, zároveň některé hostingy přímo blogují problematickou URL, případně rovnou aplikovaly výše uvedený fix. Díky!!!
Komentáře
sucho #1
Ja som v poslednej dobe sledoval celkom podivné logy
samozrejme veľa bolo takých ako by sa skúšal niekto dostať do Wordpresu a teda samé wp-admin
ale potom bolo pomerne dosť URL s podivnými [zatvorkovými] parametrami
potom sa mi aj na FTP začali objavovať divné index.php súbori a potom nejaké s úplne divným názvom a obsahom
a po konzultácii s hostingom sme zistili že bol to útok
taktiež som to vyhľadal cez access.log konkrétnu IP a dané POST requesty a celé FTP som premazal
čo bolo horšie na tom jednom hostingu som mal 12 projektov a bolo to vo všetkých ale v Nette som mal len ten jeden hlavný ostatné boli Wordpress a OpenCart …a teda neviem odkiaľ tie súbory vznikli či práve cez Nette alebo skôr dieru v inom projekte
David Grudl #2
#1 sucho, tyhle logy, co popisuješ, jsou zcela běžné už drahně let, jde o automatizované útoky na Wordpress a další populární projekty. (Nemusí vůbec na webu běžet.)
Když je v katalogu CVE vyhledáš, zjistíš, že těch bezpečnostních chyb mají opravdu hodně a je nutné je všechny pravidelně aktualizovat.
Další věc je, že se běžně kradou FTP přístupy, ať už „po cestě“, pokud nepoužíváš šifrované spojení, nebo se vykrádají různé Total Commandery a podobně, kde jsou spojení uložená včetně hesel. Darebáci se pak připojují přímo na FTP a modifikují soubory nebo nahrávají nějaké další, obvykle právě index.php.
Lukáš #3
Budou prosím aktualizované verze k dispozici ke stažení jako zip v archivu starších verzí ?
David Grudl #4
#3 Lukáši, doplnil jsem je
Lukáš #5
#4 Davide Grudle, Děkuji
Vláďa #6
Dá se předpokládat, že tento exploit funguje to i na pre-release 2.0?
Používám tuto úžasnou verzi Nette:
version 2.0-dev released on 2011–10–12
Marek #7
Davide to s tím isImage jsem reportoval já a absolutně s tebou nesouhlasím. Pokud metoda isImage kontroluje pouze hlavičku co příjde od klienta je to špatně, porgramátor volá v kodu pak isImage a spoléha na fakt ze nette isImage osetri správně a ehle nem ono tam může být PHP kod jen klient NETTE řekl je to JPG/PNG/GIF a pak to projde touto validací, tedy vlastně je to metoda k ničemu. Kdybys mi odpověděl tenkrát na email mohli jsme o tom vést diskuzi, tak jí můžem vést tady i s ostatnimi navíc Michal Špaček na některých přednáškách říká ze ošetrovat na zakladě hlaviček je chybně, když se dají podvrhnout. Mimochodem díky této chybě jsem hacknul nespočet webů postavený na nette.
Michal Špaček #8
#7 Marku, Když už jsem i v komentářích… 🙂 Pokud metoda isImage kontroluje pouze hlavičku co příjde od klienta:
FileUpload::isImage()
se kouká na typ souboru, do samotného souboru, ne do HTTP hlaviček. A dělá to tak aspoň 10 let, to je udělané správně. Browser musí poslat soubor s GIF hlavičkou, aby Nette mohlo říct, že to je GIF, co o souboru tvrdí klient je nepodstatné.Andrej #9
Byl záměr, že v Nette 3 je to ošetřeno vyhozením Nette\InvalidStateException a ve starších verzích Application\BadRequestException? Proč?
Vít Sikora #10
Bylo by prosím možné zveřejnit nějaký closed-source nástroj, kde člověk zadá URL adresu a nástroj zkontroluje, zda je projekt zranitelný? Máme mnoho starých nette projektů, kde se např. používá jen malá část frameworku (staženého, ne přes composer, v2.0) a bylo by nákladné to opravovat. Hlavně bych chtěl zjistit, zda je to vůbec napadnutelné.
Andrej #11
#10 Víte Sikoro, Access log mám zaprasenej requestama z https://www.salamek.cz/nette-test.php
Michal Špaček #12
#6 Vláďo, Ano, dá se více než úspěšně předpokládat, že „version 2.0-dev released on 2011–10–12“ je také zranitelná.
David Grudl #13
#6 Vláďo, nemám archiv těchto verzí, ale můžeš ji fixnout tak, že smažeš soubor MicroPresenter.php, pokud tam je. Ale bál bych se, že v deset let staré nestable verzi budou onačejší problémy.
#7 Marku, můžeš mi napsat do emailu postup jak tímto způsobem hackuješ web na nette?
#9 Andreji, v další verzi nette/application to bude zpátky BadRequestException
#10 Víte Sikoro, v takové situaci, kdy nepoužíváš composer, můžeš použít automatizovaný nástroj napsaný v php nebo shellu
Miloš #14
Aktualizujte, útoky na tenhle exploit už běžej od blackhatů. Nahráli nám na server nějaké části wordpressu ale asi se jim nepodařilo útok zprovoznit, index ale házel 500 na chybějících součástech.
#stary-odkaz-#stary-odkaz-https://www.abuseipdb.com/check/188.165.211.206
Salamek #15
#12 Michale Špačku, To je tool na kontrolu zda li je web děravý, nějaký white hat jej volá z Python crawleru a parsuje mailto z vulnerable webu kam posila emaily s infem o nutnosti aktualizace… více info na https://www.abclinuxu.cz/…testing-tool
#10 Vít Sikora Viz ^
Michal Špaček #16
#15 Salamku, Zatracený off-by-one chyby, to asi měla být reakce na #11 Andrej 🙂
Jan Nový #17
Tato zranitelnost může způsobit kompromitaci vaší databáze aniž by jste si toho vůbec museli všimnout. I když vám web funguje normálně mohl si útočník odnést kompletní databázi, privátní klíče a jiná data uložená mimo veřejně dostupný adresář aplikace. Po aktualizaci si zkontrolujte access log.
Martin Pištora #18
Pokud hostingy problematickou URL přímo blogují, tak se mohla zveřejnit i zde. Spíše by ji měly blokovat.
Marek #19
#13 Davide Grudle, Já když zpětně po sobě četl co jsem ti psal, tak to nebylo dobře napsané. Popis a i uvažování proč si to myslím jsem ti hodil na email. Samozřejmě pokud stále vyhodnotíš, že za to nemůže samotné nette, ale bud PHP finfo_file či programátor co to chybně používá, tak by to v tom případě v nette být nemělo ať si validaci na image dělá programátor sám, ale když jí tam máš, měla by skutečně zvalidovat IMAGE nikoliv, že přes tu validaci projde i PHP které půjde pustit, pak je chybně napsaná právě ta validace. Vše máš v emailu.
antijouda #20
Tak jsem alespoň zjistil, že mi na webu chyběla složka nette.
David Grudl #21
#19 Marku, shrnu ten email pro zdejší čtenáře: poukazuješ na problém způsobený tím, že programátor uloží do veřejného adresáře uploadovaný soubor pod názvem podstrčeným útočníkem. Např. obrázek uloží pod názvem
image.php
a pak jej lze pochopitelně spustit na serveru.To samozřejmě je fatální chyba. Ale programátora, nikoliv validátoru obrázku.
<?=
. A jde o zcela platné obrázky.Co by se dalo udělat z pohledu Nette? V docce i phpDoc je řečeno, že názvu od klienta se nesmí důvěřovat. Asi by byl dobrý nápad přejmenovat metodu
getName()
nagetUntrustedName()
apod. Ale validátor obrázků je imho uplně ok.antijouda #22
#20 antijoudo,
ou, tak už mi na web nahráli nějaký servershell.php, 16.10.
Tento článek byl uzavřen. Už není možné k němu přidávat komentáře.