使用AFL来FUZZ Apache服务器【通过】

AFL(American Fuzzy Lop)是一款用于测试程序安全性的模糊测试工具,其主要针对命令输入类型的程序进行FUZZ,例如文档类型的FUZZ(通过构造畸形文档作为文档解析程序的输入)。而对网络协议类型的程序并不能很好的支持,例如http server程序。所以本文将以Apache Server为例来讲解如何使用AFL来FUZZ该类程序。

01 环境准备

 系统环境:Ubuntu 14 linux 64位(其它linux都行debian/kali)

 编译器环境:Clang+LLVM (kali自带,也可以自行下载最新版,下载路径http://releases.llvm.org/download.html)

 实验目录(不分目录也行,只是为了实验过程方便说明):

Victims :fuzz的目标程序存放目录

Fuzzers :fuzz程序安装包目录

Sessions: 存放fuzz中间过程文件

Testcases: 存放测试样本

Compiler: 编译器存放目录

首先配置好编译器环境,这里我直接下载的Clang+LLVM最新版放在compiler下,并配置好环境变量,修改/etc/profile如下:

image

然后再把clang建立两个软链接(由于afl的afl-clang.c和afl-clang-fast.c编译需要/bin/clang或/usr/bin/clang两路径):

然后安装AFL,很简单直接去
http://lcamtuf.coredump.cx/afl/releases/afl-latest.tgz
下载,然后解压安装即可:

image

最后下载apache源码包,编译并安装。之所以需要源码包安装,是因为后续需要修改源码编译才能让AFL正常FUZZ apache http server。编译之前需要准备好APR(Apache Portable Runtime)、APR Utils、nghttp2(用于支持http2)、Pcre,相关版本如下:

image

编译过程比较繁琐(中途可能需要手动安装libtool和g++),这里提供一个自动化编译shell

https://gist.githubusercontent.com/n30m1nd/14418fd425a3b2d14b64650710fae301/raw/e1cff738eb1ffaa55cb8a1a66bb1a2b06ed7f97e/compile_httpd_with_flags.sh

编译过程有问题可自行修改,然后执行以下命令来编译apache:

image

若能成功编译完成,即实验环境准备就绪。

02 Apache修改编译

由于AFL 不支持针对网络服务程序的Fuzz,即无法实现与apache建立连接、发送畸形报文,所以接下来我们需要修改下apache,让其能够接收来自文本文件的输入。这里我们提供一个patch,它针对server/main.c文件进行修改,修改完成后编译即可实现上述功能,并能被AFL Fuzz。

Patch链接地址如下:https://gist.githubusercontent.com/n30m1nd/28d193d99e02ad572927905cb315aad8/raw/31fe4d7df5db8d00c5e246b0f6b0b27c11f8de7e/apatching_apache_for_AFL_fuzzing.diff

该Patch主要在apache内起了一个线程,该线程跟web server自身建立连接,并能接收AFL Fuzz的输入并发送给web server进程。

修改关键代码如下:

 通过-F 参数接受FUZZ文件的输入:

image

 新启的线程会调用GETDATA函数,会对文件内容读取,然后对服务进程建立连接发送数据:

image

Path的使用方法(下载至源码包下,然后执行如下命令):

image

03 开始Fuzzing

打好补丁后,我们就可以开始编译修改后的apache,然后开始Fuzz。编译过程依然可以使用上述的自动化脚本:

然后创建两个简单的测试模板,当然这里仅仅是实验验证可以用AFL来FUZZ apache,若要想通过FUZZ来发现安全问题,还需根据分析的实际情况来构造更多模板:

image

然后可以通过如下命令来进行Fuzz了,其中-i 是模板路径,-o 是fuzz中间过程路径, -m 是子进程内存大小限制,–t 是每次启动程序允许的超时时间。

image

然后AFL会载入测试模板开始测试:

image

image

但是这里我们发现exec speed的速度太慢了,只有6.35/sec,正常的速度至少在1000/sec以上,所以我们需要开启persistent模式,即AFL的高性能模式。

04 开启高性能模式(persistent模式)

先进入llvm_mode目录,make之后再返回上级目录,再make install安装:

image

目的是为了安装afl-clang-fast这个编译器。

然后我们同样也需要修改下原始main.c,Patch的链接如下:

https://gist.githubusercontent.com/n30m1nd/ec19fc17c6293be303b85a998cd05aa9/raw/0eef740f4998b7af8216717670f8413c52c15637/apatching_for_AFL_Persistent_fuzzing.diff

打补丁的目的是开启persistent模式之后,针对apache这种server Fuzz需要做出修改才能提高效率,因为如果每fuzz的一个测试用例就新开一个进程会大大降低效率。

官方的做法是使用包含一个while循环和一个特殊的AFL函数__AFL_LOOP(),该函数的作用是使得AFL能在一个进程中进行多个testcase的fuzzing。修改如下:

image

AFL在一个进程中fuzz 10000个test cases,然后再新开一个进程执行相同的工作。

和上节打补丁的方法一样。打完补丁之后,再用afl-clang-fast和afl-clang-fast++编译一下:

CC="afl-clang-fast" CXX="afl-clang-fast++" PREFIX="/usr/local/apache_afl_per/" ./compile_httpd_with_flags.sh

完成之后make install apache就可以开始FUZZ了,执行如下命令可以看到效果:

afl-fuzz -i testcases/ -o sess/ -m none -t 2000 -- /usr/local/apache_afl_per/bin/httpd –X

image

至此,AFL FUZZ apache的环境已准备完毕,接下来我们用afl来测试fuzz出cve-2017-7659漏洞,做一个简短的验证。

把最终POC稍微做了下修改保存成testcase,让其不会引起httpd崩溃,看看AFL能否通过变形测试并输出最终POC:

很快,几秒钟AFL便FUZZ出一个crash,通过查看crash文件发现正是我们原来的POC文件:

把fuzz出的结果发送给httpd,果然崩溃:

image

通过GDB加载core dump结果调试可以发现崩溃的位置,如下正是该漏洞的触发点:

  • 通过
  • 未通过

0 投票者

2 Likes

问一个问题,afl在persistent模式下是怎么fetch输入的?

这个是?