lundi 17 février 2014

Smashing the stack for fun and dummies

Bonjour,

Mon premier article portera sur les Stack Overflow, pourquoi ?
Certains me diront que c'est obsolète ;-) .

Je leur répondrai que pour passer aux  ROP (Returrn Oriented Programming) il faut déjà connaître les Stack Overflow...Cela reviendrai a dire faire maître nageur sans savoir nager !

Qu'est ce qu'une Stack Overflow ? Pourquoi, comment, qui, quoi ....

Quand vous lancer une application elle se charge dans la pile d’exécution (stack).
Cette stack à une taille prédéfinie par le programmeur ayant écrit le programme.
L'application demande une allocation mémoire pour charger ses différents paramètres (scalaires, tableaux fonctions,...) En temps normal l'application a la place nécessaire pour s'exécuter en mémoire à moins de coder avec les pieds... là je peux rien pour vous !


©® T.Vivien

Il y a une faiblesse dans la façon de programmer c'est de ne pas contrôler la longueur de la chaîne. voici un exemple en C

char username[512] = {1};

Pour les non initiés char est un tableau d'une taille de 512 octets.
Comme vous le constaterez "username" parle de lui même, perso je ne connais pas de prénom ou nom faisant 512 octets de long. Il aurait été plus judicieux de prévoir la longueur d'un login ou utilisateur environs 12 caractères donc en étant large 30 octets, mais comme je le dit plus haut il fallait contrôler la longueur de la chaîne.

Pour vous démontrer la suite vous allez avoir besoin de quelques notions en assembleur. L'assembleur est le premier langage qui transforme les instructions machines en langage compréhensible par l'homme, il est donc un langage de bas niveau.

Les instructions de base de ce langage sont définies par le type de processeur Intel ou Amd et l'architecture de celui-ci 32 ou 64 bits
ici nous parlerons d'un processeur Intel en 32 bits. je présenterai seulement l'essentiel

Un processeur 32 bits de type Intel dispose de 16 registres qui sont classables en trois catégories :

les 8 registres généralistes utilisés pour contenir des données et des pointeurs ;
les registres de segments utilisés pour contenir l’adresses des différents segments (données, code, etc.) ;
les registres de contrôle et de statut qui donnent des informations sur l’exécution du programme en cours.

Deux registres nous importent seulement :

Le registre EIP (Instruction Pointer) contient l’offset de la prochaine instruction à exécuter. Il est modifié automatiquement à chaque exécution et peut être manipulé par des instruction du type jmp, call, ret, etc. On ne peut pas accéder directement à ce registre.

Le registre ESP (Stack Pointer) récupère l'adresse du haut de la pile, ce pointeur est fixe et restera toujours sur le haut de la pile

J'imagine qu'un schéma ne serait pas de trop. Comme je vous le disais plus haut un programme (une fois exécuté il devient un processus) et dispose de son propre espace mémoire.

Celui-ci est divisé en trois catégories : Section texte - Section données - section Stack
(voir schéma plus bas)

La section texte(.text) contient les instructions pour exécuter le programme,il est délicat de venir modifier les instructions car cela change le déroulement du programme ou pourrait le faire crasher.
La section data (.data) contient les variables non initialisées

la  pile (stack) contient les variables et instructions en mémoire
Avant toute chose la lecture se fait dans le sens inverse de la lecture d'une page.

Voici un aperçu des segments




vous devez imaginer que cette pile est comme une stalactite la pile est fixée au plafond et avance vers le bas



------------------------- *** REPRESENTE LE PROCESSUS ***
| Section text         |
-------------------------
| Section Data        |
-------------------------
| Stack                  |
-------------------------
 * haut de la pile *


  * bas de la pile *
------------------------- ***  STACK ***
|                           |
-------------------------
|                            | < ---- EBP
-------------------------
|                            |
------------------------- < ---- ESP
 * haut de la pile *

    /\
          ||
          || EIP
          ||

©® T.Vivien

Venons en à un exemple concret notre application s'appellera binary7 type de fichier ELF 32-bit LSB exécutable, Intel 80386.Je me suis basé sur un binaire d'un site de challenge célèbre ;-)




