Skip to content
KitploitKITPLOIT
FerramentasBlog
Enviar
FerramentasBlog
Enviar

Ferramentas de Hacking, PenTest e Cibersegurança para o seu Arsenal de Segurança!

Kitploit é um diretório de ferramentas de hacking, cibersegurança e pentesting. Descubra as últimas atualizações de projetos para encontrar vulnerabilidades, analisar sistemas, automatizar testes e fortalecer sua segurança.

··Feeds·Contato·Privacidade·© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
efcf-framework — EF/CF - Fuzzing de Contratos Inteligentes Extremamente Rápido | Kitploit
Ferramentas/GitHubGitHub/uni-due-syssec/efcf-framework
Análise de VulnerabilidadesExploraçãoFuzzingAnálise de Binários
GitHubuni-due-syssec/efcf-framework

efcf-framework

EF/CF - Fuzzing de Contratos Inteligentes Extremamente Rápido

Ver Repositório
7013há 3 anosRevisado pelo Kitploit

Mais Populares

Ver todos →

Descubra as ferramentas mais usadas pela nossa comunidade.

Explore todas as ferramentas

Navegue pela nossa coleção de ferramentas

Ver todas as ferramentas →
Compartilhar

EF/CF - o Fuzzer de Contratos (ethereum smart) Extremamente Rápido

EF/CF é uma nova abordagem para fuzzing de contratos inteligentes: em vez de usar um novo fuzzer personalizado, ele reaproveita a infraestrutura de fuzzing existente para código C/C++ e a aplica a contratos inteligentes. Atualmente, o AFL++ é o fuzzer suportado principalmente, embora haja também algum suporte muito rudimentar para libfuzzer e honggfuzz.

Por que usar a infraestrutura de fuzzing existente?

  • Velocidade. Conseguimos fuzzar mais rápido. Obtemos regularmente cerca de 20 mil execuções/segundo/núcleo.
  • Fuzzers de código nativo são bem projetados e otimizados.
  • Orientação por cobertura adequada, gerenciamento de filas, reprodução determinística de casos de teste, etc.

Quais são alguns dos problemas que encontramos pelo caminho?

  • Precisamos ensinar ao fuzzer sobre estrutura: ou seja, o que é uma transação e qual é a ABI do contrato inteligente. Usamos um mutador personalizado para isso: ./src/ethmutator/
  • Para aumentar a velocidade e obter feedback de cobertura útil, traduzimos o bytecode EVM para C++ usando um transpilador personalizado ./src/evm2cpp/

Este repositório é o ponto de entrada principal para o projeto EF/CF. Ele contém todo o código relevante como subprojetos em ./src/ e vários scripts de conveniência para instalação, scripts para lançar campanhas de fuzzing e diversos conjuntos de dados para testar o fuzzer (e compará-lo com outras ferramentas).

  • ./src/ - contém todo o código-fonte necessário para compilar e executar o EF/CF; para reprodutibilidade, todas as dependências diretas são adicionadas como submódulos git.
  • ./data/ - contém os conjuntos de dados usados durante a avaliação
  • ./scripts - contém scripts para executar experimentos, instalação, etc.
  • ./docker - Dockerfile para fluxo de trabalho baseado em contêiner
    • O padrão é Ubuntu, mas você também pode ter um contêiner baseado em Fedora ou Arch Linux se preferir.
    • ./docker/tools/ contém dockerfiles para ferramentas com as quais comparamos o EF/CF. Fizemos o nosso melhor para fixar as versões que avaliamos em nosso artigo nos dockerfiles.
  • ./EXPERIMENTS.md - contém um guia para reproduzir os experimentos do nosso artigo.
  • ./examples - contém exemplos de saídas produzidas pelo EF/CF

O Artigo do EF/CF

Descrevemos a arquitetura, a implementação e resumimos os resultados de nossa avaliação em nosso artigo: pré-impressão no arxiv

Citação em Trabalhos Acadêmicos

Ao se referir ao EF/CF em trabalhos acadêmicos, use a seguinte entrada bibtex para citar:```bibtex @InProceedings{efcf2023, author = "Michael Rodler and David Paaßen and Wenting Li and Lukas Bernhard and Thorsten Holz and Ghassan Karame and Lucas Davi", title = "EF/CF: High Performance Smart Contract Fuzzing for Exploit Generation", booktitle = "{IEEE} European Symposium on Security and Privacy ({EuroS&P})", publisher = "{IEEE}", year = "2023", }

root@kitploit:~
## Início rápido

A maneira recomendada é executar EF/CF como um contêiner docker interativo.

1. Entre no contêiner com um shell   ```
   docker run --rm -it ghcr.io/uni-due-syssec/efcf-framework

