news 2026/11/2 1:53:18

codefuzzer+bufferfuzzer 将语法引入灰白盒fuzz测试

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
codefuzzer+bufferfuzzer 将语法引入灰白盒fuzz测试

fuzz测试(模糊测试)一直是非常流行的未知漏洞挖掘方法

模糊测试大概上个世纪80年代就被人提出,到目前为止已经发现了无数个安全漏洞和代码质量问题 1.随机fuzz 最早阶段的模糊测试大概就是找到被测目标的数据输入点,对数据进行随机变异,然后等待问题的产生 在发现了大量的漏洞之后,模糊测试发现的问题开始收敛 2.黑盒fuzz 大概2000年左右,基于模板格式化变异的黑盒fuzz工具开始流行起来 比较有代表性的工具就是目前仍然在流行的peach peach使用一套比较通用的模板语法,来表述要测试的文件.协议等数据格式和交互状态,并且有良好的扩展性 比如测试一个server,黑盒fuzz工具可以完整的模拟clinet端行为,并在交互过程中串改字段来触发问题 黑盒fuzz工具有个致命的短板,就是并不关心被测程序代码的运行状态 3.灰盒fuzz 大概在2010年前后,基于遗传算法的afl面世 它通过对被测代码进行编译插装,来获取被测代码运行时的动态覆盖覆盖,来决定是否将刚输入的变异样本保存到样本池里供以后使用 与afl原理类似的fuzz工具涌现很多,比如测试用户态的libfuzzer和测试内核态的syzcaller 4.白盒fuzz 伴随着灰盒fuzz的流行,一些基于符号执行等的白盒技术被融入到fuzz工具(比如微软的SAGE) 他们通常以灰盒fuzz手段作为基础,符号执行等技术作为辅助 白盒技术往往因为各种各样的技术限制,业界工程化使用并不是很广 5.目前的灰白盒fuzz也在做一些引入语法的尝试 在一些格式化极强的场景,仅靠灰白盒变异效果差强人意,人们开始场景将语法引入灰白盒fuzz测试 比如libfuzzer与protobuf结合,以及基于afl开发的AFLSmart 但都不太成熟

作者开发了codefuzzer+bufferfuzzer,彻底将语法描述方法引入到灰白盒fuzz测试 ,下面请听我慢慢道来

codefuzzer (anner910/codefuzzer)

是一款开源灰盒fuzz工具,使用的默认覆盖反馈手段类似libfuzzer

利用gcc(clang)的插装编译选项-fsanitize-coverage=trace-pc(-guard)来获取被测代码覆盖信息

codefuzzer的创新之一是将二维样本引入到灰白盒fuzz测试

这样一个样本里可以保存多个信息,比如样本权重,比如多个参数,每个参数的值,大小,类型等

比如下边是一个同时变异三个参数的用例测试时自动生成的样本的一部分

cat test_target #start corpus --------------------------------- para number =3 weight =110 random =1709357130 #para0------ type is =u32 len is =4 mutator is =MNumberMagic number is =6785158,0x678886 hexvalue is ="\x86\x88\x67\x00" stringvalue is ="\x86\x88g\x00" #over0------ #para1------ type is =string len is =10 mutator is =MNoMutator hexvalue is ="\x63\x68\x61\x6e\x67\x63\x68\x75\x21\x00" stringvalue is ="changchu!\x00" #over1------ #para2------ type is =blob len is =6 mutator is =MdataSelfToOther hexvalue is ="\x31\x32\xff\xfe\xfd\xfc" stringvalue is ="12\xff\xfe\xfd\xfc" #over2------ #end corpus1 ------------1---20221208_144514 #start corpus ---------------------------------

二维样本的引入,可以使得codefuzzer用例同时支持多参数的变异值获取(默认支持256个,

最大值可使用函数CF_SetMaxParaNumber动态调整)

比如上边样本对应的多参数函数被测fuzz代码用例如下:

