A blind (vak) SQL injectiont hagyományosan úgy szokás felfogni, mint egy bináris keresést az ASCII táblán, vagy annak egy részén. Ennek lépésszáma O(log2 n)-nel arányos, ahol n a teljes ASCII táblát figyelembe véve 255 (a nullbyte nem érdekes), így a logaritmus értéke kb. 8 lesz, azaz átlagosan ennyi kérést kell intéznünk a sebezhető kiszolgálóhoz, hogy egy mező egy karakterét megkapjuk. Persze senki nem szereti felhívni magára a figyelmet, ezért érdemes elgondolkodni azon, hogy hogyan lehetne ezt a számot minál inkább csökkenteni. Stefano Di Paola egy pofonegyszerű ötletet mutat be a blogjában (bár valószínűleg nem ő volt az első, aki ezt a módszert használta, az ötlet tulajdonképpen triviális)
Tegyük fel, hogy van egy sebezhető alkalmazás a victim.com/page.php címen, amely különböző adatbázisban tárolt oldalakat jelenít meg a neki átadott id paramétertől függően. Ez a paraméter természetesen nincs megfelelően szűrve, SQL kéréseket injektálhatunk, a hibajelzések viszont ki vannak kapcsolva, ezért csak arra hagyatkozhatunk, hogy a kérésünk lefutása után melyik oldal (nem) jelenik meg a képernyőn.
A kulcs pedig itt van, ugyanis ha az alkalmazás több oldalt is megjelenít (végülis erre találták ki), akkor összeállíthatunk egy ügyes IF-ELSE szerkezetet melynek injektálásával a vizsgált függvényünk (tipikusan a substr()) visszatérési értékét egyszerre több diszjunkt logikai kifejezéssel is vizsgálhatjuk, melyek mindegyike más és más legitim oldalra irányít minket amennyiben a kifejezés értéke IGAZ:
Hogy ez milyen hatással van a keresőalgoritmus komplexitására? Természetesen a logaritmus alapja növekszik meg annyira, ahány különböző oldalt tudunk a kimenetre varázsolni! log2(255) helyett tehát logP(255) lesz az algoritmus átlagos lépésszáma, ahol P a megjeleníthető oldalak száma, a függvénygörbénk tehát egyre laposabb lesz. Néhány számadat, összehasonlításképpen:
log2(255)=7,99 -> hagyományos bináris keresés
log5(255)=3,4
log10(255)=2,4
log255(255)=1 -> optimum :)
Öt megjeleníthető oldal esetén tehát a szükséges kérések száma kb. felére csökken. Ne szemeteljük tehát tele a logokat, ha nem muszáj, drágák a bitek ;)
Tegyük fel, hogy van egy sebezhető alkalmazás a victim.com/page.php címen, amely különböző adatbázisban tárolt oldalakat jelenít meg a neki átadott id paramétertől függően. Ez a paraméter természetesen nincs megfelelően szűrve, SQL kéréseket injektálhatunk, a hibajelzések viszont ki vannak kapcsolva, ezért csak arra hagyatkozhatunk, hogy a kérésünk lefutása után melyik oldal (nem) jelenik meg a képernyőn.
A kulcs pedig itt van, ugyanis ha az alkalmazás több oldalt is megjelenít (végülis erre találták ki), akkor összeállíthatunk egy ügyes IF-ELSE szerkezetet melynek injektálásával a vizsgált függvényünk (tipikusan a substr()) visszatérési értékét egyszerre több diszjunkt logikai kifejezéssel is vizsgálhatjuk, melyek mindegyike más és más legitim oldalra irányít minket amennyiben a kifejezés értéke IGAZ:
res=substr(<field>,pos,1);
if(res>191 and res<255)
then 1
else if(res>127 and res<192)
then 2
else if(res>63 and res<128)
then 3
else
4
Hogy ez milyen hatással van a keresőalgoritmus komplexitására? Természetesen a logaritmus alapja növekszik meg annyira, ahány különböző oldalt tudunk a kimenetre varázsolni! log2(255) helyett tehát logP(255) lesz az algoritmus átlagos lépésszáma, ahol P a megjeleníthető oldalak száma, a függvénygörbénk tehát egyre laposabb lesz. Néhány számadat, összehasonlításképpen:
log2(255)=7,99 -> hagyományos bináris keresés
log5(255)=3,4
log10(255)=2,4
log255(255)=1 -> optimum :)
Öt megjeleníthető oldal esetén tehát a szükséges kérések száma kb. felére csökken. Ne szemeteljük tehát tele a logokat, ha nem muszáj, drágák a bitek ;)
_2501 2007.11.27. 11:58:57
Nem rossz, tetszett a dolog, inspiráló.
Teljes blind injektből több értéket visszahozni az injekten belül már ninjutsu. :)
Olyan esetben mint a fenti példa, jó megoldás lehet az if szerkezet, de feltétele hogy több érték legyen kiválasztható.
Amennyiben erre nincs lehetőség arra lenne egy alternatív javaslatom.
Bár a cím az hogy gyorsabb injekt, ez most ne zavarjon, (ha már engem sem zavar :P) csak egy alternatív lehetőséget mondok.
A kulcsszó a válaszidő.
Az sql kérést úgy kraftolom fel hogy a válaszidőből lehessen következtetni az értékre.
konkrétan:
mysql> select CASE 1 when 1 then sleep(1) when 2 then sleep(2) else '...' END;
1 row in set (1.00 sec)
mysql> select CASE 2 when 1 then sleep(1) when 2 then sleep(2) else '...' END;
1 row in set (2.01 sec)
Nem pastoltam be a teljes outputot, nem az a lényeg.
Ha egy webes alkalmazásnak küldesz be egy ilyet, akkor a kiszolgálás válaszideje a query futásának idejétől is függ, és ha ezt az időt nézed akkor tudsz következtetni egy egy értékre.
Jobb eset ha az oldalon megjelenik valahol h mennyi ideig futott a query.
Nagy terhelésű szervereken a terheltség függvényében ingadozhat a válaszidő szal nem 100%-os módszer.
Csak egy lehetőség.
Vélemény?
buherator · http://buhera.blog.hu 2007.11.27. 12:12:20