ou construa o container a partir do repositório clonado ``` make gitmodules # to fetch the git submodules make container-enter

root@kitploit:~
1. Compile e então faça fuzz de um contrato solidity até que o primeiro crash/bug seja
descoberto:   ```
efcfuzz --until-crash --out ./baby_bank_results/ --source ./data/examples/baby_bank.sol
  1. Inspecione a falha identificada ``` cd /tmp/baby_bank_results/ ./r.sh crashes_min/default_id:000000*
    root@kitploit:~

Instalação / Configuração

Submódulos Git

Sem git? se você usa uma release tarball/docker, ignore isto.

Execute git submodule update --init para buscar os últimos commits dos submódulos em repositórios já clonados. Certifique-se de executar isso também em ./src/eEVM.``` git submodule update --init; cd src/eEVM/; git submodule update --init; cd ../../

root@kitploit:~
*Aviso:* Executar `git clone --recursive $repo` ou passar o argumento `--recursive` para `git sumbodule (update|init)` fará com que o git entre recursivamente nos submódulos do repositório AFL++, que não são necessários para este projeto. Portanto, para economizar espaço, é melhor evitar os checkouts recursivos de submódulos.


### Contêiner

Oferecemos os seguintes alvos de conveniência do make para fluxos de trabalho baseados em contêineres:```sh
make container-build  # build default efcf container
make container-enter  # enter default efcf container in current working dir

Se você quiser garantir um build limpo, pode usar o seguinte comando```sh make container-build CLEAN_CHECKOUT=1

root@kitploit:~
Alternativamente, o container pode ser construído com o seguinte comando docker:```sh
docker build \
    -f docker/ubuntu.Dockerfile \
    -t efcf:latest \
    .

Note que há também um Dockerfile baseado em Archlinux e Fedora. Eles devem funcionar também, mas não são tão bem testados.

Para distribuir manualmente uma imagem docker (por exemplo, se incluindo algumas alterações locais), use:``` make container-release docker load -i ./efcf*.tar

root@kitploit:~
Recomendamos as seguintes opções do docker para execução:

* `--security-opt seccomp=unconfined` - melhor desempenho de fuzzing
* `--net=host` - para acesso fácil a um nó Ethereum local
* `--tmpfs "/tmp/efcf/":exec,size=6g` - coloque os arquivos temporários do EF/CF em um ramdisk, se possível (menos desgaste do disco)
* `--privileged` - para executar `afl-system-config` ou `efcfuzz --configure-system`
* `-v` - para persistir os dados de saída do EF/CF


### VM / Bare-Metal

Para fluxos de trabalho baseados em VM ou bare-metal:```sh
make system-install   # install efcf to current system (requires root or sudo rights)

Note que muitos dos scripts funcionam com a estrutura de diretórios relativa de qualquer forma, então isso principalmente instala dependências e algumas ferramentas que são úteis de ter no seu PATH. Testamos a execução de EF/CF nas seguintes distribuições Linux:

  • Ubuntu Jammy (ou posterior)
  • Fedora ($ > 35 $)
  • Archlinux

(A distribuição não importa muito; testamos LLVM 13 e 14, sendo o 14 a escolha preferida. LLVM 11 ou 12 também podem funcionar, mas como sempre — quanto mais novo, melhor. O importante é que exista um LLVM compatível com o nosso fork do AFL++.)

No Mac OS / M1

Não testamos EF/CF nativamente no Mac OS. Provavelmente algumas coisas não funcionarão (por exemplo, afl-clang-lto no Mac OS parece não funcionar). A melhor opção é utilizar o docker.```sh

make sure that the submodules are initialized

make gitmodules

pull the linux/amd64 base image

docker pull ubuntu:jammy --platform linux/amd64

build the ef/cf image

docker build -t efcf:latest -f docker/ubuntu.Dockerfile --platform linux/amd64 .

launch the EF/CF container

docker run --tmpfs "/tmp/efcf/":exec,size=8g --platform linux/amd64 --rm -it -v $(pwd):$(pwd) -w $(pwd) efcf:latest

root@kitploit:~
Testamos usando o docker desktop v4.21.1 e o uso básico de EF/CF funciona. No entanto, considere o seguinte:
* Se você vir segfaults durante a compilação: tente aumentar o limite de memória da VM que o docker usa no Mac OS.
* Tente habilitar a aceleração usando rosetta no docker - esperamos que isso seja um pouco mais rápido.


### Configuração de Desenvolvimento

As ferramentas geralmente não precisam ser instaladas. Instale as dependências
necessárias conforme o script `system-install.sh` ou conforme os Dockerfiles.

