下载和安装

wget http://lcamtuf.coredump.cx/afl/releases/afl-latest.tgz
tar -xvf ./afl-latest.tgz
cd afl-2.52b/
sudo make && sudo make install

检测是否安装成功

root@b855926e8d87:~# afl-fuzz 
afl-fuzz 2.52b by <lcamtuf@google.com>

afl-fuzz [ options ] -- /path/to/fuzzed_app [ ... ]

Required parameters:

  -i dir        - input directory with test cases
  -o dir        - output directory for fuzzer findings

有源码fuzz

由于我们用afl来fuzz upx项目,这个有源码的要用afl-gcc来编译,所以编辑Makefile文件

git clone https://github.com/upx/upx.git
cd upx/
vim Makefile

添加:CC = /usr/local/bin/afl-gcc (我直接在第一行加)

查看位置

which afl-g++
/usr/local/bin/afl-g++

./src/Makefile文件中修改: CXX ?= /usr/local/bin/afl-g++ (应该在31行)

cd ./src
vim Makefile

对于upx项目,我们还要安装这个

apt install zlib1g zlib1g-dev

对于upx项目,安装lzma-sdk

root@b855926e8d87:~/upx# git submodule update --init --recursive
Submodule 'src/lzma-sdk' (https://github.com/upx/upx-lzma-sdk.git) registered for path 'src/lzma-sdk'
Cloning into 'src/lzma-sdk'...
remote: Enumerating objects: 440, done.
remote: Total 440 (delta 0), reused 0 (delta 0), pack-reused 440
Receiving objects: 100% (440/440), 334.59 KiB | 289.00 KiB/s, done.
Resolving deltas: 100% (151/151), done.
Checking connectivity... done.
Submodule path 'src/lzma-sdk': checked out '426fe82d122e2cf140a86751055ee523378fe2ef'

对于upx项目,安装ucl

wget http://www.oberhumer.com/opensource/ucl/download/ucl-1.03.tar.gz
tar -xvf ./ucl-1.03.tar.gz
cd ucl-1.03/
./configure && sudo make && sudo make install
export UPX_UCLDIR=/path/to/ucl-1.03    # !!!!!你自己的路径啊

最后到我们编译upx了,可以看到很多afl-cc alf-as的字样

root@b855926e8d87:~/upx# make all
make -C src all
make[1]: Entering directory '/root/upx/src'
Updating .depend
afl-cc 2.52b by <lcamtuf@google.com>
/usr/local/bin/afl-g++ '-DUPX_VERSION_GITREV="7a3637ff5a80+"' -I/root/ucl-1.03/include -O2 -fno-delete-null-pointer-checks -fno-strict-aliasing -fwrapv -funsigned-char -Wall -W -Wcast-align -Wcast-qual -Wmissing-declarations -Wpointer-arith -Wshadow -Wvla -Wwrite-strings -Werror -o c_file.o -c c_file.cpp
afl-cc 2.52b by <lcamtuf@google.com>
afl-as 2.52b by <lcamtuf@google.com>

最后编译生成的文件在src目录下的upx.out

在ida中打开,发现文件变得不同了

.text:00000000004030E0                 lea     rsp, [rsp-98h]
.text:00000000004030E8                 mov     [rsp+0], rdx
.text:00000000004030EC                 mov     [rsp+arg_0], rcx
.text:00000000004030F1                 mov     [rsp+arg_8], rax
.text:00000000004030F6                 mov     rcx, 5010h
.text:00000000004030FD                 call    __afl_maybe_log_10			#看这里
.text:0000000000403102                 mov     rax, [rsp+arg_8]
.text:0000000000403107                 mov     rcx, [rsp+arg_0]
.text:000000000040310C                 mov     rdx, [rsp+0]
.text:0000000000403110                 lea     rsp, [rsp+98h]
.text:0000000000403118                 push    r15
.text:000000000040311A                 push    r14
.text:000000000040311C                 push    r13
.text:000000000040311E                 push    r12
.text:0000000000403120                 push    rbp
.text:0000000000403121                 push    rbx
.text:0000000000403122                 sub     rsp, 28h
.text:0000000000403126                 mov     [rsp+58h+argc], edi
.text:000000000040312A                 mov     [rsp+58h+argv], argv
.text:000000000040312F                 lea     argc, [rsp+58h+argc] ; argc
.text:0000000000403134                 lea     argv, [rsp+58h+argv] ; argv
.text:0000000000403139                 call    _Z12acc_wildargvPiPPPc ; acc_wildargv(int *,char ***)
.text:000000000040313E                 call    _ZL16upx_sanity_checkv ; upx_sanity_check(void)
.text:0000000000403143                 mov     rdi, cs:opt     ; this
.text:000000000040314A                 call    _ZN9options_t5resetEv ; options_t::reset(void)
.text:000000000040314F                 mov     rax, [rsp+58h+argv]
.text:0000000000403154                 mov     rdx, [rax]
.text:0000000000403157                 test    rdx, rdx
.text:000000000040315A                 jz      loc_403A8A
.text:0000000000403160                 lea     rsp, [rsp-98h]
.text:0000000000403168                 mov     [rsp+58h+var_58], rdx
.text:000000000040316C                 mov     [rsp+58h+c2], rcx
.text:0000000000403171                 mov     [rsp+58h+argv], rax
.text:0000000000403176                 mov     rcx, 3887h
.text:000000000040317D                 call    __afl_maybe_log_10			#看这里

开启core dump

echo core >/proc/sys/kernel/core_pattern

开始fuzz(下面用file文件作为样本)

root@giant:~/aflfuzz/fuzztarget/upx# mkdir afl_in afl_out
root@giant:~/aflfuzz/fuzztarget/upx# cp /usr/bin/file afl_in
root@giant:~/aflfuzz/fuzztarget/upx# afl-fuzz -i afl_in -o afl_out ./src/upx.out @@		#其中./src/upx.out为运行的文件

运行界面

                       american fuzzy lop 2.52b (upx.out)

lq process timing qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqwq overall results qqqqqk
x        run time : 0 days, 0 hrs, 3 min, 38 sec       x  cycles done : 0      x
x   last new path : 0 days, 0 hrs, 1 min, 0 sec        x  total paths : 50     x
x last uniq crash : none seen yet                      x uniq crashes : 0      x
x  last uniq hang : none seen yet                      x   uniq hangs : 0      x
tq cycle progress qqqqqqqqqqqqqqqqqqqqwq map coverage qvqqqqqqqqqqqqqqqqqqqqqqqu
x  now processing : 0 (0.00%)         x    map density : 2.13% / 3.27%         x
x paths timed out : 0 (0.00%)         x count coverage : 1.20 bits/tuple       x
tq stage progress qqqqqqqqqqqqqqqqqqqqnq findings in depth qqqqqqqqqqqqqqqqqqqqu
x  now trying : bitflip 2/1           x favored paths : 1 (2.00%)              x
x stage execs : 60.7k/152k (39.77%)   x  new edges on : 40 (80.00%)            x
x total execs : 215k                  x total crashes : 0 (0 unique)           x
x  exec speed : 992.1/sec             x  total tmouts : 0 (0 unique)           x
tq fuzzing strategy yields qqqqqqqqqqqvqqqqqqqqqqqqqqqwq path geometry qqqqqqqqu
x   bit flips : 45/152k, 0/0, 0/0                     x    levels : 2          x
x  byte flips : 0/0, 0/0, 0/0                         x   pending : 50         x
x arithmetics : 0/0, 0/0, 0/0                         x  pend fav : 1          x
x  known ints : 0/0, 0/0, 0/0                         x own finds : 49         x
x  dictionary : 0/0, 0/0, 0/0                         x  imported : n/a        x
x       havoc : 0/0, 0/0                              x stability : 100.00%    x
x        trim : 0.00%/1181, n/a                       tqqqqqqqqqqqqqqqqqqqqqqqqj
mqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqj          [cpu000: 50%]

无源码fuzz

对无源码的程序进行fuzz一般有两种方法:

  • 对二进制文件进行插桩
  • 使用-n选项进行传统的fuzz测试

第一种由afl-qemu实现,如果使用第二种方法,把-Q改成-n就行

编译一个AFL版的qemu

root@giant:~/aflfuzz/afl-2.52b# cd qemu_mode/
root@giant:~/aflfuzz/afl-2.52b/qemu_mode# ls
build_qemu_support.sh  patches  README.qemu
root@giant:~/aflfuzz/afl-2.52b/qemu_mode# ./build_qemu_support.sh 
root@giant:~/aflfuzz/afl-2.52b/qemu_mode#cp ../afl-qemu-trace /usr/local/bin/

如果缺少libtool

apt install libtool-bin

Error: devel version of ‘glib2’ not found, please install first.

apt-get install libgtk2.0-dev

最终显示

[+] Build process successful!
[*] Copying binary...
-rwxr-xr-x 1 root root 10351056 Dec  6 08:14 ../afl-qemu-trace
[+] Successfully created '../afl-qemu-trace'.
[*] Testing the build...
[+] Instrumentation tests passed. 
[+] All set, you can now use the -Q mode in afl-fuzz!

下面使用无源码方式fuzz readelf 同样也是创建文件夹,放入原始样本(test你自己准备吧)

mkdir afl_in afl_out
mv test ./afl_in/										#这个是readelf需要读取的文件
cp /usr/bin/readelf .
afl-fuzz -i afl_in -o afl_out -Q ./readelf -a @@		#-Q就是无源码进行二进制插装fuzz,如果选传统fuzz,把-Q改成-n就行

运行界面


                       american fuzzy lop 2.52b (readelf)

lq process timing qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqwq overall results qqqqqk
x        run time : 0 days, 0 hrs, 0 min, 18 sec       x  cycles done : 0      x
x   last new path : 0 days, 0 hrs, 0 min, 0 sec        x  total paths : 77     x
x last uniq crash : none seen yet                      x uniq crashes : 0      x
x  last uniq hang : none seen yet                      x   uniq hangs : 0      x
tq cycle progress qqqqqqqqqqqqqqqqqqqqwq map coverage qvqqqqqqqqqqqqqqqqqqqqqqqu
x  now processing : 0 (0.00%)         x    map density : 2.89% / 3.98%         x
x paths timed out : 0 (0.00%)         x count coverage : 1.55 bits/tuple       x
tq stage progress qqqqqqqqqqqqqqqqqqqqnq findings in depth qqqqqqqqqqqqqqqqqqqqu
x  now trying : bitflip 1/1           x favored paths : 1 (1.30%)              x
x stage execs : 1006/50.4k (2.00%)    x  new edges on : 52 (67.53%)            x
x total execs : 3181                  x total crashes : 0 (0 unique)           x
x  exec speed : 122.2/sec             x  total tmouts : 0 (0 unique)           x
tq fuzzing strategy yields qqqqqqqqqqqvqqqqqqqqqqqqqqqwq path geometry qqqqqqqqu
x   bit flips : 0/0, 0/0, 0/0                         x    levels : 2          x
x  byte flips : 0/0, 0/0, 0/0                         x   pending : 77         x
x arithmetics : 0/0, 0/0, 0/0                         x  pend fav : 1          x
x  known ints : 0/0, 0/0, 0/0                         x own finds : 76         x
x  dictionary : 0/0, 0/0, 0/0                         x  imported : n/a        x
x       havoc : 0/0, 0/0                              x stability : 100.00%    x
x        trim : 0.00%/1558, n/a                       tqqqqqqqqqqqqqqqqqqqqqqqqj
mqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqj          [cpu000: 50%]

输出的结果

tree -L 3
.
|-- crashes		#导致目标接收致命signal而崩溃的独特测试用例。
|   |-- README.txt												#保存了目标执行这些crash文件的命令行参数。
|   |-- id:000000,sig:11,src:000007,op:flip1,pos:63
|   |-- id:000001,sig:11,src:000007,op:flip1,pos:63
|   |-- id:000002,sig:11,src:000007,op:flip1,pos:63
|   |-- id:000003,sig:11,src:000007,op:flip1,pos:63
|   |-- id:000004,sig:11,src:000007,op:flip1,pos:192
|   |-- id:000005,sig:11,src:000007,op:flip1,pos:192
|   |-- id:000006,sig:11,src:000007,op:flip1,pos:770
|   |-- id:000007,sig:11,src:000007,op:flip1,pos:914
|   |-- id:000008,sig:11,src:000007,op:flip1,pos:1035
|   |-- id:000009,sig:11,src:000007,op:flip1,pos:1154
|   |-- id:000010,sig:11,src:000007,op:flip1,pos:1154
|   `-- id:000011,sig:11,src:000007,op:flip1,pos:1178
|-- fuzz_bitmap
|-- fuzzer_stats									#afl-fuzz的运行状态。
|-- hangs											#导致目标超时的独特测试用例。
|-- plot_data										#用于afl-plot绘图。
`-- queue											#存放所有具有独特执行路径的测试用例。
    |-- id:000000,orig:file
    |-- id:000001,src:000000,op:flip1,pos:0,+cov
    |-- id:000002,src:000000,op:flip1,pos:4,+cov
    |-- id:000003,src:000000,op:flip1,pos:5,+cov
    |-- id:000004,src:000000,op:flip1,pos:6,+cov
    |-- id:000005,src:000000,op:flip1,pos:7,+cov

漏洞是否能够利用的验证

afl-collect:alf-utils套件中的一个工具,项目地址:https://gitlab.com/rc0r/afl-utils.git

或者将crash文件用作输入可以使程序崩溃 ./afl_test fuzz_out/crashes/id:000002,sig:06,src:000002,op:havoc,rep:8

gdb调试

r id\:000010\,sig\:11\,src\:000007\,op\:flip1\,pos\:1154

bt

gdb-peda$ bt
#0  0x00000000005306da in PackLinuxElf64::calls_crt1 (this=this@entry=0x9ca030, rela=0x9cb3b8, sz=0x258, sz@entry=0x3c0) at p_lx_elf.cpp:1677
#1  0x000000000053e46a in PackLinuxElf64::canPack (this=0x9ca030) at p_lx_elf.cpp:2108
#2  0x00000000005f88f0 in try_pack (p=0x9ca030, user=0x7fffffffda40) at packmast.cpp:91
#3  0x00000000005fa879 in PackMaster::visitAllPackers (func=0x5f8840 <try_pack(Packer*, void*)>, f=0x7fffffffda40, o=0x7fffffffdbf8, 
    user=0x7fffffffda40) at packmast.cpp:194
