Software vulnerabilities remain one of the most significant threats challenging information security. Memory-unsafe programming languages such as C/C++ allow bugs that could be maliciously exploited in order to tamper with the system, exposing users to risk. Fuzzing is a widespread and effective software testing technique for discovering unknown security vulnerabilities, which consists in executing a program continuously with a large number of random inputs to cause a crash. Most state-of-the-art fuzzers are coverage-based, i.e., they leverage the code coverage to favour inputs that contribute at exploring new paths. The coverage is collected by instrumenting the program source code at compile time; and, intuitively, a higher code coverage can lead fuzzers to find more bugs. However, when it comes to fuzzing binary-only software (source-unavailable), compiler instrumentation is not possible, subjecting the field to further research. revng is a reverse engineering framework based on LLVM. It features a static binary translation tool that translates machine code into LLVM IR, a higher-level intermediate representation, independent from the input architecture, and suitable to perform a variety of analyses and transformations. From a security standpoint, it allows to instrument programs in order to analyze their behavior. In this work, we propose a novel framework based on revng and libFuzzer, the LLVM fuzz testing library, to perform coverage-guided binary fuzzing of executable programs. We show that our approach is fast, semantic-preserving and simply requires to implement the so-called fuzz target, a dedicated function that the fuzzer calls to pass its inputs to the interesting functions to fuzz, just as occurs for programs with source code available. We evaluate our framework on a real-world vulnerability and we show we manage to reproduce the bug successfully.

Le vulnerabilità nel software continuano ad essere una delle minacce che la sicurezza informatica si trova ad affrontare. La mancata gestione automatica della memoria in linguaggi come C/C++ può causare errori di programmazione tali da essere sfruttati da malintenzionati per rubare dati sensibili o scalare i privilegi. In questo contesto, il fuzzing si configura come una tecnica di comprovata efficacia di ricerca di vulnerabilità, la quale consiste nell'eseguire un programma ripetutamente con input anomali al fine di causare un crash di quest'ultimo. I fuzzer più moderni fanno uso di coverage, ossia favoriscono input che contribuiscono a esplorare nuove aree del programma misurando quali zone di codice sono state eseguite finora. La coverage è raccolta con apposita instrumentazione del codice sorgente a tempo di compilazione, e intuitivamente, più alta è la coverage, più sono alte le possibilità di far sì che il fuzzer trovi bug. Tuttavia, quando si tratta di effettuare fuzzing su programmi di cui non si dispone del codice sorgente, instrumentare il codice non è più un'opzione fattibile. Ciò rende il fuzzing di software chiuso ancora area di ricerca. revng, un framework per attività di reverse engineering basato su LLVM, dispone di uno strumento che è in grado di tradurre codice macchina in LLVM IR: una rappresentazione intermedia ad alto livello indipendente dall'architettura d'origine, particolarmente adatta per svolgere analisi di programmi. Da un punto di vista della sicurezza, permette di instrumentare programmi al fine di analizzarne il loro comportamento. In questa tesi, proponiamo un nuovo framework basato su revng e su libFuzzer, la libreria di fuzzing parte di LLVM, per poter effettuare coverage-guided fuzzing di programmi di cui non si dispone del codice sorgente. Mostriamo come il nostro approccio sia veloce, preservi la funzionalità del programma originale e richieda semplicemente di implementare la funzione apposita per poter fare fuzzing, proprio come avviene per i programmi con codice sorgente disponibile. Testiamo il nostro framework su una vulnerabilità vera e propria e mostriamo come siamo in grado di riprodurre il bug con successo.

Coverage-guided binary fuzzing with REVNG and LLVM libfuzzer

Frighetto, Antonio
2019/2020

Abstract

