Kitty 简介
Kitty is an open-source modular and extensible fuzzing framework written in python, inspired by OpenRCE’s Sulley and Michael Eddington’s (and now Deja Vu Security’s) Peach Fuzzer.
Kitty 是一个 python 版本的模糊测试框架。其目标是帮助模糊测试特定的受害者。受害者通常运行于非TCP/IP通道上的私有和内部协议。
特性
- 模块性:fuzzer的每一个部分都是独立的,这意味着你能够用相同的监视代码监控不同的程序,用相同的载荷生成工具(aka Data Model)生成的数据可以在不同的信道中传递;
- 扩展性:如过你想测试新的东西,不需要修改Kitty的核心代码。即便不是所有,大部分功能应该在用户代码中实现。这包括监视,控制以及和被fuzz的目标的通信;
- 丰富的数据模型:数据模型的核心要丰富,能够描述高级的数据结构,包括字符串,哈希,长度,条件及其它。而且和其它框架一样,还要设计好,将来需要的时候可以扩展;
- 状态性:支持多阶段的模糊测试。不仅要能描述单独消息的载荷应该是什么样,还要能描述消息的顺序,甚至按照顺序进行fuzzing;
- 客户端和服务端fuzzing:假设你有一个配对的程序栈,你可以对服务端和客户端进行fuzz。这听起来是一个很高的要求,但实际上不是:只需要你像通常一样能够和目标通信即可;
- 跨平台:可以在Linux,OS X和Windows上运行。
框架结构
kitty 主要架构如下图所示:
Fuzzer +--- Model *--- Template *--- Field
|
+--- Target +--- Controller
| |
| *--- Monitor
|
+--- Interface
Fuzzer
Fuzzer 是最高级的控制结构,由三部分组成 Interface(可视化)、Target(控制被测试的对象)、Model(数据模型)。Fuzzer 从 Model 获取改变后的数据,执行数据交换,从 Target 获取测试报告,在需要时执行更多的操作。一般我们采用自底向上的构造方法,即最后配置 Fuzzer。
根据被测试对象的属性,我们可以分别使用 ClientFuzzer 和 ServerFuzzer.
Fuzzer 类常用 api:
set_model(model)
为 Fuzzer 设置数据模型set_target(target)
为 Fuzzer 设置控制结构set_interface(interface)
为 Fuzzer 设置可视化start()
开始模糊测试stop()
结束模糊测试set_delay_between_test(delay_secs)
设置测试之间的间隙
Model
数据模型定义了 Fuzzer 要发送的消息的结构。 通常将消息分成几个部分(如头部、长度、负载),并包含这几部分的类型(如字符串、校验码、十六进制编码的32位整数)和这些部分之间的关系。此外,数据模型还描述了不同消息被联系起来形成模糊会话的顺序。数据模型还可以指定模糊发送消息的顺序。
Target
Target 模块负责管理与受测者有关的一切。其主要功能包括:
- 管理 Monitors 和 Controller
- 当受测者是一个 server 时,Target 模块通过向服务器发送请求并处理服务器可能返回的响应来启动模糊会话。
- 当受测者是一个 client 时,Target 模块通过使客户端向服务器发起请求来启动模糊会话。服务器在stack的帮助下将向 client 发送一个模糊的响应。
Target 类常用 api:
set_controller(controller)
为 Target 设置控制器add_monitor(monitor)
为 Target 添加一个监控器
Controller
Controller 负责将受测者控制到合适的状态以做好测试的准备。 Controller 也需要执行基本的监控,并需要报告受测者是否准备好进行下一次测试。
Monitor
Monitor 监控受测者的行为,它可以监控网络流量、内存消耗、串行输出或者其它任何内容。
kitty.monitors 包提供了基本的监视器类 BaseMonitor,一般需要对其进行继承而不要直接实例化。
继承了 BaseMonitor 的子类,建议对以下函数进行继承:
__init__()
函数应先调用父类的构造函数进行初始化setup()
函数应对子类新增的变量进行配置后再调用父类的setup
函数_monitor_func()
函数会在setup
函数调用并在新线程内进行无限循环直至发送终止命令,所以此函数一般用来进行数据收集teardown()
函数应对子类新增变量进行清理工作,并调用父类构造函数pre_test()
函数应先调用父类函数再对子类新增变量进行每次测试前的初始化post_test()
函数应对收集到的数据进行处理生成报告,并调用父类构造函数
在每次测试前,应对上次收集到的数据进行清理防止上次测试结束时数据清理工作不彻底,一般来说直接将私有变量初始化即可。每次测试后进行数据分析,然后也应对收集到的数据进行清理。
启动过程分析
一次模糊会话的测试过程主要由以下几步组成
- 定义测试过程中发送给受测者的数据模型model
- 实例化Controller子类
- 实例化一系列Monitor子类
- 实例化Target子类
- 为 Target 设置 controller,并增加 monitors
- 实例化Fuzzer类
- 为Fuzzer设置model和target
- 执行
Fuzzer.start()
开始测试 - 执行
Fuzzer.stop()
停止测试
对 Fuzzer.start()
进行分析
这里只对受测者是server时进行分析
进入 serverFuzzer.start()
- 进行初始化工作
- 打印
start
消息日志 执行
target.setup()
- 执行
controller.setup()
- 对所有的
monitor
执行setup()
- 执行
- 进行环境测试
执行
_start()
进入循环,循环终止判断条件为
_next_mutation()
函数返回值- 根据model获取sequence
执行
_run_sequence(sequence)
- 执行
_check_pause()
等待用户命令 执行
_pre_test()
执行
target.pre_test()
- 执行
controller.pre_test()
- 执行
monitor.pre_test()
- 执行
根据 sequence 里的数据执行
_transmit()
函数执行
target.transmit()
函数发送数据- 执行
_send_to_target()
函数发送数据 - 如果需要等待
response
并返回
- 执行
执行
_post_test()
执行
target.post_test()
- 执行
controller.post_test()
- 执行
monitor.pre_test()
- 生成报告
- 执行
- 获得报告
- 进行报告分析
- 执行
- 打印
end
消息日志