Para conveniência, temos alguns scripts para atualizar seu `PATH`:```sh
# POSIX-like shells (i.e., bash, ...)
source ./scripts/env.sh

# for the fish shell
source ./scripts/env.fish

Chave de API do Etherscan

Alguns dos scripts exigem uma chave de API para buscar metadados (por exemplo, ABI) do serviço Etherscan. Se você tiver uma chave de API, deve definir a variável de ambiente ETHERSCAN_API_KEY para passá-la aos scripts. Para um fluxo de trabalho baseado em Docker, você pode iniciar o contêiner Docker com a flag --env ou colocar sua chave de API no arquivo .etherscan_api_key, o que incorporará a chave de API ao contêiner Docker.

Iniciando EF/CF com o lançador

Por conveniência, utilizamos um script wrapper que cuida de todos os detalhes para você ao iniciar o fuzzer EF/CF: efcfuzz

Você pode definir várias opções de linha de comando para configurar o comportamento do fuzzer em relação ao processo de compilação e fuzzing. Dê uma olhada em efcfuzz --help para uma lista de opções.

Exemplos

Compile o código-fonte solidity para código nativo EF/CF e inicie o fuzzing por 5 minutos (ou seja, 300 segundos).```bash efcfuzz --timeout 300 --source ./data/examples/baby_bank.sol

root@kitploit:~
Alternativamente, lance com saída de fuzzing reduzida (`--quiet` suprime a saída do fuzzer base, enquanto `--print-progress` imprimirá um breve resumo do progresso do fuzzing), e execute o fuzzer em 4 núcleos.```bash
efcfuzz --quiet --print-progress --cores 4 --timeout 300 --source ./data/examples/baby_bank.sol

Use o bytecode já compilado e compile o bytecode para código nativo EF/CF e comece o fuzzing.```bash

efcfuzz can handle the combined.json output of the solidity compiler

pushd ./data/examples/; make baby_bank.combined.json; popd efcfuzz --timeout 300 --bin-runtime ./data/examples/baby_bank.combined.json

but you can also explicitely pass the runtime and deploy bytecode and the ABI

definition. This is useful if you want to fuzz contracts using other

compilers (e.g., vyper).

pushd ./data/examples/; make baby_bank; popd efcfuzz --timeout 300
--bin-runtime ./data/examples/baby_bank.bin-runtime
--bin-deploy ./data/examples/baby_bank.bin
--abi ./data/examples/baby_bank.abi

root@kitploit:~
O wrapper pode exportar o estado de um contrato a partir de um nó go-ethereum/erigon e iniciar
fuzzing a partir daí.```bash
$ efcfuzz --timeout 300 --live-state 0xfffF8D17CB019E0825c478c666B251A7099df3FD

Além disso, você pode passar --include-address-deps=y para pesquisar recursivamente endereços de outras contas no armazenamento do contrato exportado e também incluir esses endereços na exportação de estado. No entanto, isso não inclui outros contratos armazenados em tipos mapping do Solidity. Para realmente exportar todo o estado recursivamente, passe também a flag --include-mapping-deps=y.

Mas atenção: essa busca recursiva pode levar a longos tempos de compilação e baixo desempenho de fuzzing. Especialmente, contratos muito usados podem ter muito estado interno, e usar o estado exportado deles pode tornar o fuzzing lento. Verifique se o fuzzer consegue alcançar mais de 1k execuções/seg. Se não, é melhor tentar criar um estado artificial e menor. Tente executar um nó go-ethereum local no modo --dev e implantar seus contratos nele. Em seguida, exporte o estado ativo a partir dele.

O wrapper armazena em cache as compilações, então uma segunda execução do fuzzing deve iniciar muito mais rápido, pois o tempo de compilação inicial não é mais necessário. Se você quiser apenas compilar e colocá-lo no cache, basta passar o argumento --build-only.

Exemplo: Fuzzing com propriedades

O EF/CF também suporta fuzzing baseado em propriedades usando a mesma definição de propriedade do fuzzer echidna. Propriedades (ou invariantes) são expressas como funções Solidity que atuam como um oráculo de bugs para o fuzzer. Por exemplo, você pode adicionar uma função Solidity:```solidity function test_property_balance() public view returns (bool) { return total_balance < 1000; }

root@kitploit:~
Que representa a propriedade de que o total_balance deve estar sempre abaixo de
1000. O EF/CF reportará um bug se conseguir violar essa propriedade usando
alguma sequência de transações, ou seja, o oráculo retorna `false`.

Para dizer ao EF/CF que essa é uma propriedade, é preciso especificar uma lista de
assinaturas de funções em um arquivo, que será reconhecida pelo EF/CF como uma lista
de propriedades para verificar durante o fuzzing.

A maneira mais fácil é obter as assinaturas relevantes usando a flag `--hashes`
do compilador Solidity, por exemplo,```
solc --hashes ./path/to/your.sol | grep test_property > property_list

Agora você pode iniciar o fuzzer com:``` efcfuzz --source ./path/to/your.sol --properties ./property_list -C

root@kitploit:~
Você também pode adicionar `--disable-detectors` para desabilitar os oráculos de bugs integrados baseados em ether.

