Skip to content
KitploitKITPLOIT
StrumentiBlog
Invia
StrumentiBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

··Feed·Contatto·Privacy·© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
efcf-framework — EF/CF - Fuzzing di smart contract estremamente veloce | Kitploit
Strumenti/GitHubGitHub/uni-due-syssec/efcf-framework
Analisi delle VulnerabilitàExploitFuzzingAnalisi di Binari
GitHubuni-due-syssec/efcf-framework

efcf-framework

EF/CF - Fuzzing di smart contract estremamente veloce

Vedi Repository
70133 anni faRevisionato da Kitploit

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →
Condividi

EF/CF - il Fuzzer per Contratti (ethereum smart) Estremamente Veloce

EF/CF è un nuovo approccio al fuzzing di smart contract: invece di usare un nuovo fuzzer costruito su misura, riutilizza l'infrastruttura di fuzzing esistente per codice C/C++ applicandola agli smart contract. Attualmente, AFL++ è il fuzzer supportato principalmente, sebbene esista anche un supporto molto rudimentale per libfuzzer e honggfuzz.

Perché usare l'infrastruttura di fuzzing esistente?

  • Velocità. Possiamo fare fuzzing più velocemente. Raggiungiamo regolarmente circa 20k esecuzioni/sec/core.
  • I fuzzer per codice nativo sono ben progettati e ottimizzati.
  • Corretta guida basata sulla copertura, gestione della coda, riproduzione deterministica dei casi di test, ecc.

Quali sono alcuni problemi che incontriamo lungo il percorso?

  • Dobbiamo insegnare al fuzzer la struttura: cioè cos'è una transazione e qual è l'ABI dello smart contract. Usiamo un mutatore personalizzato per questo: ./src/ethmutator/
  • Per aumentare la velocità e ottenere un feedback di copertura utile, traduciamo il bytecode EVM in C++ usando un transpiler personalizzato ./src/evm2cpp/

Questo repository è il punto di ingresso principale per il progetto EF/CF. Contiene tutto il codice rilevante come sotto-progetti in ./src/ e diversi script di comodità per l'installazione, script per avviare campagne di fuzzing e vari dataset per testare il fuzzer (e confrontarlo con altri strumenti).

  • ./src/ - contiene tutto il codice sorgente necessario per compilare ed eseguire EF/CF; per riproducibilità tutte le dipendenze dirette sono aggiunte come sottomoduli git.
  • ./data/ - contiene i dataset usati durante la valutazione
  • ./scripts - contiene script per eseguire esperimenti, installazione, ecc.
  • ./docker - Dockerfile per un flusso di lavoro basato su container
    • Lo standard è Ubuntu, ma puoi anche avere un container basato su Fedora o Arch Linux se preferisci.
    • ./docker/tools/ contiene i dockerfile per gli strumenti con cui abbiamo confrontato EF/CF. Abbiamo fatto del nostro meglio per fissare le versioni che abbiamo valutato nel nostro articolo nei dockerfile.
  • ./EXPERIMENTS.md - contiene una guida per riprodurre gli esperimenti del nostro articolo.
  • ./examples - contiene output di esempio prodotti da EF/CF

L'Articolo su EF/CF

Descriviamo l'architettura di EF/CF, l'implementazione e riassumiamo i risultati della nostra valutazione nel nostro articolo: preprint su arxiv.org

Citazione in Lavori Accademici

Quando si fa riferimento a EF/CF in lavori accademici, si prega di usare la seguente voce bibtex per la citazione:```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:~
## Avvio rapido

Il metodo consigliato è eseguire EF/CF come container docker interattivo.

1. Entra nel container con una shell   ```
   docker run --rm -it ghcr.io/uni-due-syssec/efcf-framework

oppure crea il container dal repository clonato ``` make gitmodules # to fetch the git submodules make container-enter

root@kitploit:~
1. Compila e poi fai fuzzing su un contratto solidity finché non viene scoperto il primo
crash/bug:   ```
efcfuzz --until-crash --out ./baby_bank_results/ --source ./data/examples/baby_bank.sol
  1. Ispeziona il crash identificato ``` cd /tmp/baby_bank_results/ ./r.sh crashes_min/default_id:000000*
    root@kitploit:~

Installazione / Configurazione

Sottomoduli Git

Niente git? se usi una release tarball/docker, ignora questo.

Esegui git submodule update --init per recuperare gli ultimi commit dei sottomoduli su repository già clonati. Assicurati di eseguirlo anche in ./src/eEVM.``` git submodule update --init; cd src/eEVM/; git submodule update --init; cd ../../