extern void targer(int num, char* blob,int len, char* string); void test_target(void) { printf("test_target start\r\n"); CF_SetReportPath("./"); CodeFuzz_start(0,100,1000000,"test_target",0) { static int i = 0; printf("\r%d",i++); fflush(stdout); int a = *(u32*)CF_GetU32(0, 0x345678); char* string = CF_GetString(1, "changchu!", 10, 1, 1000); char* blob = CF_GetBlob(2, "123457", 6, 0, 1000); int len = CF_GetMutatorLen(2); targer(a, blob, len, string); } CodeFuzz_end() printf("test_target end\r\n"); }

二维样本的引入,可以使得codefuzzer支持多种数据类型,并且更有针对性的编写出更多的变异算法

而传统的灰白盒fuzz工具一般仅支持的buf,size类型,并且变异算法单一

下边是codefuzzer目前支持的变异数据类型,其中CF_GetBlob对应的是传统buf,size类型

extern char* CF_GetS8( int no, s8 initValue); extern char* CF_GetS16(int no, s16 initValue); extern char* CF_GetS32(int no, s32 initValue); extern char* CF_GetS64(int no, s64 initValue); extern char* CF_GetU8( int no, u8 initValue); extern char* CF_GetU16(int no, u16 initValue); extern char* CF_GetU32(int no, u32 initValue); extern char* CF_GetU64(int no, u64 initValue); extern char* CF_GetFloat(int no, float initValue); extern char* CF_GetDouble(int no, double initValue); extern char* CF_GetNumberRange(int no, s32 initValue, int minValue, int maxValue); extern char* CF_GetNumberOnlyTable(int no, s32 initValue, int* table, int count); extern char* CF_GetNumberOutOfTable(int no, s32 initValue, int* table, int count); extern char* CF_GetNumberBasedOnTable(int no, s32 initValue, int* table, int count); extern char* CF_GetString(int no, char* initValue, int initLen, int minLen, int maxLen); extern char* CF_GetStringOnlyTable(int no, char* initValue, int initLen,int minLen, int maxLen, char** table, int count); extern char* CF_GetStringOutOfTable(int no, char* initValue, int initLen,int minLen, int maxLen, char** table, int count); extern char* CF_GetStringBasedOnTable(int no, char* initValue, int initLen,int minLen, int maxLen, char** table, int count); extern char* CF_GetBlob(int no, char* initValue, int initLen, int minLen, int maxLen); extern char* CF_GetBlobOnlyTable(int no, char* initValue, int initLen, int minLen, int maxLen, char** table, int* tablelen, int count); extern char* CF_GetBlobOutOfTable(int no, char* initValue, int initLen, int minLen, int maxLen, char** table, int* tablelen, int count); extern char* CF_GetBlobBasedOnTable(int no, char* initValue, int initLen, int minLen, int maxLen, char** table, int* tablelen, int count); extern char* CF_GetMySelf(int no, char* initValue, int initLen, int minLen, int maxLen);

codefuzzer一个简单的完整使用举例请参考

doc/简单使用举例1.md · anner910/codefuzzer - Gitee.com

codefuzzer的另一个创新是他被直接实现成一个库,并且本身并不包括main函数,每个用例就是一个代码调用片段

因此他可以很好的与其他测试框架融合,并且也可以很容易开发成单独工具,应用具有极强的灵活性

单独命令工具请参考

doc/简单使用举例2.md · anner910/codefuzzer - Gitee.com

gtest下使用请参考

doc/场景适配/gtest下使用.md · anner910/codefuzzer - Gitee.com

运行libfuzzer用例请参考

doc/场景适配/运行libfuzzer用例.md · anner910/codefuzzer - Gitee.com

bufferfuzzer (anner910/bufferfuzzer)

因为引入二维样本,使得codefuzzer在支持遗传进化的基础上,支持多参数同时变异,解决了多参数编写与变异效率的问题

但对于那些拥有复杂结构的buf参数,fuzz工具还仍然不能知道其中的语法结构

基于此,作者开发了bufferfuzzer

bufferfuzzer基于codefuzzer工具扩展开发,支持一套完整的模板语法,用来解析和描述各种复杂buf的结构

并具有良好的可扩展性

比如下边是构建好的arp报文协议模板

