
Uma ferramenta de instrumentação baseada em LLVM para rastreamento universal de taint, análise de fluxo de dados e rastreamento.
O PolyTracker é uma ferramenta originalmente criada para a Automated Lexical Annotation and Navigation of Parsers, um backronym concebido unicamente com o propósito de referir-se a ele como The ALAN Parsers Project. No entanto, ele evoluiu para uma ferramenta de propósito geral para realizar com eficiência a análise de fluxo de dados e fluxo de controle de programas. O PolyTracker é um pass do LLVM que instrumenta programas para rastrear quais bytes de um arquivo de entrada são operados por quais funções. Ele gera um banco de dados contendo as informações de fluxo de dados, bem como um trace de execução. O PolyTracker também fornece uma biblioteca Python para interagir com e analisar sua saída, além de um REPL Python interativo.
O PolyTracker pode ser usado em conjunto com PolyFile para determinar automaticamente a finalidade semântica das funções em um parser. Ele também possui um recurso experimental capaz de gerar uma gramática livre de contexto que representa a linguagem aceita por um parser.
Diferentemente de alternativas de instrumentação dinâmica como o Taintgrind, o PolyTracker impõe sobrecarga de desempenho insignificante para quase todas as entradas e é capaz de rastrear cada byte de entrada de uma só vez. O PolyTracker começou como um fork do LLVM DataFlowSanitizer e se inspira fortemente no Angora Fuzzer. No entanto, diferentemente do sistema Angora, o PolyTracker é capaz de rastrear toda a proveniência de um taint. Em fevereiro de 2021, o LLVM DataFlowSanitizer adicionou um novo recurso para rastrear a proveniência de taint chamado origin tracking. No entanto, ele só é capaz de rastrear no máximo 16 taints por vez, enquanto o PolyTracker pode rastrear até 231-1.
Este README serve como guia geral de uso para instalar o PolyTracker e compilar/instrumentar binários. Para interagir programaticamente com ou estender o PolyTracker por meio de sua API Python, bem como para interagir com traces de execução produzidos por código instrumentado, consulte a documentação do Python.
O PolyTracker é controlado por meio de um script Python chamado polytracker. Você pode
instalá-lo executando
pip3 install polytracker
O PolyTracker exige um ambiente de sistema muito específico para ser executado, então quase todos
os usuários provavelmente o executarão em um ambiente conteinerizado. Por sorte,
polytracker torna isso fácil. Tudo o que você precisa fazer é ter o docker instalado,
e então executar:
polytracker docker pull
e
polytracker docker run
O último comando montará o diretório de trabalho atual no contêiner Docker do PolyTracker e permitirá que você compile e execute programas instrumentados.
O script de controle polytracker—que você pode executar a partir do seu sistema host
ou de dentro do contêiner Docker—possui uma variedade de comandos, tanto para
instrumentar programas quanto para analisar os artefatos resultantes. Por
exemplo, você pode explorar os fluxos de dados na execução, reconstruir o grafo de fluxo
de controle do programa instrumentado e até mesmo extrair uma gramática livre de
contexto que corresponda às entradas aceitas pelo programa. Você pode explorar esses
comandos executando
polytracker --help
O script polytracker também é um REPL, se for executado sem argumentos de linha de comando:
$ polytracker
PolyTracker (4.0.0)
https://github.com/trailofbits/polytracker
Type "help" or "commands"
>>> commands
O PolyTracker também vem com um comando build. Esse comando permite que o usuário
execute qualquer comando de build em um ambiente instrumentado com Blight.
Isso produzirá um arquivo blight_journal.jsonl que
registra todos os comandos executados durante o build. Se você tiver um alvo C/C++, você pode
instrumentá-lo invocando polytracker build e passando seu comando de build:
polytracker build gcc -g -o my_binary my_source.c
Para instrumentar um alvo de build, use o comando instrument-targets. Por padrão
o comando utilizará o blight_journal.jsonl no seu diretório de trabalho atual para
criar uma versão instrumentada do seu alvo de build. O
alvo de build instrumentado será compilado usando os mesmos flags do alvo de build original.
polytracker instrument-targets my_binary
O build também suporta programas mais complexos que usam um sistema de build como
autotiools ou CMake:
polytracker build cmake .. -DCMAKE_BUILD_TYPE=Release
polytracker build ninja
# ou
polytracker build ./configure
polytracker build make
Em seguida, execute instrument-targets em qualquer alvo do build:
polytracker instrument-targets a.bin b.so
Então, a.instrumented.bin e b.instrumented.so serão as versões
instrumentadas. Veja os Dockerfiles no diretório
examples
para exemplos de como programas do mundo real podem ser instrumentados.
O software instrumentado gravará sua saída no caminho especificado em
POLYDB, ou em polytracker.tdag se omitido. Este é um arquivo binário que pode ser
manipulado executando:
from polytracker import PolyTrackerTrace, taint_dag
trace = PolyTrackerTrace.load("polytracker.tdag")
tdfile = trace.tdfile
first_node = list(tdfile.nodes)[0]
print(f"First node affects control flow: {first_node.affects_control_flow}")
# Operate on all Range nodes
for index, node in enumerate(tdfile.nodes):
if isinstance(node, taint_dag.TDRangeNode):
print(f"Node {index}: first {node.first}, last {node.last}")
# Access taint forest
tdforest = trace.taint_forest
n1 = tdforest.get_node(1)
print(
f"Forest node {n1.label}. Parent labels: {n1.parent_labels}, "
f"source: {n1.source.path if n1.source is not None else None}, "
f"affects control flow: {n1.affected_control_flow}"
)
Você também pode executar um binário instrumentado diretamente do REPL:
$ polytracker
PolyTracker (4.0.0)
https://github.com/trailofbits/polytracker
Type "help" or "commands"
>>> trace = run_trace("path_to_binary", "path_to_input_file")
Isso executará automaticamente o binário instrumentado em um contêiner Docker, se necessário.
⚠️ Se você estiver executando o PolyTracker dentro do Docker ou de uma VM: o PolyTracker pode ser muito lento se estiver sendo executado em um ambiente virtualizado e o arquivo de entrada ou, especialmente, o banco de dados de saída estiverem localizados em um diretório mapeado ou montado a partir do sistema operacional host. Isso é particularmente verdadeiro ao executar o PolyTracker no Docker a partir de um host macOS. A solução é gravar o banco de dados em um caminho dentro do contêiner/VM e depois copiá-lo para o sistema host no final.
A documentação da API Python está disponível aqui.