<summary><strong>Erlernen Sie AWS-Hacking von Grund auf mit</strong><ahref="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
* 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)!
* **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 senden.
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.
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.
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**:
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)
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.
**`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.
**`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**.\
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.
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.
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).
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.
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.
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.
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->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.
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).
**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**
**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 += 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**
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.
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”.
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().
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.
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.
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.
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)
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.
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
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.
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.
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.
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
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).
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.
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).
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 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.
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:
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 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.
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)
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.
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.
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 <MINSIZEist.
Zum Beispiel muss die Größe auf 1552 gesetzt werden, damit 1552 - 1544 = 8 <MINSIZE(dieSubtraktionkannnichtnegativsein,daeinunsigned-Wertverglichenwird)
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.
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.
<summary><strong>Erlernen Sie AWS-Hacking von Grund auf mit</strong><ahref="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
* 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)!
* **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.