Você pode tentar o seguinte exemplo para fuzzing baseado em propriedades:```
efcfuzz \
    --properties ./data/examples/harvey_baz_properties.signatures
    --disable-detectors \
    --until-crash --timeout 120 \
    --source ./data/examples/harvey_baz.sol \

Exemplo: Fuzzing para Eventos

EF/CF suporta fuzzing para violações de asserção expressas através de eventos. Na verdade, também suportamos o uso de eventos personalizados arbitrários como oráculo de bug. Por padrão, o EF/CF identificará um bug se o contrato alvo registrar um dos seguintes eventos: AssertionFailed(), AssertionFailed(uint256), AssertionFailed(string) e Panic(uint256).``` efcfuzz --event-assertions
--timeout 120 --until-crash
--source ./data/properties-assertions-tests/verifyfunwithnumbers.sol

root@kitploit:~
Você também pode especificar tópicos/hashes de eventos personalizados adicionais para observar em um arquivo com `--event-assertions-list ./path/to/eventslist.txt`. Assim como na lista de propriedades anterior, você pode obter o formato usando `solc --hashes` e copiando os hashes e nomes de eventos para o arquivo da lista de eventos.

Por padrão, o EF/CF ignorará eventos que não foram emitidos pelo contrato alvo. Se quiser mudar isso, use `--event-assertions-target-only=n`.

(Nota: você pode usar `--assertions` para habilitar a verificação de asserções de eventos e do Solidity)

**Exemplo: Fuzzing para asserções do Solidity ^0.8**