#4  0x00000000005fd0da in PackMaster::getPacker (f=<optimized out>) at packmast.cpp:240
#5  PackMaster::pack (this=0x7fffffffdbe0, fo=0x7fffffffdb10) at packmast.cpp:260
#6  0x00000000006669a5 in do_one_file (iname=iname@entry=0x7fffffffe8ff "id:000010,sig:11,src:000007,op:flip1,pos:1154", 
    oname=oname@entry=0x7fffffffe180 "id:000010,sig:11,src:000007,op:flip1,pos:1154.001") at work.cpp:158
#7  0x000000000066717c in do_files (i=i@entry=0x1, argc=0x2, argv=0x7fffffffe6f8) at work.cpp:271
#8  0x00000000004054b1 in main (argc=argc@entry=0x2, argv=argv@entry=0x7fffffffe6f8) at main.cpp:1539
#9  0x00007ffff727b830 in __libc_start_main (main=0x4030e0 <main(int, char**)>, argc=0x2, argv=0x7fffffffe6f8, init=<optimized out>, 
    fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffe6e8) at ../csu/libc-start.c:291
#10 0x0000000000406349 in _start ()

代码覆盖率及其相关概念

基本块:缩写为BB,指一组顺序执行的指令,BB中第一条指令被执行后,后续的指令也会被全部执行,每个BB中所有指令的执行次数是相同的,也就是说一个BB必须满足以下特征:

  • 只有一个入口点,BB中的指令不是任何跳转指令的目标。
  • 只有一个退出点,只有最后一条指令使执行流程转移到另一个BB

