一、NEUZZ思路解析
《NEUZZ Efficient Fuzzing with Neural Program Smoothing》这篇文章将模糊测试(fuzzing)的过程转化为了一个最优化问题:
最优化的 x 为程序每次运行的输入;
最优化的目标函数 y 一开始是:使程序输入产生的输出能找到的bug数量最大化,但是这个目标函数非常拉胯,有大量的陡峭的变化和平坦的部分。
而因为bug在程序中的分布一般来说是稀疏且均匀的,所以可以认为程序输入遍历的代码量越大,能找到的bug也就越多。
所以一般做fuzzing的时候最优化的目标函数 y 都会改成:使程序输入遍历到的代码数量最大化,最终目标为全覆盖整个程序的代码。
想要解决这个最优化问题,但是即使是改后的目标函数仍然拉胯,存在陡峭的变化和平坦的部分,所以一般的优化方式是随机变输入,随机碰,这种碰能碰上但是效率很低。
所以本文尝试用一个神经网络拟合优化目标函数,拟合函数相较于原函数更加平滑,即可以使用梯度或高阶导这种信息来指导程序输入的突变,不再依赖随机突变。
但是神经网络拟合需要已有的输入输出对进行训练,所以在程序一开始需要用随机碰的算法先产生一小部分输入输出对。
我们不能指望这一小部分输入输出对能够将神经网络训练得很好,所以后续的“程序输入的突变与测试”与“神经网络训练”两个过程需要反复交替进行。我们一边要训练神经网络,产生梯度信息,一边要在梯度信息的指导下对程序输入进行突变,测试,以求找到能够触发新代码段的输入,一边又要将触发了新的代码段的输入输出对提供给神经网络做进一步的拟合。
当然在论文中为了应对一些可能出现的问题还采取了相应的应对措施,在此就不做讨论了。
二、配置环境
为了运行 neuzz ,我在 VMware 中安装了一个 ubantu 系统的虚拟机。
环境配置的主要步骤参考了这篇文章:NEUZZ源码阅读笔记(一)
2.1 安装 Anaconda
首先在 terminal 中登入 root 账户
su
安装一些必备的库
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
我在安装时将 Anaconda 安装在了 “/home/ubuntu/anaconda3/bin” 这个路径中
2.2 安装环境包
安装完成后就可以通过conda命令建立虚拟环境了
conda create -n neuzz python=2.7
如果上一步显示错误,可以尝试以下命令刷新一下
source ~/.bashrc
激活虚拟环境
conda activate neuzz
激活完成后命令行应该变成这样
安装TensorFlow
pip install --upgrade tensorflow==1.8.0
安装Keras
pip install --upgrade keras==2.2.3
2.3 安装编译NEUZZ
下载NEUZZ源码:
git clone https://github.com/Dongdongshe/neuzz.git && cd neuzz
编译neuzz
gcc -O3 -funroll-loops ./neuzz.c -o neuzz
三、使用NEUZZ
上面所有的操作都不要求在哪个文件夹的 terminal ,但是接下来的操作必须在 /home/neuzz 中,并且必须确保激活 neuzz 环境
这里我们以测试 readelf 为例子,首先还是安装一些必备包
dpkg --add-architecture i386
apt-get update
apt-get install libc6:i386 libncurses5:i386 libstdc++6:i386 lib32z1
然后拷贝 nn.py 和 neuzz.c 这两个文件到工作目录下
(nn.py 和 neuzz.c是块砖,哪个数据集需要往哪搬)
cp neuzz ./programs/readelf/
cp nn.py ./programs/readelf/
然后设置一些内核参数
cd /sys/devices/system/cpu
echo performance | tee cpu*/cpufreq/scaling_governor
echo core >/proc/sys/kernel/core_pattern
但是我在做“echo performance | tee cpu*/cpufreq/scaling_governor”这一步的时候,系统报错说:
tee: ‘cpu*/cpufreq/scaling_governor’: No such file or directory
performance
不知道是为什么,但是没有影响后续运行,有知道的朋友可以交流一下
然后利用 cd 命令回到 /home/neuzz/programs/readelf/ 文件夹下,建立种子文件夹.
mkdir seeds
然后运行 nn.py 作为服务器端
python nn.py ./readelf -a
然后在另外一个终端里面运行neuzz
./neuzz -i neuzz_in -o seeds -l 7507 ./readelf -a @@
等双方通过套接字建立联系,便开始持续工作
工作一开始是 .c 文件通过随机突变获取一定的初始种子,测试过这些种子后将输入输出对递交 .py 文件开始训练神经网络模型。
.py 文件会训练100个epoch,然后生成指导下次突变的梯度信息递交给 .c 文件,.c文件拿到梯度信息后按照梯度信息的指导开始突变种子并对其进行测试(突变过程又分为顺梯度方向,逆梯度方向和随机突变三个步骤),记录测试中发现新的输出边缘的输入种子,并将这些种子再次递交 .py 文件开始下一轮训练。
总结
NEUZZ的原理比较好懂,我觉得最有意义的是他的思考方式。
当我们遇到一个问题发现梯度下降法不再适用,我们可以舍弃梯度下降法转而寻求随机突变或其他算法,也可以通过神经网络等手段改善/拟合目标函数,从而使改进后的目标函数适用于梯度下降算法。
这两种思路的优劣需要具体情况具体分析,但两种思路本身都是我们需要学习和在实践中留心使用的好方法。