Atualmente, não suportamos fuzzing para asserções arbitrárias em código Solidity para versões do Solidity anteriores à 0.8. Anteriormente, asserções do Solidity simplesmente acionavam um opcode `invalid`, resultando em um revert bastante abrupto. A versão 0.8 do Solidity mudou o comportamento: em vez de usar o opcode `invalid` para reverter transações, agora utiliza o mecanismo `revert` e sinaliza erros de volta ao chamador. Podemos utilizar esse tipo de propagação de erros como um oráculo de bugs no EF/CF. Atualmente, o EF/CF suporta a verificação do tipo de erro do Solidity `Panic(uint256)`. [Mais informações sobre erros do Solidity.](https://docs.soliditylang.org/en/v0.8.0/control-structures.html?highlight=assert#panic-via-assert-and-error-via-require)```
efcfuzz --sol-assertions \
    --timeout 120 --until-crash \
    --source ./data/assertions-tests/overflow.sol

(Nota: você pode usar --assertions para habilitar a verificação de asserções tanto de eventos quanto de solidity)

Especificações e Configuração do Sistema

Recomendamos alocar de 4 a 16 núcleos e aproximadamente 1 GB de memória por núcleo. Você pode utilizar a flag --configure-system para configurar seu sistema para alta velocidade de fuzzing, ou configurá-lo você mesmo. Em containers docker, você também precisa configurar o host para obter o melhor desempenho. Se for um host não crítico, você pode iniciar o container como --privileged e usar /usr/local/bin/afl-system-config para configurar o sistema para alta velocidade de fuzzing (observe que isso essencialmente executa o container como root).```

configure system

docker run --rm -it --privileged efcf afl-system-config

run fuzzer (somewhat sandboxed and using a tmpfs for less SSD wear)

docker run --rm -it
--security-opt seccomp=unconfined
--tmpfs "/tmp/efcf/":exec,size=6g
efcf

root@kitploit:~
## Executando um Experimento de Fuzzing

Para executar o experimento no conjunto de dados `data/tests/`, você pode usar o seguinte
comando para construir os contratos e o respectivo harness de fuzzing e depois executar o
fuzzer com diferentes configurações, e múltiplas repetições, etc. Como isso
levaria bastante tempo, podemos executar esses experimentos em paralelo. Dividimos os
experimentos de fuzzing em uma etapa de build e uma etapa de fuzz. As etapas de build irão
construir todos os contratos inteligentes sequencialmente (a construção em si usa múltiplos núcleos,
no entanto). Em seguida, lançamos 8 instâncias do fuzzer em segundo plano, que pegarão
os artefatos de build da etapa de build e iniciarão execuções de fuzzing. O Makefile
tentará automaticamente lançar tudo no container adequado se
`docker` ou `podman` estiver disponível.```bash
make build-tests
make fuzz-tests CONTAINER_BACKGROUND=1 FUZZER_INSTANCES=8

Desativamos o seccomp e o sandboxing de rede ao iniciar os contêineres em segundo plano. Desativar o sandboxing do seccomp melhora o desempenho de fuzzing. Usar a rede do host permite que EF/CF acesse os nós Ethereum na rede local sem configuração adicional.

Usamos o script ./scripts/run-tools-on-dataset.py para executar as outras ferramentas dentro de contêineres docker nesses datasets, por exemplo, com estes comandos para o multi dataset:```bash python3 ./scripts/run-tools-on-dataset.py ./data/multi/ cd ./results/tools-multi/ python3 ../../scripts/get-tools-on-dataset-stats.py head stats.csv

root@kitploit:~
Você precisa adaptar o script para configurar as ferramentas e o número de execuções.

### Configurando um Experimento de Fuzzing

Aqui, usamos o experimento `tests` como exemplo. Basta substituir a string
`tests` pelo nome do experimento nas seguintes etapas:

1. Reúna seu dataset em `./data/`, por exemplo, o dataset `./data/tests` com contratos de teste.
   Para contratos Solidity, temos um `Makefile` genérico para compilar os
   contratos: `sol.Makefile`. Você pode reutilizá-lo se desejar, veja
   `./data/tests/Makefile` para um exemplo.
2. Crie um script para gerar os artefatos de build, incluindo qualquer etapa de
   pré-processamento/coleta necessária. Por exemplo, para o dataset `tests`, temos
   o script `./scripts/build-tests.sh`. Os artefatos de build devem ser
   armazenados em `./builds/tests/${contract}.build.tar.xz`.
3. Crie um script para lançar a campanha de fuzzing, por exemplo, para o dataset `tests`,
   crie um script chamado `./scripts/fuzz-tests.sh`. Normalmente, você pode usar a
   função comum de campanha de fuzzing de `./scripts/common.sh`. Dê uma olhada no
   `fuzz-tests.sh` como modelo.
4. Os resultados de `fuzz-tests.sh` serão armazenados em `./results/run-fuzz-tests/`.
5. Para resumir os resultados, fornecemos `./scripts/summarize.py` para os scripts de
   lançamento baseados em bash e `./scripts/summarize_l.py` para scripts de lançamento
   em python (a ferramenta `efcfuzz`).  
   Você pode precisar adaptar esses scripts dependendo da sua etapa 3.
   


### Experimentos de Fuzzing Existentes

#### Benchmarks

* <a href="./data/multi/">`./data/multi`</a> contém o benchmark de escalabilidade
  que usamos para avaliar o quão bem uma ferramenta de análise escala para sequências
  de transações mais longas. Ele consiste em três tipos de contratos:
    * `multi_gen_*.sol` - contratos sintetizados automaticamente, que fazem uma série
      de `require(input <= MAGIC)` e depois definem uma variável de estado interna. Se
      todas as variáveis de estado forem definidas, então o `selfdestruct` (ou oráculo
      do echidna) pode ser acionado.
    * `multi_man_complex_*.sol` - variantes criadas manualmente que funcionam de forma
      semelhante aos contratos do tipo `multi_gen`, mas apresentam restrições um pouco
      mais complicadas (por exemplo, outras coisas além de igualdade e desigualdade com
      um valor mágico)
    * `justlen_*.sol` - estes são retirados do [exemplo echidna-parade](https://github.com/crytic/echidna-parade/blob/main/examples/justlen.sol)
    * `multi_simple_*.sol` - verificações de sanidade que verificam se um fuzzer/ferramenta
      pode, em teoria, encontrar bugs que exigem 9 ou 10 transações. Aqui, o
      analisador só precisa chamar 10 funções na ordem correta, sem argumentos.
      Isso é bastante fácil para a maioria das ferramentas de análise.
* <a href="./data/throughput/">`./data/throughput`</a> contém os contratos que usamos
  para avaliar o throughput. Esta é uma seleção de contratos de
  tamanhos variados. Observe que corrigimos todas as vulnerabilidades nesses contratos,
  para que as vulnerabilidades encontradas não impactem as medições de throughput.
* <a href="./data/cov-max-testset">`./data/cov-max-testset`</a> contém os
  contratos que usamos para comparação de fuzzers baseados em cobertura de código.

#### Detecção de Bugs
  
* <a href="./data/ethbmc-vuln">`./data/ethbmc-vuln`</a> lista de contratos que
  o EthBMC detectou como vulneráveis.
* <a href="./data/ethbmc-timeouts">`./data/ethbmc-timeouts`</a> lista de
  contratos em que o EthBMC interrompeu a análise devido a timeout.
* <a href="./data/reentrancy">`./data/reentrancy`</a> um conjunto de contratos
  vulneráveis a ataques de reentrância.
* <a href="./data/sailfish-dao-tp">`./data/sailfish-dao-tp`</a> um conjunto de contratos
  que foram verificados como contendo um bug de reentrância como parte do
  [estudo sailfish](https://github.com/ucsb-seclab/sailfish/tree/master/data/ground-truth).
* <a href="./data/sailfish-dao">`./data/sailfish-dao`</a> lista de todos os contratos
  em que o
  [sailfish](https://github.com/ucsb-seclab/sailfish/tree/master/data/bugs)
  encontrou um bug de reentrância.
* <a href="./data/sereum">`./data/sereum`</a> uma lista de contratos
  vulneráveis a ataques de reentrância de acordo com o [Sereum](https://github.com/uni-due-syssec/sereum-results).
* <a href="./data/smartbugs-curated-accesscontrol">`./data/smartbugs-curated-accesscontrol`</a>
  contratos do smartbugs curado, classificados como bugs de "controle de acesso"
  ([github smartbugs](https://github.com/smartbugs/smartbugs/tree/master/dataset/access_control))
* <a href="./data/smartbugs-curated-reentrancy">`./data/smartbugs-curated-reentrancy`</a>
  contratos do smartbugs curado, classificados como bugs de "reentrância"
  ([github smartbugs](https://github.com/smartbugs/smartbugs/tree/master/dataset/reentrancy))

#### Testes

Os seguintes datasets contêm contratos de teste sintéticos básicos para testar as
capacidades do fuzzer:
  
* <a href="./data/tests">`./data/tests`</a> testes básicos reunidos de múltiplas
  fontes que verificam as capacidades básicas de um fuzzer. Todos usam um oráculo
  de selfdestruct.
* <a href="./data/tests-not-vuln">`./data/tests-not-vuln`</a> igual aos testes, mas não deve
  ser detectado como vulnerável.
* <a href="./data/properties-tests">`./data/properties-tests`</a> testes para
  fuzzing baseado em propriedades
* <a href="./data/assertions-tests">`./data/assertions-tests`</a> testes para
  fuzzing de asserções.


## Fuzzing em Mais Detalhe

Utilizamos scripts wrapper para lançar o fuzzer real (AFL++ no nosso caso).
Isso é feito automaticamente ao usar o lançador `efcfuzz`.```bash
$ cd data/tests
$ make SimpleDAO.evm2cpp
$ cd ../../src/eEVM/
$ env AFL_BENCH_UNTIL_CRASH=1 ./fuzz/launch-aflfuzz.sh SimpleDAO

Se você tem tmux e tmuxp instalados, então para desenvolvimento e inspeção a versão interativa do script pode ser útil:```bash $ ./fuzz/interactive-aflfuzz.sh -b SimpleDAO

root@kitploit:~
Isso irá então compilar e executar o fuzzing por um bom tempo. Você pode então
`cd ./fuzz/out/SimpleDAO*` para ver os resultados do fuzzing. Nossos scripts de
wrapper fazem um trabalho extra além de iniciar o programa `afl-fuzz`, ou seja,
principalmente o pós-processamento dos resultados. Além disso, eles gerarão vários
scripts de conveniência para analisar os casos de teste gerados.

* `./a.sh` - Exibe uma forma legível para humanos de um caso de teste, wrapper do
  `efuzzcaseanalyzer`.
* `./r.sh` - executa um caso de teste com as mesmas configurações de quando o
  fuzzer foi executado.
* `./m.sh` - minimiza um caso de teste com as mesmas configurações de quando o
  fuzzer foi executado.
* `./c.sh` - analisa a "cadeia" de casos de teste que levam ao caso de teste
  fornecido. Útil para analisar/otimizar o fuzzer. Você pode ver rapidamente qual
  caso de teste foi produzido por qual cadeia de mutações em quais entradas de fila.
  Requer `fzf`.

Há também alguns outros relatórios de conveniência, como

* `./bugs` e `./bugtypes`, que resumem quaisquer bugs que foram identificados.
* `./crashes_min`, que contém crashes minimizados de todas as instâncias do
  `afl-fuzz`.

**Visualizar a Cobertura de Código por Blocos Básicos da EVM**```bash
$ cat coverage-percent-all.evmcov
70.73170731707317

O script fuzz/evm-bb-coverage.sh calculará a cobertura de blocos básicos dado um diretório de saída do AFL. O harness pode opcionalmente despejar um trace de blocos básicos, que são então comparados a uma lista de blocos básicos gerada por evm2cpp (ou seja, os arquivos .bb_list em eEVM/contracts/).

Por padrão, também calculamos a cobertura que nossas sementes genéricas padrão (veja eEVM/fuzz/generic_seeds) produzem:```bash $ cat coverage-percent-seeds.evmcov 10.5890

root@kitploit:~
A lista de blocos básicos cobertos é armazenada no arquivo `all.evmcov`.


**Ver Resumo dos Casos de Teste Gerados**

`efuzzcaseanalyzer` pode ser usado para visualizar/resumir os casos de teste gerados, por exemplo,```
$ efuzzcaseanalyzer -a ./contract.abi -s ./crashes_min/
Transactions Sequences:
--------------------------------------------------------------
TX [🪙]
    deposit()[🪙];
    withdraw(uint256)[↕️ ↩️ ];
    withdraw(uint256)[];
--------------------------------------------------------------
Number of fuzzcases: 1
Average number of TXs: 3
Number of unique TX sequences: 1
Number of unique TX sequences (consecutive deduplicated): 1

Os resumos geralmente são armazenados nos arquivos crashes_tx_summary e queue_tx_summary, mas este último pode ser um pouco verboso.

Analisar um único caso de teste que causa falha``` $ ./a.sh default/crashes/id:000000,...

roughly equivalent to running

$ efuzzcaseanalyzer -a ./contract.abi default/crashes/id:000000,... Block header: number: 0 difficulty: 0 gas_limit: 0 timestamp: 0 initial_ether: 0

TX with tx_sender: 54 (selector); call_value: 0x0; length: 36; block+=1; #returns=0 func: withdraw(uint256) input: { Uint(80), } TX with tx_sender: 238 (selector); call_value: 0x246ddf979; length: 4; block+=1; #returns=0 func: deposit() input: { } TX with tx_sender: 153 (selector); call_value: 0x3860e6373; length: 4; block+=1; #returns=0 func: deposit() input: { } TX with tx_sender: 166 (selector); call_value: 0x0; length: 36; block+=1; #returns=1 func: withdraw(uint256) input: { Uint(37000000000000000000), } returns: return val: 1; allows reenter: 2; data: 0x0000000000000000000000000000000000000000000000000000000000000001 TX with tx_sender: 166 (selector); call_value: 0x0; length: 36; block+=1; #returns=0 func: withdraw(uint256) input: { Uint(37000000000000000000), }

root@kitploit:~
E para obter o resultado real do alvo de fuzz, você pode executar:```
$ ./r.sh default/crashes/id:000000,sig:06,src:000000+000010,time:1584,EM-________SAO_______AD
# roughly equivalent to running
$ env EVM_DEBUG_PRINT=1 ./build/fuzz_multitx default/crashes/id:000000,sig:06,src:000000+000010,time:1584,EM-________SAO_______AD

[...]

account 0xc4b803ea8bc30894cc4672a9159ca000d377d9a3 has balance 0x100000000000000000000000000000001bc16d67562e80000( > 0x1000000000000000000000000000000000000000000000000)
Aborted (core dumped)

Isso gera muita saída detalhada, incluindo algumas partes dos rastros de execução dos contratos e o resultado da verificação de saldo que o harness realiza.

Minimizando Entradas que Causam Falhas

Entradas que causam falhas frequentemente contêm transações não relacionadas devido à abordagem de teste aleatório. Isso pode ser mitigado realizando uma minimização na entrada que causa a falha (ou seja, reduzir a entrada enquanto ela ainda causar uma falha). Se você quiser minimizar entradas que não causam falhas, então pode usar a flag -M para ativar a minimização de acordo com a cobertura como critério de minimização.

O seguinte comando reduzirá o testcase e sobrescreverá o arquivo:``` $ efuzzcaseminimizer -oa ./contract.abi ./build/fuzz_multitx ./default/crashes/id:000000,sig:06,src:000000+000010,time:1584,EM-________SAO_______AD

[..]

=== Before minimizing: === Block header: number: 0 difficulty: 0 gas_limit: 0 timestamp: 0 initial_ether: 0

TX with tx_sender: 54 (selector); call_value: 0x0; length: 36; block+=1; #returns=0 func: withdraw(uint256) input: { Uint(80), } TX with tx_sender: 238 (selector); call_value: 0x246ddf979; length: 4; block+=1; #returns=0 func: deposit() input: { } TX with tx_sender: 153 (selector); call_value: 0x3860e6373; length: 4; block+=1; #returns=0 func: deposit() input: { } TX with tx_sender: 166 (selector); call_value: 0x0; length: 36; block+=1; #returns=1 func: withdraw(uint256) input: { Uint(37000000000000000000), } returns: return val: 1; allows reenter: 2; data: 0x0000000000000000000000000000000000000000000000000000000000000001 TX with tx_sender: 166 (selector); call_value: 0x0; length: 36; block+=1; #returns=0 func: withdraw(uint256) input: { Uint(37000000000000000000), }

=== After minimizing: === Block header: number: 0 difficulty: 0 gas_limit: 0 timestamp: 0 initial_ether: 15133991795

TX with tx_sender: 4 (selector); call_value: 0x246ddf979; length: 4; block+=0; #returns=0 func: deposit() input: { } TX with tx_sender: 4 (selector); call_value: 0x0; length: 36; block+=1; #returns=1 func: withdraw(uint256) input: { Uint(37000000000000000000), } returns: return val: 1; allows reenter: 2; data: 0x TX with tx_sender: 0 (selector); call_value: 0x0; length: 36; block+=1; #returns=0 func: withdraw(uint256) input: { Uint(37000000000000000000), }

root@kitploit:~
## Lendo o formato de caso de teste

O formato de caso de teste é voltado para fuzzing e não é tão simples de ler. Existem várias sutilezas das quais você precisa estar ciente.

* O formato de caso de teste é considerado como uma "fila" de transações que podem ser executadas. Assim que qualquer problema é encontrado, o processamento do caso de teste é interrompido. Isso inclui:
    * Quando uma transação é revertida.
    * Quando qualquer erro é encontrado pelo código de harness.
    * Quando qualquer bug é acionado e detectado.
  Como consequência, um caso de teste impresso não corresponde necessariamente ao que é executado - pode haver transações no final que não são executadas. Verifique a saída detalhada e use o minimizador para se livrar delas!
* Da mesma forma, pode haver `returns` demais ou flags `reenter` espúrias. Use
  o minimizador de casos de teste para se livrar delas.
* Um contrato só sofre reentrada quando há outra transação na lista
  após a transação que deveria fazer a reentrância (ou seja, há
  outra entrada seguinte na fila).
* Mesmo que a flag `reenter` esteja definida para algo, isso não significa
  necessariamente que o contrato sofrerá reentrada, apenas que o código de
  harness tentará fazê-lo se possível. Por exemplo, se o contrato não realizar
  uma chamada, a flag `reenter` é ignorada, pois não há possibilidade de
  reentrar. Normalmente, o minimizador removerá quaisquer flags `reenter`
  espúrias.

Em geral, muitos desses problemas desaparecem quando você usa o minimizador de casos de teste,
então é sempre uma boa ideia usá-lo antes de analisar casos de teste
gerados.


## Falsos Alarmes Conhecidos

Observamos vários tipos de falsos alarmes que parecem ser recorrentes ao fazer fuzzing de contratos com EF/CF.

* Contratos que pagam Ether por design. O oráculo de bugs Ether-gains do EF/CF
  detectará esses contratos como vulneráveis, embora estejam operando conforme
  o projetado:
    * Contratos de apostas: muitos contratos de apostas apresentam alguma forma de
      aleatoriedade, o que já é uma má prática no Ethereum. No entanto,
      alguns contratos de apostas são implementados de uma forma que força você a adivinhar,
      por exemplo, os dois últimos dígitos do próximo blockhash ou algo semelhante.
      Isso pode ser habilitado usando um esquema de compromisso, ou seja, a primeira
      transação compromete o usuário a um determinado valor e a segunda aciona
      a adivinhação e o pagamento se ganhar. Esses contratos geralmente não são
      exploráveis em uma blockchain real. No entanto, na blockchain simulada
      do EF/CF, o fuzzer pode adaptar o compromisso depois que o valor na
      segunda transação é observado. Esse fato é importante para o EF/CF 
      alcançar uma melhor cobertura de código. No entanto, também facilita para o EF/CF
      identificar uma sequência de TX que permite ao fuzzer vencer deterministicamente no
      contrato de apostas.
    * Contratos que pagam juros: existem muitos contratos pequenos que permitem
      investir Ether e depois pagar uma certa porcentagem de juros a cada
      `N` blocos. O atacante simulado do EF/CF é capaz de esperar por `N` blocos
      e então recebe o pagamento de juros, que é novamente detectado pelo 
      oráculo de bugs Ether-gains.
    * Airdrops: alguns contratos de token permitem airdrops, ou seja, simplesmente
      distribuem tokens para qualquer pessoa que os solicite até que certos limites
      sejam atingidos. Por exemplo, os airdrops geralmente são habilitados apenas
      por um curto período de tempo. Se tal contrato for implantado no EF/CF, há
      grandes chances de que o limite de tempo seja definido de forma que os
      airdrops ainda estejam habilitados. O EF/CF então detecta um Ether-gains se
      os tokens distribuídos puderem ser vendidos novamente.
* Relato antecipado de `DELEGATECALL` controlável: atualmente, relatamos um
  delegatecall controlável assim que ele é invocado. No entanto, existem vários
  contratos que possuem funções que intencionalmente permitem ao chamador
  realizar um delegatecall para um endereço arbitrário. No entanto, essas
  funções revertem incondicionalmente a transação imediatamente após o
  delegatecall. Isso impede que quaisquer atualizações de estado ou transferências
  de ether persistam. Normalmente, essas funções têm palavras como "simulate"
  em seus nomes de função e, então, são fáceis de identificar.
    * Isso poderia ser corrigido no EF/CF adiando o relato até o final da
      execução. No entanto, isso complica bastante o oráculo de bugs.
    * Atualmente, não há planos para corrigir isso.
* Inicializador chamável: observamos que, ao fazer fuzzing de contratos
  exportados da blockchain, o EF/CF às vezes consegue chamar funções
  inicializadoras, mesmo que o contrato já tenha sido inicializado.
  Normalmente, isso deveria acionar um revert, mas não o faz no ambiente EVM
  do EF/CF. Chamar o inicializador novamente geralmente leva a ganhos triviais
  de Ether, porque, por exemplo, o inicializador define uma variável *owner*
  ou algo semelhante.
    * Ainda não temos certeza de qual é a causa raiz desse problema. No entanto,
      geralmente é fácil de identificar, já que a função inicializadora
      normalmente é chamada de `initializer`, `init`, ou algo semelhante.
      
## Armadilhas Comuns

Fizemos o nosso melhor para tornar isso razoavelmente utilizável, mas ainda é um protótipo de pesquisa. Espere que coisas quebrem. Aqui estão alguns problemas comuns que observamos:

* *Q: Recebo um erro de compilação estranho devido a uma macro `TOKENPASTE`.*  
  A: Isso geralmente acontece quando o `efcfuzz` adivinha o nome errado do contrato (ou seja,
  um contrato abstrato). Tente passar `--name YourContract` para
  especificar o contrato alvo.
Baixar ferramenta