
EF/CF - 초고속 스마트 계약 퍼징
EF/CF는 스마트 컨트랙트 퍼징에 대한 새로운 접근 방식입니다. 새로 맞춤 제작된 퍼저를 사용하는 대신 C/C++ 코드용 기존 퍼징 인프라를 스마트 컨트랙트에 재사용합니다. 현재 AFL++가 기본 지원 퍼저이며, libfuzzer와 honggfuzz에 대한 매우 기초적인 지원도 일부 포함되어 있습니다.
왜 기존 퍼징 인프라를 사용하나요?
그 과정에서 겪게 되는 문제들은 무엇일까요?
./src/ethmutator/./src/evm2cpp/이 저장소는 EF/CF 프로젝트의 기본 진입점입니다. 관련 코드는 모두
./src/의 하위 프로젝트로 포함되어 있으며, 설치용 편의 스크립트,
퍼징 캠페인 실행용 스크립트, 그리고 퍼저를 테스트(및 다른 도구와
비교)하기 위한 다양한 데이터셋도 포함합니다.
./src/ - EF/CF를 빌드하고 실행하는 데 필요한 모든 소스를 포함합니다. 재현성을 위해 모든 직접 의존성은 git 서브모듈로 추가됩니다../data/ - 평가에 사용된 데이터셋을 포함합니다../scripts - 실험 실행, 설치 등을 위한 스크립트를 포함합니다../docker - 컨테이너 기반 워크플로우용 Dockerfile
./docker/tools/에는 EF/CF를 평가할 때 비교 대상으로 사용한 도구들의 dockerfile이 들어 있습니다. 논문에서 평가한 버전을 dockerfile에 고정하기 위해 최선을 다했습니다../EXPERIMENTS.md - 논문의 실험을 재현하기 위한 가이드를 포함합니다../examples - EF/CF가 생성한 예제 출력물을 포함합니다.EF/CF의 아키텍처, 구현, 그리고 평가 결과 요약은 다음 논문에서 확인할 수 있습니다: arxiv.org 프리프린트
학술 연구에서 EF/CF를 인용할 때는 다음 bibtex 항목을 사용해 주십시오:```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", }
## Quickstart
권장 방법은 EF/CF를 대화형 docker 컨테이너로 실행하는 것입니다.
1. 셸로 컨테이너에 진입합니다. ```
docker run --rm -it ghcr.io/uni-due-syssec/efcf-framework
또는 복제된 저장소에서 컨테이너를 빌드하세요 ``` make gitmodules # to fetch the git submodules make container-enter
1. solidity 계약을 컴파일한 다음 첫 번째 크래시/버그가 발견될
때까지 퍼즈합니다: ```
efcfuzz --until-crash --out ./baby_bank_results/ --source ./data/examples/baby_bank.sol
git이 없나요? tarball/docker 릴리스를 사용한다면 이 부분은 무시하세요.
이미 클론한 저장소에서 최신 서브모듈 커밋을 가져오려면 git submodule update --init을 실행하세요.
이 작업을 ./src/eEVM에서도 실행해야 합니다.```
git submodule update --init; cd src/eEVM/; git submodule update --init; cd ../../
*경고:* `git clone --recursive $repo`를 실행하거나 `git sumbodule (update|init)`에 `--recursive` 인수를 전달하면 git이 AFL++ 저장소의 서브모듈까지 재귀적으로 처리하게 되는데, 이 프로젝트에는 필요하지 않습니다. 따라서 공간을 절약하려면 재귀적 서브모듈 체크아웃을 피하는 것이 좋습니다.
### 컨테이너
컨테이너 기반 워크플로를 위해 다음과 같은 편리한 make 타겟을 제공합니다.```sh
make container-build # build default efcf container
make container-enter # enter default efcf container in current working dir
클린 빌드를 보장하려면 다음 명령을 사용할 수 있습니다.```sh make container-build CLEAN_CHECKOUT=1
또는 다음 docker 명령으로 컨테이너를 빌드할 수 있습니다:```sh
docker build \
-f docker/ubuntu.Dockerfile \
-t efcf:latest \
.
참고로 Archlinux 및 Fedora 기반 Dockerfile도 있습니다. 이들은 작동해야 하지만, 그만큼 잘 테스트되지는 않았습니다.
docker 이미지를 수동으로 배포하려면(예: 일부 로컬 변경 사항을 포함하는 경우), 다음을 사용하세요:``` make container-release docker load -i ./efcf*.tar
We recommend the following docker options for launching:
* `--security-opt seccomp=unconfined` - better fuzzing perf
* `--net=host` - for easy access to a local ethereum node
* `--tmpfs "/tmp/efcf/":exec,size=6g` - put EF/CF's temporary files onto a ramdisk if possible (less disk wear)
* `--privileged` - to run `afl-system-config` or `efcfuzz --configure-system`
* `-v` - to persist the output data of EF/CF
### VM / 베어메탈
VM 또는 베어메탈 기반 워크플로우의 경우:```sh
make system-install # install efcf to current system (requires root or sudo rights)
참고로 많은 스크립트가 어차피 상대 디렉터리 구조에서 동작하므로,
이는 주로 PATH에 두면 유용한 의존성 및 몇 가지 도구를 설치하는 것입니다. 우리는 다음 Linux 배포판에서 EF/CF를 테스트했습니다:
(배포판은 그다지 중요하지 않습니다. 우리는 LLVM 13과 14를 테스트했으며 14를 선호합니다. LLVM 11 또는 12도 여전히 동작할 수 있지만, 언제나 그렇듯이 최신이 더 좋습니다. 중요한 것은 AFL++ 포크와 호환되는 LLVM이 있다는 것입니다.)
우리는 Mac OS에서 EF/CF를 네이티브로 테스트하지 않았습니다. 아마도 동작하지 않을 가능성이 높습니다(예: Mac OS에서 afl-clang-lto는 동작하지 않는 것으로 보입니다). 가장 좋은 방법은 docker를 활용하는 것입니다.```sh
make gitmodules
docker pull ubuntu:jammy --platform linux/amd64
docker build -t efcf:latest -f docker/ubuntu.Dockerfile --platform linux/amd64 .
docker run --tmpfs "/tmp/efcf/":exec,size=8g --platform linux/amd64 --rm -it -v $(pwd):$(pwd) -w $(pwd) efcf:latest
docker desktop v4.21.1을 사용하여 테스트했으며 기본적인 EF/CF 사용이 작동합니다. 그러나 다음 사항을 고려하세요:
* 빌드 중 segfault가 발생하는 경우: Mac OS에서 docker가 사용하는 VM의 메모리 제한을 늘려 보세요.
* docker에서 rosetta를 사용하여 가속을 활성화해 보세요. 아마 조금 더 빨라질 것입니다.
### 개발 환경 설정
이 도구들은 일반적으로 설치할 필요가 없습니다. `system-install.sh` 스크립트나 Dockerfiles에 명시된 대로 필수
종속성을 설치하세요.
편의를 위해 `PATH`를 업데이트하는 몇 가지 스크립트가 있습니다:```sh
# POSIX-like shells (i.e., bash, ...)
source ./scripts/env.sh
# for the fish shell
source ./scripts/env.fish
일부 스크립트는 Etherscan 서비스에서 메타데이터(예: ABI)를 가져오기 위해 API 키가 필요합니다. API 키가 있다면 이 키를 스크립트에 전달하기 위해 ETHERSCAN_API_KEY 환경 변수를 설정해야 합니다. docker 기반 워크플로우의 경우 --env 플래그로 docker 컨테이너를 실행하거나 .etherscan_api_key 파일에 API 키를 넣을 수 있으며, 그러면 API 키가 docker 컨테이너에 포함됩니다.
편의를 위해, EF/CF 퍼저를 실행할 때 모든 세부 사항을 처리해 주는 래퍼 스크립트인 efcfuzz를 사용합니다.
빌드 및 퍼징 프로세스와 관련하여 퍼저의 동작을 구성하는 많은 명령줄 옵션을 설정할 수 있습니다. 옵션 목록은 efcfuzz --help를 참조하세요.
예제
Solidity 소스 코드를 EF/CF 네이티브 코드로 컴파일하고 5분(즉 300초) 동안 퍼징을 시작합니다.```bash efcfuzz --timeout 300 --source ./data/examples/baby_bank.sol
또는, 퍼징 출력을 줄여서 실행할 수 있습니다 (`--quiet`는 기본 퍼저의 출력을
억제하고, `--print-progress`는 퍼징 진행 상황에 대한 간단한 요약을
출력합니다), 그리고 4개 코어에서 퍼저를 실행합니다.```bash
efcfuzz --quiet --print-progress --cores 4 --timeout 300 --source ./data/examples/baby_bank.sol
이미 컴파일된 바이트코드를 사용하고 해당 바이트코드를 EF/CF 네이티브 코드로 컴파일한 다음 퍼징을 시작합니다.```bash
pushd ./data/examples/; make baby_bank.combined.json; popd efcfuzz --timeout 300 --bin-runtime ./data/examples/baby_bank.combined.json
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
래퍼는 go-ethereum/erigon 노드에서 컨트랙트의 상태를 내보내고
그 상태에서 퍼징을 시작할 수 있습니다.```bash
$ efcfuzz --timeout 300 --live-state 0xfffF8D17CB019E0825c478c666B251A7099df3FD
또한, --include-address-deps=y를 전달하면 내보낸 컨트랙트의 스토리지에 있는 다른 계정의 주소를 재귀적으로 검색하여 해당 주소들도 상태 내보내기에 포함할 수 있습니다. 하지만 이는 Solidity mapping 유형에 저장된 다른 컨트랙트는 포함하지 않습니다. 정말로 전체 상태를 재귀적으로 내보내려면 --include-mapping-deps=y 플래그도 함께 전달하세요.