2018年12月26日星期三

IoT(七)通过qemu调试IoT固件和程序

0x0 QEMU简介

QEMU是一款开源的模拟器及虚拟机监管器(Virtual Machine Monitor, VMM)。QEMU主要提供两种功能给用户使用,一是作为用户态模拟器,利用动态代码翻译机制来执行不同于主机架构的代码。二是作为虚拟机监管器,模拟全系统,利用其他VMM(Xen, KVM, etc)来使用硬件提供的虚拟化支持,创建接近于主机性能的虚拟机。
系统模式(虚拟机监管器qemu-system):功能类似于VMware或者VMtools,对整个系统进行虚拟化运行,相当于启动了另外一个虚拟机系统。
用户模式(用户态模拟器qemu):将单独的可执行文件使用虚拟化环境运行,例如在x86架构的环境下执行mips可执行文件等,便于进行进一步的动态调试等工作。

0x1 系统模式调试固件

0x11 安装qemu系统模式

qemu系统模式可以直接通过包管理器安装:
//macOS
$ brew install qemu
//Linux
$ apt install qemu

0x12 启动参数

使用qemu系统模式,需要的文件以一段qemu启动参数作为例子,重点文件在于系统内核kernel和文件系统rootfs.img,获取到这两个文件后,还需弄清楚kernel对应的cpu类型,使用的内存大小等信息:
qemu-system-arm \
    -kernel ./kernel \
    -dtb ./kernel.dtb \
    -cpu arm1176 \
    -m 256 \
    -M versatilepb \
    -serial stdio \
    -append "root=/dev/sda2 panic=1 rootfstype=ext4 rw" \
    -hda rootfs.img
-kernel: 指定kernel文件。
-dtb: 指定dtb(Device Tree Blob)文件,假如kernel包含dtb。
-cpu: 指定cpu类型。(qemu-system-arm -M highbank -cpu help查看可选项,(这个可能版本有bug, 必须指定-M才能查看))
-m: 指定内存大小。
-M: 制定机器类型。 (qemu-system-arm -machine help查看可选项)
-serial: 重定向串口。
-append: 为kernel指定启动参数。
-hda: 指定磁盘镜像。
qemu系统模式工具(末尾为cpu类型)
qemu-system-aarch64      qemu-system-microblaze   qemu-system-or1k         qemu-system-sh4eb
qemu-system-alpha        qemu-system-microblazeel qemu-system-ppc          qemu-system-sparc
qemu-system-arm          qemu-system-mips         qemu-system-ppc64        qemu-system-sparc64
qemu-system-cris         qemu-system-mips64       qemu-system-ppcemb       qemu-system-tricore
qemu-system-hppa         qemu-system-mips64el     qemu-system-riscv32      qemu-system-unicore32
qemu-system-i386         qemu-system-mipsel       qemu-system-riscv64      qemu-system-x86_64
qemu-system-lm32         qemu-system-moxie        qemu-system-s390x        qemu-system-xtensa
qemu-system-m68k         qemu-system-nios2        qemu-system-sh4          qemu-system-xtensaeb
支持的cpu类型参数
$ qemu-system-arm -M highbank -cpu help
Available CPUs:
  arm1026
  arm1136
  arm1136-r2
  arm1176
  arm11mpcore
  arm926
  arm946
  cortex-a15
  cortex-a7
  cortex-a8
  cortex-a9
  cortex-m3
  cortex-m33
  cortex-m4
  cortex-r5
  cortex-r5f
  max
  pxa250
  pxa255
  pxa260
  pxa261
  pxa262
  pxa270-a0
  pxa270-a1
  pxa270
  pxa270-b0
  pxa270-b1
  pxa270-c0
  pxa270-c5
  sa1100
  sa1110
  ti925t
