- Author:ZERO-A-ONE
- Date:2021-03-20
这个部门我们主要介绍Driller的安装与使用,我使用的环境是腾讯云的VPS:
- CPU:Intel® Xeon® Platinum 8255C CPU @ 2.50GHz * 4vCPUs
- RAM:4GB
- OS:Ubuntu 18.04 LTS
一、安装
首先我们需要安装一些必备的库
$ sudo apt-get install build-essential libtol-bin automake bison flex python libglib2.0-dev build-dep qemu-system libacl1-dev python3 python3-pip python3-dev git libssl-dev libffi-dev
$ sudo apt-get install build-essential gcc-multilib libtool automake autoconf bison debootstrap debian-archive-keyring libtool-bin python3-dev libffi-dev virtualenvwrapper git wget
$ sudo apt-get install build-essential gcc-multilib libtool automake autoconf bison debootstrap debian-archive-keyring libtool-bin
$ sudo apt-get build-dep qemu
1.1 安装AFL
我们为了方便安装,建议新建一个文件夹来保存所有的过程文件
$ mkdir driller && cd driller
然后从GitHub上可以下载AFL源码:
$ git clone https://github.com/google/AFL.git
然后进入源码文件夹:
$ cd AFL
执行编译命令:
$ sudo make -j4
编译QEMU模式支持:
$ ./build_qemu_support.sh
1.2 安装Driller
在安装与使用Driller时,最好在一个单独的Python虚拟环境中进行,我在这里使用的是Aconda环境
1.2.1 安装Aconda
先安装一些必备的库
$ sudo apt-get install python3 python3-pip python3-dev git libssl-dev libffi-dev build-essential
然后从官网里面下载Anaconda的安装脚本
$ wget https://repo.anaconda.com/archive/Anaconda3-2020.11-Linux-x86_64.sh
然后给脚本赋予执行权限
$ chmod +x Anaconda3-2020.11-Linux-x86_64.sh
然后运行安装脚本即可
$ ./Anaconda3-2020.11-Linux-x86_64.sh
这里不建议使用root权限安装,如果你自己使用的用户就不是root账户的话
这里如果出现找不到conda命令的情况可能需要手动修改shell的环境配置
$ sudo vim ~/.bashrc
然后就修改为类似这样的实际安装路径
export PATH="/home/ubuntu/anaconda3/bin:$PATH"
然后刷新重新运行
$ source ~/.bashrc
1.2.2 建立Driller虚拟环境
使用Aconda建立一个名字叫做driller的虚拟环境
$ conda create -n driiler python=3.8
然后进入虚拟环境中
$ conda activate driiler
1.2.3 安装driller
然后开始如下安装:
$ pip install angr
$ pip install cle
$ pip install git+https://github.com/angr/tracer
$ pip install git+https://github.com/shellphish/driller
安装成功的标识是可以import driller
(driiler) ubuntu@VM-0-17-ubuntu:~/driller$ python
Python 3.8.8 (default, Feb 24 2021, 21:46:12)
[GCC 7.3.0] :: Anaconda, Inc. on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import driller
>>>
二、使用
2.1 Driller和AFL并行运行
这种安装方法是采用一种Driller和AFL并行运行的过程,将driller中求解输入的部分和AFL fuzz的部分分别放在两个terminal运行
Fuzz的程序源码为buggy.c
#include <stdio.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
char buffer[6] = {0};
int i;
int *null = 0;
read(0, buffer, 6);
if (buffer[0] == '7' && buffer[1] == '/' && buffer[2] == '4'
&& buffer[3] == '2' && buffer[4] == 'a' && buffer[5] == '8') {
i = *null;
}
puts("No problem");
}
编译,由于使用AFL QEMU模式,因此不需要对源码进行插桩:
$ gcc -o buggy buggy.c -g
打开一个terminal, 用AFL进行FUZZ:
$ mkdir -p workdir/input
$ echo 'init' > workdir/input/seed1 # 提供初始化种子输入
$ echo core | sudo tee /proc/sys/kernel/core_pattern
$ AFL/afl-fuzz -M fuzzer-master -i workdir/input/ -o workdir/output/ -Q ./buggy
然后就可以成功开始AFL的Fuzz过程
然后我们使用一个脚本来运行driller,名字叫run_driller.py
#!/usr/bin/env python
import errno
import os
import os.path
import sys
import time
from driller import Driller
def save_input(content, dest_dir, count):
"""Saves a new input to a file where AFL can find it.
File will be named id:XXXXXX,driller (where XXXXXX is the current value of
count) and placed in dest_dir.
"""
name = 'id:%06d,driller' % count
with open(os.path.join(dest_dir, name), 'wb') as destfile:
destfile.write(content)
def main():
if len(sys.argv) != 3:
print('Usage: %s <binary> <fuzzer_output_dir>' % sys.argv[0])
sys.exit(1)
_, binary, fuzzer_dir = sys.argv
# Figure out directories and inputs
with open(os.path.join(fuzzer_dir, 'fuzz_bitmap'), 'rb') as bitmap_file:
fuzzer_bitmap = bitmap_file.read()
source_dir = os.path.join(fuzzer_dir, 'queue')
dest_dir = os.path.join(fuzzer_dir, '..', 'driller', 'queue')
# Make sure destination exists
try:
os.makedirs(dest_dir)
except os.error as e:
if e.errno != errno.EEXIST:
raise
seen = set() # Keeps track of source files already drilled
count = len(os.listdir(dest_dir)) # Helps us name outputs correctly
# Repeat forever in case AFL finds something new
while True:
# Go through all of the files AFL has generated, but only once each
for source_name in os.listdir(source_dir):
if source_name in seen or not source_name.startswith('id:'):
continue
seen.add(source_name)
with open(os.path.join(source_dir, source_name), 'rb') as seedfile:
seed = seedfile.read()
print('Drilling input: %s' % seed)
for _, new_input in Driller(binary, seed, fuzzer_bitmap).drill_generator():
save_input(new_input, dest_dir, count)
count += 1
# Try a larger input too because Driller won't do it for you
seed = seed + b'0000'
print('Drilling input: %s' % seed)
for _, new_input in Driller(binary, seed, fuzzer_bitmap).drill_generator():
save_input(new_input, dest_dir, count)
count += 1
time.sleep(10)
if __name__ == '__main__':
main()
再打开另一个窗口,运行driller部分
$ source ~/.bashrc
$ conda activate driiler
$ python run_driller.py ./buggy workdir/output/fuzzer-master
然后成功开启driiler
2.2 使用shellphuzz
官方推荐的driller的使用方法是通过shellphuzz工具来使用,使用方式如下,“-i”选项指定afl-fuzz的线程数,“-d”选项指定driller(即符号执行工具)的线程数,如果不使用-d或者-d 0,则不使用符号执行
# fuzz with 4 AFL cores
$ shellphuzz -i -c 4 /path/to/binary
# perform symbolic-assisted fuzzing with 4 AFL cores and 2 symbolic tracing (drilling) cores.
$ shellphuzz -i -c 4 -d 2 /path/to/binary
2.3 代码调用
直接调用Fuzzer对象(包含了fuzz和angr)
#change from /fuzzer/shellphuzz.py
import driller
import time
import fuzzer
def test():
def robo_fuzzer():
"""fuzz a single cb,copy it from shellphuzz"""
work_path = './work'
print "[*] Drilling..."
drill_extension = driller.LocalCallback(num_workers=4)
grease_extension = None
# Timeout=1800
first_crash = True
stuck_callback = (
(lambda f: (grease_extension(f), drill_extension(f))) if drill_extension and grease_extension else drill_extension or grease_extension)
print "[*] Creating fuzzer..."
fuzz = fuzzer.Fuzzer("./20190529", "./work", afl_count=1, force_interval=None,create_dictionary=False, stuck_callback=stuck_callback, time_limit=1000000)
# start it!
print "[*] Starting fuzzer..."
fuzz.start()
start_time = time.time()
robo_fuzzer()
test()