Stack Overflow
tip
Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE)
Apprenez et pratiquez le hacking Azure :
HackTricks Training Azure Red Team Expert (AzRTE)
Soutenir HackTricks
- Vérifiez les plans d'abonnement !
- Rejoignez le 💬 groupe Discord ou le groupe telegram ou suivez-nous sur Twitter 🐦 @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépôts github.
Qu'est-ce qu'un débordement de pile
Un débordement de pile est une vulnérabilité qui se produit lorsqu'un programme écrit plus de données dans la pile que ce qui lui est alloué pour les contenir. Ces données excédentaires vont écraser l'espace mémoire adjacent, entraînant la corruption de données valides, une perturbation du flux de contrôle, et potentiellement l'exécution de code malveillant. Ce problème survient souvent en raison de l'utilisation de fonctions non sécurisées qui ne vérifient pas les limites des entrées.
Le principal problème de cet écrasement est que le pointeur d'instruction sauvegardé (EIP/RIP) et le pointeur de base sauvegardé (EBP/RBP) pour revenir à la fonction précédente sont stockés sur la pile. Par conséquent, un attaquant pourra écraser ceux-ci et contrôler le flux d'exécution du programme.
La vulnérabilité survient généralement parce qu'une fonction copie dans la pile plus d'octets que la quantité qui lui est allouée, permettant ainsi d'écraser d'autres parties de la pile.
Certaines fonctions courantes vulnérables à cela sont : strcpy
, strcat
, sprintf
, gets
... De plus, des fonctions comme fgets
, read
& memcpy
qui prennent un argument de longueur, peuvent être utilisées de manière vulnérable si la longueur spécifiée est supérieure à celle allouée.
Par exemple, les fonctions suivantes pourraient être vulnérables :
void vulnerable() {
char buffer[128];
printf("Enter some text: ");
gets(buffer); // This is where the vulnerability lies
printf("You entered: %s\n", buffer);
}
Trouver les offsets des débordements de pile
La façon la plus courante de trouver des débordements de pile est de donner une très grande entrée de A
s (par exemple, python3 -c 'print("A"*1000)'
) et de s'attendre à un Segmentation Fault
indiquant que l'adresse 0x41414141
a été tentée d'être accédée.
De plus, une fois que vous avez trouvé qu'il y a une vulnérabilité de débordement de pile, vous devrez trouver l'offset jusqu'à ce qu'il soit possible de surcharger l'adresse de retour, pour cela, on utilise généralement une séquence de De Bruijn. Qui pour un alphabet donné de taille k et des sous-séquences de longueur n est une séquence cyclique dans laquelle chaque sous-séquence possible de longueur n apparaît exactement une fois en tant que sous-séquence contiguë.
De cette façon, au lieu de devoir déterminer manuellement quel offset est nécessaire pour contrôler l'EIP, il est possible d'utiliser comme remplissage l'une de ces séquences et ensuite de trouver l'offset des octets qui ont fini par la surcharger.
Il est possible d'utiliser pwntools pour cela :
from pwn import *
# Generate a De Bruijn sequence of length 1000 with an alphabet size of 256 (byte values)
pattern = cyclic(1000)
# This is an example value that you'd have found in the EIP/IP register upon crash
eip_value = p32(0x6161616c)
offset = cyclic_find(eip_value) # Finds the offset of the sequence in the De Bruijn pattern
print(f"The offset is: {offset}")
ou GEF :
#Patterns
pattern create 200 #Generate length 200 pattern
pattern search "avaaawaa" #Search for the offset of that substring
pattern search $rsp #Search the offset given the content of $rsp
Exploiter les débordements de pile
Lors d'un débordement (en supposant que la taille du débordement soit suffisamment grande), vous pourrez écraser les valeurs des variables locales à l'intérieur de la pile jusqu'à atteindre le EBP/RBP et EIP/RIP sauvegardés (ou même plus).
La manière la plus courante d'abuser de ce type de vulnérabilité est de modifier l'adresse de retour afin que lorsque la fonction se termine, le flux de contrôle soit redirigé là où l'utilisateur a spécifié dans ce pointeur.
Cependant, dans d'autres scénarios, il se peut que l'écrasement de certaines valeurs de variables dans la pile soit suffisant pour l'exploitation (comme dans des défis CTF faciles).
Ret2win
Dans ce type de défis CTF, il y a une fonction à l'intérieur du binaire qui n'est jamais appelée et que vous devez appeler pour gagner. Pour ces défis, vous devez simplement trouver l'offset pour écraser l'adresse de retour et trouver l'adresse de la fonction à appeler (généralement ASLR serait désactivé) afin que lorsque la fonction vulnérable retourne, la fonction cachée soit appelée :
{{#ref}} ret2win/ {{#endref}}
Shellcode de pile
Dans ce scénario, l'attaquant pourrait placer un shellcode dans la pile et abuser de l'EIP/RIP contrôlé pour sauter au shellcode et exécuter du code arbitraire :
{{#ref}} stack-shellcode/ {{#endref}}
Techniques ROP & Ret2...
Cette technique est le cadre fondamental pour contourner la principale protection de la technique précédente : Pile non exécutable (NX). Et elle permet d'exécuter plusieurs autres techniques (ret2lib, ret2syscall...) qui finiront par exécuter des commandes arbitraires en abusant des instructions existantes dans le binaire :
{{#ref}} ../rop-return-oriented-programing/ {{#endref}}
Débordements de tas
Un débordement ne se produira pas toujours dans la pile, il pourrait également se produire dans le tas, par exemple :
{{#ref}} ../libc-heap/heap-overflow.md {{#endref}}
Types de protections
Il existe plusieurs protections essayant de prévenir l'exploitation des vulnérabilités, consultez-les dans :
{{#ref}} ../common-binary-protections-and-bypasses/ {{#endref}}
Exemple du monde réel : CVE-2025-40596 (SonicWall SMA100)
Une bonne démonstration de pourquoi sscanf
ne devrait jamais être considéré comme fiable pour analyser des entrées non fiables est apparue en 2025 dans l'appareil SSL-VPN SMA100 de SonicWall. La routine vulnérable à l'intérieur de /usr/src/EasyAccess/bin/httpd
tente d'extraire la version et le point de terminaison de toute URI qui commence par /__api__/
:
char version[3];
char endpoint[0x800] = {0};
/* simplified proto-type */
sscanf(uri, "%*[^/]/%2s/%s", version, endpoint);
- La première conversion (
%2s
) stocke en toute sécurité deux octets dansversion
(par exemple,"v1"
). - La deuxième conversion (
%s
) n'a pas de spécificateur de longueur, doncsscanf
continuera à copier jusqu'au premier octet NUL. - Parce que
endpoint
est situé sur la pile et mesure 0x800 octets, fournir un chemin plus long que 0x800 octets corrompt tout ce qui se trouve après le tampon ‑ y compris le stack canary et l'adresse de retour sauvegardée.
Une preuve de concept en une seule ligne suffit pour déclencher le crash avant l'authentification :
import requests, warnings
warnings.filterwarnings('ignore')
url = "https://TARGET/__api__/v1/" + "A"*3000
requests.get(url, verify=False)
Bien que les canaris de pile abortent le processus, un attaquant obtient toujours un Denial-of-Service primitif (et, avec des fuites d'informations supplémentaires, éventuellement une exécution de code). La leçon est simple :
- Toujours fournir une largeur de champ maximale (par exemple,
%511s
). - Préférer des alternatives plus sûres telles que
snprintf
/strncpy_s
.
Références
tip
Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE)
Apprenez et pratiquez le hacking Azure :
HackTricks Training Azure Red Team Expert (AzRTE)
Soutenir HackTricks
- Vérifiez les plans d'abonnement !
- Rejoignez le 💬 groupe Discord ou le groupe telegram ou suivez-nous sur Twitter 🐦 @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépôts github.