Sully:
监视网络,并系统的自动维护着相应记录.
监视目标的健康状况,并有能力使用多种方法使其恢复到一个好的状态.
Sully 能够发现,跟踪,以及对检测到的错误进行分类.
Sully 能够并行执行,增加了测试的速度.
Sully 能够自动的确定测试案例中那一个单一系列引发的错误.
Sully的使用:
数据表示: 是使用任何fuzzer的第一步.运行目标程序,将协议独立的请求和响应 ,并使用sully中的blocks表示.
会话 : 将开发的请求连接在一起形成会话,并附加上各种可用的监视代理(socket,debugger,etc..)然后开始fuzzing
事后分析:检查生成的数据和监控结果,重放单一测试案例.
目录结构:
archived_fuzzies: 这是个自由形态的目录,以fuzz目标名组织在一起,用来存储已存档的fuzzer和fuzz 会话产生的数据.
audits: 一个活动会话所记录的PCAP数据,崩溃的二进制文件,代码覆盖范围和分析的图标都应该放在此目录.
一旦fuzz会话完成,所有的数据都要移到"Archived_fuzzies"目录中.
docs: 文档和生成的Epydoc API references
requests: Sully requests 库,每个目标应该拥有它自己的能被用来存储多个请求的文件.
___REQUESTS__.html: 包含已存储请求的类别和个别类型列表说明,按字母顺序维护.
http.py : 各种各样的web 服务fuzzing 请求
trend.py : 包含一个完整的fuzz 演练相关请求,在稍后的文档中讨论.
sulley: fuzzer 框架.除非你想扩展这个框架,否则不要轻易的改动这些文件.
legos: 用户定义的复杂原语
ber.py ASN.1/ BER 原语
dcerpc.py 微软RPC NDR 原语
misc.py 诸如E-mail 地址和主机名等各种各样的未分类原语
xdr.py XDR types
pgraph: python 图形抽象库,建立sessions时使用.
utils: 各种辅助例程
dcerpc.py 微软RPC 帮助例程.比如绑定一个接口以及生成一个请求.
misc.py 各种未分类的例程,比如CRC-16 以及UUID 处理例程
scada.py SCADA特有的帮助例程,包含DNP3 块编码器
__init__.py : 用于创建请求时定义的各种各样的别名.
blocks.py : Blocks 和block 帮助在这里定义.
instrumentation.py 外置仪表特征,用于并不支持debugger的监视目标
pedrpc.py 用于定义sully 在不同的代理和主fuzzer之间通信的客户端和服务器类.
primitives.py 各种fuzzer原语,包括静态,随机,字符串和整数定义
sessions.py 创建并执行一个会话的功能函数.
sex.py sully的自定义异常处理类
unit_tests: sully 的单元测试装置
utils: 各种独立的实用工具
crashbin_explorer.py 命令行工具,用于扫描序列化存储于crash 二进制文件结果。
pcap_cleaner.py 命令行工具,用于清除没有错误关联的PACP 目录
network_monitor.py PedRpc驱动的网络监视代理
process_monitor.py PedRpc驱动,基于调试器的目标监视代理
unit_test.py sulley的单元测试
vmcontrol.py PedRpc驱动的VMWare 控制代理 。
作者:
Pedram Amini
433K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4m8W2k6s2u0S2L8g2)9J5k6h3!0H3k6h3&6J5j5$3g2Q4x3X3g2G2M7X3M7`.
Aaron Portnoy
33cK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8X3c8$3L8r3q4T1M7#2)9J5k6i4c8A6M7s2m8A6L8X3N6H3L8$3W2F1N6q4)9J5k6h3y4G2L8g2)9J5c8Y4c8W2j5h3#2Q4x3V1k6S2M7r3!0J5N6r3&6G2P5b7`.`.
安装和需求:
network_monitor.py :
CORE Pcapy,
22dK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8X3!0K6M7#2)9J5k6h3y4G2M7X3g2K6k6h3y4#2M7X3W2@1P5g2)9J5k6h3y4G2L8g2)9J5c8Y4m8J5L8$3A6W2j5%4c8K6i4K6u0r3M7r3y4S2M7s2W2Q4x3X3g2Z5N6r3#2D9
CORE Impacket
954K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8X3!0K6M7#2)9J5k6h3y4G2M7X3g2K6k6h3y4#2M7X3W2@1P5g2)9J5k6h3y4G2L8g2)9J5c8Y4m8J5L8$3A6W2j5%4c8K6i4K6u0r3K9h3#2H3j5h3y4C8k6i4c8Q4x3X3g2Z5N6r3#2D9
process_monitor.py
PaiMei
50aK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8X3y4G2k6r3g2Q4x3X3g2Y4L8$3!0Y4L8r3g2Q4x3X3g2U0L8$3#2Q4x3V1k6H3i4K6u0r3M7r3q4A6L8h3g2A6i4K6u0r3
1f5K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4N6%4N6#2)9J5k6h3!0H3k6h3&6J5j5$3g2Q4x3X3g2G2M7X3N6Q4x3V1k6V1L8%4N6F1L8r3!0S2k6s2y4Q4x3V1k6V1k6i4c8S2K9h3I4K6i4K6u0r3x3U0l9^5i4K6u0r3f1r3q4A6e0h3g2A6
53dK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4N6%4N6#2)9J5k6h3&6G2L8r3!0Y4K9h3&6Q4x3X3g2G2M7X3N6Q4x3V1k6E0j5h3W2F1i4K6u0W2M7r3I4Q4x3@1k6S2j5%4c8A6L8$3&6Q4x3@1c8U0L8$3c8W2e0r3W2K6N6q4)9J5y4R3`.`.
数据表示:
初始化并命名一个请求
sulley使用基于数据块表示的方法来生成独立的请求,然后将这些请求放在一起生成一次会话。
s_initialize("new request")
现在,你可以添加原语,blocks 或者嵌套的blocks 来生成请求。每一个原语都能被单独的rendered或突变。rendering 一个原语
将返回其关联的raw data数据格式内容。突变一个原语将变化它内部的内容。rendering 和mutating 的概念被大多数fuzzer开发者
抽象出来的,所以不用为它担心。然而,当fuzzable 的值被穷尽时,任何可突变的原语都接受一个默认的值。
静态数据 以及 随机数据:
让我们开始一个最简单的原语,s_static(),这个原语添加一个任意长度静态不突变的值到request中,为了便利,sully 使用了
各种不同的别名 s_dunno(),s_raw(),s_unknown()都是s_static()的别名。
# these are all equivalent:
s_static("pedram\x00was\x01here\x02")
s_raw("pedram\x00was\x01here\x02")
s_dunno("pedram\x00was\x01here\x02")
s_unknown("pedram\x00was\x01here\x02")
原语,block 等,都有一个可选的名字关键字参数。指定一个名字项可以直接使用request 变量request.names["name"] 存取,而
不需要遍历block结构来找到你期望的值。
s_binary 和s_static类似,但不相同,s_binary 接受多种形式表示的二进制数据,SPIKE 用户应该很熟悉它的使用,
# yeah, it can handle all these formats.
s_binary("0xde 0xad be ef \xca fe 00 01 02 0xba0xdd f0 0d", name="complex")
大多数sulley原语又fuzz 启发式驱动,因此它们突变的数目是有限的,但是s_random除外,它被利用来生成各种长度的随机数值,该原语必须携带两个
参数'min_length','max_length',用来说明在每一次迭代生成随机数值得最大,最小长度值,该原语,还接受如下关键字参数.
num_mutations: (integer, default=25) 在恢复到默认值前的突变次数
fuzzable: (boolean, default=True) 开启和关闭该原语的可突变性
name: (string, default=None) 通过名字,sulley可以对该原语直接存取.
number_mutations 关键字参数指定在被认为该原语耗尽时应该突变该原语多少次。如果要生成固定长度的随机数,指定min_length 和max_length
相等即可
整数
二进制和anscii协议中可能会包含各种大小的整数域,如http协议的内容长度域,和所有的fuzz框架一样,我们在这里也需要来产生这些数据:
1 byte: s_byte(), s_char()
2 bytes: s_word(), s_short()
4 bytes: s_dword(), s_long(), s_int()
8 bytes: s_qword(), s_double()
每一个整数类型至少要接受一个单一的参数,即默认整数值,此外,下面这些可选关键字参数可被指定.
endian: (character, default='<') bit 位序 指定 '<' 为小端,'>'为大端
format: (string, default="binary")输出格式, "binary" 或 "ascii", 控制者原语表示的整数格式, 例如,值100 ascii格式为 ‘100’ 而 "\x64" 是二进制格式
signed: (boolean, default=False) 使得大小为有符号数,还是无符号数,仅当format="ascii"时适用
full_range: (boolean, default=False) 使该原语突变所有的可能值
fuzzable: (boolean, default=True) 开启和关闭该原语的可突变性
name: (string, default=None) 可以通过在request中指定该名称来直接存储该原语的值
full_range 参数是上面所有参数中最值得关注的。考虑一下,当你fuzz一个DWORD类型的值时,一共有4294967295 种可能值,以每秒10个测试案例的速度
你需要13年才能fuzz完这个原语,通过定义一些smart数值集来减小原有穷举空间,包括在0边界处,+,- 10,以及最大值除2,4,6,8,10.16,32等得到
的集合,而穷尽减小的空间值(141 测试案例) 仅需要10几秒。
字符串和分隔符
字符串能在协议中的使用非常广泛,邮件地址,主机名,用户名,密码等等,你不用怀疑,字符串的应用贯穿在整个fuzzing的过程中,s_string 原语
负责这些域,这个原语只需要带一个默认参数值为必选参数,下面这些附加参数也可被指定。
size: (integer, default=-1) 字符串的静态大小,对于动态大小,指定该值为-1
padding: (character, default='\x00') 如果明确大小被指定,而产生的大小小于指定值, 使用这个值来填充直到满足条件为止。
encoding: (string, default="ascii") 字符串使用的编码,有效的选项包含无论在python中任何地方都能被接受的s.encode,对于微软unicode字符串,指定 utf_16_le
fuzzable: (boolean, default=True) 开启和关闭该原语的可突变性
name: (string, default=None) 可以通过在request中指定该名称来直接存储该原语的值
字符串通常被分割符划分为几个子域,例如,空格被用作http协议请求的分割符,"GET /index.html HTTP/1.0"前面的/ 和 . 同样作为该请求的分割符。
但你定义协议时,请确保使用s_delim()原语代替分割符,正如其它原语一样,必须指定一个默认值作为它的第一个参数,同样,和其它参数一致,
s_delim()同样接受可选的fuzzable 和name 参数,定界符的突变包括,重复,替代,排除。
作为一个完整的例子,fuzzing http 标签时使用如下系列原语:
# fuzzes the string:
s_delim("<")
s_string("BODY")
s_delim(" ")
s_string("bgcolor")
s_delim("=")
s_delim("\"")
s_string("black")
s_delim("\"")
s_delim(">")
Blocks:
必须精通的原语,让我们来看下,如何组织并嵌入一个块,新的块使用s_block_start()定义,使用s_bolck_end()关闭,每个块必须给定
一个名称,作为s_block_start()的第一个参数,这个例程同样可以指定如下可选参数:
group: (string, default=None) 和该块关联的组的名称
encoder: (function pointer, default=None) 函数指针,在reader 该block数据返回之前,提供一次处理该block数据的机会
dep: (string, default=None) 可选的参数,用来指定该block依赖的值
dep_value: (mixed, default=None) 如使该block的值 能被readered,该值必须在dep域中被包含
dep_values: (list of mixed types, default=[]) 为了该block的值能被readerd,dep可能包含的值列表.
dep_compare (string, default="==") 应用于依赖的比较方法,有效的可选操作为"==", "!=", ">", ">=", "<" and "<=".
Group ,encoding,以及依赖性是大多数fuzz框架没有的特性,我们将在下面论述它们。
组
group允许你连接一个块到指定的group原语,和一个组关联的block必须为每一个组中的值循环穷尽该block的所有空间,例如,在表示一个有效的opcode列表或一些有
相同参数的行为时,组原语是非常有用的,s_group定义一个组,并接受两个必须的参数,第一个参数指定组名称,第二个参数指定一个需要迭代的原始值列表。
例如,下面的请求完成web ,服务器的fuzz:
# import all of Sulley's functionality.
from sulley import *
# this request is for fuzzing: {GET,HEAD,POST,TRACE} /index.html HTTP/1.1
# define a new block named "HTTP BASIC".
s_initialize("HTTP BASIC")
# define a group primitive listing the various HTTP verbs we wish to fuzz.
s_group("verbs", values=["GET", "HEAD", "POST", "TRACE"])
# define a new block named "body" and associate with the above group.
if s_block_start("body", group="verbs"):
# break the remainder of the HTTP request into individual primitives.
s_delim(" ")
s_delim("/")
s_string("index.html")
s_delim(" ")
s_string("HTTP")
s_delim("/")
s_string("1")
s_delim(".")
s_string("1")
# end the request with the mandatory static sequence.
s_static("\r\n\r\n")
# close the open block, the name argument is optional here.
s_block_end("body")
该脚本由sulley组件的引入开始,接下来,初始化并一个请求,并为该请求命名为“HTTP BASIC”,该名称稍后被引用,来对request进行直接存取,
下一步,一个组被定义,名称为“verbs”,其可能的字符串值为"GET", "HEAD", "POST", "TRACE",一个名为body的block被定义,并使用group参数连接到
先前定义的group原语,注意,s_block_start总是返回True,这让你可以通过使用if语句来组织block的结构,让程序更具有可读性,注意,
s_block_end()的名称参数是可选的,一系列的基本原语和数据原语被限定在body 块中,当定义的请求被载入到一个sulley的会话中时,fuzzer将为
每一个定义在组中的值,生成并传输body块中的所有可能值。
Encoders
编码者是一个简单但非常有效的block修改器,在block将readered的内容返回并传输到物理线路之前,一个函数能被指定并附加到该block上来对该数据进行修改。
下面是一个xor加密器:
def trend_xor_encode (str):
key = 0xA8534344
ret = ""
# pad to 4 byte boundary.
pad = 4 - (len(str) % 4)
if pad == 4:
pad = 0
str += "\x00" * pad
while str:
dword = struct.unpack("
str = str[4:]
dword ^= key
ret += struct.pack("
key = dword
[注意]看雪招聘,专注安全领域的专业人才平台!