Verständnisfragen: Exploits schreiben

#1
Hi Leute,
gestern Nacht habe ich ein altes, aber gutes Tutorial gefunden und es direkt versucht umzusetzen, was dann nach ein paar Stunden auch geklappt hat.
Es handelt sich dabei um dieses Tutorial: Exploit writing tutorial part 1 : Stack Based Overflows | Corelan Team

Dazu musste ich natürlich erstmal Windows XP in Virtual Box aufsetzen und Easy RM to Mp3 Conversion Utility, einen Perl Interpreter und das Debugprogramm Windbg darauf installieren.
(Metasploit habe ich ausgelassen, da es für das Verständnis nicht wichtig ist und die Ergebnisse aus dem Tutorial übernommen werden können)
Das hatte auch alles geklappt: Ich konnte Easy RM .. mit einem ersten Perl Skript zum Absturz bringen und mit einem weiteren Perl Skript, die Inhalte von EIP, EBP und ESP so belegen,dass es in weiteren Schritten möglich werden sollte, einen Shellcode in ESP zu legen und in EIP eine instruction die dann dorthin springt.
Anhand einer DLL Datei hat man dann einen opcode für "jmp esp" gefunden und einen Shellcode erzeugt, der "CALC" ausführt, also den Windows Taschenrechner startet.

Soviel zur Vorgeschichte, bei mir tun sich jetzt einige Fragen auf:

> Das Tutorial ist ja nun schon fast 9 Jahre alt. Läuft das heute noch genau so ab?
1. Bug überprüfen, "stürzt das Programm wirklich ab wenn man eine Datei öffnet die 30.000 A's enthält"? (mir ist schon bewusst dass es nicht nur um Dateien öffnen geht, es könnte auch einen nicht begrenzte Passwortlänge oder ähnliches sein..)
2. Durch Skripte Dateien erstellen und daran herumspielen, bis man im Debugger sieht, dass man EIP und ESP passend belegt hat.
3. opcode für jmp esp herausfinden - Muss man das eigentlich jedes mal aufs neue oder kann man immer den selben benutzen?
4. Shellcode erzeugen, der in den esp passt und sozusagen den Sinn des Exploits bezweckt.

> Macht man die meisten Tätigkeiten um das Exploitschreiben "drumherum" heutzutage in Metasploit?
Im Tutorial wurden z.B. so spezielle Muster durch das Tool "pattern_create.rb" erstellt, mit denen man exakt herausfinden konnte, wann der Pufferüberlauf beginnt.
Anscheinend sind in Metasploit schon viele vorgefertigte Exploits drin. Wenn die Frage mit "ja" beantwortet werden sollte,
würde das für mich heißen, dass sich eine Einarbeitung in Metasploit für Hacker (und solche die es werden wollen) schon lohnen würde.

> Informieren sich Exploitwriter auf Seiten wie https://www.exploit-db.com/ über die neuesten Exploits und bauen dann dazu passende, wenn sie genügend Informationen dazu haben?
Manche werden sich wohl auch Zero Days im Dark Net oder so kaufen?

> Welche Debugger benutzt ihr dafür aktuell in Windows und in Linux?

Sorry für die eventuell dummen Fragen und den recht langen Text :)
 
Zuletzt bearbeitet:
#3
> Das Tutorial ist ja nun schon fast 9 Jahre alt. Läuft das heute noch genau so ab?
Grundsätzlich ja. Allerdings werden auch die Stackschutz-Mechanismen immer weiter entwickelt, die man natürlich zusätzlich umgehen muss.

> Macht man die meisten Tätigkeiten um das Exploitschreiben "drumherum" heutzutage in Metasploit?
Metasploit spart einem halt ziemlich viel Zeit.

