Celý článek se točí kolem hacknutí jednoho webu, detailně ale zmiňuje i další postupy, které jsem nemusel využít. Využívám pouze chyby, kterých se dopouštění programátoři webových aplikací, takže se nedozvíte, jak obejít firewall, otrávit DNS, ani jak odchytávat zabezpečené připojení a lámat hesla. Začínám SQL injekcí. I pokud víte o co jde, dozvíte se něco nového. Než začnu hledat nezabezpečené vstupy, zjistím si co nejvíc informací. Je dobré projít detaily domény (whois), http hlavičky a další…
SQL injection
Až příliš častý problém při práci s databází je SQL injection – ohnutí uživatelského vstupu tak, aby pozměnil původní SQL příkaz. Dá se příjemně snadno otestovat: stačí vyzkoušet různé varianty uvozovek a klíčových slov na některé uživatelské vstupy. Náchylná stránka se v drtivé většině případů rozbije, protože programátor s chybou v SQL samozřejmě nepočítá. Jestli jsme úspěšní, zjistíme tedy často na první pohled: server pošle jenom část odpovědi (neúplnou/useknutou stránku) nebo se výstup nějak kriticky změní – typicky se mohou načíst články bez omezení, protože se změní LIMIT
, nebo se načtou všechny kategorie/tagy místo vybrané ap.
Můj první cíl bylo pole pro vyhledávání mezi příspěvky. Zkusil jsem zadat jenom apostrof a uvozovky "'
. Po odeslání se mi vrátila escapovaná varianta "'
– téměř jistě známka zapnutých magic quotes.
Jakkoliv se na tuhle dnes zastaralou a z PHP 5.4 úplně odstraněnou vlastnost dívá s despektem, svou roli splňuje výborně. Zatím mi brání vyskočit z SQL příkazu a upravovat ho podle chuti… nebo ne?
Oťukávání vstupů
Jako programátor se můžu zkusit vžít do toho, jak původní autor postupoval při vytváření aplikace: text je jasně v uvozovkách, číslo se přece píše rovnou. Kámen úrazu jsou proměnné. To když si vývojář po proměnou cislo_stranky
nedokáže představit jako text a do SQL ji zapíše takhle:
SELECT * FROM articles LIMIT 50 OFFSET 50 * $_GET['cislo_stranky']
Číselné vstupy jsou různá id, stránkovač, nebo rovnou offset/limit a podobné, rozhodně by neměl být problém nějaký najít a prozkoušet.
Kliknul jsem si tedy na druhou stránku výpisu a v url jsem přidal k číslu ještě '2 OR 1=1'
. To je vstup, který původní SQL příkaz nerozbije, jenom nechá vypsat všechno bez omezení. Tentokrát jsem měl štěstí a našel jsem tady bezpečnostní díru. Kdyby byly všechny vstupy v uvozovkách, musel bych obcházet magic_quotes.
Vícebajtová kódování
Málo známý problém s magic_quotes jsou vícebajtová kódování. Zjednodušeně jde o to, že PHP vyhledává všechny bajty 0x22
(uvozovky), resp. 0x27
(apostrof) a přidává před ně 0x5C
(lomítko). To znamená, že z vstupu 0xKL 0x22
(nějaký bajt a uvozovky) se stane 0xKL 0x5C 0x22
. Běžné ASCII, které má pro každý znak právě jeden bajt, je v bezpečí. Běží-li ale cílový server na kódování s proměnlivou délkou znaků, stačí nám zvolit takový bajt, aby 0xKL 0x5C
byl validní znak. Celkem tedy vzniknou dva znaky: paskvil z našeho bajtu a lomítka od PHP a jedny čisté uvozovky, díky kterým můžeme napsat SQL injekci.
(Zdroj: shiflett.org)
Anonymita
Když si nedáte pozor, skončíte dřív, než jste vůbec začali. V dobrém případě jenom v blacklistu (to pokud je admin úplně matlas), v horším případě si chyby všimne a opraví ji. Samozřejmostí by měla být nějaká spolehlivá proxy (ne, jestli posílá X-Forwarded-For
, není to ideální volba).
Dobrá síť je TOR, možná jsem ale zatím jenom nenašel nic lepšího. Zpátky se k vašemu PC se prakticky nikdo nemůže nedostat. Když nepracujete nad secured http, může si sice první a poslední node přečíst, co vlastně děláte, ale to není riziko, nad kterým bych si osobně lámal hlavu.
U SQL injection je teoreticky dobré se vyvarovat vstupů, které skončí chybou na serveru, protože ty se logují explicitně. Jelikož je ale rychlejší zkusit deset nápadů než jeden složitě promýšlet, radši doufám, že správce se na log nekoukne. A jestli obdrží při každé chybě e-mail, nedostali bychom se moc daleko tak jako tak.
Je obecně dobré vybírat si POST formuláře, protože GET parametry se logují (POST se pochopitelně loguje také, ale jenom adresa, ne parametry). POST navíc nemá omezení na délku požadavku tak tragicky krátké. Na to je dobré myslet při posílání dat na server.
A pochopitelně jestli na sebe nechcete vůbec upozorňovat, posílejte požadavky přiměřeně velikosti serveru a hlavně v rozumnou dobu. Nic nepřekvapí víc než peak v datech Google Analytics kolem dvou hodin v noci. To když jste zrovna pouštěli nějaký testovací skript.
Plán
Už víme, že cílový server je náchylný na SQL injection. Nastává dobrý čas připravit si další postup – seznam čeho a hlavně jak chceme dosáhnout. V tomto případě si chci vypsat z tabulky obsahující uživatele jejich hesla a přihlašovací jména. Na to potřebuji znát, jak přesměrovat původní SELECT
na jinou tabulku a musím také zjistit, jak se vůbec tato tabulka jmenuje. Budu pokračovat tím, že si zjistím typ a verzi databáze, se kterou bojuji. Tou samou databází si přečtu /etc/passwd
a zkusím zapsat php shell. A samozřejmě už dávno budu mít seznam potenciálních uživatelů a jejich hesla.
… ale to až v příštím díle!
Přehled komentářů