Pour éviter les débordements de tampon, plusieurs protections sont disponibles telles que l'utilisation des valeurs Canaries, ASLR, DEP, NX. Mais, là où il y a une volonté, il y a un moyen. Je fais des recherches sur les différentes méthodes qu'un attaquant pourrait éventuellement contourner ces schémas de protection. Il semble qu'il n'y ait pas un seul endroit où des informations claires sont fournies. Ce sont certaines de mes pensées.
Canary - Un attaquant pourrait déterminer la valeur du canari et l'utiliser dans son injection de tampon pour tromper le garde de la pile de détecter un exploit
DEP, NX - S'il y a des appels à VirtualAlloc(), VirtualProtect()
, l'attaquant pourrait essayer de rediriger le code vers ces fonctions et désactiver DEP, NX sur les pages sur lesquelles il souhaite injecter du code arbitraire.
[~ # ~] aslr [~ # ~] - Aucun indice. Comment fonctionnent l'ASLR et le DEP?
Canaries
Les canaris de pile fonctionnent en modifiant les régions de prologue et d'épilogue de chaque fonction pour placer et vérifier une valeur sur la pile respectivement. Ainsi, si un tampon de pile est écrasé lors d'une opération de copie de mémoire, l'erreur est remarquée avant l'exécution revient de la fonction de copie. Lorsque cela se produit, une exception est déclenchée, qui est retransmise dans la hiérarchie du gestionnaire d'exceptions jusqu'à ce qu'elle atteigne finalement le gestionnaire d'exceptions par défaut du système d'exploitation. Si vous pouvez remplacer une structure de gestionnaire d'exceptions existante dans la pile, vous pouvez la faire pointer vers votre propre code. Il s'agit d'un exploit de gestion d'exception structurée (SEH), et il vous permet d'ignorer complètement la vérification des canaris.
DEP/NX
DEP et NX marquent essentiellement les structures importantes de la mémoire comme non exécutables et forcent des exceptions au niveau matériel si vous essayez d'exécuter ces régions de mémoire. Cela fait des débordements de tampon de pile normaux où vous définissez eip
sur esp+offset
et exécutez immédiatement votre shellcode impossible, car la pile n'est pas exécutable. Contourner DEP et NX nécessite une astuce cool appelée Return-Oriented Programming .
ROP consiste essentiellement à rechercher des extraits de code existants dans le programme (appelés gadgets) et à y accéder, de manière à produire le résultat souhaité. Étant donné que le code fait partie de la mémoire exécutable légitime, DEP et NX n'ont pas d'importance. Ces gadgets sont enchaînés ensemble via la pile, qui contient votre charge utile d'exploit. Chaque entrée de la pile correspond à l'adresse du prochain gadget ROP. Chaque gadget se présente sous la forme de instr1; instr2; instr3; ... instrN; ret
, pour que ret
passe à l'adresse suivante de la pile après avoir exécuté les instructions, enchaînant ainsi les gadgets. Souvent, des valeurs supplémentaires doivent être placées sur la pile afin de terminer une chaîne avec succès, en raison d'instructions qui autrement gêneraient.
L'astuce consiste à enchaîner ces ROP afin d'appeler une fonction de protection de la mémoire telle que VirtualProtect
, qui est ensuite utilisée pour rendre la pile exécutable, afin que votre shellcode puisse s'exécuter, via un jmp esp
ou gadget équivalent. Des outils comme mona.py
peut être utilisé pour générer ces chaînes de gadgets ROP, ou trouver des gadgets ROP en général.
[~ # ~] aslr [~ # ~]
Il existe plusieurs façons de contourner l'ASLR:
jmp esp
.Lecture recommandée:
Canaries et autres volatils n'empêchent pas le débordement; ils essaient juste de faire face aux conséquences d'un débordement qui s'est produit . Le canari tente de détecter le cas d'un débordement qui a écrasé l'adresse de retour dans une trame de pile. DEP est un peu plus loin, il suppose que l'adresse de retour a été écrasée et suivie , et elle restreint les zones où l'exécution pourrait sauter. ASLR est encore un peu plus loin: il "mélange" les zones où l'exécution est autorisée.
Historiquement, le buffer déborde où il est exploité pour écraser l'adresse de retour dans la pile, de manière à faire sauter l'exécution dans les données mêmes qui ont été utilisées pour déborder le buffer. Le canari essaie de détecter cela avant de sauter, et DEP est utilisé pour rendre l'espace de pile non exécutable. DEP fonctionne également en cas de débordement de tampons dans le tas (le canari n'est utile que pour les débordements de tampon de pile, mais le tas peut également contenir des tampons, ainsi que des données sensibles à écraser, telles que des pointeurs vers des fonctions - en particulier dans le contexte de = OOP langages tels que C++). Pour contourner DEP et le canari, les attaquants ont commencé à rechercher les débordements qui permettent d'écraser les pointeurs pour fonctionner, afin de faire sauter l'exécution dans code de bibliothèque standard qui est nécessairement "là" et aussi nécessairement exécutable. C'est pourquoi ASLR a été inventé: pour rendre ces jeux plus difficiles. ASLR peut toujours être vaincu en étant chanceux: depuis ASLR doit maintenir l'alignement des pages (4 Ko sur x86), dans un espace d'adressage pas trop grand (généralement moins de 2 Go sur x86 32 bits), il n'y a pas tellement d'endroits où le code cible peut être (au plus la moitié d'un Selon le contexte de l'attaque et la fréquence à laquelle le script de l'attaquant peut essayer, cela peut être trop faible pour plus de confort.
Le thème important ici est que les canaris, DEP et ASLR ne défont pas les débordements eux-mêmes, mais ciblent les méthodes génériques d'exploitation de débordement qui ont été traditionnellement utilisées. Dans toute application, un débordement qui écrase les données non pointées peut être aussi mortel qu'un exploit Shell distant (par exemple, imaginez un débordement qui modifie un champ de chaîne appelé "authenticated_user_name
"). La course aux armes entre attaquants et défenseurs devient trop spécialisée et, à mon avis, passe de plus en plus à côté. De manière générale, il vaut bien mieux ne jamais laisser déborder, c'est-à-dire bloquer/tuer le processus/thread offensant avant d'écrire des octets en dehors du tampon cible. C'est ce qui se passe avec presque n'importe quel langage de programmation décent (Java, C #, VB.NET, Python , Ruby, Node.js, OCaml, PHP ... le choix est large).
Le niveau de protection de base est ASLR + DEP.
Si vous n'utilisez pas les deux, il existe de nombreuses techniques puissantes pour exploiter un dépassement de tampon (par exemple, informatique orientée retour, pulvérisation de tas, devinettes répétées). Par exemple, le DEP seul peut être vaincu en utilisant une informatique orientée retour; et ASLR seul peut être vaincu en utilisant une pulvérisation en tas et des tentatives répétées.
Cependant, si la cible utilise les deux ASLR + DEP, l'exploitation devient beaucoup plus difficile. Les techniques mentionnées ci-dessus ne sont pas suffisantes pour vaincre ASLR + DEP. ASLR + DEP sont comme un coup de poing un-deux qui rend la vie de l'attaquant beaucoup plus difficile. Vaincre la combinaison ASLR + DEP n'est pas impossible, mais cela demande beaucoup plus d'intelligence.
Mon exemple préféré de méthodes pour vaincre ASLR + DEP est expliqué dans le diaporama, Exploitation des interprètes: inférence de pointeur et pulvérisation JIT . Là, l'auteur décrit comment il a exploité une erreur de sécurité de mémoire dans Flash. Il a exploité les propriétés du Flash JIT pour organiser la mémoire de manière à lui permettre de monter une attaque par injection de code, malgré la présence d'ASLR + DEP. Rappelons qu'un JIT est un compilateur juste à temps; il compile les bytecodes Flash en code natif. Le code natif sera stocké quelque part en mémoire et le Flash JIT le marquera comme exécutable (malgré DEP). L'auteur a trouvé un moyen de générer des octets Flash qui, une fois compilés, généreraient une séquence d'octets intégrant son shellcode malveillant (compensé par un octet). Il a ensuite utilisé des techniques de pulvérisation en tas pour s'assurer qu'il y avait de nombreuses copies de cela en mémoire. Enfin, il a exploité le bogue de sécurité de la mémoire pour faire passer le programme à une autre adresse; en raison de l'ASLR, c'était comme sauter vers une adresse aléatoire, mais les nombreuses copies assuraient qu'avec une forte probabilité, cela sauterait dans son shellcode. De cette façon, il a contourné ASLR et DEP - un exploit astucieux.
Une dernière remarque: il convient de mentionner que ASLR est beaucoup plus efficace sur les architectures 64 bits. Sur les architectures 32 bits, ASLR peut souvent être vaincu en effectuant simplement plusieurs tentatives. Il n'y a tout simplement pas assez de degrés de liberté sur les plates-formes 32 bits pour introduire suffisamment d'aléatoire, de sorte que les chances de l'attaquant de réussir par une chance stupide restent trop élevées, sur les plates-formes 32 bits. Pour la défense la plus puissante, utilisez une plate-forme 64 bits.