AFL & Angr 学习笔记

前言

最近因为实验室要看的论文有fuzz相关的,同时自己也想看一下angr、afl这些,就学了一段时间afl和angr,记录一下学到的东西,算是入个门(

Angr学习

angr还是比较有趣的,感觉web中如果有这种东西,那directed fuzz也能实现一下。就是官方文档太捞了hhh

Lab

实现了一下这个
https://github.com/angr/angr-doc/tree/master/examples/secuinside2016mbrainfuzz

-w941

学习笔记

Lab具体思路:

  1. 首先通过CFGFast拿到cfg,然后通过function()方法拿到main函数的BlockNode,然后拿到main函数的所有callee(get_call_sites)
  2. 在main的最后一个callee跟进并递归,拿到符合要求的最后一个callee,即最后puts flag的地址。
  3. 同样遍历main的callee并拿到最后一个callee,即第一个sub函数,也就是explore的入口
  4. 接下来需要初始化一下全局变量,也就是scanf的参数。这个数据在bss段,我的思路是通过遍历cfg拿到赋值时的asm,这样就能拿到这个参数的bss地址和xor的数值,然后用memmory方法store进去即可。
  5. 然后explore即可。参数通过BVS初始化,注意最后三关要加0x30的约束。
  6. 求解得到结果后,根据C写一下和拿到的xor数据的xor操作即可。

用过的api

只列学到的比较好用的API

  • 将一个addr转换成block

    1
    node = angr_project.factory.block(addr)
  • 拿到该node的汇编语句

    1
    node.capstone.insns[0].op_str
  • 在cfg中拿到main函数,返回一个BlockNode

    1
    block = cfg.functions.function(name="main")
  • main的callee

    1
    block.get_call_sites()
  • 拿到该block的所有node

    1
    block.get_call_sites.transition_graph.nodes()
  • 初始化一个求解参数,用来explore求解,大小是51字节

    1
    scanf_args = claripy.BVS("args", 8 * 51)
  • 加求解约束,使用get_byte访问参数的某字节

    1
    state.solver.add()
  • 从一个addr创建状态。这个api很常用,与entry_state对比,entry_state从一个入口函数开始,比如main,而blank_state可以从任意函数开始,比如本题可以从第一个sub函数开始。注意blank_state可能需要初始化一些依赖的变量。

    1
    angr_project.factory.blank_state(addr)

然后就是explore、eval等,老生常谈了。最后代码如下:
https://github.com/LFYSec/AngrLab

参考链接

https://zhuanlan.zhihu.com/p/51753624 很棒
https://www.bookstack.cn/read/CTF-All-In-One/doc-5.3.1_angr.md 官方文档的翻译
https://docs.angr.io/
https://github.com/angr/angr-doc/blob/master/CHEATSHEET.md
https://github.com/jakespringer/angr_ctf 一些angr的lab

AFL

学习笔记

AFL没学到很多,只是看文章对着源码,大概看了下编译策略,然后跑了libxml,测试了dictionary等功能。大概列一下学到的基础知识。

个人理解

之前觉得afl不就是个工具么,搭起来跑一下不就好了,有啥好研究的,而且就算跑出来crash写不出exp有啥用。后来和leader聊了一下,感觉自己可能理解有误。目前的模式可能是,研究fuzz的人会去研究afl的mutate策略、要fuzz的目标,然后针对要fuzz的目标去改afl的mutate策略。同时,也要大概理解elf的功能,知道该去fuzz目标的哪些接口,io啥的是否要patch掉,比如fuzz libxml是不是用xml做种子会更好一些等等。
产生crash后,再针对crash做调试看能否写成exp,这个过程是需要多练习的。

AFL原理和场景

AFL工作原理是,通过编译时对汇编插桩,实现当afl-fuzz运行时,如果探索到了新的path使coverage增大,则实时的将更新的coverage从fork server写进共享内存。AFL-Fuzz和fork server之间通过管道通信。

AFL还有LLVM Mode和QEMU Mode,LLVM Mode使用clang插桩,可以加速fuzz,QEMU Mode用qemu来模拟,可以实现黑盒fuzz。

个人感觉,对于web狗来说,afl的qemu_mode可能应用场景会更大,比如某mail、某vpn都有很多so,某些so的入口可能能被web的preauth point控制,因此用qemu mode去fuzz这些大型目标可能有意想不到的收获。

下边是对AFL不同配置下的对比,分别是随机种子,使用xml文件做种子,随机种子+xml dict进行测试的结果,发现针对libxml,还是使用xml dict效果会好很多。

random_seed
-w568

xml_seed
-w557

random_seed with -x xml.dict
-w574

AFL策略学习 & 修改

很多老生常谈的就不写了,很多blog写的很好了,贴几篇看完觉得不错的:

1
2
3
http://zeroyu.xyz/2019/05/15/how-to-use-afl-fuzz/ 配置、使用从入门开始,很棒,以及一些AFL窗口中各个参数的含义
https://paper.seebug.org/841/
https://paper.seebug.org/1732/ sxf写的一片解析

懒 //TODO

Proudly powered by Hexo and Theme by Hacker
© 2021 LFY