支持的机器类型参数
$ qemu-system-arm -machine help
Supported machines are:
akita                Sharp SL-C1000 (Akita) PDA (PXA270)
ast2500-evb          Aspeed AST2500 EVB (ARM1176)
borzoi               Sharp SL-C3100 (Borzoi) PDA (PXA270)
canon-a1100          Canon PowerShot A1100 IS
cheetah              Palm Tungsten|E aka. Cheetah PDA (OMAP310)
collie               Sharp SL-5500 (Collie) PDA (SA-1110)
connex               Gumstix Connex (PXA255)
cubieboard           cubietech cubieboard
emcraft-sf2          SmartFusion2 SOM kit from Emcraft (M2S010)
highbank             Calxeda Highbank (ECX-1000)
imx25-pdk            ARM i.MX25 PDK board (ARM926)
integratorcp         ARM Integrator/CP (ARM926EJ-S)
kzm                  ARM KZM Emulation Baseboard (ARM1136)
lm3s6965evb          Stellaris LM3S6965EVB
lm3s811evb           Stellaris LM3S811EVB
mainstone            Mainstone II (PXA27x)
mcimx7d-sabre        Freescale i.MX7 DUAL SABRE (Cortex A7)
midway               Calxeda Midway (ECX-2000)
mps2-an385           ARM MPS2 with AN385 FPGA image for Cortex-M3
mps2-an505           ARM MPS2 with AN505 FPGA image for Cortex-M33
mps2-an511           ARM MPS2 with AN511 DesignStart FPGA image for Cortex-M3
musicpal             Marvell 88w8618 / MusicPal (ARM926EJ-S)
n800                 Nokia N800 tablet aka. RX-34 (OMAP2420)
n810                 Nokia N810 tablet aka. RX-44 (OMAP2420)
netduino2            Netduino 2 Machine
none                 empty machine
nuri                 Samsung NURI board (Exynos4210)
palmetto-bmc         OpenPOWER Palmetto BMC (ARM926EJ-S)
raspi2               Raspberry Pi 2
realview-eb          ARM RealView Emulation Baseboard (ARM926EJ-S)
realview-eb-mpcore   ARM RealView Emulation Baseboard (ARM11MPCore)
realview-pb-a8       ARM RealView Platform Baseboard for Cortex-A8
realview-pbx-a9      ARM RealView Platform Baseboard Explore for Cortex-A9
romulus-bmc          OpenPOWER Romulus BMC (ARM1176)
sabrelite            Freescale i.MX6 Quad SABRE Lite Board (Cortex A9)
smdkc210             Samsung SMDKC210 board (Exynos4210)
spitz                Sharp SL-C3000 (Spitz) PDA (PXA270)
sx1                  Siemens SX1 (OMAP310) V2
sx1-v1               Siemens SX1 (OMAP310) V1
terrier              Sharp SL-C3200 (Terrier) PDA (PXA270)
tosa                 Sharp SL-6000 (Tosa) PDA (PXA255)
verdex               Gumstix Verdex (PXA270)
versatileab          ARM Versatile/AB (ARM926EJ-S)
versatilepb          ARM Versatile/PB (ARM926EJ-S)
vexpress-a15         ARM Versatile Express for Cortex-A15
vexpress-a9          ARM Versatile Express for Cortex-A9
virt-2.10            QEMU 2.10 ARM Virtual Machine
virt-2.11            QEMU 2.11 ARM Virtual Machine
virt-2.12            QEMU 2.12 ARM Virtual Machine
virt-2.6             QEMU 2.6 ARM Virtual Machine
virt-2.7             QEMU 2.7 ARM Virtual Machine
virt-2.8             QEMU 2.8 ARM Virtual Machine
virt-2.9             QEMU 2.9 ARM Virtual Machine
virt                 QEMU 3.0 ARM Virtual Machine (alias of virt-3.0)
virt-3.0             QEMU 3.0 ARM Virtual Machine
witherspoon-bmc      OpenPOWER Witherspoon BMC (ARM1176)
xilinx-zynq-a9       Xilinx Zynq Platform Baseboard for Cortex-A9
z2                   Zipit Z2 (PXA27x)

0x13 启动示例

0x131 获取必备文件

