Exploitation avancée


<< Exécution arbitraire par format strings Return into libc >>


I°) Nouveaux mécanismes de protection

   Depuis la fin des années 1990, le paysage de la défense contre les différents exploits en mémoire a beaucoup changé. Sous Linux, ce changement s'est essentiellement traduit par l'introduction du patch PaX, introduisant de nouvelles fonctionnalités au cours des années, allant la randomisation de la base de mmap() pour le chargement des librairies, ASLR (Adress Space Layout Randomization) à la non-exécutabilité de la pile, en passant par l'émulation de trampolines ou l'introduction dans les compilateurs de cookies, ou canaries. Dans cette section, je vous propose un bref rappel des principales fonctionnalités et défenses apparues.

NX ou la pile non exécutable
   Dans l'exploitation classique des buffer-overflows, l'adresse de retour se situe dans la pile : dans le buffer vulnérable, après l'adresse de retour, dans les arguments ou dans l'environnement. Il a donc été naturel dans un premier temps d'empêcher les exécutions sur la pile. Plus généralement, empêcher qu'une page mémoire puisse être à la fois en écriture et en exécution. De cette façon, il n'est plus possible d'exécuter du code injecté au préalable. Finalement, pourquoi continuer à se servir de la pile lorsque les fonctions que nous cherchons à exécuter dans le shellcode existent déjà dans l'espace mémoire ? En effet, que ce soit les fonctions du programme, présentes dans la GOT (Global Offset Table) ou celles des librairies (notamment la libc, contenant toutes les fonctions que nous cherchons, comme seteuid, system ou la famille des exec), ces fonctions prennent leurs arguments de la pile, que nous contrôlons. Il est donc possible de reconstruire de fausses frames avec les adresses de retour pointant vers les fonctions voulues et contenant les paramètres désirés. Une autre idée aura été d'appeller mprotect afin de modifier les protections de la pile et donc de pouvoir ensuite exécuter ce que bon nous semble. Cependant, certaines options de PaX permettent de désactiver mprotect() et mmap() demandant de rendre une page exécutable.

Architectures 64-bits
   L'arrivée des architectures 64-bits a également changé la donne. En premier lieu, la protection des permissions des pages ont été inclues au niveau matériel. Ainsi, la pile est non-exécutable par défaut. De plus, les paramètres ne sont plus passés par la pile mais pas les registres rax, rbx, rcx, rdx, rsi et rdi (pour ADM64 et Intel x86_64) pour les fonctions à 6 arguments ou moins. Enfin, l'injection des adresses de retour peut comporter beaucoup de zéros, puisque les adresses sont codées sur 64-bits également (même si dans les exploits actuels, les bon vieux strcpy() sont relativement désuets). Ces modifications de l'environnement d'exploitation ont supprimé du paysage les exploits old school et notamment les return into libc et return into plt. Dans cette section, je me contenterai d'utiliser des programmes 32-bits. Si les exploitations sont plus difficiles en 64-bits, elles ne sont pas impossibles, en particulier lorsque l'on peut injecter des 0. Si cela vous intéresse, je vous ramène au write-up Secure FS du Plaid CTF 2012, une épreuve comprenant un exécutable 64-bits PIE (les segments .text, .data et .bss sont également randomizés), dans un environnement ASLR + NX d'activé.

ASLR
   Le chef d'oeuvre en matière de sécurité est certainement celui-ci. En effet, bon nombre d'exploits se basent sur la prédiction des adresses de retour, que ce soit dans la pile, dans le heap ou dans les librairies partagées. ASLR a ainsi été conçu pour éliminer ces classes d'exploits. Le programme ldd permet d'observer ces changements. Il place la variable d'environnement LD_TRACE_LOADED_OBJECTS à 1, qui va arrêter prématurément l'exécution d'un programme et afficher l'adresse de chargement des librairies partagées :
    $ ldd /bin/sh
    linux-gate.so.1 => (0xffffe000)
    libncurses.so.5 => /lib/libncurses.so.5 (0xb7fd6000)
    libdl.so.2 => /lib/tls/i686/cmov/libdl.so.2 (0xb7fd2000)
    libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0xb7e74000)
    /lib/ld-linux.so.2 (0xb801e000)
    $ ldd /bin/sh

    linux-gate.so.1 => (0xffffe000)
    libncurses.so.5 => /lib/libncurses.so.5 (0xb7eb9000)
    libdl.so.2 => /lib/tls/i686/cmov/libdl.so.2 (0xb7eb5000)
    libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0xb7d57000)
    /lib/ld-linux.so.2 (0xb7f01000)
    $