<BufferFuzzer name="arp_buffer" author="wanghao 6482543@qq.com"> <!-- ARP RFC826 --> <!-- 字段名称来自wireshark --> <Buffer name="arp_packet" > <Struct name="eth" > <Buf name="eth_dst" length="6"/> <Buf name="eth_src" length="6"/> <U16 name="eth_type" /> </Struct> <Struct name="arp" > <U16 name="arp_hw_type" /> <!-- 1 request 2 reply --> <U16 name="arp_proto_type" /> <U8 name="arp_hw_size" > <Relation type="size" of="arp_src_hw_mac"/> </U8> <U8 name="arp_proto_size" > <Relation type="size" of="arp_src_proto_ipv4"/> </U8> <U16 name="arp_opcode" /> <Buf name="arp_src_hw_mac" length="6"/> <Buf name="arp_src_proto_ipv4" length="4"/> <Buf name="arp_dst_hw_mac" length="6"/> <Buf name="arp_dst_proto_ipv4" length="4"/> </Struct> <Buf /> </Buffer> </BufferFuzzer>

通过模板的定义,可以知道被测buf由哪些字段构成,每个字段的大小,类型,值

(一些场景字段的值通过使用模板解析bin文件或者buf内存获得),子段之间的关系如(length value等)

使用上述arp.xml模板的用例大概如下