Software vulnerabilities remain one of the most significant threats challenging information security. Memory-unsafe programming languages such as C/C++ allow bugs that could be maliciously exploited in order to tamper with the system, exposing users to risk. Fuzzing is a widespread and effective software testing technique for discovering unknown security vulnerabilities, which consists in executing a program continuously with a large number of random inputs to cause a crash. Most state-of-the-art fuzzers are coverage-based, i.e., they leverage the code coverage to favour inputs that contribute at exploring new paths. The coverage is collected by instrumenting the program source code at compile time; and, intuitively, a higher code coverage can lead fuzzers to find more bugs. However, when it comes to fuzzing binary-only software (source-unavailable), compiler instrumentation is not possible, subjecting the field to further research. revng is a reverse engineering framework based on LLVM. It features a static binary translation tool that translates machine code into LLVM IR, a higher-level intermediate representation, independent from the input architecture, and suitable to perform a variety of analyses and transformations. From a security standpoint, it allows to instrument programs in order to analyze their behavior. In this work, we propose a novel framework based on revng and libFuzzer, the LLVM fuzz testing library, to perform coverage-guided binary fuzzing of executable programs. We show that our approach is fast, semantic-preserving and simply requires to implement the so-called fuzz target, a dedicated function that the fuzzer calls to pass its inputs to the interesting functions to fuzz, just as occurs for programs with source code available. We evaluate our framework on a real-world vulnerability and we show we manage to reproduce the bug successfully.
DI FEDERICO, ALESSANDRO
GUSSONI, ANDREA
ING - Scuola di Ingegneria Industriale e dell'Informazione
28-apr-2021
2019/2020
Le vulnerabilità nel software continuano ad essere una delle minacce che la sicurezza informatica si trova ad affrontare. La mancata gestione automatica della memoria in linguaggi come C/C++ può causare errori di programmazione tali da essere sfruttati da malintenzionati per rubare dati sensibili o scalare i privilegi. In questo contesto, il fuzzing si configura come una tecnica di comprovata efficacia di ricerca di vulnerabilità, la quale consiste nell'eseguire un programma ripetutamente con input anomali al fine di causare un crash di quest'ultimo. I fuzzer più moderni fanno uso di coverage, ossia favoriscono input che contribuiscono a esplorare nuove aree del programma misurando quali zone di codice sono state eseguite finora. La coverage è raccolta con apposita instrumentazione del codice sorgente a tempo di compilazione, e intuitivamente, più alta è la coverage, più sono alte le possibilità di far sì che il fuzzer trovi bug. Tuttavia, quando si tratta di effettuare fuzzing su programmi di cui non si dispone del codice sorgente, instrumentare il codice non è più un'opzione fattibile. Ciò rende il fuzzing di software chiuso ancora area di ricerca. revng, un framework per attività di reverse engineering basato su LLVM, dispone di uno strumento che è in grado di tradurre codice macchina in LLVM IR: una rappresentazione intermedia ad alto livello indipendente dall'architettura d'origine, particolarmente adatta per svolgere analisi di programmi. Da un punto di vista della sicurezza, permette di instrumentare programmi al fine di analizzarne il loro comportamento. In questa tesi, proponiamo un nuovo framework basato su revng e su libFuzzer, la libreria di fuzzing parte di LLVM, per poter effettuare coverage-guided fuzzing di programmi di cui non si dispone del codice sorgente. Mostriamo come il nostro approccio sia veloce, preservi la funzionalità del programma originale e richieda semplicemente di implementare la funzione apposita per poter fare fuzzing, proprio come avviene per i programmi con codice sorgente disponibile. Testiamo il nostro framework su una vulnerabilità vera e propria e mostriamo come siamo in grado di riprodurre il bug con successo.
File allegati
File Dimensione Formato  
2021_04_Frighetto.pdf

accessibile in internet per tutti

Dimensione 2.69 MB
Formato Adobe PDF
2.69 MB Adobe PDF Visualizza/Apri

I documenti in POLITesi sono protetti da copyright e tutti i diritti sono riservati, salvo diversa indicazione.

Utilizza questo identificativo per citare o creare un link a questo documento: https://hdl.handle.net/10589/173614