Dans l'exemple précédent, on observe bien qu'entre deux exécutions successives, l'adresse de base du chargement des librairies est différente. Les différentes pages mémoires d'un processus sont également visibles dans /proc/<pid>/maps. On peut donc également vérifier le même comportement pour la pile et le heap :
    $ cat get_map.sh
    #!/bin/sh
    cat /proc/$$/maps
    $ ./get_map.sh | egrep "stack|heap"
    09923000-099b6000 rw-p 00000000 00:00 0 [heap]
    bfd1c000-bfd31000 rw-p 00000000 00:00 0 [stack]
    $ ./get_map.sh | egrep "stack|heap"
    089b6000-08a49000 rw-p 00000000 00:00 0 [heap]
    bfdde000-bfdf3000 rw-p 00000000 00:00 0 [stack]
    $
Encore une fois, une classe entière d'exploits a pu être supprimée. Ceci dit, il existe bien sûr des moyens de passer outre et c'est ce que nous allons tenter d'effectuer tout au long de cette section.

Stack Canary
   L'utilisation de cookies ou de canaries n'est pas une protection matérielle ou du système d'exploitation comme précedemment, mais une protection au niveau logiciel. En réalité, dès la compilation, les préludes et prologues des fonctions sont modifiés. Au tout début de l'exécution, le canary est placé dans le segment data et initialisé. C'est un entier aléatoire, de la taille d'un registre. Inutile de dire qu'il est initialisé avec des valeurs fortement aléatoires (quoique des travaux ont montré que l'on pouvait fortement diminuer l'entropie des cookies). Quoiqu'il en soit, à chaque début de fonction, le cookie est placé soit entre le Saved Frame Pointer (valeur enregistrée de l'ebp) et l'adresse de retour, soit après la sauvegarde du contexte (donc plus haut que les variables locales, mais plus bas que le SFP, l'adresse de retour et les éventuels registres sauvegardés à l'entrée de la procédure). Au contraire, à la fin d'une fonction, avant le leave/ret, la valeur du cookie est vérifiée et le programme se termine si la comparaison échoue.
Inutile de dire que lorsque un overflow intervient, la valeur du cookie n'est plus égale à celle spécifiée dans le segment data, puisqu'il est a priori très difficile de deviner le cookie. Ceci dit, ces protections peuvent être détournées de plusieurs façons selon l'implémentation : par exploitation de format strings permettant de passer outre l'écrasement du cookie, par exploitations type off-by-one (lorsque on peut écraser le SFP, on est capable de bouger la prochaine frame plus bas dans la pile ou dans la GOT, afin de pouvoir forcer la prochaine adresse de retour qui sera popée) ou encore par overflows dans le heap ou le segment data (écrasement du cookie).
Ceci dit, contrairement à Windows, sous Linux ces exploitations sont très différentes selon le contexte, je ne ferais donc pas de généralités et partirait du principe que le programme n'est pas compilé avec ce genre de protections. Certaines distributions, comme Ubuntu, incluent par défaut cette option dans gcc. Il faut compiler avec l'argument -fno-stack-protector pour ne pas l'inclure.

Historiquement, la première défense diffusée fû la non-exécutabilité de la pile. De ce fait, les attaquants ont très vite cherché à sortir de celle-ci. D'ici sont nées les attaques de type return-into-libc, que nous allons maintenant détailler. Dans les prochaines sections, nous nous placerons exclusivement dans le cas où la base de la pile est random, la base du mapping des librairies également et la pile n'est pas exécutable. A la fin de cette section, j'expliquerai également brièvement les modifications à apporter aux différents exploits pour pouvoir les porter sur 64-bits, qui a notamment apporté des modifications à la manière de passer les arguments aux fonctions.


<< Exécution arbitraire par format strings Return into libc >>




0 Commentaires




Commentaires désactivés.

Apprendre la base du hacking - Liens sécurité informatique/hacking - Contact

Copyright © Bases-Hacking 2007-2014. All rights reserved.