> Informieren sich Exploitwriter auf Seiten wie https://www.exploit-db.com/ über die neuesten Exploits und bauen dann dazu passende, wenn sie genügend Informationen dazu haben?
Dort werden halt fertige Exploits veröffentlicht, die man sowohl als Pentester als auch zur Integration in Botnetze etc. nutzen kann. Die Leute, die Exploits schreiben, schauen dort eher, ob es bereits passende Exploits zu den Lücken gibt, die sie gerade bearbeiten, damit sie sich die Arbeit nicht doppelt machen müssen.

> Welche Debugger benutzt ihr dafür aktuell in Windows und in Linux?
Linux: GDB
 
#4
Metasploit spart einem halt ziemlich viel Zeit
Das macht Sinn. In Part 2 des Tutorials habe ich jetzt auch etwas mit Metasploit herumgespielt und die Shellcodes selbst in der msfconsole erstellen lassen.
Ich habe gesehen dass du einen Artikel im HaBo-Wiki zu Shellcodes verfasst hast: Shellcode (Exploit) – HaBo WiKi

Sind selbstgeschriebene Shellcodes sicherer vor der Antivirenprogramm-Detektion als von Metasploit erstellte?
Es erscheint mir sehr aufwendig zu sein selbst Shellcodes zu schreiben, deswegen frage ich mich was der Vorteil daran ist.
Mit "payload/windows/exec" kann man doch einen Shellcode erzeugen, der quasi jedes ausführbare Programm auf einer Windows Plattform startet.
Oder verstehe ich das falsch?


Das freut mich, ich bin e GNU bzw. MinGW Fan :)
 
#5
Der Artikel dient dazu ein grundlegendes Verständnis dafür zu vermitteln, wie Shellcodes generell funktionieren, wie sie erstellt werden und wie man sie lesen kann. Es macht für die Funktionalität kaum einen Unterschied ob man einen Generator verwendet, Shellcodes von PacketStormSecurity o.ä. nutzt oder sie from scratch selbst erstellt.
 
#6
Ok klar, es ist immer besser wenn man auch genau weiß was man tut :)

Auf https://www.offensive-security.com/metasploit-unleashed/generating-payloads/ habe ich halt gelesen gehabt, dass die mehrfache Anwendung eines "shellcode encoders" bzw. die nacheinander abfolgende Anwendung verschiedener encoder die Detektionsrate verringern soll. Daher kam ich auf den Gedankengang dass selbstgeschriebene dort eventuell überlegen sind.

Was hat es in Shellcodes eigentlich mit diesen "bad charachters" auf sich?
Das man keinen Nullpointer benutzen darf, kann ich aufgrund von Erfahrungen mit Strings in C und C++, nachvollziehen, was sind denn andere typische bad charachters, die man in einem Shellcode vermeiden will und warum?

Konnte diesbezüglich leider nichts befriedigend stellendes finden.
 

CDW

Moderator
Mitarbeiter
#7
Was hat es in Shellcodes eigentlich mit diesen "bad charachters" auf sich?
Das man keinen Nullpointer benutzen darf, kann ich aufgrund von Erfahrungen mit Strings in C und C++, nachvollziehen, was sind denn andere typische bad charachters, die man in einem Shellcode vermeiden will und warum?
Kommt auf die Eingabemethode an - wird da [in der Zielanwendung] z.B zeilenweise eingelesen, so sind Zeilenumbrüche, Linefeeds (\n\r) 0x0A,0x0D, Formfeeds xFF die "bad characters". Wird die Eingabe noch zusätzlich irgendwie bearbeitet, so sollten z.B keine Escape-sequenzen "\<foo>" vorkommen.
 
#8
Zusätzlich zur Eingabemethode kommt es auch auf die Schutzmechanismen des angegriffenen Systems an. So können zum Beispiel angehängte NOPs relativ leicht durch ein IDS identifiziert werden. Sie sind aber manchmal notwendig, wenn man eine bestimmte Speichermenge mit seinem Shellcode füllen muss. In dem Fall muss man dann auf 2-Byte-NOPs zurückgreifen. Der einfache NOP (0x90) wäre damit ein "bad character". Eine Left-to-Right-Markierung kann ggf. auch einen "Fehler" an das System signalisieren, wenn das laufende Programm ausschliesslich Right-to-Left-Input erlaubt. usw.

