• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Sstic09 Article G Campana Fuzzgrind Un Outil De Fuzzing Automatique
 

Sstic09 Article G Campana Fuzzgrind Un Outil De Fuzzing Automatique

on

  • 1,829 views

 

Statistics

Views

Total Views
1,829
Views on SlideShare
1,829
Embed Views
0

Actions

Likes
0
Downloads
4
Comments
0

0 Embeds 0

No embeds

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Sstic09 Article G Campana Fuzzgrind Un Outil De Fuzzing Automatique Sstic09 Article G Campana Fuzzgrind Un Outil De Fuzzing Automatique Document Transcript

    • Fuzzgrind : un outil de fuzzing automatique Gabriel Campana Sogeti/ESEC R´sum´ Le fuzzing est devenu au cours de ces derni`res ann´es une des principales m´thodes e e e e e de recherche de vuln´rabilit´s. Les fuzzers actuels reposent principalement sur la g´n´ration e e e e de donn´es invalides ` partir de mod`les, qui n´cessitent d’ˆtre r´´crit pour chaque nouvelle e a e e e ee cible. Nous d´taillerons le fonctionnement de Fuzzgrind, un nouvel outil de fuzzing enti`rement e e automatique, g´n´rant de nouvelles donn´es de test ` partir de l’ex´cution symbolique du e e e a e programme cible sur une entr´e donn´e, dans le but de rechercher de nouvelles vuln´rabilit´s. e e e e 1 Introduction 1.1 D´finition du fuzzing et outils actuels e Le fuzzing est une technique de recherche d’erreurs d’impl´mentation logicielle e par injection de donn´es invalides. L’injection de donn´es invalides est bien entendu e e relative a l’impl´mentation logicielle test´e, pour trouver les tests les plus pertinents ` e e susceptibles de d´couvrir des erreurs d’impl´mentation classiques (d´bordement de e e e tampon, bug de chaˆ de format, etc). ıne Il existe actuellement une multitude de logiciels de fuzzing 1 , g´n´rant principale- e e ment les donn´es de tests de deux fa¸ons : e c – al´atoirement, e – ` partir d’une grammaire ou d’un mod`le auquel certaines heuristiques de a e mutation sont appliqu´es pour rendre les donn´es g´n´r´es invalides. e e e ee Au vu des vuln´rabilit´s trouv´es par cette seconde cat´gorie de fuzzer, leur effi- e e e e cacit´ et leur puissance n’est plus ` prouver. Ils poss`dent cependant de nombreux e a e inconv´nients et limitations. e L’´criture du mod`le ou de la grammaire est un processus sans fin, complexe et e e fastidieux, n´cessitant de disposer des sp´cifications du protocole ou du format de e e fichier cible (ce qui n’est bien ´videmment pas toujours le cas, en particulier pour les e logiciels propri´taires). Les ´tapes d’ing´nierie inverse, d’´tude des sp´cifications et e e e e e de description de la grammaire prennent un temps cons´quent, et doivent de plus e ˆtre renouvel´es pour chaque nouveau protocole ou format de fichier test´. e e e L’impl´mentation cible, quant a elle, ne respecte pas n´cessairement les sp´cifications. e ` e e 1 Liste de frameworks et de logiciels de fuzzing : http://www.nosec.org/web/fuzzers.
    • G. Campana 213 Bien que fortement susceptibles de comporter des vuln´rabilit´s, les fonctionnalit´s e e e non document´es n’auront que peu de chance d’ˆtre test´es. e e e Enfin, certaines vuln´rabilit´s semblent peu enclines ` ˆtre trouv´es par ce moyen. e e ae e Cet exemple de buffer overflow dans la commande PASS d’un serveur FTP, seulement d´clench´ lorsque le mot de passe commence par une virgule 2 , illustre parfaitement le e e fait que de nombreuses vuln´rabilit´s ´chapperont toujours a cette classe de fuzzers. e e e ` Parall`lement, de nouveaux fuzzers reposant sur des th´ories innovantes ont vu le e e jour : – Autodaf´ [1] analyse tous les appels de fonctions « dangereuses » d’un programme e pendant son ex´cution, a l’aide du debugger gdb. Si ces fonctions d´pendent de e ` e donn´es contrˆl´es par l’utilisateur, elles sont mut´es dans le but de d´clencher e oe e e un buffer overflow. – Catchconv [2] est un outil de g´n´ration de donn´es destin´es a d´clencher des e e e e ` e integer overflows, bas´ sur Valgrind et STP. e – Bunny the Fuzzer [3] injecte dans la source du programme cible des fonctions d’instrumentation pendant la compilation. Ces fonctions permettent au fuzzer de recevoir des informations sur le chemin d’ex´cution, les arguments des fonctions, e les valeurs de retour, ainsi que de modifier ces valeurs ` l’ex´cution. a e – Flayer [4] est un plugin pour Valgrind reposant sur la technique de tainted data flow analysis, destin´ ` tracer et modifier manuellement le chemin des entr´es. ea e L’approche utilis´e par Fuzzgrind est une extension audacieuse de celle utilis´e e e par Flayer. – DART [5], CUTE [6], et EXE [7] extraient du code source les prototypes des fonctions, et g´n`rent al´atoirement des entr´es. Le programme cible est ex´cut´ e e e e e e symboliquement sur ces entr´es pour inverser chaque path condition. e – SAGE [8] ´mule et trace symboliquement les instructions du programme cible e afin de g´n´rer des donn´es de test pour fuzzer des formats de fichier sous e e e Windows. L’existence de ces fuzzers montre qu’il n’y a pas une seule et unique technique de fuzzing, et que toutes les voies de recherche sont loin d’ˆtre explor´es. Les vuln´rabilit´s e e e e trouv´es par ces m´thodes sont la plupart du temps diff´rentes ; chacune d’entre elle e e e est sp´cifique a une cible particuli`re : protocoles r´seaux, formats de fichier, langage e ` e e de scripts, etc. 2 http://blogs.securiteam.com/index.php/archives/677
    • 214 Fuzzgrind : un outil de fuzzing automatique 1.2 Concept de Fuzzgrind L’ex´cution symbolique, un concept introduit par King dans les ann´es 1970, fut e e le point de d´part de plusieurs projets de recherche d’erreurs dans des programmes, e notamment [2,5,6,7,8] qui ont inspir´ le fonctionnement de Fuzzgrind. L’ex´cution e e symbolique d’un programme consiste ` utiliser des expressions alg´briques pour a e repr´senter les valeurs des variables tout au long de l’ex´cution. Le chemin d’ex´cution e e e du programme (c’est a dire la suite de branches conditionnelles prises ou non par le ` programme) est repr´sent´ par les path conditions, qui correspondent aux contraintes e e sur les variables symboliques devant ˆtre satisfaites pour ex´cuter le chemin. Les e e r´sultats de l’ex´cution peuvent ainsi ˆtre repr´sent´s a l’aide des valeurs symboliques e e e e e ` des variables et des conditions de chemins ; comme le montre la figure 1. // execution concrete | execution symbolique // - - - - - - - - - - - - - - - - - - - -+ - - - - - - - - - - - - - -+ - - - - - - - - - - - - - // etat concret | etat symb . | path constr . // - - - - - - - - - - - - - - - - - - - -+ - - - - - - - - - - - - - -+ - - - - - - - - - - - - - int calc ( uint y ) { // y =4 | 0 <= y < 2^32| uint x = 2 * y ; // x =8 | x = 2 y | // | | if ( y % 2 == 0) { // | | y % 2 == 0 if ( y > 10) { // | | y > 10 y += x ; // | | } // | | y *= 5; // y =20| y = 5 y | } // | | // | | return y ; // | | } Fig. 1. Repr´sentation des ex´cutions concr`tes et symboliques d’un programme. e e e L’approche utilis´e par Fuzzgrind est d’analyser les conditions de chemin de e l’ex´cution symbolique d’un programme sur une entr´e donn´e afin de g´n´rer de e e e e e nouvelles entr´es, susceptibles de provoquer des erreurs (et pouvant potentiellement e ˆtre la source de vuln´rabilit´s). Le programme cible est ex´cut´ symboliquement sur e e e e e une entr´e donn´e (typiquement un fichier ou l’entr´e standard), enregistrant toutes e e e les contraintes symboliques li´es aux instructions de branchement conditionnelles e d´pendant de l’entr´e rencontr´e sur le chemin d’ex´cution. Chaque contrainte est e e e e invers´e pour que la branche qui n’a pas ´t´ suivie le soit. Un solveur de contraintes e ee est appel´ sur ces nouvelles contraintes pour g´n´rer de nouvelles entr´es de test. e e e e
    • G. Campana 215 L’ex´cution suivante du programme sur ces nouvelles entr´es suivra ainsi de nouveaux e e chemins d’ex´cution. Cet algorithme est r´p´t´ (en suivant une heuristique bas´e e e ee e sur la couverture de code pour ex´cuter en priorit´ le programme sur des entr´es e e e susceptibles de d´clencher des erreurs), id´alement jusqu’` ce que tous les chemins e e a d’ex´cution soient couverts. e Ces id´es ont ´t´ impl´ment´es dans Fuzzgrind. Nous d´taillerons dans la suite de e ee e e e cet article son fonctionnement ainsi que celui des outils utilis´s sur lesquels repose e notre impl´mentation, Valgrind et STP. Enfin, nous analyserons les r´sultats obtenus e e sur des exemples simples, et des librairies utilis´es par des programmes r´pandus, e e ainsi que les am´liorations possibles. e 2 Description des logiciels Valgrind et STP Fuzzgrind repose sur les deux logiciels libres Valgrind 3 et STP 4 . Valgrind est un framework d’instrumentation binaire dynamique (Dynamic Binary Instrumentation) sous licence GPL, supportant de nombreuses architectures 5 et destin´ ` la cr´ation ea e d’outil d’analyse binaire dynamique (Dynamic Binary Analysis). STP est un solveur de contraintes sous licence MIT. Seuls les m´canismes internes de Valgrind et STP e n´cessaires ` la compr´hension de Fuzzgrind seront expos´s dans la suite de cette e a e e partie. L’article [9] pr´sente en d´tail les fonctionnements complets de Valgrind et e e Memcheck. Le fonctionnement interne et les th´ories derri`re STP sont d´taill´s dans e e e e l’article [10]. 2.1 Valgrind Pr´sentation g´n´rale Le framework d’instrumentation binaire dynamique Val- e e e grind comporte par d´faut quatre outils dont le c´l`bre Memcheck 6 , destin´ a d´couvrir e ee e` e des probl`mes d’utilisation de la m´moire. Son architecture est modulaire, de fa¸on e e c ` ce que de nouveaux outils puissent ˆtre cr´´s facilement sans avoir ` modifier sa a e ee a structure interne. Le cœur de Valgrind est constitu´ de deux parties, coregrind et e VEX. VEX est responsable de la traduction dynamique de code et de l’appel des fonctions de l’outil pour l’instrumentation de la repr´sentation interm´diaire, tandis e e que coregrind est responsable de tout le reste (l’ordonnancement, le cache des blocs, la gestion des symboles, etc). 3 http://www.valgrind.org 4 http://people.csail.mit.edu/vganesh/STP_files/stp.html 5 x86, x86-64, PPC32 et PPC64 sous le syst`me d’exploitation GNU/Linux ; PPC32 et PPC64 sous AIX e 6 http://valgrind.org/docs/manual/mc-manual.html
    • 216 Fuzzgrind : un outil de fuzzing automatique Coregrind Apr`s avoir lanc´ Valgrind en sp´cifiant un outil et un programme cible, e e e le cœur, l’outil et le programme cible sont charg´s dans un mˆme processus. Le code e e machine du programme cible est analys´ par basic block 7 de cinquante instructions e maximum. Valgrind ne peut ´videmment pas analyser le code ex´cut´ par le noyau. Lorsqu’un e e e appel syst`me est effectu´ par le programme cible, le contrˆle revient a l’ordonnanceur, e e o ` qui effectue quatre op´rations : e – tous les registres du programme cible sont copi´s a la place du programme hˆte, e ` o hormis le pointeur d’instruction (Program Counter, PC), – l’appel syst`me est appel´, e e – les registres de l’invit´ sont copi´s, hormis le pointeur d’instruction, e e – le pointeur de pile de l’outil est restaur´. e Les appels syst`me n´cessitant des ressources partag´es entre les deux processus e e e comme de la m´moire (par exemple mmap) ou des descripteurs de fichier (par exemple e open) sont v´rifi´s pour s’assurer qu’ils ne causent pas de conflit avec l’outil. Par e e exemple, si le client tente de mmaper de la m´moire utilis´e par l’outil, Valgrind le e e fait ´chouer sans effectuer aucun appel syst`me. e e VEX La traduction des blocs est effectu´e par VEX en huit phases cons´cutives : e e 1. Le d´sassemblage du code du programme cible : le code d´pendant de l’architecture e e sur laquelle le programme est lanc´, est traduit dans la repr´sentation interm´diaire e e e de VEX, ind´pendant de l’architecture. e 2. L’optimisation de la repr´sentation interm´diaire. e e 3. L’instrumentation : VEX appelle la fonction principale de l’outil s´lectionn´, e e responsable de l’instrumentation de la repr´sentation interm´diaire. e e 4. L’optimisation de la repr´sentation interm´diaire, similaire ` la phase 2. e e a 5. Tree building : mise ` plat de la repr´sentation interm´diaire pour simplifier la a e e phase 6. 6. La s´lection d’instructions : la repr´sentation interm´diaire est convertie en code e e e machine. 7. L’allocation des registres : les registres r´els de la machine hˆte sont allou´s. e o e 7 Bloc d’instructions sans aucun jump (instruction de branchement) ni destination de jump ; la destination d’un jump d´signe le d´but du bloc, et un jump la fin). e e
    • G. Campana 217 8. La g´n´ration du code final : le code machine final est g´n´r´, en encodant les e e e ee instructions g´n´r´es pr´c´demment et en les enregistrant dans un bloc de m´moire. e ee e e e ` A la fin de chaque bloc, VEX sauve tous les registres invit´s en m´moire, pour e e que la traduction de chaque bloc soit ind´pendante des autres. Nous noterons que e Valgrind recompile chaque instruction du code machine du programme cible ` la a vol´e, et qu’` aucun moment, le code original du programme est ex´cut´. e a e e L’instrumentation d’un programme par Valgrind poss`de n´anmoins un impact e e important sur les performances. Avec un plugin n’effectuant aucune action, l’ex´cution e du programme cible par Valgrind prend quatre fois plus de temps. Avec le plugin Memcheck, la taille du code ex´cut´ est multipli´e par douze, et l’ex´cution est e e e e vingt-cinq ` cinquante fois plus lente. a Repr´sentation interm´diaire et instrumentation Le code d’instrumentation e e du plugin Fuzzgrind est appel´ par VEX pendant la troisi`me phase. La repr´sentation e e e interm´diaire de VEX est consitu´e de petits blocs de cinquante instructions max- e e imum. Une instructions du code machine original est traduite en une ou plusieurs instructions de la repr´sentation interm´diaire. Celle-ci est constitu´e d’instructions e e e avec effet de bord (enregister une valeur en m´moire, assigner une valeur a un tempo- e ` raire, etc), manipulant des expressions sans effet de bord (op´rations arithm´tiques, e e chargement d’une valeur enregistr´e en m´moire, etc). Une traduction de code machine e e en repr´sentation interm´diaire est pr´sent´e par la figure 2. e e e e 0 x4000A99 : movl % eax ,% ecx ------ IMark (0 x4000A99 , 2) ------ PUT (4) = GET : I32 (0) ; copie d ’ EAX dans ECX 0 x4000A9B : leal 0 x2C (% ebx ) , % esi ------ IMark (0 x4000A9B , 6) ------ PUT (60) = 0 x4000A9B : I32 ; mise a jour d ’ EIP ` t0 = Add32 ( GET : I32 (12) ,0 x2C : I32 ) ; addition du contenu d ’ EBX avec 0 x2C PUT (24) = t0 ; copie du ´ rsultat dans ESI e Fig. 2. Exemple de code machine x86 d´sassembl´ en repr´sentation interm´diaire, e e e e pendant la phase 1.
    • 218 Fuzzgrind : un outil de fuzzing automatique Le nombre de registres est fixe, tandis que le nombre de temporaires n’est pas limit´. Un environnement de types contient la taille de chaque temporaire. L’ensemble e de la repr´sentation interm´diaire est d´crit dans VEX/pub/libvex ir.h, et expliqu´ e e e e plus en d´tail dans [2]. Chaque basic block est instrument´ s´par´ment dans Valgrind. e e e e Les outils impl´mentent une fonction de callback qui prend en param`tre un basic e e block, et retourne un pointeur vers une copie du basic block instrument´. Cette e fonction peut boucler sur chaque instruction du basic block en entr´e, et le copier e normalement dans le basic block de sortie. L’instrumenteur peut ajouter, supprimer, ou modifier des instructions. Il est par exemple possible d’ajouter directement des appels de fonction dont le corps peut ˆtre ´crit en C dans le code source de l’outil. e e 2.2 STP Pr´sentation du langage STP est un solveur de contraintes g´n´r´es en pratique e e ee par des programmes d’analyse statique et dynamique. Il est notamment utilis´ dans e le projet de g´n´ration automatique de proof of concepts ` partir de patches d´crit e e a e par l’article [11], et dans Catchconv. STP accepte en entr´e une unique requˆte constitu´e d’une ou plusieurs contraintes. e e e La sortie indique si la formule est satisfiable ou non, et le cas ´ch´ant, une valeur est e e assign´e ` chaque variable pour exhiber un contre-exemple. Le langage de STP 8 , e a constitu´ d’un ensemble de fonctions et de pr´dicats, est suffisant pour repr´senter les e e e contraintes correspondant aux conditions d’un programme. Ce langage est caract´ris´e e par : – des fonctions de manipulation de variables : CONCAT, EXTRACT, >>, <<, SIGN EXTEND. – des fonctions de logique combinatoire : AND, OR, NOT, XOR, NAND, NOR, XNOR. – des fonctions arithm´tiques : ADD, MULT, SUB, DIV, SIGNED DIV, MODULO, SIGNED e MODULO. – des pr´dicats : =, <, >, <=, >= sign´s et non sign´s. e e e La figure 3 pr´sente l’ex´cution de STP sur une contrainte. Deux variables x et y e e de 8 bits sont d´clar´es. La formule requiert que le r´sultat de la multiplication sur e e e 8 bits de x et y soit diff´rent de 16. Cette contrainte n’est pas satisfiable puisqu’il e existe au moins un couple de valeurs (x, y) tel que (x * y) % 256 = 16, comme le montre le contre-exemple r´sultant de l’ex´cution de STP. La contrainte est donc e e 8 d´crit succinctement dans la documentation accessible ` l’adresse http://people.csail.mit.edu/ e a vganesh/STP_files/stp-docs.html.
    • G. Campana 219 invalide avec les valeurs x = 5 et y = 208. % cat file . stp x : BITVECTOR (8) ; y : BITVECTOR (8) ; QUERY ( NOT ( BVMULT (8 , x , y ) = 0 h10 ) ) ; % stp -p file . stp Invalid . ASSERT ( y = 0 hex05 ); ASSERT ( x = 0 hexD0 ); Fig. 3. Exemple de r´sultat d’ex´cution de STP sur une contrainte. e e 3 Fuzzgrind Le but de Fuzzgrind est de trouver des vuln´rabilit´s dans des programmes en e e partant d’une entr´e fix´e, et en g´n´rant de nouveaux fichiers de test pour passer e e e e par de nouveaux chemins d’ex´cution. Fuzzgrind fonctionne directement sur le code e machine du programme cible, et n’a pas besoin de ses sources. 3.1 Algorithme L’algorithme utilis´ est celui impl´ment´ dans SAGE et d´crit par Microsoft e e e e dans [8]. Il est divis´ en deux parties : la fonction search d´finie dans la figure 4 prend e e en argument le fichier ou l’entr´e standard initiale, input seed. La liste worklist, e initialis´e avec input seed, sera ´tendue par les nouveaux fichiers g´n´r´s. Le premier e e e ee ´l´ment est retir´ de la liste et d´velopp´ par la fonction expand execution, qui ee e e e g´n`re de nouveaux fichiers. Une note est attribu´e a chacun de ces nouveaux fichiers e e e ` par la fonction score, pour ex´cuter en priorit´ les fichiers dont la couverture de e e code est maximale. L’algorithme est r´p´t´ sur l’entr´e poss´dant le score le plus e ee e e ´lev´ tant que la liste worklist n’est pas vide. e e La fonction expand execution de la figure 5 est destin´e ` g´n´rer de nouvelles e a e e entr´es, a partir de l’entr´e input donn´e en param`tre. Une liste pc de conditions de e ` e e e chemin est g´n´r´e par l’ex´cution symbolique du programme cible sur l’entr´e input. e ee e e Apr`s avoir ´t´ optimis´es, ces conditions sont invers´es une ` une, et pass´es ` un e ee e e a e a solveur de contraintes par la fonction solve. S’il existe une solution a ces conditions, `
    • 220 Fuzzgrind : un outil de fuzzing automatique def search ( input_seed ) : worklist = [ input_seed ] while worklist : # entree p o s s e d a n t le score le plus eleve input = worklist . pop () # e x e c u t i o n symbolique , r e s o l u t i o n des # contraintes , et c r e a t i o n de n o u v e a u x # f i c h i e r s de test child_inputs = e x p a n d _e x e c u t i o n ( input ) for input in child_inputs : input . fault = check ( input ) # ajout des n o u v e a u x f i c h i e r s de tests worklist . append ( child_inputs ) # tri de la liste en f o n c t i o n du r e s u l t a t de # la f o n c t i o n score a p p l i q u e e a chaque fichier worklist . sort ( score ) Fig. 4. Algorithme d’ex´cution symbolique du programme sur les entr´es de test. e e l’entr´e input est modifi´e pour g´n´rer un nouveau fichier de test. Une variable e e e e bound est associ´e ` chaque entr´e pour ne pas analyser plusieurs conditions de e a e chemins identiques bien qu’issues d’entr´es diff´rentes. e e Un exemple d’ex´cution de cet algorithme est illustr´ par la figure 6. e e 3.2 Impl´mentation e Recherche des conditions de chemin La premi`re ´tape de l’algorithme est de e e chercher les path conditions li´es ` une entr´e donn´e. Pour ce faire, un outil pour e a e e Valgrind a ´t´ d´velopp´, affichant les contraintes li´es aux instructions de branchement ee e e e conditionnelles d´pendant de l’entr´e rencontr´e sur le chemin d’ex´cution (un exemple e e e e de sortie de cet outil est pr´sent´ dans la figure 7). Il repose sur le marquage des e e donn´es issues de l’entr´e suivie, et de la propagation des contraintes d´pendant de e e e ces donn´es. L’impl´mentation du tra¸age des donn´es marqu´es (taint tracing) est e e c e e divis´e en trois ´tapes principales : e e 1. le marquage initial des donn´es issues de la source suivie, e 2. la propagation et l’affichage des contraintes associ´es aux donn´es marqu´es, e e e 3. la suppression du marquage.
    • G. Campana 221 def e x p a n d _ e x e c u t i o n ( input ) : child_inputs = [] # e x e c u t i o n s y m b o l i q u e et r e c u p e r a t i o n des # c o n t r a i n t e s sur l ’ entree donnee pc = c o m p u t e _ p a t h _ c o n s t r a i n t ( input ) pc = optimize ( pc ) for j in range ( input . bound , len ( pc ) ) : # i n v e r s i o n de la d e r n ie r e c o n t r a i n t e negate ( pc [ j ]) # r e s o l u t i o n des c o n t r a i n t e s solution = solve ( pc ) if solution : # g e n e r a t i o n d ’ un nouveau fichier de test new_input = modify_bytes ( input , solution ) new_input . bound = j child_inputs . append ( new_input ) return child_inputs Fig. 5. Algorithme de g´n´ration de nouvelles entr´es. e e e Fig. 6. Graphe de l’ex´cution de l’algorithme de g´n´ration des fichiers de test sur la e e e fonction strcmp(buffer, "fuzz"), o` buffer est une entr´e marqu´e initalis´e par u e e e la chaˆ de caract`res lust. Les num´ros indiquent l’ordre dans lequel les entr´es ıne e e e ont ´t´ g´n´r´es. Les caract`res rouge sont les caract`res diff´rents par rapport ` ee e ee e e e a l’entr´e pr´c´dente et le point repr´sente le caract`re nul. e e e e e
    • 222 Fuzzgrind : un outil de fuzzing automatique % valgrind -- tool = fuzzgrind -- taint - file = yes -- file - filter =/ etc / passwd ./ target / etc / passwd ... 0 x08048e0d : CmpEQ32 ( And32 (8 Uto32 ( GET : I8 ( PUT (8 Uto32 ( LDle : I8 ( input (0) ) ) ) ) ) , 0 xff : I32 ) ,0 x0 : I32 ) = > 0 0 x08048e16 : CmpEQ8 (32 to8 (8 Uto32 ( GET : I8 ( PUT (8 Uto32 ( LDle : I8 ( input (0) ) ) ) ) ) ) , 0 x2d : I8 ) = > 0 0 x08048e26 : CmpEQ8 (32 to8 (8 Uto32 ( GET : I8 ( PUT (8 Uto32 ( LDle : I8 ( input (0) ) ) ) ) ) ) , 0 x2b : I8 ) = > 0 0 x08048e39 : CmpEQ8 (32 to8 (8 Uto32 ( GET : I8 ( PUT (8 Uto32 ( LDle : I8 ( input (0) ) ) ) ) ) ) , 0 x72 : I8 ) = > 1 ... Fig. 7. Extrait du r´sultat de l’ex´cution de l’outil sur le programme target. Les e e quatre lignes principales sont constitu´es de l’adresse de l’instruction de branchement e conditionnelle, la contrainte associ´e, suivi de 1 si le branchement a ´t´ pris ou 0 e ee sinon. Dans cet exemple, chaque contrainte compare le premier octet de l’entr´e ` e a une constante, et seul le dernier saut a ´t´ pris (le premier octet de l’entr´e est donc ee e ’r’ (0x72)). Les fichiers et l’entr´e standard sont les deux types d’entr´e support´es par l’outil. e e e La source d’entr´e suivie est sp´cifi´e par la ligne de commande. Si la source d’entr´e e e e e suivie est l’entr´e standard, toutes les donn´es provenant du descripteur de fichier e e 0 sont marqu´es. Dans le cas d’un fichier, l’appel syst`me open d´termine si le de- e e e scripteur de fichier doit ˆtre suivi ou non. Un descripteur de fichier arrˆte d’ˆtre suivi e e e lorsqu’il est ferm´ par l’appel syst`me close. Lorsque l’application cible effectue un e e appel syst`me ` read ou mmap et que le descripteur de fichier est suivi, les adresses e a e e ` auxquelles les donn´es sont lues ou mmapp´es sont marqu´es. A chaque donn´e lue e e marqu´e est associ´e une contrainte, correspondant au num´ro i de l’octet du fichier e e e lu ou mmap´, et repr´sent´e par input(i). e e e La propagation des contraintes est effectu´e par la fonction de l’outil responsable e de l’instrumentation de la repr´sentation interm´diaire issue de la phase 3. Les e e donn´es marqu´es sont les registres virtuels et temporaires de Valgrind, ainsi que les e e adresses m´moires et les registres du programme cible. Suivant les instructions de la e repr´sentation interm´diaire, une des actions suivantes doit ˆtre effectu´e : e e e e – Si l’instruction ne d´pend pas d’une donn´e marqu´e, celle-ci est ignor´e. e e e e – Si l’instruction effectue une op´ration sur une donn´e marqu´e, le temporaire e e e sauvegardant le r´sultat doit ˆtre marqu´, et la contrainte associ´e a l’op´ration e e e e ` e lui ˆtre associ´e. e e
    • G. Campana 223 – Si l’instruction effectue une op´ration sur une donn´e non marqu´e, mais le e e e temporaire sauvegardant le r´sultat est marqu´, alors il doit ˆtre d´marqu´. e e e e e – Enfin, si une condition d´pend d’une donn´e marqu´e, la contrainte associ´e est e e e e affich´e. e Ces actions sont effectu´es par des fonctions appel´es sur chaque instruction de la e e repr´sentation interm´diaire de Valgrind. e e G´n´ration, optimisation et r´solution des contraintes Une fois les conditions e e e de chemin affich´es, elles sont traduites dans le langage de STP avant d’ˆtre optimis´es, e e e invers´es, puis r´solues, comme le montre la figure 8. e e % cat v a lg ri nd _ ou tp ut . txt CmpEQ8 (32 to8 (8 Uto32 ( LDle : I8 ( input (0) ) ) ) ,0 x72 : I8 ) = > 0 CmpEQ8 (32 to8 (8 Uto32 ( LDle : I8 ( input (1) ) ) ) ,0 x00 : I8 ) = > 1 % ./ convert . py v al g ri nd _o u tp ut . txt x0 : BITVECTOR (8) ; x1 : BITVECTOR (8) ; QUERY ( NOT ( NOT ( x0 = 0 h72 ) AND ( x1 = 0 h00 ) ) ) ; Fig. 8. La sortie de Valgrind est compos´e de deux conditions associ´es a des instruc- e e ` tions de branchement : le premier octet de l’entr´e doit ˆtre ´gal a 0x72, est le second e e e ` a 0x00. Le premier branchement n’a pas ´t´ pris, le second si. Le script convert.py ` ee convertit ces conditions dans le langage STP. Toutes ces ´tapes sont effectu´es par un script Python qui parse la sortie de e e Valgrind afin de r´cup´rer chaque contrainte. Quelques optimisations basiques sont e e effectu´es pour r´duire la taille des contraintes et supprimer les doublons, avant d’ˆtre e e e converties dans le langage de STP. Les conditions des instructions conditionnelles sont ensuite invers´es puis r´solues une ` une. La r´solution des contraintes est e e a e effectu´e en enregistrant les contraintes dans un fichier, pass´ en entr´e a STP. STP e e e ` est capable d’afficher un contre-exemple (constitu´ de valeurs assign´es aux variables e e de la contrainte), lorsque la requˆte effectu´e est invalide. Cette propri´t´ est utilis´e e e ee e pour assigner ces nouvelles valeurs ` certains octets de l’entr´e. Les contraintes a e r´solues g´n`rent ainsi de nouveaux fichiers de test, qui d´couvriront de nouveaux e e e e chemins d’ex´cution. e
    • 224 Fuzzgrind : un outil de fuzzing automatique D´tection de fautes L’ex´cution du programme cible sur les fichiers g´n´r´s e e e ee d´couvre de nouveaux chemins d’ex´cution, susceptibles de d´clencher des bugs pou- e e e vant ´ventuellement ˆtre des vuln´rabilit´s. e e e e La d´tection de fautes est faite par un simple programme utilisant ptrace pour e examiner tous les signaux re¸us par le programme. Si l’un d’entre eux fait partie c d’une liste donn´e (SIGSEGV, SIGILL, SIGABORT, etc), alors l’entr´e de ce programme e e est consid´r´e comme d´clenchant un bug. Il faudra alors v´rifier manuellement si ee e e c’en est effectivement un, et le cas ´ch´ant, analyser si ce bug est exploitable ou non. e e Score Le programme associant un score a chaque entr´e calcule seulement le nombre ` e de basic block ex´cut´s. Ce fonctionnement est temporaire et doit ˆtre encore am´lior´. e e e e e 4 R´sultats e 4.1 R´sultats e Actuellement, les fichiers de test g´n´r´s par Fuzzgrind couvrent enti`rement l’es- e ee e pace des entr´es de programmes simples, appelant des fonctions de la libc (strcmp, e atoi, etc), et effectuant des op´rations sur des chaˆ e ınes de caract`res et des entiers. e Des vuln´rabilit´s jusqu’alors inconnues ont ´t´ d´couvertes dans les derni`res e e ee e e versions de readelf 9 et swfextract 10 en moins d’une heure. Ces vuln´rabilit´s ont e e ´t´ d´couvertes de fa¸on automatique en donnant a Fuzzgrind le programme cible et ee e c ` un fichier valide, et en attendant que les fichiers de test g´n´r´s d´clenchent une erreur. e ee e La version 3.8.2 de la biblioth`que libtiff 11 a ´t´ fuzz´e. Le programme cible e ee e (utilisant cette biblioth`que) est tiffinfo, et l’entr´e initiale est une image tiff de e e 2x2 pixels, de 961 octets. Une premi`re vuln´rabilit´ est trouv´e en 6 minutes. Au e e e e 12 cours d’un audit de cette biblioth`que, Tavis Ormandy avait d´j` d´couvert cette e ea e vuln´rabilit´. D´licate ` trouver manuellement, elle est ` l’origine des exploits 13 14 e e e a a permettant le d´blocage de la console PSP et de l’Iphone. e 9 http://www.gnu.org/software/binutils/ 10 http://www.swftools.org/swfextract.html 11 http://www.libtiff.org 12 http://www.scary.beasts.org/security/tavis_libtiff.txt 13 http://www.toc2rta.com/?q=node/23 14 http://www.maxconsole.net/?mode=news&newsid=9516
    • G. Campana 225 Chose amusante, les dix crackmes de IOLI 15 sont r´solus en quelques secondes, e apr`s avoir sp´cifi´ des variables d’environnement correctes. e e e Un nombre plus important de logiciels, ` jour ou non, devra ˆtre test´ afin a e e d’´valuer les capacit´s de Fuzzgrind ` effectivement trouver des vuln´rabilit´s dans e e a e e des programmes de taille cons´quente. e 4.2 Performances Les performances globales de Fuzzgrind d´pendent des performances des outils e utilis´s a chaque ´tape d’un cycle d’une session, compos´ de : e ` e e 1. l’ex´cution de Valgrind sur une entr´e donn´e, e e e 2. l’analyse des contraintes par un ensemble de scripts Python, 3. la r´solution des contraintes par STP, e 4. la d´tection de fautes ´ventuelles sur les nouvelles entr´es g´n´r´es, e e e e ee 5. l’assignation d’un score ` chaque nouvelle entr´e. a e Les performances de l’outil de Valgrind, d´velopp´ pour suivre et propager les e e conditions de chemin, sont acceptables. Les adresses, les registres, et les temporaires sont actuellement stock´s dans des tableaux statiques, qui sont parcourus a quasiment e ` chaque instruction. Leur remplacement par des tables de hachage devrait am´liorer e les performances. Les performances de STP sont quant a elles impressionnantes. La figure 9 pr´sente ` e quelques statistiques obtenues par l’ex´cution de STP sur des contraintes g´n´r´es e e ee par Fuzzgrind : Fig. 9. Temps d’ex´cution de STP sur des contraintes g´n´r´es par Fuzzgrind. e e ee nb de contraintes taille temps d’ex´cution e 1 95o 0.003s 102 21,4Ko 0.082s 1000 156,6Ko 0.349s 1251 189,4Ko 0.984s 15 http://radare.nopcode.org/wiki/index.php?n=Examples.Crackme
    • 226 Fuzzgrind : un outil de fuzzing automatique Le temps d’ex´cution de l’outil de d´tection de fautes est sensiblement le mˆme e e e que celui du programme test´ sans ptrace. e L’ex´cution de l’outil assignant un score a chaque fichier de test est relativement e ` lente, mais cet outil n’est cependant pas d´finitif. e La figure 10 pr´sente quelques statistiques sur les programmes suivants : e – strcmp : un simple programme faisant appel a la fonction strcmp, ` – readelf -h input.elf, o` input.elf est un binaire ELF stripp´ de 3Ko, u e – tiffinfo input.tiff, o` input.tiff est une image TIFF de 961 octets. u Fig. 10. Temps d’ex´cution de chaque ´tape du premier cycle d’une session, obtenues e e avec un processeur Intel Core 2 Duo a 2,40Ghz et poss´dant 3Go de RAM. ` e ´ Etape 1 2 3 4 5 strcmp 0s 0s 0s 0s 0s readelf 3s 36m 1h10 1s 56s tiffinfo 1s 5s 7m 1s 7s 4.3 Limitations L’analyse de programmes cons´quents entraˆ une explosion du nombre de e ıne chemins d’ex´cution possible. Il est possible de limiter le nombre de contraintes ` e a analyser, mais la couverture des chemins sera forc´ment r´duite. Si le programme e e ` analyser contient des fonctions cryptographiques (hash md5 par exemple), il est a envisageable de les d´sactiver (` moins qu’elles ne soient la cible des tests). e a Par ailleurs, Fuzzgrind ne suit que les contraintes sur des nombres entiers (de taille inf´rieure ou ´gale a 32 bits). Les contraintes sur les nombres flottants ne sont e e ` pas suivies. 4.4 Am´liorations envisageables e Valgrind pr´sente le tr`s grand avantage d’ˆtre un logiciel libre, en plus d’avoir des e e e performances correctes. Bien que supportant une multitude d’architectures, il ne fonc- tionne cependant que sur des syst`mes d’exploitation compatibles UNIX, limitant les e
    • G. Campana 227 applications pouvant ˆtre test´es par Fuzzgrind. Intel a de son cot´ d´velopp´ un outil e e e e e 16 d’instrumentation binaire dynamique, PIN , supportant la plupart des architectures Intel et les syst`mes d’exploitation Linux et Windows. D’apr`s les benchmarks publi´s e e e par Intel, ses performances seraient bien meilleures que celles de Valgrind. La licence de son noyau est cependant propri´taire (mais ses outils d’instrumentation sont libres). e Fuzzgrind suit actuellement les entr´es de type fichier et entr´e standard. Le suivi e e de ces entr´es est simple puisque les fichiers ouverts peuvent ˆtre filtr´s par leur e e e nom, et l’entr´e standard est toujours associ´e au descripteur de fichier 0. Il serait e e int´ressant d’´tendre les entr´es support´es aux entr´es r´seaux, ce qui est l´g`rement e e e e e e e e plus compliqu´. Cette am´lioration est envisageable par le suivi des appels syst`me e e e accept, connect, et socketpair ; et le filtrage des descripteurs de fichiers r´sultant e de ces appels grˆce ` l’appel syst`me getsockbyname (retournant des informations a a e sur les couple adresse IP/port source et destination). L’outil de calcul de score des nouvelles entr´es repose actuellement sur le plugin e 17 Lackey de Valgrind, destin´ a faire des statistiques sur l’ex´cution d’un programme. e` e Sa fonctionnalit´ de calcul approximatif du nombre de blocs basiques ex´cut´s est e e e utilis´ pour calculer les scores. Les performances et la pr´cision de ce plugin d’exemple e e restent d´sirables, et la fonction de calcul de score doit donc ˆtre am´lior´e. Bien que e e e e cons´quent a impl´menter, un outil d´terminant correctement la couverture de code e ` e e de l’ex´cution de chaque nouvelle entr´e serait assur´ment int´ressante. e e e e Enfin, les performances globales de l’outil peuvent encore ˆtre am´lior´es. Un e e e moteur de simplification des contraintes ainsi qu’un syst`me de cache augmenteraient e la vitesse d’ex´cution. e 5 Conclusion Bien que Fuzzgrind soit encore en d´veloppement intensif, les quelques vuln´rabilit´s e e e d´couvertes sont encourageantes et confirment que ses concepts sont prometteurs. e Son impl´mentation montre que la r´alisation d’outils de fuzzing compl`tement au- e e e tomatiques est possible, offrant la possibilit´ de tester la s´curit´ de logiciels sans e e e aucun pr´-requis. e 16 http://www.pintool.org 17 http://www.valgrind.org/docs/manual/lk-manual.html
    • 228 Fuzzgrind : un outil de fuzzing automatique R´f´rences ee 1. Vuagnoux, M. : Autodaf´ : an act of software torture. http://autodafe.sourceforge.net/paper/ e autodafe.pdf (2006) 2. Molnar, D., Wagner, D. : Catchconv : Symbolic execution and run-time type inference for integer conversion errors. http://www.eecs.berkeley.edu/Pubs/TechRpts/2007/EECS-2007-23.pdf 3. Zalewski, M. : Bunny the fuzzer. http://code.google.com/p/bunny-the-fuzzer/ 4. Drewry, W., Ormandy, T. : Flayer : exposing application internals. In : WOOT ’07 : Proceedings of the first USENIX workshop on Offensive Technologies. (2007) 1–9 5. Godefroid, P., Klarlund, N., Sen, K. : Dart : directed automated random testing. http://cm.bell-labs. com/who/god/public_psfiles/pldi2005.pdf (2005) 6. Sen, K., Marinov, D., Agha, G. : Cute : a concolic unit testing engine for c. http://srl.cs.berkeley. edu/~ksen/pubs/paper/C159-sen.pdf (2005) 7. Cadar, C., Ganesh, V., Pawlowski, P.M., Dill, D.L., Engler, D.R. : Exe : automatically generating inputs of death. http://www.stanford.edu/~engler/exe-ccs-06.pdf (2006) 8. Godefroid, P., Levin, M., Molnar, D. : Automated whitebox fuzz testing. http://research.microsoft. com/users/pg/public_psfiles/ndss2008.pdf (2008) 9. Nethercote, N., Seward, J. : Valgrind : a framework for heavyweight dynamic binary instrumentation. (2007) 10. Ganesh, V., Dill, D.L. : A Decision Procedure for Bit-Vectors and Arrays. PhD thesis (2007) 11. Brumley, D., Poosankam, P., Song, D., Zheng, J. : Automatic patch-based exploit generation is possible : Techniques and implications. http://www.cs.cmu.edu/~dbrumley/pubs/apeg.pdf (April 2008)