树莓派raspberrypi为例,Raspbian 的镜像有两个版本,一个带图形界面的完整版和一个没有图形界面的 lite 版本,对于分析而言 lite 版本就足够了,本次获取最新镜像文件为2018-11-13-raspbian-stretch-lite.zip
此外,还需qemu版kernel,下载对应kernel版本kernel-qemu-4.14.50-stretch和dtb文件versatile-pb.dtbkernel-qemu-4.*.*-stretch等较新kernel需要dtb文件,老版本不用)。若调试的IoT镜像kernel不支持,可自行编译对应版本的kernel,或者使用树莓派的kernel。
解开镜像后,在macOS里树莓派镜像双击即可挂载,挂载后内容如下:
➜ /Volumes/boot >file *
COPYING.linux:            ASCII text
LICENCE.broadcom:         ASCII text
LICENSE.oracle:           UTF-8 Unicode text, with very long lines
bcm2708-rpi-0-w.dtb:      Device Tree Blob version 17, size=23315, boot CPU=0, string block size=2279, DT structure block size=20964
bcm2708-rpi-b-plus.dtb:   Device Tree Blob version 17, size=23071, boot CPU=0, string block size=2299, DT structure block size=20700
bcm2708-rpi-b.dtb:        Device Tree Blob version 17, size=22812, boot CPU=0, string block size=2244, DT structure block size=20496
bcm2708-rpi-cm.dtb:       Device Tree Blob version 17, size=22589, boot CPU=0, string block size=2225, DT structure block size=20292
bcm2709-rpi-2-b.dtb:      Device Tree Blob version 17, size=24115, boot CPU=0, string block size=2371, DT structure block size=21672
bcm2710-rpi-3-b-plus.dtb: Device Tree Blob version 17, size=25574, boot CPU=0, string block size=2538, DT structure block size=22964
bcm2710-rpi-3-b.dtb:      Device Tree Blob version 17, size=25311, boot CPU=0, string block size=2447, DT structure block size=22792
bcm2710-rpi-cm3.dtb:      Device Tree Blob version 17, size=24087, boot CPU=0, string block size=2319, DT structure block size=21696
bootcode.bin:             data
cmdline.txt:              ASCII text
config.txt:               ASCII text
fixup.dat:                data
fixup_cd.dat:             data
fixup_db.dat:             data
fixup_x.dat:              data
issue.txt:                ASCII text
kernel.img:               Linux kernel ARM boot executable zImage (little-endian)
kernel7.img:              Linux kernel ARM boot executable zImage (little-endian)
overlays:                 directory
start.elf:                ELF 32-bit LSB executable, Broadcom VideoCore III, version 1 (SYSV), statically linked, stripped
start_cd.elf:             ELF 32-bit LSB executable, Broadcom VideoCore III, version 1 (SYSV), statically linked, stripped
start_db.elf:             ELF 32-bit LSB executable, Broadcom VideoCore III, version 1 (SYSV), statically linked, stripped
start_x.elf:              ELF 32-bit LSB executable, Broadcom VideoCore III, version 1 (SYSV), statically linked, stripped
双击挂载实际只挂载了第一个启fat32分区,并没有挂载文件系统。通过fdisk指令查看镜像,可以看到镜像有两个分区,其中linux文件系统分区偏移为98304*512=50331648:
//$ fdisk -l 2018-11-13-raspbian-stretch-lite.img
$ fdisk 2018-11-13-raspbian-stretch-lite.img
Disk: 2018-11-13-raspbian-stretch-lite.img geometry: 904/64/63 [3645440 sectors]
Signature: 0xAA55
         Starting       Ending
 #: id  cyl  hd sec -  cyl  hd sec [     start -       size]
------------------------------------------------------------------------
 1: 0C    0 130   3 -    6  26  18 [      8192 -      89854] Win95 FAT32L
 2: 83    6  30  25 -  226 234   8 [     98304 -    3547136] Linux files*
 3: 00    0   0   0 -    0   0   0 [         0 -          0] unused
 4: 00    0   0   0 -    0   0   0 [         0 -          0] unused
文件系统可通过如下指令进行挂载,挂载后可直接对其读写:
$ sudo mkdir /mnt/raspbian
$ sudo mount -v -o offset= 50331648 -t ext4 [path-of-your-img-file.img] /mnt/raspbian

0x132 qemu模拟raspberrypi