root@kitploit:~
*Avvertenza:* Eseguire `git clone --recursive $repo` o passare l'argomento `--recursive` a `git sumbodule (update|init)` farà sì che git entri ricorsivamente nei sottomoduli del repository AFL++, che non sono necessari per questo progetto. Quindi, per risparmiare spazio, è meglio evitare i checkout ricorsivi dei sottomoduli.


### Container

Forniamo i seguenti comodi target make per workflow basati su container:```sh
make container-build  # build default efcf container
make container-enter  # enter default efcf container in current working dir

Se vuoi assicurarti una build pulita, puoi usare il seguente comando```sh make container-build CLEAN_CHECKOUT=1

root@kitploit:~
In alternativa, il container può essere creato con il seguente comando docker:```sh
docker build \
    -f docker/ubuntu.Dockerfile \
    -t efcf:latest \
    .

Nota che esiste anche un Dockerfile basato su Archlinux e Fedora. Dovrebbero funzionare anche loro, ma non sono altrettanto testati.

Per distribuire manualmente un'immagine docker (ad es., se si includono alcune modifiche locali), usa:``` make container-release docker load -i ./efcf*.tar

root@kitploit:~
Consigliamo le seguenti opzioni docker per l'avvio:

* `--security-opt seccomp=unconfined` - prestazioni di fuzzing migliori
* `--net=host` - per un facile accesso a un nodo ethereum locale
* `--tmpfs "/tmp/efcf/":exec,size=6g` - metti i file temporanei di EF/CF su un ramdisk se possibile (minore usura del disco)
* `--privileged` - per eseguire `afl-system-config` o `efcfuzz --configure-system`
* `-v` - per persistere i dati di output di EF/CF


### VM / Bare-Metal

Per flussi di lavoro basati su VM o bare-metal:```sh
make system-install   # install efcf to current system (requires root or sudo rights)

Nota che molti degli script funzionano comunque con il layout di directory relativo, quindi questo installa principalmente dipendenze e alcuni strumenti utili da avere nel tuo PATH. Abbiamo testato l'esecuzione di EF/CF sulle seguenti distribuzioni Linux:

  • Ubuntu Jammy (o successiva)
  • Fedora ($ > 35 $)
  • Archlinux

(La distro non ha molta importanza: abbiamo testato LLVM 13 e 14, con 14 come scelta preferita. LLVM 11 o 12 potrebbero funzionare ancora, ma come sempre - più nuovo è, meglio è. La parte importante è che ci sia un LLVM compatibile con il nostro fork di AFL++.)

Su Mac OS / M1

Non abbiamo testato EF/CF nativamente su Mac OS. Probabilmente molte cose non funzioneranno (ad es., afl-clang-lto su Mac OS sembra non funzionare). L'opzione migliore è utilizzare 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:~
Abbiamo testato utilizzando docker desktop v4.21.1 e l'uso di base di EF/CF funziona. Tuttavia, considera quanto segue:
* Se riscontri segfault durante la compilazione: prova ad aumentare il limite di memoria della VM che docker usa su Mac OS.
* Prova ad abilitare l'accelerazione usando rosetta in docker - speriamo che sia un po' più veloce.


### Configurazione di sviluppo

Gli strumenti generalmente non necessitano di essere installati. Installa le dipendenze richieste come nello script `system-install.sh` o come nei Dockerfile.

Per comodità abbiamo alcuni script per aggiornare il tuo `PATH`:```sh
# POSIX-like shells (i.e., bash, ...)
source ./scripts/env.sh

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

Etherscan API Key

Alcuni script richiedono una chiave API per recuperare metadati (es. ABI) dal servizio Etherscan. Se disponi di una chiave API, devi impostare la variabile d'ambiente ETHERSCAN_API_KEY per passarla agli script. Per un flusso di lavoro basato su Docker, puoi avviare il contenitore Docker con il flag --env oppure inserire la tua chiave API nel file .etherscan_api_key, che incorporerà la chiave API nel contenitore Docker.

