Segurança de AplicaçãoUncategorized

Construindo um fuzzer com Ruckus e DFuzz

Introdução

A comunidade de segurança da informação já está bastante acostumada com a palavra fuzzing. Para aqueles que ainda não conhecem, fuzzing é uma técnica de teste tendo como objetivo a descoberta de vulnerabilidades. Existem diversas ferramentas (fuzzers) disponíveis que implementam esta técnica. Neste post é apresentado alternativas Ruby-like para a realização de fuzzing, são elas: Ruckus[1] e DFuzz[2]. Primeiramente é apresentado o Ruckus, os principais tipos de dados que o mesmo é capaz de representar e como é possível através dele modelar um formato de dados. Em seguida é mostrado como o DFuzz pode ser utilizado para a realização de fuzzing. Por fim, é feita a combinação do Ruckus com o DFuzz para demonstrar que a dupla pode ser usada na construção de um smart fuzzer.

Ruckus

Ruckus é um smart fuzzer escrito em Ruby. Considera-se smart fuzzer as ferramentas que fazem fuzzing levando em consideração o tipo dos dados que estão sendo testados [3]. Com o Ruckus pode-se fazer a modelagem de formatos de dados (formato de arquivo ou protocolo) utilizando a própria linguagem Ruby para isto. Para começar a modelar uma estrutura basta criar uma nova classe herdando de Ruckus::Structure, conforme visto na Figura 1.

Figura 1: Modelagem de estrutura no Ruckus.

Tipos

Uma vez feito isto, é hora de representar os campos que o formato a ser testado contém. No Ruckus os principais tipos de dados disponíveis são: Number e Str.

Number, como o nome já diz, é usado para representar diversos tipos de inteiros. Para campos deste tipo é possível definir algumas características, conforme visto na tabela 1.

Tabela 1: Propriedades do Ruckus::Number

 


:width
Quantidade de bits do campo.
:endian
Representação em :big ou :little endian.
:ascii
Representação textual do campo (:true ou :false).
:radix
Definir base do número caso o campo seja textual.


Do tipo Number originaram-se outros tipos, são eles: byte, be16, be32, le16, le32, le64, be64, decimal, entre outros. Na Figura 2 pode-se ver um exemplo de definição de campos inteiros (be32 e be16).

 

Figura 2: Exemplo de campos inteiros.

Para um campo do tipo Str, também é possível definir características. Estas características podem ser vistas na tabela 2.

Tabela 2: Propriedades do Ruckus::Str

:size
Tamanho (absoluto) do campo (forçará padding se preciso).
:min
Tamanho mínimo do campo.
:max
Tamanho máximo do campo.
:padding
Caractere usado em caso de padding (padrão: ”)
:pad_to
Alinhamento do padding.
:unicode
Define se o campo deve ser unicode.
:nul_terminated
Define se o campo deve ser terminado com nulo.

Na Figura 3 pode-se observar um exemplo de uso do Str, neste exemplo é definido um campo chamado filename e setado seu valor padrão para “default.txt”.

  Figura 3: Definição do campo filename do tipo str.

Há outros campos interessantes que podem ser usados no Ruckus como: ipv4, bit e nibble. Com os tipos disponíveis é possível modelar diversos formatos de arquivos e protocolos.

Relação

O Ruckus é capaz de manter relações entre campos. Na definição do formato PseudoFileFormat existe o campo len que é um inteiro de 16 bits, big endian e o campo filename que contém uma string. Pode-se relacionar o campo len com o tamanho da string em filename. Toda vez que essa string for alterada este campo será automaticamente atualizado. Na Figura 4, pode-se ver a criação do relacionamento utilizando o método relate_value.

Figura 4: Relacionamento entre o campo len e o campo filename.

 

Resultado do PseudoFileFormat

Para visualização em hexdump o formato definido, foi utilizanda a gem Ruby BlackBag[4]. Pode-se observar na Figura 5 que o campo len é setado automaticamente para o tamanho da string filename. Na Figura 6 vemos que após a alteração de filename o campo len é atualizado para refletir a modificação.