获取kernel和文件系统后,即可使用如下指令启动qemu来模拟raspberrypi:
$ qemu-system-arm -kernel kernel-qemu-4.14.50-stretch \
  -cpu arm1176 \
  -m 256 \
  -M versatilepb \
  -dtb versatile-pb.dtb \
  -no-reboot \
  -append "root=/dev/sda2 panic=1 rootfstype=ext4 rw" \
  -net nic \    #使用默认NAT方式连接网络
  -net user,hostfwd=tcp::5022-:22 \   # 为 ssh 预留,将模拟器的22端口转发到电脑5022端口
  -net user,hostfwd=tcp::2333-:2333 \   # 为 gdbserver 预留,用于远程调试
  -hda 2018-11-13-raspbian-stretch-lite.img
启动成功后界面如下,树莓派系统默认账户(pi)密码(raspberry):
遇到的坑
  • Error: unrecognized/unsupported machine ID (r1 = 0x00000183).
    • kernel-qemu-4.*.*-stretch等较新kernel需要加载dtb文件

0x133 调试系统

1、使用默认账户(pi)密码(raspberry)登录raspberry
2、开启 ssh 服务,并设置开机启动
$ sudo service ssh start
$ sudo update-rc.d ssh enable
3、之后即可在电脑端通过 ssh 访问虚拟机
$ ssh [email protected] -p 5022
$ scp -P 5022 *.* [email protected]:/tmp  //scp传递文件
4、安装gdb-multiarch
由于默认安装的 gdb 只支持 x86/x64 架构(可以启动 gdb 然后输入命令set architecture arm查看),而gdb-multiarch 是 gdb 支持多种硬件体系架构的版本,安装指令如下:
//安装gdb-multiarch
$ sudo apt install gdb-multiarch
//启动gdb-multiarch
$ gdb-multiarch
5、编译gdbserver
虽然Raspbian 系统中自带 gdb,但如果调试其他IoT系统,则可能需要自己下载对应版本源码并编译相应版本的gdbserver:
//安装交叉编译环境
$ apt install gcc-5-arm-linux-gnueabi  gcc-5-arm-linux-gnueabihf
//下载解压后进入`gdb-<version>/gdb/gdbserver`目录
$ CC="arm-linux-gnueabi-gcc-5" CXX="arm-linux-gnueabi-g++-5" ./configure --target=arm-linux-gnueabi --host="arm-linux-gnueabi"
$ make install
$ file arm-linux-gnueabi-gdbserver
arm-linux-gnueabi-gdbserver: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.3, for GNU/Linux 3.2.0,
BuildID[sha1]=32ad2025951ee428276ac2fbadb199bfd39e2278, not stripped
6、使用 scp 将 gdbserver 上传到虚拟树莓派中并启动
//pc端
$ scp -P 5022 arm-linux-gnueabi-gdbserver [email protected]:/tmp/
//树莓派端
$ ln -s arm-linux-gnueabi-gdbserver gdbserver
$ gdbserver 0.0.0.0:2333 *
Process hello created; pid = 702
Listening on port 2333
7、电脑端gdb remote连接gdbserver
//建议先安装 gdb 增强脚本gef
$ wget -q -O- https://github.com/hugsy/gef/raw/master/scripts/gef.sh | sh
//设置目标硬件体系架构为 arm
gef> set architecture arm
//使用 gef-remote 命令连接 gdbserver,如果使用 gdb 自带的“ target remote ”命令会出现一些[非预期的问题](https://github.com/hugsy/gef/issues/7)
gef> gef-remote –q 127.0.0.1:2333

0x2 用户模式调试程序

qemu的用户模式功能比较局限,程序依赖的外部资源无法正常提供,只有静态编译的可执行程序才能比较顺利的执行。

0x21 安装qemu-user

Linux下,可以直接通过apt包管理器来安装qemu user模式工具:
$ apt install qemu-user
另外qemu-user对macOS支持不够友好,brew也未提供user模式工具,需要手动下载qemu源码编译安装,但编译过程中错误较多:
$ wget https://download.qemu.org/qemu-3.1.0.tar.xz
$ tar xvf qemu-3.1.0.tar.xz
$ cd qemu-3.1.0
$ ./configure
$ make
$ make install
安装完成后,qemu-[cpu架构]*系列指令即qemu user工具,如32位arm为qemu-armqemu-arm-static,64位arm为qemu-aarch64qemu-aarch64-static

