Software security : combining fuzzing and symbolic methods for vulnerability detection - Laboratoire Méthodes Formelles
Thèse Année : 2021

Software security : combining fuzzing and symbolic methods for vulnerability detection

Fuzzing et méthodes symboliques pour la détection de vulnérabilités à large échelle

Résumé

As computer programs spread, the risk of bugs increases. In this thesis, we want to find possible bugs in finished and released programs. We do this through automatic test generation, a major topic in software engineering and security. A complement to hand-crafted tests, test generators automatically build test suites, aiming to maximize program coverage and minimize human effort. Currently, most test generation techniques and tools studied by researchers and applied in industry rely on some form of either symbolic execution or fuzzing.- Symbolic execution aim to exhaustively explore the possible execution paths. It achieves this by executing each path on a symbolic input, and infering a constraint on said input. When the analysis reaches the end of a path, this constraint is a path predicate, and a concrete execution of the program on any of its solution will follow the intended path. Such test cases are generated using an off-the-shelf solver, and form the test suite. However, it is not always possible to explore all paths in reasonable time, and we often have to bound the exploration.- Fuzzing aims to run the program on many test cases, in order to hopefully trigger all possible paths. As such, it relies on quick and easy test case generation. While the most basic fuzzers function in a blackbox manner and generate random test cases independently from the program, greybox fuzzers also rely on an analysis to gain some information about the program. This information is then used to make the test case generation more efficient. However, despite this improvement, fuzzers still struggle with finding the solution to conditions that have a low probability of being true, such as password checks. Hence, symbolic execution and fuzzing exhibit rather complementary strengths and weaknesses, calling for a proper integration between the two techniques. During this thesis, we developed an automated test generation technique, combining the reasoning power of symbolic execution to tackle complex code with the light cost of greybox fuzzing to generate test cases efficiently. The solution we propose combines two novel ideas: Lightweight Symbolic Execution (LSE) and Constrained Fuzzing. Lighweight Symbolic Execution is a variant of symbolic execution where the analysis targets a condition on a path, rather than a full path, and the target constraint language is restricted to an easily-enumerable fragment of the usual one. As a consequence, deriving (correct) path predicates in this language is more complicated but test cases following a given path are then easy to enumerate, without using any off-the-shelf constraint solver. Second, a Constrained Fuzzer operates over a test case and an easily-enumerable constraint in order to quickly generate test cases which follow the intended path, up to the targeted condition. Overall, LSE will lead the exploration past difficult conditions and towards interesting parts of the code, while the constrained fuzzer will efficiently create test cases, including solutions to the constraints. This allows us to explore the program without systematically relying on symbolic analysis, and removes the need for an SMT solver to create test cases satisfying the constraints. We evaluated the performances of the resulting tool, called ConFuzz, on a standard fuzzing benchmark, and found that we improved upon the performance of standard fuzzing and symbolic execution.
Alors que les programmes informatiques se répandent, le risque de bugs augmente. Dans cette thèse, nous voulons trouver d'éventuels bugs dans des programmes finis et publics. Pour cela, nous utilisons la génération automatique de tests. Complémentant les tests écrits à la main, les générateurs de tests fabriquent automatiquement une série de tests, avec pour but de maximiser la couverture de code et de minimiser l'effort humain. Actuellement, les techniques de génération de test les plus répandues dans l'académique et dans l'industrie sont basées sur l'exécution symbolique ou le fuzzing.- L'exécution symbolique vise à explorer complètement les chemins d'exécution. Pour cela, chaque chemin est exécuté sur une entrée symbolique, et une contrainte est inférée sur cette entrée. Quand l'analyse atteint la fin d'un chemin, cette contrainte est un prédicat de chemin, et l'exécution concrète du programme sur n'importe laquelle de ses solutions suivra le chemin voulu. De telles entrées concrètes sont générées avec un solveur de contraintes, et forment la série de tests. Cependant, il n'est pas toujours possible d'explorer tous les chemins en un temps raisonnable, et il est souvent nécessaire de borner l'exploration.- Le fuzzing vise à exécuter le programme sur de nombreuses entrées, en espérant explorer tous les chemins possibles. Il dépend donc d'une génération d'entrées rapide et facile. Tandis que les fuzzers de base fonctionnent en boîte noire et génèrent des entrées aléatoires indépendamment du programme, les fuzzers en boîte grise utilisent une analyse pour obtenir des informations à propos du programme. Ces informations sont alors utilisées pour améliorer la génération d'entrées. Cependant, malgré ces améliorations, les fuzzers ont toujours de la difficulté à trouver la solution de conditions qui ont une faible probabilité d'être vraies. Ainsi, l'exécution symbolique et le fuzzing exhibent des forces et des faiblesses complémentaires, nous poussant à les combiner. Pendant cette thèse, nous avons développé une technique de génération de test automatisée, qui combine la puissance de raisonnement de l'exécution symbolique pour s'attaquer au code complexe, et le faible coût du fuzzing pour générer des entrées efficacement. La solution que nous proposons combine deux nouvelles idées: l'Exécution Symbolique Légère (ESL) et le Fuzzing Contraint. L'Exécution Symbolique Légère est une variante de l'exécution symbolique où l'analyse s'arrête sur une condition d'un chemin, plutôt qu'à la fin, et le langage de contraintes ciblé est réduit à un fragment facilement énumérable de l'habituel. Par conséquent, dériver des prédicats de chemin (corrects) dans ce langage est plus compliqué, mais il est facile d'énumérer des entrées exerçant un chemin, sans utiliser de solveur de contraintes. Deuxièmement, le Fuzzer Contraint manipule une entrée et une contrainte facilement énumérable, et génère de nouvelles entrées qui satisfont la contrainte et suivent donc le chemin, jusqu'à la condition ciblée. En général, l'ESL guidera l'exploration au-delà des conditions difficiles et vers les parties intéressantes du code, tandis que le fuzzer contraint créera efficacement des entrées, y compris des solutions aux contraintes. Cela nous permet d'explorer le programme sans systématiquement faire appel à l'analyse symbolique, et supprime la dépendance à un solveur pour créer des entrées satisfaisant les contraintes. Nous avons évalué les performances de l'outil utilisant ces techniques, appelé ConFuzz, sur un banc de tests standard du fuzzing. La conclusion de cette expérimentation est que ConFuzz a de meilleures performances que l'état de l'art du fuzzing et de l'exécution symbolique.
Fichier principal
Vignette du fichier
96762_VINCONT_2021_archivage.pdf (876.2 Ko) Télécharger le fichier
Origine Version validée par le jury (STAR)

Dates et versions

tel-03652389 , version 1 (26-04-2022)

Identifiants

  • HAL Id : tel-03652389 , version 1

Citer

Yaëlle Vinçont. Software security : combining fuzzing and symbolic methods for vulnerability detection. Cryptography and Security [cs.CR]. Université Paris-Saclay, 2021. English. ⟨NNT : 2021UPASG112⟩. ⟨tel-03652389⟩
220 Consultations
322 Téléchargements

Partager

More