Codificação segura é uma prática muito difícil. Normalmente, quando os programadores desenvolvem software, o seu objectivo é fazer o software funcionar em vez de quebrar. Neste processo, podem desenvolver-se vulnerabilidades nos casos em que foi utilizada uma função herdada em vez de uma função mais segura. Consequentemente, software legado é especialmente vulnerável.
C é uma daquelas linguagens que é inerentemente muito versátil e poderosa, mas tem um inconveniente crítico – a segurança de software baseado em C depende do conhecimento do programador. Isto significa que se o programador estiver bem ciente da codificação segura, o seu software também estará seguro. Por outro lado, e isto forma a maior parte, se o programador não for suficientemente sofisticado, haverá lacunas no seu software que acabarão por levar a um exploit.
Para pessoas como eu, que conhecem programação mas são novas na indústria da segurança, é muito importante estudar código vulnerável e compreender as possíveis consequências. Isso ajuda a refinar as habilidades de codificação e desenvolver uma atitude de ataque DURANTE a fase de codificação ao invés de DEPOIS de codificar todo o software.
Com toda honestidade, é bastante complicado estudar o código fonte completo de uma aplicação quando se procura por vulnerabilidades como estouros de buffer. Embora este método tenha seus próprios méritos, ele não é o método mais fácil de encontrar vulnerabilidades simples que podem ser críticas. Tais vulnerabilidades devem ser imediatamente resolvidas e a maneira mais fácil de encontrá-las é através de uma técnica chamada Fuzzing.
Fuzzing é uma técnica para encontrar vulnerabilidades “fáceis” no código, enviando dados gerados “aleatoriamente” para um executável. Em geral, existem três tipos de fuzzers:
Mutation: Um tipo de fuzzing “burro” onde amostras de entrada mal-formadas são geradas e fornecidas ao executável. Esse input pode ou não estar de acordo com o tipo de input esperado pela aplicação, portanto a probabilidade de encontrar bugs reais não é alta.
Generation: Um tipo de fuzzing “inteligente” que requer alguns dados de teste iniciais a partir dos quais o algoritmo fuzzer pode gerar um input malformado a partir do zero. Este tipo de fuzzing é melhor que o fuzzing burro em muitos casos porque o programa recebe a entrada que espera.
Evolucionário: Estes tipos de fuzzers usam feedback de cada “fuzz” para aprender ao longo do tempo o formato do input.
Neste post, vamos ver o fuzzing com o American Fuzzy Lop (AFL). É um tipo de fuzzer evolutivo que é adequado para programas fuzz que recebem input do STDIN ou de um arquivo.