0x22 使用用户模式执行

使用用户模式执行程序的方法很简单,只需要在原来的程序执行命令之前添加qemu-[cpu架构]*即可,如:
//原来运行命令
$ <executable> <arg1> <arg2> ...
//使用qemu-arm运行
$ qemu-arm <executable> <arg1> <arg2> ...
如以Android系统中的adbd工具为例,使用对应系统架构的qemu user指令执行即可,但由于qemu模拟环境缺少Android中adbd需要的socket等资源,故adbd提示错误:
$ file adbd
adbd: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), statically linked, BuildID[md5/uuid]=2ef781f7497eaad0b8ba145996afd9a1, not stripped
$ qemu-aarch64 adbd
adbd E 12-26 07:15:03  5304  5304 adbd_auth.cpp:183] Failed to get adbd socket: No such file or directory
adbd E 12-26 07:15:03  5304  5304 adbd_auth.cpp:192] Failed to get adbd socket: No such file or directory
adbd: libminijail[5304]: prctl(PR_SET_SECUREBITS) failed: Operation not permitted
adbd: libminijail[5304]: locking securebits failed: Operation not permitted
libc: Fatal signal 6 (SIGABRT), code -6 (SI_TKILL) in tid 5304 (qemu-aarch64), pid 5304 (qemu-aarch64)
libc: failed to spawn debuggerd dispatch thread: Invalid argument

0x23 调试IoT程序

由于缺少adbd需要的外部资源,虽然运行提示错误,但其实依然是成功运行了,故可以使用gdb直接进行调试。qemu工具自带有gdbserver ,通过-g选项可以指定监听端口,即可在另一终端中启动gdb-multiarch进行远程调试:
//qemu-aarch64 –g [gdbserver port] *
$ qemu-aarch64 –g 2333 adbd
//新终端
$ gdb-multiarch
gef> set architecture aarch64
gef> gef-remote –q 127.0.0.1:2333

2018年12月16日星期日

IoT(六)uboot镜像解析

0x1 uboot镜像格式

通常Linux krenel经过编译后会生成名称为vmlinux或vmlinuz的ELF格式文件,嵌入式系统在部署时烧录的文件格式需要用objcopy工具去制作成烧录镜像格式文件Image。但由于Image太大,因此linux kernel项目对Image进行了压缩,并且在image压缩后的文件的前端附加了一部分解压缩代码,构成压缩镜像格式zImage。
uboot自身为了支持linux kernel的启动,构建了uImage镜像格式,uImage有两种类型,Legacy-uImage和FIT-uImage:
Legacy-uImage是在zImage压缩镜像的基础上增加了64字节的头信息,使用uboot自带的mkimage工具生成了uboot自身的压缩镜像格式uImage。
FIT-uImage(flattened image tree)类似于FDT(flattened device tree)的一种实现机制。其通过一定语法和格式将一些需要使用到的镜像(例如kernel、dtb以及文件系统)组合到一起生成一个image文件。

0x2 Legacy-uImage解析

Legacy-uImage镜像格式解析比较简单,去掉64字节即0x40的头信息,即可得到zImage压缩镜像,是vmlinux经过objcopy gzip压缩后的文件,可以被qemu、boot等直接加载。
另外,uboot自带的mkimage工具,可以识别所有uboot镜像格式信息。

0x3 FIT-uImage解析

以某FIT-uImage格式的boot.img镜像为例,在头部可以看见U-Boot fitImage for Yocto GENIVI Baseline (Poky/meta-ivi)/4.4/ailabs_m1的明文信息:
FIT uImageu-boot推出了全新的image格式,其中FIT是flattened image tree的简称;而Yocto GENIVI Baseline (Poky/meta-ivi)则是一种嵌入式专用的linux发行版。
kernel镜像作为FIT的configure中的一个节点,其信息则是以节点中的属性来进行描述的。 uboot的工作就是要从FIT中提取相应的kernel节点,在节点中获取相应的属性,从而得到kernel的信息。
以下指令可以安装uboot的mkimage工具,并使用mkimage获取boot.img信息,可以看到Linux kernel偏移在0x40080000,共4254829 Bytes=0x40EC6D,使用lz4 compressed压缩但。这个偏移只是运行后的加载偏移,不是kernel在boot.img的偏移:

$ brew install u-boot-tools
//$ apt install u-boot-tools

$ mkimage -l boot.img

FIT description: U-Boot fitImage for Yocto GENIVI Baseline (Poky/meta-ivi)/4.4/ailabs_m1

Created:         Tue Apr 17 19:17:30 2018

 Image 0 (kernel@1)

  Description:  Linux kernel

  Created:      Tue Apr 17 19:17:30 2018

  Type:         Kernel Image

  Compression:  lz4 compressed

  Data Size:    4254829 Bytes = 4155.11 KiB = 4.06 MiB

  Architecture: AArch64

  OS:           Linux

  Load Address: 0x40080000

  Entry Point:  0x40080000

...
编译kernel时是通过dtc(device-tree-compiler)编译工具将.dts编译为.dtb,并将其与kernel合并打包出boot.img。所以要从dtb格式的boot.img提取kernel等文件,需要通过dtc工具进行分别提取,方式如下:
$ apt install device-tree-compiler

$ dtc -o boot.conf boot.img
得到以下文件boot.conf:
通过以上kernel与DTB中的data提取出hex数据存入文件(如使用010editor,View -> Edit As -> HexEdit -> Paste From -> Paste from Hex Test),即分别得到kernel与dtb文件。通过file指令查看kernel文件,显示为lz4压缩数据,与上文获取的信息一致;lz4 -d kernel kernel_out指令可以解开lz4压缩:
$ file kernel
kernel: LZ4 compressed data (v0.1-v0.9)
$ lz4 -d kernel kernel_out

2018年12月11日星期二

AFL(一)源码fuzz

0x0 概述

American Fuzz Lop简称 AFL,号称是当前最高级的Fuzzing测试工具之一,由lcamtuf所开发的开源模糊测试工具。
AFL同时支持两种Fuzz模式:
有源码模式:使用AFL来进行有源码fuzz基本上是依赖于AFL中的代码插桩。
无源码模式(afl-qemu):AFL的无源码模式的fuzz依赖于qemu虚拟化。
使用有源码模式需要使用afl-clang或afl-clang++来编译工程代码,然后以文件(尽量 <1K)为输入,然后启动afl-fuzz程序,将testcase(seed) 喂给程序代码,然后程序接收此次输入执行程序,如果发现新的路径则保存此testcase到一个queue中,afl-fuzz继续编译testcase,因此程序每次接收不同的输入,如果程序崩溃,则记录crash。
与其他基于插桩技术的fuzzers相比,afl-fuzz具有较低的性能消耗,有各种高效的fuzzing策略和tricks最小化技巧, 不需要先行复杂的配置,能无缝处理复杂的现实中的程序。

0x1 安装

0x11 包管理器安装

macOS:
$ brew install afl-fuzz
Linux:
$ apt install afl

0x12 源码编译安装

如果需要较新版本的AFL,也可通过AFL的官网下载源码自行编译:
$ wget http://lcamtuf.coredump.cx/afl/releases/afl-latest.tgz
$ tar xvf afl-latest.tgz
$ make
$ sudo make install

0x2 使用有源码模式

0x21 AFL Fuzzing步骤

  1. 使用afl-gcc编译项目代码,将编译脚本中的CC=afl-gcc/CXX=afl-g++
  2. 新建两个文件夹,如fuzz_in/fuzz_out,文件夹名随意;
  3. 将初始化testcase放到fuzz_in目录下;
  4. 执行afl-fuzz -i fuzz_in -o fuzz_out ./xxx @@,xxx为可执行程序名,@@表示从文件中读入
  5. 观察fuzzing结果,如有crash,定位问题。

0x22 fuzz测试示例

0x221 示例代码afl_test.c

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

int vuln(char *Data) {
int num = rand() % 100 + 1;
printf("Data is generated, num is %d\n", num);
if(Data[0] == 'C' && num == 25)
{
    raise(SIGSEGV);
}
else if(Data[0] == 'F' && num == 90)
{
    raise(SIGSEGV);
}
else{
    printf("it is good!\n");
}
return 0;
}

