【转】模糊测试(fuzzing)是什么

一、说明

大学时两个涉及“模糊”的概念自己感觉很模糊。一个是学数据库出现的“模糊查询”,后来逐渐明白是指sql的like语句;另一个是学专业课时出现的“模糊测试”。

概念是懂的,不外乎是“模糊测试是一种软件测试技术,其核心思想是自动或半自动的生成随机数据输入到一个程序中,并监视程序异常,如崩溃,断言(assertion)失败,以发现可能的程序错误,比如内存泄漏”。

这种定义也许很准确,但对没接触过的人还是很模糊。我觉得搞学问的有个毛病,喜欢把一个简单的东西讲得很复杂然后就是不告诉你到底是什么。就好比如在介绍职业时什么“公司全系统物理安全保障专员”责任多么重大多么神圣啦、“世界互联网信息终端及人类信息科技部信息集成应用导师”涉及哪些高深技术啦,就是不直接叫保安和网管照片你更别想有了。

 

二、fuzzing定义

模糊测试 (fuzz testing, fuzzing)是一种软件测试技术。其核心思想是自动或半自动的生成随机数据输入到一个程序中,并监视程序异常,如崩溃,断言(assertion)失败,以发现可能的程序错误,比如内存泄漏。模糊测试常常用于检测软件或计算机系统的安全漏洞。

我们使用维基百科的这个定义,然后着重讲一下“随机数据”长什么样,又如何“输入到另一个程序中”。

 

三、测试用例

3.1 测试用例类别

随机数据这个词用得有点宽泛得不负责任,随机数据那是不是我从0到无穷大每个数都要测一下,总得有些指导性的测试用例类别吧。

缓冲区溢出类测试用例:超长字符串。比如几时上百个a,也可以更长只要自己觉得足够长就行。超长字符串一般是等价的不需要a来一串b来一串什么的,来两三个长度差别稍微大的测试用例就行了。

随机数测试用例:很多系统支持的配置值是固定的,比如屏幕只支持1080p我们故意设1081p系统就可能把错了。负数,浮点数,超大数等分别来个测试用率就行了。

格式化字符串测试用例:%d、%s等符号在很多语言中是指导格式化用的,如果用做做为输入可能引发报错。长长短短随便来几个测试用例就行了。

特殊字符测试用例:~!@#$%等等符号在很多语言中是有特殊含义的,作为输入可能会引发报错。最好每个字符及不同长度都来一个测试用例。

unicode编码测试用例:有些程序是不支持unicode的,输入unicode可能会引发报错。%uxxxx等长短不一来几个测试用例。

 

3.2 测试用例构造方法

我们以http为例,其他应用层协议也是类似生成测试用例即可。首先一个http请求包如下

复制代码
GET /index.php
Host: www.baidu.com User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:60.0) Gecko/20100101 Firefox/60.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 Accept-Encoding: gzip, deflate, br Cookie: BAIDUID=DE7A3603AFE90C7C9B7848944652D535:FG=1; BIDUPSID=DE7A3603AFE90C7C9B7848944652D535; PSTM=1525757648; BD_UPN=13314352; __cfduid=d557d51bf4d18d86c9c3ad0df8f78186b1526712772; MCITY=-%3A; ispeed_lsm=2; sug=3; sugstore=1; ORIGIN=0; bdime=0; H_PS_PSSID=; delPer=0; BD_CK_SAM=1; PSINO=2; BDSVRTM=0; pgv_pvi=3566222336; pgv_si=s6214074368 Connection: keep-alive Upgrade-Insecure-Requests: 1
复制代码

单项测试用例----测试时尽量使用“控制变量法”,比如测Host头是其他头部就要保持正常数据,以免其他头部的值影响到Host头效果。

多项测试用例----与单项测试用例相反,正因为有些项是关联的,有可能需要某项是某一值另一项才会起效果,所以要生成多项联动的测试用例。比如同时修改Accept头和Accept-Encoding。

同类字符不必区分法则:如前所述0-9这类数字,a-z这类字母都是同类,不是很有必要测了一个再去测其他。

长度不必过细法则:还是如前所述长度这种东西,选几个有代表性的就行没必要长度100来一个测试用例,长度101来一个测试用例。

 

3.3 测试用模板

前面我们说了测试用例的生成方法,但是怎么使用呢或者说怎么将测试用例施加在目标软件上进行测试呢?

正如3.2中我们是拦截一个数据包,在此基础上修改各项的值生成测试用例。一般测试(不管理普通测试还是渗透测试)是不会强行把软件撕开一个口子去测试的,测试就是就着目标系统提供的接口对接口中的各项值进行修改以此生成测试用例去进行测试。

比如web所有的接请求或者api接口,就是测试用例的模板。

 

3.4 fuzzing和web扫描器的区别

fuzzing是通过前述三点生成测试用例去进行测试。

web扫描器其实本质也是通过使用测试用例去发现问题,不过web扫描器使用的是漏洞针对性的测试用例,比如测sql就用sql注入的测试用例、测xss就用xss的测试用例。比如两个sql测试用例如下:

# 测试用例1
union select user,password,authentication_string from mysql.user;
# 测试用例2
union/**/select/**/user,password,authentication_string/**/from/**/mysql.user;

所以fuzzing和web扫描器区分还算是比较清晰的,当然相互重叠也很正常。

 

四、模糊测试工具

4.1 全自动模糊测试工具bed

bed是全自动的协议模糊测试工具,可对FTP/SMTP/POP/HTTP/IRC/IMAP/PJL/LPD/FINGER/SOCKS4/SOCKS5等多种协议的各种请求及请求头部进行模糊测试,使用也不复杂就几个参数。

我对本地http服务器执行了bed -s http -t 192.168.220.1大概花了一下午的时间。

 

4.2 半自动模糊测试工具burpsuite

bed只能对协议的标准请求、标准头部进行模糊测试,对http的post等自定义的主体的各项是没法进行模糊测的,但其实这部份才是我们要测试的主要部分,所以单依靠bed是不行的。

burpsuite的intruder就是一个高度可配置的模糊测试功能,intruder只要设置好变量然后在payloads中设置好测试用例,即可进行模糊测试。

 

4.3 半自动模糊测试框架spike/sulley

使用burpsuite要受制于工具,一是可能会用得不爽,二是模糊测试要输出结果到其他代码的环境中不太适合,所以我们需要代码式的框架。

spike听说是自动化框架的鼻祖,但是文档不全。

sulley是模仿spike的一个自动化配架,在github上下载(https://github.com/OpenRCE/sulley.git)后其INSTALL.txt有安装说明按其说明安装即可。windows搞得很复杂有些依赖程序没安装成功就放弃了,在kali上那个说得很重要的vtrace(vdb)网站都关了所以其实也没装但我下边的代码可以成功运行(可能因为vdb只有部分功能才用到什么功能会用到就没去管了)。

sulley本质上就是一个python2写的程序,我们要做的就是在其上进行二次开发,所谓二次开发更具体就是打开sulley项目、使写正常python2程序一样写出自己的测试代码然后保存成py文件、最后运行py文件即可。代码示例如下:

复制代码
# -*- coding: utf-8 -*-
from sulley import *

# 规范而言将此部份存到requests文件夹下,比如存为ftp_ability.py再通过以下语句导入进来
# from requests import ftp_ability
# user等既不是变理也不是函数也不是类所以没法直接import进来,但s_get函数会自动去查找不用担心

# 定义一个名为user的模糊测试模版
s_initialize("user")
# s_static指定此部份固定字符串
s_static("USER")
# s_delim指定此部份为非字母字符,且重复次数任意
s_delim(" ")
s_static("ftp")
s_static("\r\n")

# 定义一个名为pass的模糊测试模版
s_initialize("pass")
s_static("PASS")
s_delim(" ")
s_static("ftp")
s_static("\r\n")

# 定义一个名为stor的模糊测试模版
s_initialize("stor")
s_static("STOR")
s_delim(" ")
# s_string指定此部份为需要进行模糊测试的字符串,测试时sulley该部份替换为各类测试用例类
s_string("AAAA")
s_static("\r\n")

# session用于发送测试用例
sess = sessions.session()
# 这步可以理解为与目标端建立网络连接
target = sessions.target("192.168.220.1", 21)
# 设定本次测试使用的网络连接
sess.add_target(target)
# 单独使用user测试模版进行测试
sess.connect(s_get("user"))
# 先发一个依据user模板生成的数据包,再发送一个pass模板生成的数据包进行测试
sess.connect(s_get("user"),s_get("pass"))
# 先发一个依据pass模板生成的数据包,再发送一个stor模板生成的数据包进行测试
sess.connect(s_get("pass"),s_get("stor"))
# 使用上边配置开始进行模糊测试
sess.fuzz()
复制代码

项目在ide中的组织如下,其实就只是将上方代码在sulley项目目录下保存成ftp_fuzzing_test.py然后运行

wireshark拦截的user模板生成的测试用例部分数据包截图,可以看到根据模板生成的测试用例首先是把空格重复不同次数:

更多语法说明可参见:https://fuzzinginfo.files.wordpress.com/2012/05/introducing_sulley.pdf

 

4.4 手动编写模糊测试工具

使用框架,一是虽然一般来说能用更少代码实现更优的模糊测试,但是这有两种成本一是要学习其语法,二是要安装框架安装有时搞得很复杂。

前面测试用例种类我们已经清楚了,这时如果不是很复杂,还不如索性自己从头写个模糊测试工具。

自主实现示例:https://www.cnblogs.com/lsdb/p/10958933.html

 

参考:

https://zh.wikipedia.org/wiki/%E6%A8%A1%E7%B3%8A%E6%B5%8B%E8%AF%95

https://github.com/OpenRCE/sulley/wiki/Windows-Installation

http://www.fuzzing.org/wp-content/SulleyManual.pdf

posted @ 2019-08-01 20:53  我只吃大碗  阅读(1077)  评论(0编辑  收藏  举报