Avvio di EF/CF con il launcher

Per comodità, utilizziamo uno script wrapper che si occupa di tutti i dettagli per te, quando avvii il fuzzer EF/CF: efcfuzz

Puoi impostare molte opzioni da riga di comando per configurare il comportamento del fuzzer per quanto riguarda il processo di build e fuzzing. Dai un'occhiata a efcfuzz --help per un elenco di opzioni.

Esempi

Compila il codice sorgente solidity in codice nativo EF/CF e avvia il fuzzing per 5 minuti (ovvero 300 secondi).```bash efcfuzz --timeout 300 --source ./data/examples/baby_bank.sol

root@kitploit:~
In alternativa, puoi avviare con output di fuzzing ridotto (`--quiet` sopprime l'output del fuzzatore di base, mentre `--print-progress` stamperà un breve riepilogo dell'avanzamento del fuzzing), avviando il fuzzatore su 4 core.```bash
efcfuzz --quiet --print-progress --cores 4 --timeout 300 --source ./data/examples/baby_bank.sol

Usa il bytecode già compilato e compila il bytecode in codice nativo EF/CF e inizia il 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:~
Il wrapper può esportare lo stato di un contratto da un nodo go-ethereum/erigon e avviare
il fuzzing da lì.```bash
$ efcfuzz --timeout 300 --live-state 0xfffF8D17CB019E0825c478c666B251A7099df3FD

Inoltre, puoi passare --include-address-deps=y per cercare ricorsivamente gli indirizzi di altri account nello storage del contratto esportato e includere anche quelli nell'esportazione dello stato. Tuttavia, questo non include altri contratti memorizzati in tipi mapping di Solidity. Per esportare davvero l'intero stato in modo ricorsivo, passa anche il flag --include-mapping-deps=y.

Ma attenzione: questa ricerca ricorsiva può portare a tempi di compilazione lunghi e a scarse prestazioni di fuzzing. In particolare, i contratti usati di frequente possono avere molto stato interno e usare il loro stato esportato può rendere il fuzzing lento. Controlla se il fuzzer riesce a superare 1k execs/sec. Se non ci riesce, dovresti piuttosto provare a creare uno stato artificiale e più piccolo. Prova a eseguire un nodo go-ethereum locale in modalità --dev e distribuisci lì i tuoi contratti. Poi esporta lo stato live da lì.

Il wrapper memorizza le build nella cache, quindi una seconda esecuzione di fuzzing dovrebbe avviarsi molto più velocemente, perché il tempo di compilazione iniziale non è più necessario. Se vuoi solo compilare e inserire il risultato nella cache, puoi passare l'argomento --build-only.

Esempio: Fuzzing con proprietà

EF/CF supporta anche il fuzzing basato su proprietà usando la stessa definizione di proprietà del fuzzer echidna. Le proprietà (o invarianti) sono espresse come funzioni Solidity che fungono da oracolo di bug per il fuzzer. Ad esempio, puoi aggiungere una funzione Solidity:```solidity function test_property_balance() public view returns (bool) { return total_balance < 1000; }

root@kitploit:~
Che rappresenta la proprietà che `total_balance` dovrebbe essere sempre inferiore a 1000. EF/CF riporterà quindi un bug se riesce a violare questa proprietà usando una qualche sequenza di transazioni, cioè se l'oracolo restituisce `false`.

Per comunicare a EF/CF che questa è una proprietà, devi specificare un elenco di firme di funzione in un file, che verrà raccolto da EF/CF come elenco di proprietà da controllare durante il fuzzing.

Il modo più semplice è ottenere le firme pertinenti usando il flag `--hashes` del compilatore Solidity, ad esempio,```
solc --hashes ./path/to/your.sol | grep test_property > property_list

Ora puoi avviare il fuzzer con:``` efcfuzz --source ./path/to/your.sol --properties ./property_list -C

root@kitploit:~
Puoi anche aggiungere `--disable-detectors` per disabilitare gli oracoli di bug integrati basati su ether.

