题外话
现在搜索引擎已经很少搜到技术博客了,搜到的技术文章也都是2020年左右的,前几年个人建站的博客非常火,但是现在落寞了,思考了下原因,个人博客是没有正反馈,不像csdn有创作激励,有流量等等。
今年7月份我也转向了csdn写博客,用流量券曝光,有点赞、收藏、关注,这些正反馈,是我创作的动力,respect!
libfuzzer
libFuzzer 是一个由 LLVM 项目提供的功能强大的模糊测试工具,它是一个内置于 LLVM 编译器中的覆盖引导的进化模糊测试引擎
前置
编写用例
可以看到FuzzMe函数,如果DataSize =3并且data=“FUZ”时,调用Data[3],会发生内存越界错误
#include <iostream>
#include <cstdint>
#include <cstddef>
using namespace std;
// clang++ -fsanitize=fuzzer,address fuzz_target.cc -o fuzz_target
// ./fuzz_target corpus -max_total_time=30
bool FuzzMe(const uint8_t *Data, size_t DataSize) {
return DataSize >= 3 &&
Data[0] == 'F' &&
Data[1] == 'U' &&
Data[2] == 'Z' &&
Data[3] == 'Z';
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
FuzzMe(Data, Size);
return 0;
}
编译
clang++ -fsanitize=fuzzer,address fuzz_target.cc -o fuzz_target
创建初始种子 corpus (corpus
目录)
创建一个包含一些初始输入样本的目录,这些样本将被 libFuzzer 用来开始模糊测试。
mkdir corpus
# 将一些初始样本放入 corpus 目录。
# 例如,你可以使用一些简单的文本文件或二进制文件。
运行
./fuzz_target corpus -max_total_time=30
如果不设定时间和次数,程序会一直运行下去直至崩溃
使用 -max_total_time=N
来设置 libFuzzer 运行的总时间(秒)。
使用 -runs=N
来设置 libFuzzer 执行的测试用例次数。
打印结果
[root@pekphis94681:jishufenxiang]# ./fuzz_target corpus -max_total_time=30
INFO: Seed: 1131142770
INFO: Loaded 1 modules (9 inline 8-bit counters): 9 [0x5a7f00, 0x5a7f09),
INFO: Loaded 1 PC tables (9 PCs): 9 [0x56b1b8,0x56b248),
INFO: 27 files found in corpus
INFO: -max_len is not provided; libFuzzer will not generate inputs larger than 32720 bytes
INFO: seed corpus: files: 27 min: 1b max: 32720b total: 107413b rss: 28Mb
#28 INITED cov: 7 ft: 7 corp: 5/14b exec/s: 0 rss: 29Mb
=================================================================
==1776595==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000010573 at pc 0x000000550593 bp 0x7fffa7186990 sp 0x7fffa7186988
READ of size 1 at 0x602000010573 thread T0
#0 0x550592 in FuzzMe(unsigned char const*, unsigned long) (/mnt/mount_data2/k30056123/jishufenxiang/fuzz_target+0x550592)
#1 0x550634 in LLVMFuzzerTestOneInput (/mnt/mount_data2/k30056123/jishufenxiang/fuzz_target+0x550634)
#2 0x458771 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) (/mnt/mount_data2/k30056123/jishufenxiang/fuzz_target+0x458771)
#3 0x457eb5 in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool*) (/mnt/mount_data2/k30056123/jishufenxiang/fuzz_target+0x457eb5)
#4 0x45a157 in fuzzer::Fuzzer::MutateAndTestOne() (/mnt/mount_data2/k30056123/jishufenxiang/fuzz_target+0x45a157)
#5 0x45ae55 in fuzzer::Fuzzer::Loop(std::__Fuzzer::vector<fuzzer::SizedFile, fuzzer::fuzzer_allocator<fuzzer::SizedFile> >&) (/mnt/mount_data2/k30056123/jishufenxiang/fuzz_target+0x45ae55)
#6 0x44980e in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) (/mnt/mount_data2/k30056123/jishufenxiang/fuzz_target+0x44980e)
#7 0x472652 in main (/mnt/mount_data2/k30056123/jishufenxiang/fuzz_target+0x472652)
#8 0x7f7b714f7082 in __libc_start_main /build/glibc-LcI20x/glibc-2.31/csu/../csu/libc-start.c:308:16
#9 0x41e5ad in _start (/mnt/mount_data2/k30056123/jishufenxiang/fuzz_target+0x41e5ad)
0x602000010573 is located 0 bytes to the right of 3-byte region [0x602000010570,0x602000010573)
allocated by thread T0 here:
#0 0x51e2dd in malloc (/mnt/mount_data2/k30056123/jishufenxiang/fuzz_target+0x51e2dd)
#1 0x432997 in operator new(unsigned long) (/mnt/mount_data2/k30056123/jishufenxiang/fuzz_target+0x432997)
#2 0x457eb5 in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool*) (/mnt/mount_data2/k30056123/jishufenxiang/fuzz_target+0x457eb5)
#3 0x45a157 in fuzzer::Fuzzer::MutateAndTestOne() (/mnt/mount_data2/k30056123/jishufenxiang/fuzz_target+0x45a157)
#4 0x45ae55 in fuzzer::Fuzzer::Loop(std::__Fuzzer::vector<fuzzer::SizedFile, fuzzer::fuzzer_allocator<fuzzer::SizedFile> >&) (/mnt/mount_data2/k30056123/jishufenxiang/fuzz_target+0x45ae55)
#5 0x44980e in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) (/mnt/mount_data2/k30056123/jishufenxiang/fuzz_target+0x44980e)
#6 0x472652 in main (/mnt/mount_data2/k30056123/jishufenxiang/fuzz_target+0x472652)
#7 0x7f7b714f7082 in __libc_start_main /build/glibc-LcI20x/glibc-2.31/csu/../csu/libc-start.c:308:16
SUMMARY: AddressSanitizer: heap-buffer-overflow (/mnt/mount_data2/k30056123/jishufenxiang/fuzz_target+0x550592) in FuzzMe(unsigned char const*, unsigned long)
Shadow bytes around the buggy address:
0x0c047fffa050: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa
0x0c047fffa060: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa
0x0c047fffa070: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa
0x0c047fffa080: fa fa fd fa fa fa fd fd fa fa fd fd fa fa fd fd
0x0c047fffa090: fa fa fd fa fa fa fd fa fa fa fd fd fa fa fd fa
=>0x0c047fffa0a0: fa fa fd fa fa fa fd fa fa fa fd fa fa fa[03]fa
0x0c047fffa0b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fffa0c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fffa0d0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fffa0e0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fffa0f0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
Shadow gap: cc
==1776595==ABORTING
MS: 1 EraseBytes-; base unit: de3a753d4f1def197604865d76dba888d6aefc71
0x46,0x55,0x5a,
FUZ
artifact_prefix='./'; Test unit written to ./crash-0eb8e4ed029b774d80f2b66408203801cb982a60
Base64: RlVa
报错:heap-buffer-overflow内存越界错误
查看种子文件crash-0eb8e4ed029b774d80f2b66408203801cb982a60内容为FUZ
查看代码覆盖率
clang++ -fsanitize=fuzzer,address -fprofile-instr-generate -fcoverage-mapping fuzz_target.cc -o fuzz_target
加上fprofile-instr-generate -fcoverage-mapping 这两个编译选项
创建目录
mkdir CORPUS
运行:
echo -n F > CORPUS/A && ./fuzz_target CORPUS/* && llvm-profdata merge -sparse *.profraw -o default.profdata && llvm-cov show fuzz_target -instr-profile=default.profdata -name=FuzzMe
其中FuzzMe是函数名
打印信息:
红色行表示代码没有被运行
参考:
kimi大模型