Die Frage, was ein bad character ist, hängt also davon ab, wie das Programm arbeitet, das man exploitet und was das System dahinter von dem Programm erwartet bzw. wie weit das System den Programmablauf überwacht.
 
#9
CypherL0rd hat gesagt.:
Das Tutorial ist ja nun schon fast 9 Jahre alt. Läuft das heute noch genau so ab?
bitmuncher hat gesagt.:
Grundsätzlich ja. Allerdings werden auch die Stackschutz-Mechanismen immer weiter entwickelt, die man natürlich zusätzlich umgehen muss.
Also das Exploit führt den injecteten Shellcode ja aus, indem die Rücksprungadresse des Stackframes mit einer Adresse überschrieben wird, die die Instruktion "jmp esp" referenziert. Im Fall des Tutorials liegt diese Adresse dann ja in einer Dll des Betriebssystems, bei welcher sich die Baseaddress offensichtlich nicht ändert. Ich glaube nicht dass das bei modernen Schutzmechanismen noch funktioniert.

1. ASLR wird heutzutage sicherlich auch die Adressen der System-Dlls randomisieren. Einfach mal so die Rücksprungadresse mit einer fixen Adresse überschreiben sollte da nicht funktionieren.
2. Stack Cookies beschützen die Rücksprungadresse, sodass ein Überschreiben der Rücksprungadresse automatisch detektiert wird.
3. Moderne Prozessoren verfügen über die Möglichkeit schon hardwareseitig das Ausführen bestimmter Speicherabschnitte explizit zu verbieten. Auf diese Weise wird eigentlich standardmäßig der Stackspeicherbereich als nicht ausführbar markiert, sodass der Shellcode nicht gestartet werden würde.


Inwiefern diese 3 Schutzmechanismen jetzt bei Windows 10 implementiert sind weiss ich nicht. Aber es gibt sie eigentlich schon recht lange, und das Umgehen ist afaik ziemlich schwierig.

PS: Wenn du Lust hast einfach mal ein paar einfache Exploits aus Spaß selber zu schreiben, kann ich dir so typische Hackingchallenges oder Wargames empfehlen. Auf Overthewire.org kann man sich z.B. per SSH mit nem Server verbinden, bei dem die Schutzmechanismen deaktiviert sind.
 
Zuletzt bearbeitet:
#10
Hey Leute :)

Ok, also es kommt darauf an als was der Shellcode im Programm interpretiert wird, damit das bugbehaftete Programm den Shellcode nicht zerschießt.

Zum Versuch habe ich gerade mal ein fehlerhaftes Programm geschrieben, zumindest halte ich es für fehlerhaft??
(es wird ja nicht überprüft ob die Stringgröße von 10 Byte überschritten wurde, bevor auf diese Variable wieder zugegriffen wird bzw. bevor sie im Stack abgelegt wird)

Code:
Code:
#include "string.h"
#include "stdio.h"

int main() {
    printf("hi dude, please enter your password: ");
    char password[10] = { 0 };
    scanf("%s", password);
    printf("dude, your password is: %s \n", password);
    return 0;
}
Wenn ich euch richtig verstanden habe, dann wären bad charachters in diesem Fall nun z.B. alle (oder zumindest einige) Escape-Sequenzen, richtig?

Der Shellcode, die "jmp esp"-Adresse und die ganzen Platzfüller zuvor (z.B. 10 x A) werden jetzt in der Form eines Strings im Stack des Programms abgelegt.

Von daher sind bad characters hier: (ich gehe mal davon aus dass es diese Escape Sequenzen auch in Shellcode-Form gibt)

- '\n'
- '\0'
- '\t'
- '\r'
- '\f'
- zu viele NOP's bei modernen Instrusion Detection Systemen