边(edge):边就是基本块的跳转

元组:具体到AFL的实现中,使用二元组(branch_src, branch_dst)来记录当前基本块 + 前一基本块 的信息,从而获取目标的执行流程和代码覆盖情况

另一个有源码例子

vuln.c

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <string.h> 
#include <signal.h> 

int vuln(char *str)
{
    int len = strlen(str);
    if(str[0] == 'A' && len == 66)
    {
        raise(SIGSEGV);
        //如果输入的字符串的首字符为A并且长度为66,则异常退出
    }
    else if(str[0] == 'F' && len == 6)
    {
        raise(SIGSEGV);
        //如果输入的字符串的首字符为F并且长度为6,则异常退出
    }
    else
    {
        printf("it is good!\n");
    }
    return 0;
}

int main(int argc, char *argv[])
{
    char buf[100]={0};
    gets(buf);//存在栈溢出漏洞
    printf(buf);//存在格式化字符串漏洞
    vuln(buf);

    return 0;
}

插桩编译

afl-gcc -g -o vuln vuln.c

创建输入输出,并填入输入数据

mkdir afl_in afl_out
echo "hello" > afl_in/test.txt

开始fuzz

afl-fuzz -i afl_in/ -o afl_out/ ./vuln

其crash中文件的内容,就是导致程序崩溃的输出,我们可以用xxd命令来查看

