.. | ||
bf-forked-stack-canaries.md | ||
print-stack-canary.md | ||
README.md |
Stack Canaries
{% hint style="success" %}
Apprenez et pratiquez le piratage AWS :Formation HackTricks AWS Red Team Expert (ARTE)
Apprenez et pratiquez le piratage GCP : Formation HackTricks GCP Red Team Expert (GRTE)
Soutenez HackTricks
- Consultez les plans d'abonnement!
- Rejoignez le 💬 groupe Discord ou le groupe Telegram ou suivez-nous sur Twitter 🐦 @hacktricks_live.
- Partagez des astuces de piratage en soumettant des PR aux HackTricks et HackTricks Cloud dépôts GitHub.
StackGuard et StackShield
StackGuard insère une valeur spéciale appelée canary avant le EIP (Extended Instruction Pointer), spécifiquement 0x000aff0d
(représentant null, saut de ligne, EOF, retour chariot) pour se protéger contre les débordements de tampon. Cependant, des fonctions comme recv()
, memcpy()
, read()
, et bcopy()
restent vulnérables, et il ne protège pas l'EBP (Base Pointer).
StackShield adopte une approche plus sophistiquée que StackGuard en maintenant une pile de retour globale, qui stocke toutes les adresses de retour (EIPs). Cette configuration garantit qu'un débordement ne cause aucun dommage, car elle permet de comparer les adresses de retour stockées et réelles pour détecter les occurrences de débordement. De plus, StackShield peut vérifier l'adresse de retour par rapport à une valeur limite pour détecter si l'EIP pointe en dehors de l'espace de données attendu. Cependant, cette protection peut être contournée à l'aide de techniques comme Return-to-libc, ROP (Return-Oriented Programming), ou ret2ret, indiquant que StackShield ne protège pas non plus les variables locales.
Protecteur de débordement de pile (ProPolice) -fstack-protector
:
Ce mécanisme place un canary avant l'EBP, et réorganise les variables locales pour positionner les tampons à des adresses mémoire plus élevées, les empêchant d'écraser d'autres variables. Il copie également de manière sécurisée les arguments passés sur la pile au-dessus des variables locales et utilise ces copies comme arguments. Cependant, il ne protège pas les tableaux avec moins de 8 éléments ou les tampons à l'intérieur d'une structure utilisateur.
Le canary est un nombre aléatoire dérivé de /dev/urandom
ou d'une valeur par défaut de 0xff0a0000
. Il est stocké dans le TLS (Thread Local Storage), permettant aux espaces mémoire partagés entre les threads d'avoir des variables globales ou statiques spécifiques au thread. Ces variables sont initialement copiées du processus parent, et les processus enfants peuvent modifier leurs données sans affecter le parent ou les frères et sœurs. Néanmoins, si un fork()
est utilisé sans créer un nouveau canary, tous les processus (parent et enfants) partagent le même canary, le rendant vulnérable. Sur l'architecture i386, le canary est stocké à gs:0x14
, et sur x86_64, à fs:0x28
.
Cette protection locale identifie les fonctions avec des tampons vulnérables aux attaques et injecte du code au début de ces fonctions pour placer le canary, et à la fin pour vérifier son intégrité.
Lorsqu'un serveur web utilise fork()
, cela permet une attaque par force brute pour deviner le byte du canary octet par octet. Cependant, l'utilisation de execve()
après fork()
écrase l'espace mémoire, annulant l'attaque. vfork()
permet au processus enfant d'exécuter sans duplication jusqu'à ce qu'il tente d'écrire, à ce moment-là une duplication est créée, offrant une approche différente à la création de processus et à la gestion de la mémoire.
Longueurs
Dans les binaires x64
, le cookie canary est un qword de 0x8
octets. Les sept premiers octets sont aléatoires et le dernier octet est un octet nul.
Dans les binaires x86
, le cookie canary est un dword de 0x4
octets. Les trois premiers octets sont aléatoires et le dernier octet est un octet nul.
{% hint style="danger" %} Le byte le moins significatif des deux canaries est un octet nul car il sera le premier dans la pile venant des adresses inférieures et donc les fonctions qui lisent des chaînes s'arrêteront avant de le lire. {% endhint %}
Contournements
Fuite du canary puis écrasement de celui-ci (par exemple, débordement de tampon) avec sa propre valeur.
- Si le canary est forké dans les processus enfants, il pourrait être possible de le forcer par brute-force un octet à la fois :
{% content-ref url="bf-forked-stack-canaries.md" %} bf-forked-stack-canaries.md {% endcontent-ref %}
- S'il y a une fuite intéressante ou une vulnérabilité de lecture arbitraire dans le binaire, il pourrait être possible de laisser fuiter :
{% content-ref url="print-stack-canary.md" %} print-stack-canary.md {% endcontent-ref %}
- Écrasement des pointeurs stockés dans la pile
La pile vulnérable à un débordement de pile pourrait contenir des adresses vers des chaînes ou des fonctions qui peuvent être écrasées pour exploiter la vulnérabilité sans avoir besoin d'atteindre le canary de la pile. Vérifiez :
{% content-ref url="../../stack-overflow/pointer-redirecting.md" %} pointer-redirecting.md {% endcontent-ref %}
- Modification à la fois du canary maître et du canary du thread
Un débordement de tampon dans une fonction threadée protégée par un canary peut être utilisé pour modifier le canary maître du thread. Par conséquent, la mitigation est inutile car la vérification est effectuée avec deux canaries identiques (bien que modifiés).
De plus, un débordement de tampon dans une fonction threadée protégée par un canary pourrait être utilisé pour modifier le canary maître stocké dans le TLS. Cela est possible car il pourrait être possible d'atteindre la position mémoire où le TLS est stocké (et donc, le canary) via un débordement de tampon dans la pile d'un thread.
Par conséquent, la mitigation est inutile car la vérification est effectuée avec deux canaries identiques (bien que modifiés).
Cette attaque est réalisée dans le writeup : http://7rocky.github.io/en/ctf/htb-challenges/pwn/robot-factory/#canaries-and-threads
Consultez également la présentation de https://www.slideshare.net/codeblue_jp/master-canary-forging-by-yuki-koike-code-blue-2015 qui mentionne que généralement le TLS est stocké par mmap
et lorsqu'une pile de thread est créée, elle est également générée par mmap
selon cela, ce qui pourrait permettre le débordement comme indiqué dans le writeup précédent.
- Modifier l'entrée GOT de
__stack_chk_fail
Si le binaire a Partial RELRO, alors vous pouvez utiliser une écriture arbitraire pour modifier l'entrée GOT de __stack_chk_fail
pour être une fonction factice qui ne bloque pas le programme si le canary est modifié.
Cette attaque est réalisée dans le writeup : https://7rocky.github.io/en/ctf/other/securinets-ctf/scrambler/
Références
- https://guyinatuxedo.github.io/7.1-mitigation_canary/index.html
- http://7rocky.github.io/en/ctf/htb-challenges/pwn/robot-factory/#canaries-and-threads
- https://7rocky.github.io/en/ctf/other/securinets-ctf/scrambler/
{% hint style="success" %}
Apprenez et pratiquez le piratage AWS :Formation HackTricks AWS Red Team Expert (ARTE)
Apprenez et pratiquez le piratage GCP : Formation HackTricks GCP Red Team Expert (GRTE)
Soutenez HackTricks
- Consultez les plans d'abonnement!
- Rejoignez le 💬 groupe Discord ou le groupe Telegram ou suivez-nous sur Twitter 🐦 @hacktricks_live.
- Partagez des astuces de piratage en soumettant des PR aux HackTricks et HackTricks Cloud github repos.