Case Study 2 -- Binutils

The GNU Binutils are a collection of binary tools widely used in GNU/Linux. We use this to demonstrate how to use Hakweye to fuzz with binaries with a given build script. In this case, we deal with the CVE-2016-4487 case, where the target site is according to the bug report page.

  • Get Binutils-2.26 source code
mkdir 4487
export INFO_DIR=$PWD/4487
wget https://ftp.gnu.org/gnu/binutils/binutils-2.26.tar.gz && tar xf binutils-2.26.tar.gz
export SRC_DIR=$PWD/binutils-2.26
  • Prepare "llvm.toml" and "tgt_lines.in" in $INFO_DIR:

# llvm.toml

[tgt]
infile = "tgt_lines.in"
out_dir = "."
[ins]
proj_name = "binutils-4487"
dist_file = "bb.dist"

# tgt_lines.in

/home/hawkeye/test-ccs/binutils-2.26/libiberty/cplus-dem.c:4300
  • Preprocessing with he-pp
cd $SRC_DIR
export CFLAGS="-Wno-error -g $HE_FLAGS"
export CXXFLAGS="-Wno-error -g $HE_FLAGS"
export LDFLAGS="-ldl"
../configure --disable-shared --disable-werror --prefix=$PWD/install
make -j

There will be an LLVM Bitcode file "cxxfilt.0.0.preopt.bc".

  • Analyze the bitcode with "libhe-tgt.so"
cp cxxfilt.0.0.preopt.bc $INFO_DIR
cd $INFO_DIR
opt-6.0 -mem2reg -load /usr/local/lib/hawkeye/libhe-tgt.so -he-conf ./llvm.toml -he-analyze ./cxxfilt.0.0.preopt.bc -o /dev/null
  • Generate distances:
he-dists -b ./cxxfilt.0.0.preopt.bc -i $PWD
  • Compile and Instrument
export HE_FLAGS="-he-conf=$INFO_DIR/llvm.toml"
cd $SRC_DIR
make clean
export CFLAGS="-Wno-error -g $HE_FLAGS"
export CXXFLAGS="-Wno-error -g $HE_FLAGS"
export LDFLAGS="-ldl"
../configure --disable-shared --disable-werror --prefix=$PWD/install
make
  • Map function traces:
cd $INFO_DIR
he-funcs extract -p binutils-4487
he-funcs score -d funcs.dist -m funcs.txt -p proj_trace_funcs.json -o trace_funcs.json
  • Specify configuration for fuzzing:
[io]
in_folder = "in"
out_folder = "out"

[exec]
use_forkserver = true
mem_limit = 200
timeout = 50
qemu_mode = false

[exec.sa]
trace_func_file = "trace_funcs.json"
callgraph_file = "callgraph.yaml"
tgt_func_file = "tgt_funcs.txt"

[record]
proj_name = "binutils-4487"
interval = 2000
url = "redis://127.0.0.1/"
log_entry_info = false

[calibration]
# for simple regular case calibration
normal_cycles = 7
# for variable behaviors calibration
var_behavior_cycles = 37

[minimize]
ck_redundant_file = false

[mutation]
# ops = ["det", "dict", "havoc", "splice"]
# ops = ["havoc", "splice", "sem"]
max_file_length = 128
#dict_folder = "dicts_test"
dict_level = 0
# max_token_length: 64
# min_token_length: 2
# max_dict_size: 256
# in minutes
havoc_adjust_duration = 12

[fz]
workers = 1
bind_cpu = false
# "normal"/"crash"
keep_mode = "normal"
# "simple"/...
scorer = "simple"
exit_nonzero_as_crash = false
ignored_signals = []

[fz.conductor]
# in minutes
report_duration = 3

[fz.sync]
duration = 200
execs = 5
  • Run the fuzzer:
mkdir in
echo "" > in/file
he-fuzz -c ./Config.toml -- $SRC_DIR/binutils/cxxfilt
# cxxfilt accepts input from stdin