➜ pdf_examples git:(main) ✗ $FUZZ/fuzzing_xpdf/install/bin/pdfinfo -box -meta $FUZZ/fuzzing_xpdf/pdf_examples/helloworld.pdf
Tagged: no
Pages: 1
Encrypted: no
Page size: 200 x 200 pts
MediaBox: 0.00 0.00 200.00 200.00
CropBox: 0.00 0.00 200.00 200.00
BleedBox: 0.00 0.00 200.00 200.00
TrimBox: 0.00 0.00 200.00 200.00
ArtBox: 0.00 0.00 200.00 200.00
File size: 678 bytes
Optimized: no
PDF version: 1.7
分类: fuzzing
【Fuzzing101】学习笔记
Fuzzing101: https://github.com/antonio-morales/Fuzzing101
目录:
- 练习1: Xpdf
- 练习2: libexif
Fuzzer
文中主要使用了AFL++这个fuzzer,因为以前我没用过,在这里我是使用到AFL++的docker版本
docker pull aflplusplus/aflplusplus
docker run -ti -v /location/of/your/target:/src aflplusplus/aflplusplus
cargo-fuzz tutorial
一.安装
github: https://github.com/rust-fuzz/cargo-fuzz
安装: cargo install cargo-fuzz
➜ fuzzing cargo install cargo-fuzz
Updating https://mirrors.tuna.tsinghua.edu.cn/git/crates.io-index.git
index
Downloaded cargo-fuzz v0.10.0 (registry https://mirrors.tuna.tsinghua.edu.cn/git/crates.io-index.git
)
Downloaded 1 crate (30.5 KB) in 2.33s
Installing cargo-fuzz v0.10.0
……
Finished release [optimized] target(s) in 47.02s
Replacing /root/.cargo/bin/cargo-fuzz
Replaced package cargo-fuzz v0.8.0
with cargo-fuzz v0.10.0
(executable cargo-fuzz
)
➜ fuzzing cargo-fuzz
cargo-fuzz 0.10.0
A cargo
subcommand for using libFuzzer
! Easy to use! No need to recompile LLVM!
USAGE:
cargo-fuzz
FLAGS:
-h, –help Prints help information
-V, –version Prints version information
SUBCOMMANDS:
add Add a new fuzz target
build Build fuzz targets
cmin Minify a corpus
coverage Run program on the generated corpus and generate coverage information
fmt Print the std::fmt::Debug
output for an input
help Prints this message or the help of the given subcommand(s)
init Initialize the fuzz directory
list List all the existing fuzz targets
run Run a fuzz target
tmin Minify a test case
注意: cargo-fuzz 是集成了libfuzzer,libFuzzer依赖LLVM的,所以只能是x86-64的linux或者macos才可以,而且还需要C++编译器和C++11的支持。
用法
初始化: cargo fuzz init
- 添加目标: cargo fuzz add <target>
- 运行: cargo fuzz run <target>
- 打印测试用户输出
:cargo fuzz fmt <target> <input>
- 缩小到最小输出:
cargo fuzz tmin <target> <input>
- 缩小输入数据:
cargo fuzz cmin <target>
- 生成覆盖范围信息
: cargo fuzz coverage <target>
官方文档: https://rust-fuzz.github.io/book/cargo-fuzz.html
二.实战
我们随机选了一个好fuzzing的库,Human Time, 一个parser 时间的这种库。
crate: https://crates.io/crates/humantime
github: https://github.com/tailhook/humantime
文档: https://docs.rs/humantime/2.1.0/humantime/
第一步: 把项目clone到本地
git clone https://github.com/tailhook/humantime
我们可以看到,这个库自己是没有fuzz文件夹的,说明并没有做fuzzing
➜ humantime git:(master) ls
benches bulk.yaml Cargo.toml LICENSE-APACHE LICENSE-MIT README.md src vagga.yaml
第二步 : 项目初始化
进行项目文件夹执行
cargo fuzz init
可以看到,多了一个fuzz的文件夹
fuzz的文件夹结构:
➜ fuzz git:(master) ✗ tree
.
├── Cargo.toml
└── fuzz_targets
└── fuzz_target_1.rs
1 directory, 2 files
fuzz_target_1.rs的代码:
#![no_main]
use libfuzzer_sys::fuzz_target;
fuzz_target!(|data: &[u8]| {
// fuzzed code goes here
});
第三步,开始编写测试用例
我们查看文档,看看这个库的具体用法
https://docs.rs/humantime/2.1.0/humantime/fn.format_duration.html
#![no_main]
use libfuzzer_sys::fuzz_target;
use humantime::parse_duration;
fuzz_target!(|data: &[u8]| {
if let Ok(s) = std::str::from_utf8(data) {
let _ = parse_duration(s);
};
});
我们把data变成字符串,看看parse_duration是怎么解析的。
第四步,运行
cargo fuzz list 可以列出所有的测试用例
➜ fuzz_targets git:(master) ✗ cargo fuzz list
fuzz_target_1
我们继续添加测试用例
#![no_main]
use libfuzzer_sys::fuzz_target;
use humantime::{parse_duration, parse_rfc3339, parse_rfc3339_weak};
fuzz_target!(|data: &[u8]| {
// fuzzed code goes here
if let Ok(s) = std::str::from_utf8(data) {
let _ = parse_duration(s);
let _ = parse_rfc3339(s);
let _ = parse_rfc3339_weak(s);
};
});
第五步 分析结果
Fuzzing Tutorial (1)
The Fuzzing Book 链接: https://www.fuzzingbook.org/
01.Intro_Testing: https://www.fuzzingbook.org/html/Intro_Testing.html
libfuzzer demo-01
在上CS110l中有一个程序用来说明C/C++内存不安全的问题,我学到这里想着就用libfuzzer来fuzzer一下吧,顺便学习一下libfuzzer。
libfuzzer我已经搭建好了的,你可以根据https://github.com/Dor1s/libfuzzer-workshop来搭建环境。
源程序:
#include <stdio.h>
#include <string.h>
int main()
{
char s[100];
int i;
printf("\nEnter a string:");
gets(s);
for(i = 0; s[i] != '\0'; i++)
{
if ( s[i] >= 'a' && s[i] <= 'z')
{
s[i] = s[i] - 32;
}
}
printf("\nString in Upper Case = %s", s);
return 0;
}
很明显,这里是有缓冲区溢出的漏洞,gets函数不安全。最后发现,gets在C++11中被移除了,这个程序编译不过,放弃。