
Manul é um fuzzer paralelo guiado por cobertura para binários de código aberto e blackbox no Windows, Linux e MacOS.

O Manul é um fuzzer paralelo guiado por cobertura para binários de código aberto e caixa-preta no Windows, Linux e macOS (beta) escrito em Python puro.
pip3 install psutil
git clone https://github.com/mxmssh/manul
cd manul
mkdir in
mkdir out
echo "AAAAAA" > in/test
python3 manul.py -i in -o out -n 4 "linux/test/test_afl @@"
sudo apt-get install gcc make git wget
git clone https://gitlab.com/akihe/radamsa.git && cd radamsa && make && sudo make install
Não há necessidade de instalar o radamsa no Windows, o Manul é distribuído com a biblioteca nativa do radamsa nesta plataforma.
| CVE IDs | Produto | Descobridor |
|---|---|---|
| CVE-2019-9631 CVE-2019-7310 CVE-2019-9959 | Poppler | Maksim Shudrak |
| CVE-2018-17019 CVE-2018-16807 CVE-2019-12175 | Bro/Zeek | Maksim Shudrak |
Se você conseguiu encontrar um novo bug usando o Manul, entre em contato comigo e eu o adicionarei na lista.

pip install pywin32) na plataforma Windows (necessário apenas para o modo de persistência DBI).Atualmente, o Manul suporta dois tipos de instrumentação: baseada em AFL (afl-gcc, afl-clang e afl-clang-fast) e DBI.
Instrumente seu alvo com afl-gcc ou afl-clang-fast e Address Sanitizer (recomendado para melhores resultados). Por exemplo:
CC=afl-gcc CXX=afl-g++ CFLAGS=-fsanitize=address CXXFLAGS=-fsanitize=address cmake <path_to_your_target>
make -j 8
USE_ASAN=1 CC=afl-clang-fast CXX=afl-clang-fast++ cmake <path_to_your_target>
make -j 8
Veja estas instruções para mais detalhes.
Você não precisa instrumentar seu alvo neste modo, mas precisa baixar a versão mais recente do framework DynamoRIO para Windows ou Linux.
O Manul é distribuído com clientes pré-compilados x86/x64 para Linux e Windows. Você pode encontrá-los nas seguintes pastas:
linux/dbi_32|dbi_64/libbinafl.so (DynamoRIO client)
win/dbi_32|dbi_64/binafl.dll
Infelizmente, o DynamoRIO não é oficialmente suportado no MacOS.
Você pode encontrar os pacotes de lançamento mais recentes do DynamoRIO na página de download do DynamoRIO.
Você precisa descomentar as seguintes linhas no arquivo manul.config e fornecer o caminho correto para o lançador e cliente do DynamoRIO.
# Choose DBI framework to provide coverage back to Manul ("dynamorio" or "pin"). Example dbi = dynamorio
dbi = dynamorio
# If dbi parameter is not None the path to dbi engine launcher and dbi client should be specified.
dbi_root = /home/max/DynamoRIO/bin64/drrun
dbi_client_root = /home/max/manul/linux/dbi_64/libbinafl.so
dbi_client_libs = None
Além disso, você pode aumentar o desempenho da sua campanha de fuzzing caixa-preta usando fuzzing persistente em memória. Neste modo, você deve instruir o Manul a instrumentar uma função específica (sim, você precisa encontrá-la desmontando seu binário) e ele a executará em um loop descomentando as seguintes linhas:
dbi_persistence_mode = 1
dbi_target_module = afl_test
dbi_target_method = open_file
#dbi_target_offset = 0x3198 # optionally you can provide offset of this function instead of name
dbi_fuzz_iterations = 1000
Os autores do winAFL fornecem uma explicação muito boa sobre como isso realmente funciona aqui. O Manul usa uma grande parte do código da biblioteca de instrumentação do winAFL para se comunicar e instrumentar um alvo.
NOTA IMPORTANTE: Você deve usar o lançador de 32 bits e o cliente de 32 bits para fuzzear binários de 32 bits e o lançador de 64 bits e o cliente de 64 bits para binários de 64 bits!
Para compilar a biblioteca de instrumentação, você precisa usar a versão mais recente do DynamoRIO. O código fonte da biblioteca de instrumentação pode ser encontrado em dbi_clients_src localizado na pasta principal do Manul.
64-bit Linux
cd dbi_clients_src
wget <DynamoRIO-x86_64-Linux-X.XX.XXXX-X.tar.gz> - download the latest DynamoRIO
tar xvf DynamoRIO-x86_64-X.XX.XXXX-X.tar.gz
mkdir client_64
cd client_64
cmake ../dr_cov/ -DDynamoRIO_DIR=/home/max/manul/dbi_clients_src/DynamoRIO-x86_64-Linux-X.XX.XXXX-X.tar.gz/cmake
make
32-bit Linux
cd dbi_clients_src
wget <DynamoRIO-i386-Linux-X.XX.XXXX-X.tar.gz> - download the latest DynamoRIO
tar xvf DynamoRIO-x86_64-X.XX.XXXX-X.tar.gz
mkdir client_64
cd client_64
CFLAGS=-m32 CXXFLAGS=-m32 cmake ../dr_cov/ -DDynamoRIO_DIR=/home/max/manul/dbi_clients_src/DynamoRIO-i386-Linux-X.XX.XXXX-X.tar.gz/cmake
make
No Windows, a maneira mais fácil de compilar a biblioteca seria instalar o Visual Studio (testado nas versões 2017 e 2013), iniciar o VS20XX Cross Tools Command Prompt e executar os seguintes comandos:
64-bit Windows
cd dbi_clients_src
<Download and extract the latest version of DynamoRIO>
mkdir client_64
cd client_64
cmake -G"Visual Studio 15 Win64" ..\dr_cov\ -DDynamoRIO_DIR=C:\Users\max\manul\dbi_clients_src\DynamoRIO-Windows-XXXX.XX.X.X\cmake
cmake --build . --config RelWithDebInfo (or just Debug if needed)
32-bit Windows
cd dbi_clients_src
<Download and extract the latest version of DynamoRIO>
mkdir client_32
cd client_32
cmake -G"Visual Studio 15" ..\dr_cov\ -DDynamoRIO_DIR=C:\Users\max\manul\dbi_clients_src\DynamoRIO-Windows-XXXX.XX.X.X\cmake
cmake --build . --config RelWithDebInfo (or just Debug if needed)
O Manul inicialmente suportava fuzzing guiado por cobertura com Intel PIN, mas devido ao baixo desempenho e alta sobrecarga de manutenção, isso não é mais suportado.
As opções mais usadas podem ser fornecidas via linha de comando. Mais opções são suportadas usando o arquivo de configuração (manul.config).
Example: python3 manul.py -i corpus -o out_dir -n 40 "target @@"
argumentos posicionais:
target_binary O binário alvo e opções a serem executados (não esqueça de incluir aspas, ex.: "target e @@").
argumentos opcionais:
-h, --help mostra esta mensagem de ajuda e sai
-n NFUZZERS Número de fuzzers paralelos
-s Executar fuzzing burro (sem instrumentação de código)
-c CONFIG Caminho para o arquivo de configuração com opções adicionais (veja a seção Opções do Arquivo de Configuração abaixo)
-r Restaurar sessão anterior
Parâmetros obrigatórios:
-i INPUT Caminho para o diretório com o corpus inicial
-o OUTPUT Caminho para o diretório de saída
O Manul é distribuído com o arquivo padrão manul.config onde o usuário pode encontrar todas as opções suportadas e exemplos de uso. As opções devem ser especificadas no seguinte formato Formato: <nome_da_opção> = <valor>. O símbolo # pode ser usado para ignorar uma linha.
dict = /home/max/dictionaries/test.dict. A estratégia de mutação do AFL permite que o usuário especifique uma lista de tokens personalizados que podem ser inseridos em lugares aleatórios no arquivo fuzzeado. O Manul suporta esta funcionalidade através desta opção (caminhos absolutos preferidos).
mutator_weights=afl:7,radamsa:2,my_mutator:1. Os pesos dos mutadores permitem que o usuário informe ao Manul quantas mutações por 10 execuções devem ser realizadas por um determinado fuzzer. Neste exemplo, o mutador AFL será executado em 7/10 mutações, Radamsa 2/10 e algum mutador personalizado my_mutator receberá 1/10. Se você quiser desabilitar um determinado mutador, o peso deve ser atribuído a 0 (ex.: mutator_weights=afl:0,radamsa:1,my_mutator:9).
deterministic_seed = False|True. Ao fornecer True, as mutações do Radamsa se tornarão determinísticas, fazendo com que cada execução do Manul leve às mesmas saídas.
print_per_thread = False|True. Ao habilitar esta opção, o Manul imprimirá um resumo para cada thread sendo executada em vez do resumo total.
disable_volatile_bytes = False|True Ao habilitar esta opção, o Manul não colocará caminhos voláteis na lista negra.
forkserver_on = False|True Habilitar ou desabilitar o forkserver do AFL.
dbi = dynamorio|pin. Esta opção informa ao Manul qual framework DBI será usado para instrumentar o alvo.
dbi_root = <path>. Esta opção informa ao Manul onde encontrar o lançador principal do framework DBI.
dbi_client_root = <path>. Esta opção informa ao Manul onde encontrar o cliente DBI para realizar a instrumentação.
dbi_client_libs = name_#1,name_#2|None. Esta opção pode ser usada para especificar a lista de bibliotecas que precisam ser instrumentadas junto com o alvo principal (ex.: você tem um executável que carrega a biblioteca alvo e várias outras onde você quer procurar por bugs).
dbi_persistence_mode = 0|1|2. Esta opção é usada para escolher entre os modos persistentes DBI. 0 - sem persistência, 1 - persistência padrão (wrapping de função), 2 - ainda não suportado.
Se dbi-persistence_mode = 1|2 as seguintes opções devem ser especificadas:
dbi_target_module = <module name>. O Manul tentará buscar a função alvo no módulo especificado aqui.
dbi_target_method = <function name>. Nome da função a ser envolvida para persistência.
dbi_target_offset = <offset of function e.g. 0x3198>. Offset da função a ser envolvido para persistência. Esta opção pode ser usada em vez de dbi_target_method se os símbolos de depuração não estiverem disponíveis.
dbi_fuzz_iterations = 500. O número de iterações de fuzzing para executar em memória antes que todo o programa reinicie. Você pode ajustar este argumento para encontrar o valor que funciona melhor com seu alvo.
dbi_thread_coverage = False. Instrumentar cobertura apenas a partir de uma thread que executou a função alvo (ainda não suportado).
timeout = 10. Tempo de espera antes de matar o alvo e enviar o próximo caso de teste.
init_wait = 1. Esta opção pode ser usada para configurar um tempo limite necessário para o alvo inicializar.
As opções net_config_master e net_config_slave são usadas para distribuir instâncias do Manul pela rede. Você deve realizar os seguintes 3 passos para executar fuzzing distribuído.
IP:porta onde seus slaves serão executados.net_config_slave = 0.0.0.0:1337. O Manul iniciará a instância e aguardará a conexão de entrada da instância master na porta 1337.net_config_master = nome_do_arquivo.debug = False|True - imprime informações de depuração.
logging_enable = False|True - salva informações de depuração no log.
manul_logo = False|True - imprime o logotipo do Manul no início.
no_stats = False|True - salvar estatísticas.
sync_freq = 10000. Permite ao usuário alterar a frequência de sincronização do bitmap de cobertura. Esta opção informa ao Manul com que frequência ele deve sincronizar a cobertura entre instâncias de fuzzing paralelas. Um valor menor diminui o desempenho, mas aumenta a coordenação entre as instâncias.
#custom_path = test_path - esta opção permite salvar o caso de teste na pasta personalizada (se o alvo quiser carregá-lo de algum lugar predefinido).
cmd_fuzzing = True|False. Se esta opção estiver habilitada, o Manul fornecerá a entrada no alvo via linha de comando em vez de salvar no arquivo.
user_signals = 6,2,1|None. O usuário pode informar ao Manul quais sinais do alvo devem ser ignorados (não considerados como crash).
target_ip_port = 127.0.0.1:7715|None - usado para especificar IP e PORTA do alvo.
target_protocol = tcp|tcp - usado para especificar o protocolo para enviar entrada no alvo pela rede.
net_sleep_between_cases = 0.0. Esta opção pode ser usada para definir um atraso entre os casos de teste enviados ao alvo.
Atualmente, o fuzzing em rede é um recurso experimental (veja as issues para mais detalhes).
Um mutador personalizado pode ser adicionado nos seguintes três passos: Passo 1. Crie um arquivo python (.py) e dê a ele algum nome (ex.: example_mutator.py)
Passo 2. Crie duas funções def init(fuzzer_id) e def mutate(data). Veja example_mutator para mais detalhes. O Manul chamará a função init durante a inicialização do fuzzing e mutate para cada arquivo sendo fornecido no alvo.
Passo 3. Habilite o mutador especificando seu nome usando mutator_weights em manul.config. Ex.: mutator_weights=afl:2,radamsa:0,example_mutator:8.
NOTA: Os mutadores AFL e Radamsa devem sempre ser especificados. Se você quiser desabilitar AFL e/ou Radamsa, basta atribuir pesos 0 a eles.
TBD