/* arp Frame (42 bytes) */ static const unsigned char pkt1[42] = { 0xd0, 0xd7, 0x83, 0x99, 0xf3, 0x06, 0x4c, 0xd5, /* ......L. */ 0x77, 0xb7, 0xa9, 0x73, 0x08, 0x06, 0x00, 0x01, /* w..s.... */ 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0x4c, 0xd5, /* ......L. */ 0x77, 0xb7, 0xa9, 0x73, 0xc0, 0xa8, 0x03, 0x82, /* w..s.... */ 0xd0, 0xd7, 0x83, 0x99, 0xf3, 0x06, 0xc0, 0xa8, /* ........ */ 0x03, 0x01 /* .. */ }; extern void arp_receive(char* buf,int len); void test_arp(void) { printf("test_arp start\r\n"); //arp初始buf设置 bufferSetBuffer(0, (char*)pkt1, sizeof(pkt1) ); //第一个参数是模型文件路径名字,第二个参数是样本bin文件路径,第三个参数是模型要解析的数据模型名称 bufferDoModel(0, (char*)"./arp.xml", NULL, (char*)"arp_packet"); CodeFuzz_start(0,100,1000000,"test_arp",0) { static int i = 0; printf("\r%d",i++); fflush(stdout); int len; char* buf; //变异后的buf工具自己释放 bufferDoAction(0, &buf,&len); //使用变异buf,调用被测程序 arp_receive(buf, len); //工具释放每次变异过程中的临时内存 bufferDoFree(); } CodeFuzz_end() //工具释放模型解析过程中的内存 bufferDoClear(); printf("test_arp end\r\n"); }

bufferDoAction函数里间接调用了诸多codefuzzer get系列函数

测试过程中生成的codefuzzer样本里可以看到多个参数出现

bufferfuzzer 大概的原理如下

1.建模 通过建模描述被测buffer的结构,每个元素的大小,类型,元素之间的关系 2.解析bin 通过使用模型对bin文件的解析,知道被测buffer有多少个元素,每个元素的初始值 3.元素变异 通过调用codefuzzer get系列函数,对每个需要变异的元素进行变异 4.关系字段赋值 通过从模型得到的字段之间的关系,对关系元素进行赋值 5.模型变异 基于模型的变异 6.组合 将变异后的各元素值基于模型结构重新组合在一起 7.测试 调用被测代码开始测试

模板语法借鉴peach,十分通用,目前作者已经适配多款协议和文件类型,如下

协议 arp ipv4 dhcp http httpRest 文件 jpg mp4 通用建模 json通用建模 xml通用建模

codefuzzer可以单独使用

但bufferfuzzer需要与odefuzzer一同使用

bufferfuzzer完整的简单使用举例请参考

https://gitee.com/anner910/bufferfuzzer/blob/master/doc/%E4%BE%8B%E5%AD%901.md

小结

通过引入二维样本,codefuzzer支持对多参数多类型的测试数据进行同时变异 通过引入通用模板,bufferfuzzer支持对复杂buf的结构描述,运行测试时将之拆分为codefuzzer的多参数多类型 通过bufferfuzzer和codefuzzer结合,完成了将语法引入到灰白盒fuzz测试的全过程

讨伦:

在很多场景,比如json应用,xml应用等场景,模型变异可以轻松取得良好的测试效果 依据模型变异,可以使得fuzz工具能迅速变异出大量格式相关的样本,使得覆盖率短期内迅速提高 但是,模型同样也是一种束缚,bufferfuzzer很难变异出与模型出入巨大的样本出来 一些结构复杂多样的场景,仅靠模型变异效果并不理想 最优的步骤应该是 先用bufferfuzzer依据模型变异出大量有效样本(使用CF_SetOutBinCorpusPath调用输出), 在将样本输入(使用CF_SetInBinCorpusPath调用输入)给纯codefuzzer针对buf参数(CF_GetBlob)进行二次测试

其他

codefuzzer的样本进化原理请参考

doc/工具原理/样本生成、调度、淘汰.md · anner910/codefuzzer - Gitee.com

codefuzzer可以使用一些范围类型的元素变异结合被测函数返回值来支持发现逻辑问题,请参考

doc/用例编写/发现逻辑问题.md · anner910/codefuzzer - Gitee.com

bufferfuzzer支持基于模型的变异,请参考

doc/工具原理/变异算法.md · anner910/bufferfuzzer - Gitee.com

codefuzzer与bufferfuzzer支持多方面扩展,很方便进行fuzz新技术引入研究,具体请参考各自工具readme

动态扩展 调整变异算法 调整变异频率 调整变异位置 调整样本权重 静态扩展 自定义字典 自定义变异算法 自定义数据类型 自定义样本进化方式 模型扩展 自定义Transform 自定义Fixup 自定义Relation 自定义Analyzer 自定义check(constraint)

一款灰白盒fuzzer工具简单的测试,比较工具

anner910/testfuzzer

青草莓科技

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/11/2 1:53:02

slub shuffle_freelist

shuffle_freelist() 是 SLUB freelist 随机化机制的建链函数&#xff1a;它利用预先计算好的随机序列 s->random_seq&#xff0c;把一个新 slab 页里的所有对象按随机顺序串成 freelist&#xff0c;使分配顺序不可预测&#xff0c;增加堆溢出攻击的难度。一、函数签名static…

作者头像 李华
网站建设 2026/11/2 1:52:32

Burp Suite安装教程

一共有两个步骤先安装Java环境再安装burp suite通过网盘分享的文件&#xff1a;BurpSuite_Pro_V2026.8.zip 链接: https://pan.baidu.com/s/1qcMCHIw7AN02XBg12MjKaQ?pwdrubt 提取码: rubt先说安装Java配置环境安装java&#xff0c;双击打开jdk。选择安装位置配置Java打开【设…

作者头像 李华
网站建设 2026/11/2 1:51:45

智能家居全国交付中责任闭环架构的设计与实现:到场式交付与兜底式交付的系统差异

一、背景/痛点分析 智能家居全国交付中存在两类交付模式&#xff0c;差异不在执行端能力水平&#xff0c;在服务承诺的终点定义。 到场式交付的承诺终点是执行端到达现场并完成动作。设备安装完成、订单状态标记完成&#xff0c;交付流程即终止。系统不覆盖系统联调、场景验证、…

作者头像 李华
网站建设 2026/11/2 1:50:44

基于opencode实现聊天室项目工具的安装(上)

目录 基础工具的安装 框架安装 基础工具的安装 sudo apt-get install gcc g // 编译器安装sudo apt-get install gdb // 调试器安装sudo apt-get install make cmake // 项目构建工具安装sudo apt-get install lrzsz // 传输工具…

作者头像 李华
网站建设 2026/11/2 1:50:37

【FreeRTOS源码学习笔记】链表的实现

【FreeRTOS源码学习笔记】链表的实现前言一、核心数据结构1.1 ListItem_t 链表节点1.2 MiniListItem_t 迷你节点&#xff08;哨兵位&#xff09;1.3 List_t 链表二、链表的基本形态三、核心操作函数3.1 初始化链表节点3.2 链表初始化3.3 插入&#xff1a;vListInsert 与 vListI…

作者头像 李华