format = PseudoFileFormat.new
puts format.to_s.hexdump

 

Figura 5: Visualização em hexadecimal do formato PseudoFileFormat. O campo len está destacado.

format.filename = “post.txt”
puts format.to_s.hexdump

 

Figura 6: Visualização em hexadecimal do formato PseudoFileFormat após modificação do campo filename. O campo len está destacado.

 

DFuzz

Embora exista a capacidade de fazer fuzzing utilizando somente o código do próprio Ruckus, para este post foi escolhido o DFuzz porque o mesmo possui uma interface mais amigável para condução dos testes. A boa notícia é que o DFuzz já vem embutido no Ruckus. Mas afinal, o que é o DFuzz? DFuzz é um código em Ruby escrito pelo pesquisador Dino Dai Zovi que provê uma série de inputs que podem ser utilizados para se testar sistemas. Os inputs são gerados de acordo com o tipo de dado a ser testado. Os principais tipos suportados pelo DFuzz são: Integer, Byte, Short, Long e String. Na Figura 7 é possível ver um exemplo de uso do DFuzz. Utilizando DFuzz::String é possível encontrar falhas como buffer overflows, format strings, path traversal, entre outros.

 

Figura 7: Exemplo de uso do DFuzz.

PseudoFuzzer

Para este post foi escrito um código a fim de exemplificar como o Ruckus e o DFuzz podem ser utilizados em conjunto para criação de uma ferramenta de fuzzing. Na Figura 8 segue o que seria um fuzzer para o PseudoFileFormat. Neste exemplo, o teste focou-se apenas no campo filename, mas o código poderia ser estendido para testar os outros campos. Nem o Ruckus, nem DFuzz possuem um mecanismo para monitorar as exceções que podem ocorrer durante os testes. Para isto foi feita uma abstração na linha 27.

Figura 8: Exemplo do que seria um fuzzer para o PseudoFileFormat

Conclusão

Utilizando o Ruckus é possível modelar um formato de dados e com o DFuzz pode-se obter inputs úteis para realização de fuzzing. Com a combinação destas duas ferramentas é possível a criação de smart fuzzers utilizando funcionalidades e facilidades que estão presentes na linguagem Ruby.

Referências

[1] https://github.com/tqbf/ruckus/
[2] https://github.com/tqbf/ruckus/blob/master/ruckus/dfuzz.rb
[3] http://peachfuzzer.com/SmartFuzzer
[4] https://github.com/emonti/rbkb
[5] http://www.matasano.com/research/ruby_for_pentesters/Ruby-For-Pentesters.pdf

Autor do Post

Ricardo Silva é estudante de Computação e atualmente trabalha como Analista de Segurança da Informação na Conviso. Como exploiter já contribuiu para o metasploit framework. Sua área de interesse inclui fuzzing, análise e exploração de vulnerabilidades, engenharia reversa, arquitetura de computadores e sistemas operacionais. Acredita que 0x41414141 é um número mágico!
Originalmente postado no Blog da Conviso Application Security – Siga-nos no Twitter @conviso Google+
About author

Articles

Uma equipe de profissionais, altamente conectados com as notícias, técnicas e informações sobre a segurança de aplicações.
Related posts
Code FightersSegurança de Aplicação

Como integrar o Semgrep no CI/CD e enviar os resultados para a Conviso Platform

Atualmente, é uma prática muito comum integrar verificações de segurança durante a fase de…
Read more
Segurança de Aplicação

Impactos Negativos Gerados pela Ausência de Logs e Monitoramento de Segurança

Primeiramente, os logs são registros de atividades gerados também por sistemas, aplicações e…
Read more
Segurança de Aplicação

Dockers e Containers

Containers são soluções cada vez mais populares na indústria de desenvolvimento de software.
Read more

Deixe um comentário