Blind Injections treffen nicht immer auf Anklang, weil man sich selbst einer umständlichen Feinarbeit ausgesetzt sieht, der lange dauert und nervenaufreibend ist.
Doch gibt es ein paar Kniffe, die die Arbeit erleichtern können.
A) Zeit
„Zeit ist Geld“, das gilt in fast allen Bereichen,
und bei Blind SQL Injections ist dies besonders wichtig,
wenn es darum geht, große Datenmengen zu extrahieren.
Es geht also zunächst darum, für einen Datensatz in der
Datenbank ..
1. Möglichst wenig Zeit aufzuwenden
und
2. Mit möglichst wenigen Requests an Infos gelangen.
Beide Ziele sind selbstverständlich eng miteinander verzahnt,
und so gibt es einige Kriterien, die ihren Teil zum Faktor
„Zeit“ beitragen.
Diese sind beispielsweise:
1. Antwortzeit des Servers
2. Zu Übertragendes Datenvolumen
3. Wertebereich der zu testenden ASCII Zeichen (=> Anzahl Requests)
Ändern lässt sich die Antwortzeit des Servers nicht aktiv,
doch obliegt es unseren Möglichkeiten, die Datenvolumina zu
begrenzen.
Eine triviale Methode an Infos zu gelangen ist die unoptimierte
Content-Change Methode, die nicht unbedingt schlecht ist, doch
erst in optimierter Form zufriedenstellende Leistungen erbringt.
Ein Beispiel wie wir es kennen, wäre:
index.php?id=1+and+if((select+ascii(substr(password,1,1))+from+users+limit+0,1)>100,null,1)=1/*
Da es aber in diesem Falle schwierig sein kann, ein passendes Suchmuster zu finden, setzen wir für
die true Bedingung ein kleines Subquery ein, welches mehere Rows zurückgeben soll.
Da dies in einem Subquery nicht möglich ist, wird sich bei angeschaltetem display_errors
gleich die Fehlermeldung „Subquery returns more than 1 row“ zeigen, und wir haben unser Suchmuster.
Dies hat oft den Vorteil, dass das Skript direkt mit die() abgebrochen wird, und der Fehler schwarz auf weiß
als einziger Content auf der Seite zu finden ist.
Dies ist aber nur manchmal der Fall, und dies vermindert die Ladezeit deutlich.
Ein Beispiel dafür könnte dann so aussehen:
index.php?id=1+and+if((select+ascii(substr(password,1,1))+from+users+limit+0,1)>100,(select+1+union+select+2),1)=1/*
Der Suchstring, sollte nun in den meisten Fällen vorhanden sein, und wenn wir Glück haben,
ist auch der Content der Seite bei „true“ reduziert worden.
Jetzt gilt es selbstverständlich die Anzahl der Requests zu reduzieren.
Eine gängige Methode um die Zeichen zu bestimmen, ist selbstverständlich die,
mit den Operatoren < und > sich den den ASCII Wert des Zeichen hinanzupirschen.
Wie man diese Methode letztendlich umsetzt sei jedem selbst überlassen, doch wäre es nicht ratsam,
alle Zeichen von beispielsweise 48 bis 122 einzeln durchzutesten – wäre auch unsinnig, denn mit
Hilfe der < > Operatoren, ist es sinnvoll, die Abstände immer zu halbieren:
Wenn Zeichen größer 85, teste:
Wenn Zeichen größer 103,5 teste:
etc.
könnte man auch durchaus rekursiv lösen.
Bei sehr großen Wertebereichen, z.b. Inhalte, in denen alle Zeichen
vorkommen dürfen, gibt es aber noch eine weitere Möglichkeit, die nicht immer
zwingend weniger Requests mit sich bringt, auf große Distanzen aber eine große
Absicherung mit sich bringt.
Möchte man den Wertebereich von 32 – 126 prüfen, und unser Zeichen ist zufällig ein
„B“ müssen wir so viele Requests starten, bis wir beim Zeichencode 66 angelangt sind.
Wieviele requests dies bedeutet, hängt von unserem Code ab.
Casten wir die 66 aber zu einer Binärzahl, haben wir eine fixe Anzahl an Zeichen:
1000010
Hier müssen wir zwar 7 Requests starten, doch reicht es hier aus, nur einen Zustand zu testen:
„Ist der Wert nicht 1, dann muss er 0 sein.“
„Ist der Wert nicht 0, dann muss er 1 sein.“
7 Requests bei einem Zeichen, kann eine Verbesserung sein, aber durchaus auch eine Verschlechterung,
dies hängt wie bereits genannt vom Programmierstil ab.
Testen wir es anhand eines fiktiven MD5 Hashes:
3295c76acbf4ca8ed33c36b1b5fc2cb1
Die Zeichen a-f0-9 sind zu testen.
0 -> 110000 9 -> 111001 a -> 1100001 f -> 1100110
Wir sehen, dass die Buchstaben ein Request mehr beanspruchen.
In unserem Hash finden wir zufällig, 16 Buchstaben und 16 Zahlen.
Sofern wir wissen, dass es sich um einen MD5 handelt, und demsptsprechend
die Länge 32 Bytes ist, benötigen wir eine bestimmbare Anzahl an Requests:
(16 * 6) + (16 * 7) = 208
Ob sich dieses Verfahren bei MD5 lohnt, sei dahingestellt, sicherlich ist es
immer sinnvoller, bei größeren Wertebereichen.
B) Ablaufsteuerungsfunktionen
Das schönste Verfahren zur Zeichenbestimmung nützt einem nichts, sofern man
es nicht anwenden kann. Nicht immer trifft man mit der AND Methode auf eine Goldader,
und der Check mit and+1=1 und and+1=0 versagt, obwohl man sich der Existenz der Injection
sicher ist.
Es gibt eine weitere Möglichkeit, auf den richtigen Pfad zu kommen, mit der Kontrollstruktur „case“.
Diese besteht aus dem Fallbeispiel, also die Bedingung, durch „case“ und „when“ gekennzeichnet,
der darauf bei wahrer Aussage folgenden Wirkung „then“ und wahlweise einem „else“ Teil.
Ich stelle nun beide Versionen gegenüber, die im Grunde das gleiche bewirken:
index.php?id=1+and+if(1=1,(select+1+union+select+2),null)=1/*
index.php?id=1+and+case+when+(1=1)+then+(select+1+union+select+2)+else+null+end/*
Dies kann man selbstverständlich kombinieren, mit bereits genannten Verfahren zur Zeichenbestimmung.
——–
Viel Spaß und neue Erkenntnisse wünscht
Lidloses_Auge Quelle: http://www.novusec.com