Was wäre denn ein anderer Pufferfehler, der nichts mit Strings oder Char-Arrays und co. zu tun hat?

@@night@ Das klingt jetzt so als ob Pufferüberläufe bzw. dessen Ausnutzung bald der Vergangenheit angehören werden?

Zumindest selbstgeschriebene, auf solchen Exploitdatenbanken findet sich ja vielleicht noch was für aktuelle Plattformen, aber das interessiert mich nicht.
Ich betreibe das ja nur zum Spaß und zum Lernen.

Chrom hat da vorhin so ne Andeutung gemacht: hinkt Linux Windows in diesen Stack-Schutzmechanismen noch hinterher?
 
Zuletzt bearbeitet:

SchwarzeBeere

Moderator
Mitarbeiter
#11
Das, was du machst, ist inzwischen über 20 Jahre alt und funktioniert auf keinem der heutigen, aktuellen Systeme (was nicht heißt, dass es nur solche Systeme „da draußen“ gibt ;)) noch in der Art und Weise. Sprich, es gibt inzwischen zahlreiche Mittel und Wege, Stack Overflows zu verhindern, von Memory Access Controls (DEP, W^X, ...), Memory und Control Flow Integrity Checks (Canaries, Cookies, ...) oder die Nutzung von Zufall im Speichermanagement, um z.B. Sprungadressen bei Return-to-Libc nicht mehr vorhersagbar zu machen (z.B. ASLR). Dazu gibt es Schutzmechanismen in allen möglichen Sprachen, von Compiler-Warnings, Sprachkonstrukten (z.B. strcpy_s statt strcpy), Typsicherheit/Tagging, usw.

Moderne Angriffe nutzen z.B. das sog. Return-oriented Programming. Return-to-Libc ist eine einfache Variante davon. Hierbei baust du dir deinen Payload kurz gesagt aus Codefragmenten („Gadgets“) zusammen, die bereits im Speicher liegen und deren Speicheradressen du kennst oder vorhersagen kannst. Aber auch hier gibt es einigen Gegenmaßnahmen, z.B. Fine-grained ASLR oder Forward Simulation. Es gibt (gab?) auch Lösungen von Drittanbietern, z.B. Immunix (ehem. StackGuard...)

Microsoft EMET zeigt dir afaik an, welche Mechanismen unter Windows für welche Binaries aktiv sind. Einfach mal ausprobieren ;)

Wichtig ist, dass du verstehst, wie Bufferoverflows funktionieren, d.h. warum z.B. eine \0 im Payload verboten ist (nämlich weil sie einen String, der ja wiederum nur ein Array von Chars ist, terminiert). Wenn das mal geklappt hat, dann kannst du dir auch darüber Gedanken machen, wie der Payload verbessert werden kann, wo er gespeichert werden kann, oder wie du am besten reinspringst.
 
Zuletzt bearbeitet:
#12
Hallo SchwarzeBeere, lange nichts mehr voneinander gehört :)

Das mit den Nullpointern war mir bereits klar, danke.
Wenn ich das jetzt richtig verstehe kann man Shellcodes quasi nur in Strings (char Arrays) ablegen?
Oder kann man auch die Adresse auf die ein pointer zeigt, der eigentlich für ein int Array ausgelegt ist, mit einem Shellcode bepflanzen?
Sorry aber da hängt mein Kopf gerade noch fest.
Vielleicht sollte ich das einfach mal auf Win XP ohne SP's ausprobieren. :)

Das sind zwar alles schon alte Techniken aber irgendwo muss ich ja mal anfangen.
Bei mir an der Uni wird leider kein Hackerpraktikum angeboten.

Die von dir genannten modernen Exploittechniken sagen mir alle leider noch nichts.
Aber falls es einigermaßen realistisch ist sich da als Normalsterblicher einzuarbeiten, dann wird es mir in den nächsten Jahren hoffentlich gelingen.
 