xxd id\:000000\,sig\:11\,src\:000001\,op\:havoc\,rep\:16 
0000000: 4646 1306 5712 002c 136c 5702 f42c       FF..W..,.lW..,

另一个无源码例子

还是上边的程序普通编译

gcc vuln.c -o vuln

开始进行binary的fuzz

afl-fuzz -i afl_in/ -o afl_out/ -Q ./vuln

同样crash中文件的内容,就是导致程序崩溃的输出

xxd id\:000001\,sig\:11\,src\:000001\,op\:havoc\,rep\:64 
0000000: 46c6 c601 cb8b 0000 e200 cbfa ff7f 00cb  F...............
0000010: 0100 cb00 64cb cbcb cbcb cbcb cbed cb00  ....d...........
0000020: 0200 0100 ecc4 c5c5 c5a5 c5c5 c9c5 c5c5  ................
0000030: c5c5 c5c5 c5c5 dec5 c504 00a1 61db adab  ............a...
0000040: c67b                                     .{
xxd id\:000002\,sig\:11\,src\:000002\,op\:havoc\,rep\:16 
0000000: 4141 4141 4141 4141 5f3f 4141 4141 4141  AAAAAAAA_?AAAAAA
0000010: 4141 4141 4141 3141 4141 41c7 c7c7 c741  AAAAAA1AAAA....A
0000020: 4141 4141 4141 4141 4141 4141 4141 4141  AAAAAAAAAAAAAAAA
0000030: 1041 4141 4141 4141 41ff ff7f ff41 4141  .AAAAAAAA....AAA
0000040: 415c                                     A\

验证

more ./afl_out/crashes/id\:000001\,sig\:11\,src\:000001\,op\:havoc\,rep\:64 | ./vuln 
段错误

afl-tmin

精简payload

afl-tmin -i out/crashes/idxxxxxx -o min -Q -- ./a.out

安装afl-clang-fast

一.安装llvm(版本是3.5)

 1.需要的文件

  LLVM source code
  Clang source code
  Clang Tools Extra source code
  Compiler RT source code
  LibC++ source code

上面这些文件在这个链接:http://llvm.org/releases/download.html#3.5.0

下载好了以后,四个压缩包都解压

tar xvf XXXX.xz

得到四个目录:

  llvm-3.5.src
  cfe-3.5.src
  clang-tools-extra-3.5.src
  compiler-rt-3.5.src
  libcxx-3.5.src

然后

mv cfe-3.5.src clang
mv clang/ llvm-3.5.src/tools/

mv clang-tools-extra-3.5.src extra
mv extra/ llvm-3.5.src/tools/clang/

mv compiler-rt-3.5.src compiler-rt
mv compiler-rt llvm-3.5.src/projects/

这样以后clang,clang-tools-extra和compiler-rt就可以和llvm一起编译了。

apt install clang
apt install meson
apt install cmake

在llvm-3.5.src同一层目录上新建个目录build-3.5并进入:

mkdir build-3.5
cd build-3.5

然后

../llvm-3.5.2.src/configure --enable-optimized --enable-targets=host-only
make -j 4
make install

现在用clang++ -v查看下是否安装成功:

然后

cd /home/afl-2.52b/llvm_mode
make
cd ../
make install

这样就装完了

masker/slave 模式

master:

afl-fuzz -i testcases/ -o syncdir/ -M fuzzer1 tcpdump-4.6.2/tcpdump -nr @@

slave

afl-fuzz -i testcases/ -o syncdir/ -S fuzzer2 tcpdump-4.6.2/tcpdump -nr @@

然后输出文件夹就可以看到4个

ls syncdir/
fuzzer1  fuzzer2  fuzzer3  fuzzer4

使用afl-whatsup查看每一个进程

afl-whatsup syncdir/

configure

CC=afl-clang-fast CXX=afl-clang-fast++ LDFLAGS="-static" ./configure

配合preeny使用的一些sample命令

LD_PRELOAD=/root/preeny/src/desock.so afl-showmap -m2048 -o/dev/null /root/redis/src/redis-server /root/redis/conf < <(echo "PING");

LD_PRELOAD=/root/preeny/src/desock.so ./wget1 --debug localhost:6666  < <(echo "SHUTDOWN");

LD_PRELOAD=/root/preeny/src/desock.so ./wget1 localhost:6666 -O /dev/null < <(echo "SHUTDOWN");		#这个是字符串的形式

LD_PRELOAD=/root/preeny/src/desock.so ./wget1 localhost:6666  < index.html;		#这个是文件的形式

# compile and link our test harness using capstone's static library			#测试library使用的编译
afl-clang-fast -static harness.c capstone/libcapstone.a -o harness

LD_PRELOAD=/root/preeny/src/desock.so afl-fuzz -i afl_in -o afl_out ./wget3 localhost:6666 -O /dev/null @@

LD_PRELOAD=/root/preeny/src/desock.so afl-showmap -m2048 -o/dev/null ./wget2 localhost:6666 -O /dev/null < <(echo "PING");

ASAN结合使用

./configure CC=afl-gcc CXX=afl-g++ CFLAGS="-m32" LD=afl-gcc--disable-shared
AFL_USE_ASAN=1 make

编译

./configure CC="afl-gcc" CXX="afl-g++" --disable-shared; make

` –disable-shared`这个会让 LD_PRELOAD失效!! «««< HEAD

精简样本

使用afl-cmin进行精简样本,把执行相同路径的给去重,留下 具有相同覆盖范围的最小子集

afl-cmin -i less1k/ -o cmin-out/ -m none ./harness1 @@

=======

84da95c3c45235a33239e4945eafdaed52dad6c6