Puoi provare il seguente esempio per il fuzzing basato su proprietà:```
efcfuzz \
    --properties ./data/examples/harvey_baz_properties.signatures
    --disable-detectors \
    --until-crash --timeout 120 \
    --source ./data/examples/harvey_baz.sol \

Esempio: Fuzzing per eventi

EF/CF supporta il fuzzing per violazioni di asserzioni espresse tramite eventi. In realtà, supportiamo anche l'uso di eventi personalizzati arbitrari come oracolo per i bug. Per impostazione predefinita, EF/CF identifica un bug se il contratto target ha registrato uno dei seguenti eventi: AssertionFailed(), AssertionFailed(uint256), AssertionFailed(string) e Panic(uint256).``` efcfuzz --event-assertions
--timeout 120 --until-crash
--source ./data/properties-assertions-tests/verifyfunwithnumbers.sol

root@kitploit:~
Puoi anche specificare argomenti/hash di eventi personalizzati aggiuntivi da monitorare in un
file con `--event-assertions-list ./path/to/eventslist.txt`. Come per la
lista di proprietà precedente, puoi ottenere il formato usando `solc --hashes` e
copiando gli hash e i nomi degli eventi nel file della lista degli eventi.

Per impostazione predefinita, EF/CF ignorerà gli eventi che non sono stati emessi dal contratto
target. Se vuoi cambiare questo comportamento, usa `--event-assertions-target-only=n`.

(Nota: puoi usare `--assertions` per abilitare sia il controllo degli eventi che quello delle asserzioni
di solidity)

**Esempio: Fuzzing per asserzioni di Solidity ^0.8**

Attualmente, non supportiamo il fuzzing per asserzioni arbitrarie nel codice solidity
per versioni di solidity precedenti alla 0.8. In precedenza, le asserzioni di solidity attivavano semplicemente
un opcode `invalid`, con conseguente revert piuttosto brusco. La versione
0.8 di solidity ha cambiato il comportamento: invece di usare l'opcode `invalid` per
eseguire il revert delle transazioni, ora viene utilizzato il meccanismo `revert` e gli errori vengono segnalati
al chiamante. Possiamo utilizzare questo tipo di propagazione degli errori come oracolo
di bug in EF/CF. Attualmente, EF/CF supporta il controllo del tipo di errore di solidity
`Panic(uint256)`. [Maggiori informazioni sugli errori
di 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: puoi usare --assertions per abilitare sia il controllo delle asserzioni di eventi che di Solidity)

Specifiche di sistema e configurazione

Consigliamo di allocare da 4 a 16 core e circa 1 GB di memoria per core. Puoi utilizzare il flag --configure-system per configurare il sistema per il fuzzing ad alta velocità, oppure configurarlo manualmente. Nei container Docker devi anche configurare l'host per ottenere le migliori prestazioni. Se si tratta di un host non critico, puoi avviare il container come --privileged e usare /usr/local/bin/afl-system-config per configurare il sistema per il fuzzing ad alta velocità (nota che questo di fatto esegue il container come 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:~
## Esecuzione di un esperimento di fuzzing

Per eseguire l'esperimento sul dataset `data/tests/` puoi usare il seguente
comando per compilare i contratti e il loro harness di fuzzing e poi eseguire il
fuzzer con diverse impostazioni, e molteplici ripetizioni, ecc. Poiché questo
richiederebbe parecchio tempo, possiamo eseguire questi esperimenti in parallelo. Suddividiamo gli
esperimenti di fuzzing in una fase di build e una fase di fuzz. Le fasi di build
compileranno tutti gli smart contract in sequenza (la compilazione stessa usa più core,
comunque). Poi avviamo 8 istanze del fuzzer in background, che prenderanno
gli artefatti di build dalla fase di build e avvieranno le esecuzioni di fuzzing. Il Makefile
tenterà automaticamente di avviare tutto nel container appropriato se
è disponibile `docker` o `podman`.```bash
make build-tests
make fuzz-tests CONTAINER_BACKGROUND=1 FUZZER_INSTANCES=8

Disabilitiamo il sandboxing seccomp e di rete quando avviamo i contenitori in background. Disabilitare il sandboxing seccomp migliora le prestazioni di fuzzing. L'utilizzo della rete host consente a EF/CF di accedere ai nodi Ethereum nella rete locale senza ulteriore configurazione.

Abbiamo usato lo script ./scripts/run-tools-on-dataset.py per eseguire gli altri strumenti all'interno dei contenitori docker su questi dataset, ad esempio con questi comandi per il dataset multi:```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:~
Devi adattare lo script per configurare gli strumenti e il numero di esecuzioni.

