首页
社区
课程
招聘
[翻译]sulley 网络协议Fuzzing 测试文档
发表于: 2011-6-20 10:03 15838

[翻译]sulley 网络协议Fuzzing 测试文档

2011-6-20 10:03
15838

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




[注意]看雪招聘,专注安全领域的专业人才平台!

收藏
免费 7
支持
分享
最新回复 (2)
雪    币: 5
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
楼主好,请问LL用过其他的测试框架没,可以分享一下吗?
2016-4-27 09:45
0
雪    币: 420
活跃值: (77)
能力值: ( LV13,RANK:500 )
在线值:
发帖
回帖
粉丝
3
peach 也可以..
2016-6-27 14:40
0
游客
登录 | 注册 方可回帖
返回