Zuletzt bearbeitet:
#13
Ich werfe nur mal eben eine Spielwiese ein ;)
OverTheWire: Natas


Ein Pointer zeigt auf eine Speicherstelle. In diese Speicherstelle kannst du beliebigen Kram schreiben. Der Datentyp sagt nur, wie dieser Kram zu interpretieren ist. Ein Int wandelt also die 01 Abfolge in eine Zahl, ein Char entsprechend in einen Character. Die Datentypen legen auch fest, wie weit gelesen wird, ab dem Pointer.

Also gar nicht so schwer ;)
 
Zuletzt bearbeitet:
#14
Shalec hat gesagt.:
Ich werfe nur mal eben eine Spielwiese ein ;) OverTheWire: Natas
Ich glaube du meintest Narnia :wink:

cypherl0rd hat gesagt.:
Wenn ich das jetzt richtig verstehe kann man Shellcodes quasi nur in Strings (char Arrays) ablegen?
Oder kann man auch die Adresse auf die ein pointer zeigt, der eigentlich für ein int Array ausgelegt ist, mit einem Shellcode bepflanzen?
Sorry aber da hängt mein Kopf gerade noch fest.
Ja, das ist am Anfang etwas verwirrend. Wichtig ist, dass du verstehst wie Stackframes aufgebaut sind und wie sie im Speicher liegen. Ich finde das wird im Buch "Hacking: The Art of Exploitation" von Jon Erickson sehr gut erklärt, vielleicht gibts das ja in eurer Uni-Bibliothek.
Zu deiner Frage: Das kommt auf das Programm drauf an. Die Crux beim BufferOverflow ist ja, dass man durch einen Programmierfehler die Möglichkeit hat Teile des Stackframes (insbesondere die Rücksprungadresse) zu überschreiben. Üblicherweise kann sowas halt durch ein einfaches strcpy passieren, bei der die Länge des Buffers auf dem Stack nicht berücksichtigt wird. Wenn der Programmierer allerdings falsch auf einen Integer auf dem Stack zugreift, könnte man natürlich auch darüber die Rücksprungadresse evtl. überschreiben. Ich wüsste jetzt nur nicht, wann sowas passieren sollte.

Den Shellcode kannst du im Speicher eigentlich platzieren wie du möchtest, solange du eine Möglichkeit findest ihn irgendwie auszuführen (das Ausführen ist ja die eigentliche Schwierigkeit). In dem angesprochenen Tutorial wird der Shellcode halt im selben Buffer platziert, der auch verwundbar für den Overflow ist. Man kann den Shellcode aber auch in den Umgebungsvariablen platzieren (geht bei Remote-Exploits natürlich dann meist nicht).
Letztendlich muss man halt nur ne Möglichkeit finden den Programmfluss irgendwie auf den Shellcode zu lenken.
 

Chromatin

Moderator
Mitarbeiter
#16
Wenn ich das jetzt richtig verstehe kann man Shellcodes quasi nur in Strings (char Arrays) ablegen?
Oder kann man auch die Adresse auf die ein pointer zeigt, der eigentlich für ein int Array ausgelegt ist, mit einem Shellcode bepflanzen?
Sorry aber da hängt mein Kopf gerade noch fest.
Die Darstellung von Shellcode in Hex ist lediglich Konvention. Die Darstellung (für uns Menschen) von Maschinencode passiert immer Byteweise - deswegen bietet sich ein Char Array an.

Grundsätzlich: Für die Maschine ist es erstmal egal, wie das, was sie da reinbekommt in der Programmiersprache "genannt" wird (abgesehen von sonstigem Code/Exceptions, welcher ggf. arithmetische no-gos abfängt).

Ich kann dir noch immer "smashing the stack for fun and profit" empfehlen.
Für OS Internals: "Modern Operating Systems" und "The 4.4BSD Operating System". Das ist zwar im Detail nicht das aktuellste, aber vieles stimmt konzeptionell noch immer.
 
Oben