int main(int argc, char *argv[])
{
char buf[40]={0};
FILE *input = NULL;
input = fopen(argv[1], "r");
if(input != 0)
{
    fscanf(input, "%s", &buf);
    printf("buf is %s\n", buf);
    vuln(buf);
    fclose(input);
}
else
{
    printf("bad file!");
}
return 0;
}
如果输入的数据第一个字母是’C’并且num=25 或者第一个字母是’F’并且num=90,那么程序异常退出。

0x222 编译

$ afl-clang -g -o afl_test afl_test.c

0x223 准备环境

  1. 新建输入、输出文件夹:
    $ mkdir fuzz_in fuzz_out
    
  2. 准备初始化testcase, 将testcase内容随意写成aaa:
    $ echo aaa > fuzz_in/testcase
    
    另外官网提供了部分测试集,里面有大量的各种格式的且经过修剪处理的测试用例

0x224 开始Fuzz

使用如下指令即可开始fuzz
$ afl-fuzz -i fuzz_in -o fuzz_out ./afl_test @@
启动afl-fuzz中往往会报错,表示某些环境变量没有配置或者配置错误,如:
afl-fuzz 2.52b by <[email protected]>
[+] You have 4 CPU cores and 4 runnable tasks (utilization: 100%).
[-] Whoops, your system is configured to forward crash notifications to an
    external crash reporting utility. This will cause issues due to the
    extended delay between the fuzzed binary malfunctioning and this fact
    being relayed to the fuzzer via the standard waitpid() API.
    To avoid having crashes misinterpreted as timeouts, please run the
    following commands:
    SL=/System/Library; PL=com.apple.ReportCrash
    launchctl unload -w ${SL}/LaunchAgents/${PL}.plist
    sudo launchctl unload -w ${SL}/LaunchDaemons/${PL}.Root.plist
[-] PROGRAM ABORT : Crash reporter detected
         Location : check_crash_handling(), afl-fuzz.c:7247
按照提示配置即可:
$ SL=/System/Library; PL=com.apple.ReportCrash
$ launchctl unload -w ${SL}/LaunchAgents/${PL}.plist
$ sudo launchctl unload -w ${SL}/LaunchDaemons/${PL}.Root.plist
重新执行fuzz,运行成功如下
$ afl-fuzz -i fuzz_in -o fuzz_out ./afl_test @@

0x225 重现crash

从fuzz界面可以看到2分29秒时候afl已经发现了3个crash,afl会在./fuzz_out/crashes目录下记录crash文件:

将crash文件用作输入可以使程序崩溃
$ ./afl_test fuzz_out/crashes/id:000001,sig:06,src:000001,op:havoc,rep:16
然后调试分析即可

0x23 fuzz开源软件

0x231 编译fuzz目标

libpng是开源的png解析库
$ wget https://nchc.dl.sourceforge.net/project/libpng/libpng16/1.6.36/libpng-1.6.36.tar.xz
$ tar xvf libpng-1.6.36.tar.xz
$ cd libpng-1.6.36
$ ./autogen.sh 
$ CC=afl-clang CXX=afl-g++ ./configure --enable-static
$ make -j4
--enable-static : 用于生成静态库,fuzz开源库时会需要

0x232 准备环境

获取官网提供的测试集作为输入
$ mkdir fuzz_in fuzz_out
$ cd fuzz_in
$ wget http://lcamtuf.coredump.cx/afl/demo/afl_testcases.tgz
$ tar xvf afl_testcases.tgz

0x233 开始fuzz

$ afl-fuzz -i ../fuzz_in/png/full/images -o ../fuzz_out ../.libs/pngimage @@
其中,../fuzz_in/png/full/images为afl官网提供的测试集,里面有大量的各种格式的且经过修剪处理的测试用例,../.libs/pngimage是编译出来的被测试程序,@@代表测试输入样本,即../fuzz_in/png/full/images目录下的.png文件,在实际执行时@@会被替换成实际的测试样本。
之后就等待crash了

CVE/CNVD list

报告记录&poc: 最近fuzz出了不少crash,提交记录git: https://github.com/gandalf4a/crash_report 其中CVE记录如下: (不定期持续更新) 2025 CVE-2025-22134:heap-buffer-o...