
파이썬 애플리케이션을 위한 커버리지 기반 퍼저
pip3 install frelatage
세계가 마땅히 가져야 할 Python 퍼저
설치 | 작동 방식 | 기능 | Frelatage 사용법 | 설정
Frelatage는 Python 코드를 퍼징하는 데 사용할 수 있는 커버리지 기반 Python 퍼징 라이브러리입니다. Frelatage의 개발은 AFL/AFL++, Atheris 및 PythonFuzz를 비롯한 다양한 다른 퍼저에서 영감을 받았습니다. 이 프로젝트의 주요 목적은 이러한 퍼저들의 최고 기능을 활용하여 하나의 새로운 도구로 통합함으로써 Python 애플리케이션을 효율적으로 퍼징하는 것입니다.
면책 조항: 이 프로젝트는 알파 단계에 있으며 여전히 예상치 못한 많은 동작을 유발할 수 있습니다. 현재 Frelatage를 프로덕션 환경에서 사용해서는 안 됩니다.
pip3 install frelatage
개발자에게 권장됩니다. frelatage 저장소의 메인 브랜치를 자동으로 클론하고 소스에서 설치합니다.
# Frelatage 저장소를 자동으로 클론하고 소스에서 Frelatage 설치
bash <(wget -q https://raw.githubusercontent.com/Rog3rSm1th/Frelatage/main/scripts/autoinstall.sh -O -)
Frelatage 설계의 기본 아이디어는 가능한 한 많은 코드를 커버하는 돌연변이를 생성하기 위해 유전 알고리즘을 사용하는 것입니다. 퍼징 주기의 기능은 이 다이어그램으로 대략 요약할 수 있습니다:
graph TB
m1(Mutation 1) --> |input| function(Fuzzed function)
m2(Mutation 2) --> |input| function(Fuzzed function)
mplus(Mutation ...) --> |input| function(Fuzzed function)
mn(Mutation n) --> |input| function(Fuzzed function)
function --> generate_reports(Generate reports)
generate_reports --> rank_reports(Rank reports)
rank_reports --> select(Select n best reports)
select --> |mutate| nm1(Mutation 1) & nm2(Mutation 2) & nmplus(Mutation ...) & nmn(Mutation n)
subgraph Cycle mutations
direction LR
m1
m2
mplus
mn
end
subgraph Next cycle mutations
direction LR
nm1
nm2
nmplus
nmn
end
style function fill:#5388e8,stroke:white,stroke-width:4pxFrelatage는 파일을 입력으로 전달하여 함수를 퍼징할 수 있습니다.
import frelatage
import my_vulnerable_library
def MyFunctionFuzz(data):
my_vulnerable_library.parse(data)
input = frelatage.Input(value="initial_value")
f = frelatage.Fuzzer(MyFunctionFuzz, [[input]])
f.fuzz()
Frelatage는 파일 타입 입력 매개변수를 퍼징할 수 있는 기능을 제공합니다. 이러한 파일의 값을 초기화하려면 입력 폴더(기본값 ./in)에 파일을 생성해야 합니다.
퍼징에 사용할 파일의 값을 초기화하려면 다음과 같이 할 수 있습니다:
echo "initial value" > ./in/input.txt
그런 다음 퍼저를 실행합니다:
import frelatage
import my_vulnerable_library
def MyFunctionFuzz(data):
my_vulnerable_library.load_file(data)
input = frelatage.Input(file=True, value="input.txt")
f = frelatage.Fuzzer(MyFunctionFuzz, [[input]])
f.fuzz()
import frelatage
import my_vulnerable_library
input = frelatage.Input(file=True, value="input.txt")
@frelatage.instrument([[input]])
def MyFunctionFuzz_1(data):
my_vulnerable_library.load_file(data)
@frelatage.instrument([[input]])
def MyFunctionFuzz_1(data):
my_vulnerable_library.load_file_but_different(data)
# 추가 메서드...
# 계측된 메서드를 하나씩 퍼징합니다
frelatage.Fuzzer.fuzz_all()
한 번에 여러 파일을 코퍼스로 로드해야 하는 경우 (큰 코퍼스를 사용할 때 유용함) Frelatage의 내장 함수 load_corpus를 사용할 수 있습니다. 이 함수는 입력 목록을 반환합니다.
load_corpus(directory: str, file_extensions: list) -> list[Input]
./, ./images["jpeg", "gif"], ["pdf"]import frelatage
import my_vulnerable_library
def MyFunctionFuzz(data):
my_vulnerable_library.load_file(data)
my_vulnerable_library.load_file(data2)
# ./in 디렉토리의 모든 파일을 로드
corpus_1 = frelatage.load_corpus(directory="./")
# ./in/images 하위 디렉토리의 모든 .gif/.jpeg 파일을 로드
corpus_2 = frelatage.load_corpus(directory="./images", file_extension=["gif", "jpeg"])
f = frelatage.Fuzzer(MyFunctionFuzz, [corpus_1, corpus_2])
f.fuzz()
여기에 있는 하나 이상의 딕셔너리를 딕셔너리 전용 디렉토리(기본값 ./dict)에 복사할 수 있습니다.
차등 퍼징은 동일한 입력을 여러 라이브러리/프로그램에 제공하고 동작 차이를 관찰하여 버그를 탐지하는 인기 있는 소프트웨어 테스트 기법입니다. json 및 ujson 라이브러리를 사용한 Frelatage 차등 퍼징 사용 예제는 여기에서 찾을 수 있습니다.
퍼저와 코퍼스의 추가 예제는 examples 디렉토리에서 찾을 수 있습니다.
각 크래시 보고서는 출력 폴더(기본값 ./out)에 id:<crash ID>,err:<error type>,err_pos:<error>,err_file:<error file> 형식의 폴더 이름으로 저장됩니다.
보고서 디렉토리는 다음과 같은 형태입니다:
├── out
│ ├── id:<crash ID>,err:<error type>,err_file:<error file>,err_pos:<err_pos>
│ ├── message
│ ├── input
│ ├── 0
│ ├── <inputfile1>
│ ├── ...
│ ├── ...
각 크래시 보고서에는 오류 메시지가 포함된 message 파일이 포함되어 있습니다.
각 커버리지 증가 보고서는 커버리지 폴더(기본값 ./cov)에 coverage_<ID> 형식의 폴더 이름으로 저장되며, 보고서 디렉토리는 크래시 보고서 디렉토리와 동일한 형태입니다.
함수에 전달된 입력은 <report_folder>/input 파일에 저장되기 전에 pickle 모듈을 사용하여 직렬화됩니다. 따라서 파일 내용을 읽으려면 역직렬화해야 합니다. 이 작업은 frelatage-report 명령으로 수행할 수 있습니다.
$ frelatage-report input
Frelatage를 설정하는 방법은 두 가지입니다:
설정 예:
export FRELATAGE_DICTIONARY_ENABLE=1 &&
export FRELATAGE_SAVE_NEW_COVERAGE=1 &&
export FRELATAGE_TIMEOUT_DELAY=2 &&
export FRELATAGE_INPUT_FILE_TMP_DIR="/tmp/frelatage" &&
export FRELATAGE_INPUT_MAX_LEN=4096 &&
export FRELATAGE_MAX_THREADS=8 &&
export FRELATAGE_MAX_STAGES=1000000 &&
export FRELATAGE_MAX_CYCLES_WITHOUT_NEW_PATHS=5000 &&
export FRELATAGE_INPUT_DIR="./in" &&
export FRELATAGE_DICTIONARY_DIR="./dict" &&
python3 fuzzer.py
import frelatage
def myfunction(input1_string, input2_int):
pass
input1 = frelatage.Input(value="initial_value")
input2 = frelatage.Input(value=2)
f = frelatage.Fuzzer(
# 퍼징할 메서드
method=myfunction,
# 코퍼스
corpus=[[input1], [input2]],
# 스레드 수
threads_count=8,
# 고려할 예외
exceptions_whitelist=(OSError),
# 고려하지 않을 예외
exceptions_blacklist=(),
# 오류 보고서 저장 디렉토리
output_directory="./out",
# 커버리지 증가 보고서 저장 디렉토리
coverage_directory="./cov",
# 자동 모드 활성화/비활성화
silent=False,
# 무한 퍼징 활성화/비활성화
infinite_fuzz=False
)
f.fuzz()
계산 집약적인 다른 작업과 마찬가지로 퍼징은 하드웨어와 OS에 부담을 줄 수 있습니다. 특히 다음 사항에 유의하세요:
CPU가 뜨거워지며 적절한 냉각이 필요합니다. 대부분의 경우 냉각이 부족하거나 제대로 작동하지 않으면 CPU 속도가 자동으로 조절됩니다. 하지만 덜 적합한 하드웨어(노트북, 스마트폰 등)에서 퍼징할 때 무언가 폭발할 가능성이 완전히 없는 것은 아닙니다.
대상 프로그램이 기가바이트의 메모리를 불규칙하게 점유하거나 정크 파일로 디스크 공간을 채울 수 있습니다. Frelatage는 기본 메모리 제한을 적용하려고 노력하지만 모든 가능한 사고를 예방할 수는 없습니다. 결론적으로 데이터 손실 가능성을 감수할 수 없는 시스템에서는 퍼징을 해서는 안 됩니다.
퍼징은 파일 시스템에 대한 수십억 번의 읽기 및 쓰기를 수반합니다. 현대 시스템에서는 일반적으로 상당히 캐시되어 '물리적' I/O는 비교적 적지만 이 방정식을 변경할 수 있는 요소가 많습니다. 잠재적인 문제를 모니터링하는 것은 사용자의 책임입니다. 매우 무거운 I/O의 경우 많은 HDD 및 SSD의 수명이 단축될 수 있습니다.
Linux에서 디스크 I/O를 모니터링하는 좋은 방법은 'iostat' 명령입니다:
$ iostat -d 3 -x -k [...선택적 디스크 ID...]
저는 Rog3rSm1th입니다. 21세이며 프랑스인으로 컴퓨터와 사이버 보안에 열정을 가지고 있습니다. 저는 도구 개발(OSINT, 퍼징 등)과 CTF/워게임 플레이를 좋아합니다. 저와 제 프로젝트에 대해 더 알아보려면 여기를 클릭하세요.
➜ 프로젝트(프로그래밍, 사이버 보안 등)에 저를 고용하고 싶으시다면 [email protected]으로 연락 주시면 함께 요구 사항을 평가하겠습니다.
어떤 의견, 제안, 버그 신고 또는 Frelatage를 사용하여 버그를 발견하셨다면 [email protected] 또는 트위터 @Rog3rSm1th로 연락 주시기 바랍니다.
| 환경 변수 | 설명 | 가능한 값 | 기본값 |
|---|
| FRELATAGE_DICTIONARY_ENABLE | 딕셔너리 요소 기반 돌연변이 사용 활성화 | 1 활성화, 0 비활성화 | 1 |
| FRELATAGE_SAVE_NEW_COVERAGE | 나중에 재사용할 새로운 커버리지 입력 저장 | 1 활성화, 0 비활성화 | 1 |
| FRELATAGE_TIMEOUT_DELAY | 함수가 TimeoutError를 반환할 때까지의 지연 시간(초) | 1 - 무한대 | 2 |
| FRELATAGE_INPUT_FILE_TMP_DIR | 입력 파일이 저장되는 임시 폴더 | 절대 경로 (예: /tmp/custom_dir) | /tmp/frelatage |
| FRELATAGE_INPUT_MAX_LEN | 입력 변수의 최대 크기(바이트) | 4 - 무한대 | 4094 |
| FRELATAGE_MAX_THREADS | 최대 동시 스레드 수 | 8 - 무한대 | 8 |
| FRELATAGE_MAX_STAGES | 퍼징된 함수의 최대 단계 수 | 1 - 무한대 | 1000000 |
| FRELATAGE_MAX_CYCLES_WITHOUT_NEW_PATHS | 새 경로를 찾지 못한 후 다음 단계로 넘어갈 때까지의 최대 사이클 수 | 10 - 무한대 | 5000 |
| FRELATAGE_INPUT_DIR | 초기 입력 파일이 포함된 디렉토리. 퍼징 파일 경로에 대한 상대 경로여야 함 | 상대 경로 (예: ./in) | ./in |
| FRELATAGE_DICTIONARY_DIR | 딕셔너리 기본 디렉토리. 퍼징 파일 경로에 대한 상대 경로여야 함 | 상대 경로 (예: ./dict) | ./dict |
| FRELATAGE_DEBUG_MODE | 디버그 모드 활성화 (Frelatage 충돌 시 오류 표시) | 1 활성화, 0 비활성화 | 1 |