Fuzzing用SPIKE挖掘漏洞Word文档下载推荐.docx
《Fuzzing用SPIKE挖掘漏洞Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《Fuzzing用SPIKE挖掘漏洞Word文档下载推荐.docx(19页珍藏版)》请在冰豆网上搜索。
若是使用其他系统,SPIKE可以从
在编译SPIKE之前,建议对spike.c文件稍做改动。
在tar包的SPIKE/SPIKE/src目录的spike.c文件里,有包含两个“return0;
”字符串的代码段,在其前面的“printf(“triedtosendtoaclosedsocket!
n”);
”代码段中,用“exit
(1);
”替换“return0;
”。
修改后SIKE将在返回空值时退出,这种功能对后面要运行的封装脚本是非常有用处的。
修改完成后,正常在SPKIE的src目录下编译链接程序“./configure;
make”。
在fuzzing目标服务器上,我们需要Administrator权限来运行Ollydbg调试器。
在Vista或者Windows7系统上,右键以管理员身份运行Ollydbg调试器。
运行Vulnserver服务器很简单,将文件vulnserver.exe和essfunc.dll放在与Ollydbg同一目录下,用OllyDbg的open命令打开程序。
程序默认监听TCP9999端口,若想使用其他端口,需要将端口号作为vulnserver.exe的参数一起运行。
什么是Fuzzing?
Fuzzing是为了使程序产生失败或错误故意向程序发送错误格式数据的方法。
fuzzing通常被攻击者用于挖掘软件漏洞。
当然,还是有一些其他流行的免费模糊测试器,但本文我们将关注在软件SPIKE上。
TheSPIKEFuzzer
从技术层面上讲,SPIKE是一个模糊测试创建工具集,它允许用户用C语言基于网络协议生成他们自己的测试数据。
SPIKE定义了一些原始函数,这允许C程序员可以构建fuzzing数据向目标服务器发送,以期引起产生错误。
既然SPIKE是专门被设计用来寻找可利用bug的,so,对我们来说这是极好的。
正如我所介绍,SPIKE是一个基于C语言的模糊创建工具集,但是要想使用SPIKE你却不必非得知道如何编写C代码,会修改就行。
SPIKE还包含一些简单的脚本功能,其中有几个命令行工具,在下文中介绍。
SPIKE帮助文档不给力是出了名的,通过查看SPIKE的一些C源码,我们可以建立一系列元函数的列表。
为了节省时间,本文将列出部分元函数。
目前也有不少关于SPIKE的论文与报告,但是最有意思的还是SPIKE作者DaveAitel的日记(链接为)简简单单的几页PPT,就勾勒出SPIKE灰常NB的漏洞挖掘实力。
对此,我们很有必要探讨一番,看看那些对我们是有用的。
SPIKE的功能是什么?
SPIKE拥有大量的内置字符串用来模糊测试,这在测试程序的时候是非常有效地。
SPIKE以一种十分有效地方式,来确定能使程序产生失败的值。
这意味着我们不用自已攒出这些数据,经验丰富的作者将向我们提供这些数据。
SPIKE有块(blocks)的概念,这可以在SPIKES内部推测出指定部分的大小。
产生的数据就可以被SPIKE以不同的格式嵌入到自身测试数据中去。
当需要在特定位置嵌入精确数据的时候,blocks是非常给力的,它大大节省了我们自行计算的时间。
SPIKE支持多种网络协议数据类型,并可在不同格式下,很容易的在不同程序中分割粘贴数据。
SPIKE脚本
如前所述,SPIKE包括一个基本的脚本功能,允许您使用SPIKE脚本测试应用程序,无需自己用C语言写SPIKEFUZZER代码。
SPIKE的子函数很给力,所以我们可以针对不同的应用发送测试数据。
在基于TCP的应用服务程序下,我们可以通过用脚本解释器generic_send_tcp来执行.spk脚本文件的方式,发送特定的数据到特定的IP地址、TCP端口。
当然,还有一个generic_send_udp脚本解释器,它的作用类似,就是通过UDP的方式发送数据。
解释器generic_send_tcp将被用来fuzz我们的应用程序,BackTrack系统下,可以在/pentest/fuzzers/spike/目录下找到,如果是你自己下载并编译的SPIKE程序,generic_send_tcp在src目录下面。
不带参数的运行结果如下:
root@bt4r1vm:
/pentest/fuzzers/spike/#./generic_send_tcp
argc=1
Usage:
./generic_send_tcphostportspike_scriptSKIPVARSKIPSTR
./generic_send_tcp192.168.1.100701something.spk00
前三个参数很明确,分别定义了fuzzing主机的主机名、端口号以及SPIKE脚本的名字,参数4、5则在下面进行了详细的说明。
在SPIKE脚本中,“s_string_variables”是用来向fuzzed数据插入字符串的命令。
若是用了一个以上的“s_string_variables”参数,你可以跳过使用早起的“s_string_variables”为SKIPVAR设置为适当的值。
例如,你的脚本中包含三个“s_string_variables”参数,并且你想忽略前两个参数,直接fuzz第三个参数,我们就可以设置SKIPVAR为2(变量的编号跟数组一样,从0开始)。
每一个“s_string_variables”也有一些列内置的模糊测试字符串值。
如果你想跳过前10个字符,想从第11个字符开始fuzzing,你就可以设置SKIPSTR参数为10(同样从0开始计起)。
当你使用generic_send_tcp时,它输出变量、字符串到测试中的命令行。
因此如果你要恢复被打断的SPIKE会话,你可以用得着SKIPVAR、SKIPSTR这两个命令行参数参数。
为了最初仅用“00”这些参数开始fuzzing会话,,所以可以用test.spk脚本对主机192.168.1.101的9999端口发起fuzzing会话。
用下面这些命令行(假设generic_send_tcp是在/pentest/fuzzers/spike/目录下):
~#/pentest/fuzzers/spike/generic_send_tcp192.168.56.1019999test.spk0
SPIKE脚本命令
为了写一个SPIKE脚本,我们首先需要知道一些可用的命令以及它们做了些什么。
如果你想了解SPIKE的命令组成,我们通过检查如.spk或spike.h等文件来探索发现。
Spike.h文件会列举出可用的原函数(命令),.spk文件提供关于这些命令使用的例子。
我们要记住的是spike脚本功能只支持spike.h的子集。
因此,你只能使用SPIKE的内置命令。
为了避免探索这些文件的麻烦,我在下边将列出一些更为有用的SPIKE的原始脚本。
spike.h文件由C语言写成,它用C语言的语法与数据结构列出了每个SPIKE命令。
对于那些不熟悉C的人来说,我通过用展示例子的方式来使你更加容易的复用代码,写出你自己的脚本。
“//”在C中是用来加备注的(编译器在编译程序时将忽略//之后内容),所以接下来我会用这种方式为每个命令提供额外的解释。
当然,你可以忽略的这些解释或者添加自己的解释,这些内容都会被SPKE忽略掉。
接下来我会断断续续的介绍字符串、二进制数据、块以及其他有用的结构。
Strings字符串
strings命令提供给我们向SPIKES添加ASCII字符的方式。
同样是字符串命令的s_string_variable函数,事实上是一个向SPIKE添加fuzz字符串的非常重要的命令。
●s_string(“string”);
//作为“SPIKE”的一部分,简单的输出字符“string”
●s_string_repeat(“string”,200);
//重复字符“string”200次
●s_string_variable(“string”);
//向你的SPKIE中插入一段字符串,字符串“string”将被用作这个变量的第一次循环,以及其他循环中的s_string_variables变量。
BinaryData二进制数据
binary命令提供了一种向SPIKES添加二进制数据的方法。
它们可以支持各种各样的定制的二进制数据。
●s_binary(“\x41″);
//插入二进制数据,16进制表示为0x41,ASCII码为A
●s_binary_repeat(“\x41″,200);
//插入二进制数据0x14200次
对于SPIKE的二进制命令,相同数据不同书写方式都是可用的。
为了输出跟上面相同的16进制字符,我们可以用“41”或者“0x41”,我们还可以混合这些值(如:
用“410x41\x42”来输出ASCII码“AAB”)。
任何空格都将被忽略,所有这些方便剪切/粘贴的数据都来自于这些用16进制表示的应用程序,如包捕获工具/调试器等。
DefiningBlocks定义块
块定义命令允许你用SPIKE脚本指定已命名块的起始与结束点。
这允许你在SPIKES内用blocksize命令定义那些数据段的大小。
●s_block_start(“block1″);
//定义块“block1”的起始位置
●s_block_end(“block1″);
//定义块“block1″的结束位置
BlockSizes块大小
块大小命令允许你向SPIKES已命名的block块插入size大小的数据,这些数据可以用你自己的脚本生成,允许他们有各种大小格式等。
●s_blocksize_string(“block1″,2);
//添加一个2个字符长的字符串到SPIKE中来代表block1块的大小s_binary_block_size_byte(“block1″);
//添加1byte数据到SPIKE中来代表block1块的大小
这是向SPIKE添加块数据多种方法中的两个例子。
当然还有其他方法允许你用各种格式的块,甚至一些允许增加块预设值。
要想看一下其他选项,在src目录下的spike.h文件里执行一下grep显示,筛选“block_size”或“blocksize”即可。
OtherUsefulCommands其他有用的命令
跟先前提到的其他类别都不符合的归类到本组。
●s_read_packet();
//读取来自服务器的数据,并显示到屏幕上
●s_readline();
//从服务器上读取一行输入信息
你也可以参考SPIKE内其他脚本,用C语言添加具有额外功能的脚本。
一个特别有用的函数是printf(),他可以通过终端显示,给我们提供更多信息。
AnExampleSPIKEScript
接下来是一个SPIKE脚本的例子,这个脚本对服务器的testme.php页面上的输入变量提交POST请求,进行fuzz测试。
s_string("
POST/testme.phpHTTP/1.1rn"
);
Host:
rn"
Content-Length:
"
s_blocksize_string("
block1"
5);
rnConnection:
closernrn"
s_block_start("
inputvar="
s_string_variable("
inputval"
s_block_end("
这个脚本指定一个如下脚本,SPIKEfuzz字符串将被插入到[fuzz_string]代表的位置上,向[size_of_data]代表的数据段大小插入POST请求数据,里面包含固定字符串“inputvar=”和可变的fuzz字符串。
测试中,fuzz字符串的长度江随着字段大小自动更新变化。
POST/testme.phpHTTP/1.1
[size_of_data]
Connection:
close
inputvar=[fuzz_string]
理解模糊测试协议
成功的fuzzing测试经常是需要将一些恶意的/意想不到的数据插入到一个具体应用输入接口中。
程序在处理用户输入数据时,触发一个可利用的崩溃。
这就需要我们在向网络协议输入fuzz数据时找到正确输入位置。
数据字段/字段大小/命令行参数/输入的字符串,有时命令本身的类型就是可input输入位置,它们可以生成自身类型的错误。
换句话说,为了将错误的数据放入到正确的地方,我们需要理解与目标通讯的网络协议的结构,以便我们的fuzzing数据能被导入到应用程序的正确位置。
理解网络协议有很多方法可用,如通过查阅RFC文档,用Wireshark或tcpdump等抓取应用客户端的数据。
或者,对于非常简单的协议,可以直接与应用程序交互查看它是怎么工作的。
这就是我们针对Vulnserver服务器要做的工作。
首先我们需要启动它。
因为我们想捕获到异常数据,所以我们在Debugger调试器中运行程序。
在windows系统下启动OllyDbg,用它从本地磁盘加载vulnserver.exe文件,按F9键或按OllyDbg工具栏Play按钮或者在Debug菜单下选Run来让加载到debugger的程序运行起来。
此时,程序正常运行起来。
这时,如果我们引发了一个崩溃,debugger调试器将接管进程,让我们看明白在产生崩溃的时刻寄存器与程序内存正在干些什么。
现在,在我们Linuxfuzzing系统上,我们可以用netcat来连接Vulnserver上运行的实例。
运行netcat时用-vv参数来获取更多连接信息,-n参数禁用DNS递归查询。
~#nc-nvv192.168.56.1019999
(UNKNOWN)[192.168.56.101]9999(?
)open
WelcometoVulnerableServer!
EnterHELPforhelp.
从我们收到的响应来看,输入HELP命令时我们会得到一些帮助。
我们看看是些什么呢。
HELP
ValidCommands:
STATS[stat_value]
RTIME[rtime_value]
LTIME[ltime_value]
SRUN[srun_value]
TRUN[trun_value]
GMON[gmon_value]
GDOG[gdog_value]
KSTET[kstet_value]
GTER[gter_value]
HTER[hter_value]
LTER[lter_value]
KSTAN[lstan_value]
EXIT
好的,HELP命令给我没提供了一系列程序可用的命令。
让我们试着输入一些命令以及一些其他随机的字符串,看看有什么会发生。
STATS
UNKNOWNCOMMAND
允许不带参数的STATS命令看起来好像不被支持。
那么,我们在其后添加一些通用文字再试一下。
STATStest
STATSVALUENORMAL
好的,STATS命令看起来运行了。
那么如果我们改变STATS命令会怎么样呢。
statstest
OK,看起来命令还是分大小写的。
让我们试一下不在命令支持列表的其他随机文本。
BLAH
恩,看起来任何错误或不被支持的命令执行时,都会产生UNKNOWNCOMMAND返回信息。
我们再测试另外一个被支持的命令,以及一个随机参数。
TRUNhhh
TRUNCOMPLETE
OK,返回了不同信息。
我们看一下是否可以获得更多关于这些被支持的命令帮助信息。
HELPSTATS
Commandspecifichelphasnotbeenimplemented
遗憾的是,一点帮助也没有!
也许现在你已经意识到,我正试着通过像这样不停询问程序的方式来找出可被程序接受的数据类型,寻找我构建fuzzing数据的方法。
基于我们已知的信息,程序看起来支持若干命令,某些命令还可以附带参数。
考虑到这一点,向应用程序引进fuzz数据的方式可以被插入到:
Ø
一个支持命令的地方
作为某些函数的参数,这些函数本就支持参数(STATS,RTIME,LTIME等)
作为某些函数的参数,这些函数没有表示支持参数(HELP,EXIT等)
因此我一个关于如何向Vulnserver应用协议插入fuzz数据的想法。
关闭与Vulnserver应用的会话。
GOODBYE
这的确是一个协议分析的例子,我相信它完美的展示了一般的预fuzzing的过程。
我们确定了程序接收用户输入数据的方式以及用这种方法向应用插入fuzz过的数据。
用SPIKE模糊测试Vulnserver
根据我们分析Vulnserver协议获取的知识,用SPIKE向应用程序真正的fuzzing一把。
在上一节,我们意识到向可用命令发送fuzz数据是很有用的,并且命令的参数看起来是不支持参数的。
让我们从最简单的开始,首先发送一fuzz过的字符串给一个命令。
SPIKE脚本实现起来的效果如下:
//打印从服务收到的一行数据
●s_string_variable("
COMMAND"
//发送fuzz数据
恩,当我们连接并且发送fuzz数据到应用服务器后,我们等待着服务器会返回最初的“Welcome”信息。
保存这些内容到fuzzing系统,命名为“vscommand.spk”。
再用SPIKE加载这个脚本之前,我们先用Wireshark抓一些数据包来看一下SPIKE发送的数据。
我的Vulnserver目标副本正在监听192.168.56.101服务器的9999端口。
我们用以下命令筛选抓包数据,忽略其他数据。
输入内容如下:
host192.168.56.101andtcpport9999
开启Wireshark抓包引擎,开始SPIKE模糊测试,所用的命令如下所示。
(假设用的系统为BackTrack,SPIKE目录为/pentest/fuzzers/spike,vscommand.spk文件被保存到当前工作目录)。
若是你自己下载SPIKE,generic_send_tcp位于SPIKE/SPIKE/src目录。
~/vulnserver#/pentest/fuzzers/spike/generic_send_tcp192.168.56.1019999vscommand.spk00
TotalNumberofStringsis681
Fuzzing
FuzzingVariable0:
lineread=WelcometoVulnerableServer!
1
Variablesize=5004
2
Variablesize=5005
[...SNIP...]
2041
2042
2043
Done.
若是让它运行,SPIKE将在几分钟后完成测试工作。
这时我们检查debugger调试器,会发现程序运行的还算OK,没有出现崩溃啊神马的。
看起来只向命令发送bad数据,是不能引起Vulnserver产生崩溃的。
这没关系,在程序中我们还有其他很多地方可以用bad数据来做测试。
分析一下数据包,我们就能明白SPIKE做了写什么。
SPIKE运行状况如下,SPIKE接收到welcome信息/发送COMMAND字符串到应用。
返回字符串毫无疑问是我们在SPIKE脚本用s_string_variable命令定制的信息。
目前看来,SPIK