### Configurare un Esperimento di Fuzzing

Qui usiamo l'esperimento `tests` come esempio. Basta sostituire la stringa
`tests` con il nome dell'esperimento nei seguenti  passaggi:

1. Raccogli il tuo dataset in `./data/`, ad esempio il dataset `./data/tests` con test
   contratti. Per i contratti Solidity abbiamo un `Makefile` generico per compilare i
   contratti: `sol.Makefile`. Puoi riutilizzarlo se vuoi, vedi
   `./data/tests/Makefile` per un esempio. 
2. Crea uno script per compilare gli artefatti di build includendo qualsiasi
   passaggio di pre-processing/scraping necessario. Ad esempio per il dataset `tests` abbiamo
   lo script `./scripts/build-tests.sh`. Gli artefatti di build dovrebbero essere
   salvati in `./builds/tests/${contract}.build.tar.xz`.
3. Crea uno script per lanciare la campagna di fuzzing, ad esempio per il dataset `tests`
   crea uno script chiamato `./scripts/fuzz-tests.sh`. Di solito puoi usare la
   funzione comune di campagna di fuzzing da `./scripts/common.sh`. Dai un'occhiata a
   `fuzz-tests.sh` come modello.
4. I risultati di `fuzz-tests.sh` verranno salvati in `./results/run-fuzz-tests/`.
5. Per riassumere i risultati forniamo `./scripts/summarize.py` per gli script di lancio
   basati su bash e `./scripts/summarize_l.py` per gli script di lancio python
   (lo strumento `efcfuzz`).  
   Potresti dover adattare questi script a seconda del passaggio 3.
   

### Esperimenti di Fuzzing Esistenti

#### Benchmark