cette application attend un argument nous allons lui faire afficher des A jusqu'à ce qu'elle arrive sur un " Seg fault". A moins d'avoir 10 ans devant vous pour écrire des A à en vomir je vous conseille de rendre çà plus soft. Commencer doucement avec cette commande `perl -e 'print "A" x nombre de A`





Magnifique on a eu notre seg fault maintenant il faut vérifier si le registre EIP est plein. La valeur décimale de A est de 41, vous allez comprendre par la suite. Sortons notre à boîte outils.
Go gdb, le debugger natif sous linux. Lancer votre application avec gdb comme ceci


vous allez exécuter le programme comme tout à l'heure, c'est à dire avec l'affichage des A qui vous renvoie un seg fault.

A partir de là nous allons nous concentrer sur la valeur de EIP. Rappelez vous c'est le registre qui prend la prochaine instruction à exécuter. nous allons reprendre cette commande jusqu'à ce que EIP soit plein de A soit 41414141.




Disons que je vous ai mis le résultat où EIP est plein rien ne sert d'aller au dessus si vous vous posez la question.Pour continuer il va nous falloir créer un Payload (nop (x\90) , un shellcode, offset de retour). Donc soit On se forge notre shellcode ce que je présenterai dans un prochain article, mais là on est pressés donc Go google ! Un shellcode se choisit en fonction de son architecture, sa fonction finale et de sa longueur. Donc ici ce sera du intel 32 bits, et nous souhaitons avoir un shell (/bin/sh) et on va tâcher de trouver un code pas trop grand donc on oublie les shellcodes polymorphiques ;-) .

je vous propose celui-ci
 \x31\xc0\x31\xdb\x31\xc9\x31\xd2\x52\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x52\x53\x89\xe1\xb0\x0b\xcd\x80

Pour terminer nous allons devoir faire un peu de maths. Reprenons tout çà schématiquement, on est sûr que notre programme crashe complètement avec EIP  rempli de A avec 516 octets, ce sera notre somme de base.

516 = (xNop - longueur du shellcode - longueur de l'offset)

Nous ne connaissons que 2 éléments la valeur totale et l'offset qui vaut 4 octets

Voici un moyen de calculer la longueur de la chaîne de notre shellcode :


attention si vous passez par un script bash de type écho :
echo "votre super shellcode" | wc -c le résultat pourrait être tout autre car celui-ci prend en compte les \x. Autant vous dire vous êtes en train d'assimiler un concept nouveau ne commencez pas à partir du côté obscur .

29 octets est notre longueur de shellcode, si l'on reprend notre calcul initial

516-4= 512
512-29=483 nop !

Qu'est ce qu'un nop ? c'est son appellation en assembleur  pour dire "no opération". A ne surtout pas confondre avec un null.Un null byte est une fin de chaîne je pense que vous avez compris ce que cela signifie ? ;-)

nop = \x90
null byte=\x00


Nous avons enfin toutes nos valeurs pour forger notre Payload final, il reste encore notre adresse de retour à trouver. Où elle peut bien être ? Vous vous rappelez de ESP qui est le pointeur du haut de la pile.... je dis çà je dis rien. l'idée pour afficher quelque chose de correct on travaille depuis le début avec 516 octets, je pense qu'afficher les 400 premiers octets de ESP cela devrait suffire.


***Quelques lignes plus loin nous voyons apparaître les A ***



l'adresse de retour ne se limite pas à une adresse  unique du moment que vous tapez dans le milieu après il faut tester votre adresse de retour. Notre offset est 0xbffffdac, nous sommes sur du Intel la lecture se fait de la fin vers le début comme ceci ac bd ff bf. Une fois rajouté au Payload cela donne \xac\xfd\xff\xbf\.

Enfin nous sommes prêts pour notre test !





Great ! nous avons un shell ! il nous suffit de quitter gdb et de reproduire la même chose...




l'idée de ce challenge était de récupérer un accès pour lire le password. quelques précisions pour les plus novices. 
whoami = qui suis je ? quel utilisateur je suis 
cat = permet de lire le contenu d'un fichier 

L'article se termine ici je vous propose un petit script en perl qui va vous faire gagner un peu de temps, je vous montre ça rapidement.Le script est à votre disposition. Il exploite le binaire et renvoie les résultats ci dessous :



Merci pour votre attention, en espérant que cela vous aura permis de voir plus clair et de saisir le principe des stacks overflow. N'hésitez pas à me solliciter pour améliorer le contenu de cet article

BoF_tools.pl

### HyP ###

©® T.Vivien

Aucun commentaire:

Enregistrer un commentaire