
O fuzzer de processador x86
: o fuzzer de processadores x86
O sandsifter audita processadores x86 em busca de instruções ocultas e bugs de hardware, gerando sistematicamente código de máquina para percorrer o conjunto de instruções de um processador e monitorando a execução em busca de anomalias. O sandsifter já revelou instruções secretas de processadores de todos os principais fornecedores; bugs de software onipresentes em desmontadores, montadores e emuladores; falhas em hipervisores empresariais; e bugs de hardware, tanto benignos quanto críticos para a segurança, em chips x86.
Com a multitude de processadores x86 existentes, o objetivo da ferramenta é permitir que os usuários verifiquem seus próprios sistemas em busca de instruções ocultas e bugs.
Para executar uma auditoria básica no seu processador:
sudo ./sifter.py --unk --dis --len --sync --tick -- -P1 -t

O computador é sistematicamente varrido em busca de instruções anômalas. Na metade superior, você pode ver as instruções que o sandsifter está testando atualmente no processador. Na metade inferior, o sandsifter relata as anomalias que encontra.
A busca levará de algumas horas a alguns dias, dependendo da velocidade e da complexidade do seu processador. Quando terminar, resuma os resultados:
./summarize.py data/log

Normalmente, vários milhões de instruções não documentadas serão encontrados no seu processador, mas geralmente se enquadram em um pequeno número de grupos diferentes. Após agrupar as anomalias, a ferramenta summarize tenta atribuir cada instrução a uma categoria de problema:
Pressione 'Q' para sair e obter um resumo em texto da varredura do sistema:
Os resultados de uma varredura às vezes podem ser difíceis de classificar automaticamente pelas ferramentas, e podem exigir análise manual. Para obter ajuda na análise dos seus resultados, sinta-se à vontade para enviar o arquivo ./data/log para [email protected]. Nenhuma informação pessoal, além da marca, modelo e revisão do processador (de /proc/cpuinfo), está incluída neste log.
A varredura com o sandsifter revelou recursos não documentados de processadores em dezenas de categorias de opcodes, falhas em hipervisores empresariais, bugs em quase todas as principais ferramentas de desmontagem e emulação, e bugs críticos de hardware que abrem vulnerabilidades de segurança no próprio processador.
Detalhes dos resultados podem ser encontrados no whitepaper do projeto.
(TODO: enumeração detalhada dos resultados aqui)
O sandsifter exige primeiro a instalação do desmontador Capstone: http://www.capstone-engine.org/. O Capstone normalmente pode ser instalado com:
sudo apt-get install libcapstone3 libcapstone-dev
sudo pip install capstone
O sandsifter pode ser compilado com:
make
e então é executado com
sudo ./sifter.py --unk --dis --len --sync --tick -- -P1 -t
As flags são passadas para o sifter com --flag, e para o injetor com -- -f.
Exemplo:
sudo ./sifter.py --unk --dis --len --sync --tick -- -P1 -t
Flags do sifter:
--len
search for length differences in all instructions (instructions that
executed differently than the disassembler expected, or did not
exist when the disassembler expected them to
--dis
search for length differences in valid instructions (instructions that
executed differently than the disassembler expected)
--unk
search for unknown instructions (instructions that the disassembler doesn't
know about but successfully execute)
--ill
the inverse of --unk, search for invalid disassemblies (instructions that do
not successfully execute but that the disassembler acknowledges)
--tick
periodically write the current instruction to disk
--save
save search progress on exit
--resume
resume search from last saved state
--sync
write search results to disk as they are found
--low-mem
do not store results in memory
Flags do injetor:
-b
mode: brute force
-r
mode: randomized fuzzing
-t
mode: tunneled fuzzing
-d
mode: externally directed fuzzing
-R
raw output mode
-T
text output mode
-x
write periodic progress to stderr
-0
allow null dereference (requires sudo)
-D
allow duplicate prefixes
-N
no nx bit support
-s seed
in random search, seed value
-B brute_depth
in brute search, maximum search depth
-P max_prefix
maximum number of prefixes to search
-i instruction
instruction at which to start search (inclusive)
-e instruction
instruction at which to end search (exclusive)
-c core
core on which to perform search
-X blacklist
blacklist the specified instruction
-j jobs
number of simultaneous jobs to run
-l range_bytes
number of base instruction bytes in each sub range
m: Mode - altera o modo de busca (força bruta, aleatório ou túnel) para o sifter
q: Quit - sai do sifter
p: Pause - pausa ou retoma a busca
A varredura suporta quatro algoritmos de busca diferentes, que podem ser definidos na linha de comando ou alternados por teclas de atalho.
sudo
Para obter melhores resultados, a ferramenta deve ser executada como usuário root. Isso é necessário para que o processo possa mapear na memória uma página no endereço 0, o que exige permissões de root. Essa página impede que muitas instruções causem seg-fault em acessos à memória, o que permite uma análise de falhas mais precisa.
Prefixos
A principal limitação para a profundidade de uma busca de instruções é o número de bytes de prefixo a explorar, sendo que cada byte de prefixo adicional aumenta o espaço de busca em cerca de um fator de 10. Limite os bytes de prefixo com a flag -P.
Cores
A interface do sifter é projetada para um terminal de 256 cores. Embora os detalhes variem bastante dependendo do seu terminal, isso pode ser aproximadamente feito com:
export TERM='xterm-256color'
GUI
A interface assume que o terminal tem pelo menos um determinado tamanho; se a interface não estiver renderizando corretamente, tente aumentar o tamanho do terminal; isso muitas vezes pode ser feito diminuindo o tamanho da fonte do terminal.
Em alguns casos, pode ser desejável ou necessário executar a ferramenta sem a interface gráfica. Isso pode ser feito executando o injetor diretamente:
sudo ./injector -P1 -t -0
Para filtrar os resultados de uma invocação direta do injetor, o grep pode ser usado. Por exemplo,
sudo ./injector -P1 -r -0 | grep '\.r' | grep -v sigill
procura instruções para as quais o processador e o desmontador discordaram quanto ao comprimento da instrução (grep '.r'), mas que foram executadas com sucesso (grep -v sigill).
Fuzzing direcionado
Em muitos casos, é valioso direcionar o fuzzer para um alvo específico. Por exemplo, se você suspeitar que um emulador tem falhas em relação a prefixos 'lock' repetidos (0xf0), você pode direcionar o fuzzer para procurar nessa região do espaço de instruções com as flags -i e -e:
sudo ./sifter.py --unk --dis --len --sync --tick -- -t -i f0f0 -e f0f1 -D -P15
O sandsifter é um esforço de pesquisa de Christopher Domas (@xoreaxeaxeax).
Sistemas legados
Para varrer sistemas muito mais antigos (processadores classe i586, sistemas com pouca memória), passe a flag --low-mem para o sifter e a flag -N para o injetor:
sudo ./sifter.py --unk --dis --len --sync --tick --low-mem -- -P1 -t -N
Se você observar que suas varreduras terminam rápido demais (por exemplo, uma varredura termina em segundos), normalmente é porque essas flags são necessárias para o processador que você está varrendo.
32 vs. 64 bits
Por padrão, o sandsifter é compilado para atingir a arquitetura de bits do sistema operacional host. No entanto, algumas instruções têm comportamentos diferentes quando executadas em um processo de 32 bits em comparação com um processo de 64 bits. Para explorar esses cenários, às vezes é valioso executar um sandsifter de 32 bits em um sistema de 64 bits.
Para compilar um sandsifter de 32 bits em um sistema de 64 bits, o Capstone deve ser instalado como 32 bits; as instruções para isso podem ser encontradas em http://www.capstone-engine.org/.
Em seguida, o sandsifter deve ser compilado para uma arquitetura de 32 bits:
make CFLAGS=-m32
Com isso, o espaço de instruções de 32 bits pode ser explorado em um sistema de 64 bits.