* <a href="./data/multi/">`./data/multi`</a> contiene il benchmark di scalabilità
  che abbiamo usato per valutare quanto bene uno strumento di analisi scala a
  sequenze di transazioni più lunghe. Consiste in tre tipi di contratti:
    * `multi_gen_*.sol` - contratti sintetizzati automaticamente, che eseguono una serie di
      `require(input <= MAGIC)` e poi impostano una variabile di stato interna. Se
      tutte le variabili di stato sono impostate, allora `selfdestruct` (o l'oracolo echidna)
      può essere attivato.
    * `multi_man_complex_*.sol` - varianti create manualmente che funzionano in modo simile
      ai contratti di tipo `multi_gen`, ma presentano vincoli un po' più complessi
      (ad esempio, cose diverse dall'uguaglianza e disuguaglianza con un valore
      magico)
    * `justlen_*.sol` - questi sono presi dall'[esempio echidna-parade](https://github.com/crytic/echidna-parade/blob/main/examples/justlen.sol)
    * `multi_simple_*.sol` - sanity check che verificano che un fuzzer/strumento possa
      in teoria trovare bug che richiedono 9 o 10 transazioni. Qui
      l'analizzatore deve solo chiamare 10 funzioni nell'ordine giusto senza
      argomenti. Questo è abbastanza facile per la maggior parte degli strumenti di analisi. 
* <a href="./data/throughput/">`./data/throughput`</a> contiene i contratti che abbiamo
  usato per valutare il throughput. Questa è una selezione di contratti di
  dimensioni variabili. Nota che abbiamo corretto tutte le vulnerabilità in questi contratti,
  così le vulnerabilità trovate non influiscono sulle misurazioni del throughput.
* <a href="./data/cov-max-testset">`./data/cov-max-testset`</a> contiene i
  contratti che abbiamo usato per il confronto di fuzzer basati sulla copertura del codice.

#### Rilevamento di Bug
  
* <a href="./data/ethbmc-vuln">`./data/ethbmc-vuln`</a> elenco di contratti che
  EthBMC ha rilevato come vulnerabili.
* <a href="./data/ethbmc-timeouts">`./data/ethbmc-timeouts`</a> elenco di
  contratti in cui EthBMC ha interrotto l'analisi a causa di un timeout.
* <a href="./data/reentrancy">`./data/reentrancy`</a> un insieme di contratti
  vulnerabili ad attacchi di rientranza.
* <a href="./data/sailfish-dao-tp">`./data/sailfish-dao-tp`</a> un insieme di contratti
  che sono stati verificati contenere un bug di rientranza come parte dello
  [studio sailfish](https://github.com/ucsb-seclab/sailfish/tree/master/data/ground-truth).
* <a href="./data/sailfish-dao">`./data/sailfish-dao`</a> elenco di tutti i contratti,
  in cui
  [sailfish](https://github.com/ucsb-seclab/sailfish/tree/master/data/bugs)
  ha trovato un bug di rientranza.
* <a href="./data/sereum">`./data/sereum`</a> un elenco di contratti
  vulnerabili ad attacchi di rientranza secondo [Sereum](https://github.com/uni-due-syssec/sereum-results).
* <a href="./data/smartbugs-curated-accesscontrol">`./data/smartbugs-curated-accesscontrol`</a>
  contratti dalla raccolta curata smartbugs, classificati come bug di "controllo accessi"
  ([smartbugs github](https://github.com/smartbugs/smartbugs/tree/master/dataset/access_control))
* <a href="./data/smartbugs-curated-reentrancy">`./data/smartbugs-curated-reentrancy`</a>
  contratti dalla raccolta curata smartbugs, classificati come bug di "rientranza"
  ([smartbugs github](https://github.com/smartbugs/smartbugs/tree/master/dataset/reentrancy))

#### Test

I seguenti dataset contengono contratti di test sintetici di base per testare le
capacità del fuzzer:
  
* <a href="./data/tests">`./data/tests`</a> test di base raccolti da più
  fonti che verificano le capacità di base di un fuzzer. Tutti usano un oracolo
  selfdestruct.
* <a href="./data/tests-not-vuln">`./data/tests-not-vuln`</a> come tests, ma non dovrebbe
  essere rilevato come vulnerabile.
* <a href="./data/properties-tests">`./data/properties-tests`</a> test per
  fuzzing basato su proprietà 
* <a href="./data/assertions-tests">`./data/assertions-tests`</a> test per
  fuzzing per le asserzioni.


## Fuzzing in maggiore dettaglio

Utilizziamo script wrapper per lanciare il vero fuzzer (AFL++ nel nostro caso).
Questo viene fatto automaticamente quando si usa il launcher `efcfuzz`.```bash
$ cd data/tests
$ make SimpleDAO.evm2cpp
$ cd ../../src/eEVM/
$ env AFL_BENCH_UNTIL_CRASH=1 ./fuzz/launch-aflfuzz.sh SimpleDAO

Se hai tmux e tmuxp installati, allora per lo sviluppo e l'ispezione la versione interattiva dello script potrebbe essere utile:```bash $ ./fuzz/interactive-aflfuzz.sh -b SimpleDAO

root@kitploit:~
Questo compilerà e fuzzerà per un bel po' di tempo. Potrai poi
`cd ./fuzz/out/SimpleDAO*` per visualizzare i risultati del fuzzing. I nostri script wrapper fanno
un lavoro extra oltre al lancio del programma `afl-fuzz`, cioè principalmente
post-processing dei risultati. Inoltre genererà diversi script di comodo per analizzare i test case generati.

* `./a.sh` - Stampa una forma leggibile di un test case, wrapper attorno a
  `efuzzcaseanalyzer`.
* `./r.sh` - esegue un test case con le stesse impostazioni di quando il fuzzer è stato eseguito.
* `./m.sh` - minimizza un testcase con le stesse impostazioni di quando il fuzzer è stato
  eseguito.
* `./c.sh` - analizza la "catena" di test case che portano al test case dato. Utile per analizzare/ottimizzare il fuzzer. Puoi vedere rapidamente, quale
  test case è stato prodotto da quale catena di mutazioni su quali voci della coda. 
  Richiede `fzf`.

Ci sono anche altri report di comodo, come

* `./bugs` e `./bugtypes` che riassumono eventuali bug identificati.
* `./crashes_min`, che contiene i crash minimizzati di tutte le istanze
  `afl-fuzz`.

**Visualizza la copertura del codice dei blocchi di base EVM**```bash
$ cat coverage-percent-all.evmcov
70.73170731707317

Lo script fuzz/evm-bb-coverage.sh calcola la copertura dei basic block dato una directory di output di AFL. L'harness può opzionalmente scaricare una traccia dei basic block, che vengono poi confrontati con un elenco di basic block generato da evm2cpp (cioè i file .bb_list in eEVM/contracts/).

Per impostazione predefinita calcoliamo anche la copertura che i nostri seed generici predefiniti (vedi eEVM/fuzz/generic_seeds) producono:```bash $ cat coverage-percent-seeds.evmcov 10.5890

root@kitploit:~
L'elenco dei blocchi di base coperti è salvato nel file `all.evmcov`.


**Visualizzare il Riepilogo dei Testcase Generati**

`efuzzcaseanalyzer` può essere usato per visualizzare/riepilogare i testcase generati,
ad es.,```
$ 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

Le sintesi sono solitamente archiviate nei file crashes_tx_summary e queue_tx_summary, ma quest'ultimo può essere un po' prolisso.

Analizzare un singolo testcase di crash``` $ ./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 per ottenere il risultato effettivo del target di fuzzing, puoi eseguire:```
$ ./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)

Questo produce un output molto verboso, incluse alcune parti delle tracce di esecuzione dei contratti e il risultato del controllo del saldo eseguito dall'harness.

Minimizzazione degli input che causano crash

Gli input che causano crash spesso contengono transazioni non correlate a causa dell'approccio di test randomizzato. Questo può essere mitigato eseguendo una minimizzazione sull'input che causa il crash (cioè ridurre l'input finché causa ancora un crash). Se si desidera minimizzare input che non causano crash, è possibile utilizzare il flag -M per abilitare la minimizzazione in base alla copertura come criterio di minimizzazione.

Il seguente comando ridurrà il testcase e sovrascriverà il file:``` $ 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:~
## Lettura del formato dei casi di test

Il formato dei casi di test è pensato per il fuzzing e non è immediato da
leggere. Ci sono diverse sottigliezze di cui devi essere a conoscenza.

* Il formato dei casi di test è considerato come una "coda" di transazioni che
  possono essere eseguite. Non appena si verifica un qualsiasi problema, l'elaborazione
  del caso di test si interrompe. Questo include:
    * Quando una transazione viene revertita.
    * Qualsiasi errore riscontrato dal codice di harness.
    * Qualsiasi bug attivato e rilevato.
  Di conseguenza, un caso di test stampato non corrisponde necessariamente a ciò che
  viene eseguito: possono esserci transazioni alla fine che non vengono eseguite.
  Controlla l'output verbose e usa il minimizer per eliminare quelle!
* Allo stesso modo, possono esserci troppi `returns` o flag `reenter` spurii. Usa
  il minimizer dei casi di test per eliminarli.
* Un contratto viene rientrato solo quando nella lista è presente un'altra transazione
  dopo la transazione che dovrebbe eseguire il reentrancy (cioè, c'è
  un'altra voce successiva nella coda).
* Anche se il flag `reenter` è impostato su un valore, questo non significa
  necessariamente che il contratto venga rientrato, solo che il codice di harness
  proverà a farlo se possibile. Ad esempio, se il contratto non esegue una call, il
  flag `reenter` viene ignorato perché non c'è possibilità di rientro. Di solito il
  minimizer rimuove eventuali flag `reenter` spurii.

In generale molti di questi problemi scompaiono quando usi il minimizer dei casi di
test, quindi è sempre una buona idea usarlo prima di analizzare i casi di test
generati.

## Falsi allarmi noti

Abbiamo osservato diversi tipi di falsi allarmi che sembrano ricorrenti quando si
esegue il fuzzing di contratti con EF/CF.

* Contratti che pagano Ether per progettazione. L'oracolo dei bug per i guadagni di
  Ether di EF/CF segnala questi contratti come vulnerabili, anche se operano come
  previsto:
    * Contratti di gioco d'azzardo: molti contratti di gioco d'azzardo presentano
      una qualche forma di casualità, che è già una cattiva pratica su Ethereum.
      Tuttavia, alcuni contratti di gioco d'azzardo sono implementati in modo da
      obbligarti a indovinare, ad esempio, le ultime due cifre del blockhash
      successivo o qualcosa di simile. Questo può essere abilitato tramite uno
      schema di impegno (commitment scheme), cioè la prima transazione impegna
      l'utente a un certo valore e la seconda attiva il tentativo e il pagamento
      in caso di vittoria. Questi contratti di solito non sono sfruttabili in una
      blockchain reale. Tuttavia, nella blockchain simulata di EF/CF, il fuzzer
      può adattare l'impegno dopo che il valore nella seconda transazione è stato
      osservato. Questo fatto è importante per EF/CF per raggiungere una migliore
      copertura del codice. Tuttavia, rende anche facile per EF/CF identificare
      una sequenza di TX che consente al fuzzer di vincere deterministicamente nel
      contratto di gioco d'azzardo.
    * Contratti che pagano interessi: esistono molti piccoli contratti che ti
      consentono di investire Ether e poi pagano una certa percentuale di interessi
      ogni `N` blocchi. L'attaccante simulato di EF/CF è in grado di attendere `N`
      blocchi e poi riceve il pagamento degli interessi, che viene nuovamente
      rilevato dall'oracolo dei bug per i guadagni di Ether.
    * Airdrop: alcuni contratti token abilitano gli airdrop, cioè distribuiscono
      token a chiunque li richieda fino al raggiungimento di determinati limiti.
      Ad esempio, gli airdrop sono spesso abilitati solo per un breve periodo di
      tempo. Se un contratto di questo tipo viene distribuito all'interno di EF/CF,
      è molto probabile che il limite di tempo sia impostato in modo che gli
      airdrop siano ancora attivi. EF/CF rileva quindi un guadagno di Ether se i
      token distribuiti possono essere rivenduti.
* Segnalazione anticipata di `DELEGATECALL` controllabile: attualmente segnaliamo
  una delegatecall controllabile non appena viene invocata. Tuttavia, esistono
  diversi contratti che presentano funzioni che consentono intenzionalmente al
  chiamante di eseguire una delegatecall verso un indirizzo arbitrario. Tuttavia,
  queste funzioni revertiscono incondizionatamente la transazione immediatamente
  dopo la delegatecall. Questo impedisce che eventuali aggiornamenti di stato o
  trasferimenti di ether persistano. Tipicamente funzioni di questo tipo contengono
  parole come "simulate" nei nomi delle funzioni e quindi sono facili da individuare.
    * Questo potrebbe essere risolto in EF/CF rimandando la segnalazione fino alla
      fine dell'esecuzione. Tuttavia, questo complica non poco l'oracolo dei bug.
    * Attualmente non ci sono piani per risolvere questo problema.
* Initializer chiamabile: abbiamo osservato che quando si esegue il fuzzing di
  contratti esportati dalla blockchain, EF/CF a volte riesce a chiamare le funzioni
  initializer, anche se il contratto è già stato inizializzato. Normalmente, questo
  dovrebbe attivare un revert, ma non lo fa nell'ambiente EVM di EF/CF. Chiamare di
  nuovo l'initializer porta spesso a guadagni di Ether banali, perché ad esempio
  l'initializer imposta una variabile *owner* o qualcosa di simile.
    * Non siamo ancora sicuri di quale sia la causa principale di questo problema.
      Tuttavia, è in genere facile da individuare, poiché la funzione initializer
      è tipicamente chiamata `initializer`, `init` o simile.

## Insidie comuni

Abbiamo fatto del nostro meglio per rendere questo strumento piuttosto utilizzabile,
ma è comunque un prototipo di ricerca. Aspettati che le cose si rompano. Ecco alcuni
problemi comuni che abbiamo osservato:

* *D: ricevo uno strano errore di compilazione dovuto a una macro `TOKENPASTE`.*  
  R: questo accade spesso quando `efcfuzz` indovina il nome errato del contratto
  (cioè, indovina un contratto astratto); prova a passare `--name YourContract`
  per specificare il contratto target.
Scarica lo strumento