首页 | 安全文章 | 安全工具 | Exploits | 本站原创 | 关于我们 | 网站地图 | 安全论坛
  当前位置:主页>安全文章>文章资料>网络安全>文章内容
使用SPIKE进行安全测试
来源:http://kkqq.blogdns.com 作者:kkqq 发布时间:2003-11-08  

使用SPIKE进行安全测试


(My blog is here http://kkqq.blogdns.com)

给一个MIPS的系统porting Linux的时候被郁闷了,休息休息换换脑子。这里简单
介绍一下如果利用spike[1]对程序进行黑盒测试。这里就挑选最新的Messenger漏洞作
为测试的目标。spike一般是用来发现漏洞的,这里我们用来重现漏洞就有点...。不
过重现漏洞只是一个示例。

spike是immunitysec公司的Dave Aitel写的一个黑盒进行安全测试的工具。最开始
的spike是作为nmap-hackers邮件列表评比的Top 75 Security Tools中的spikeproxy出
名的,spikeproxy是用来做web penetration test的。spikeproxy是SPIKE Suite Tools
中的一部分,这里我们谈的是另外一部分SPIKE Fuzzer Creation Kit。这一部分为我们
提供了使用黑盒的方式对程序进行安全分析的库,以下的构造就是基于这一部分进行的。
spike的最新版本是2.8,从邮件列表上的消息看,不久2.9也快发布了。

这里简单的八卦一下,Dave Aitel以前是在@stake[3]工作的,现在你也可以在
@stake上找到spike v1.8的下载。后来Dave Aitel创建了自己的公司immunitysec。
之所以专门谈一下这个人,是因为在efnet发布的那份假的phrack62[4]上,有一篇
<<Eye on the Spy>>的文章,里边提到了Dave Aitel和iDefense,专门收购漏洞从事盈
利性活动,违背了full-disclosure的精神。不知道大家对这种行为如何评价?

这里转入正题。在进行最终的测试之前,我们需要了解一下Windows上的Messenger服
务。最开始Messenger的表现形式就是win9x中的popup程序,与现在不同的是popup之类的
Messenger一般是利用SMB协议中的Send Single Message Block Request进行消息传递的
(当然也有Multi Message Block的),相同的这种机制比如linux下的smbclient -M。而进
入到win2k/xp以后,又提供了RPC上的Messenger服务。这里针对的就是RPC上的Messenger。

[注]:目前RPC的标准有SUN RPC和DCE RPC。Windows上的RPC是对DCE RPC进行的移植,
由于对RPC接口命名方式不同,称为MS RPC。这里指得都是MS RPC。

进行分析的步骤大致如下:
1.对RPC的Messenger如何交换信息进行分析
2.构造测试框架
3.运行

--[ RPC上的Messenger的分析

在用ethereal[5]对net send命令发送的报文进行分析后,发现利用RPC发送Message
的过程大致如下(UDP):

Source port1 -> DCE-RPC的Messenger服务报文 -> Target 135

Target port2 -> DCE-RPC conv_who_are_you -> Source port1
Source port1 -> DCE-RPC conv_who_are_you2 reply -> Target port2
Target port2 -> DCE-RPC ACK -> Source port1

Target 135 -> DCE-RPC Response -> Source port1
Source port1 -> DCE-RPC ACK -> Target 135

[注]: conv_who_are_you, conv_who_are_you2 reply, Response, ACK都是RPC协议
中的PDU(Protocol Data Unit)类型。

这样一个过程做起来实在是复杂,port1除了发送Message,发送Response回应报文
外,还得负责处理发送过来的conv_who_are_you的协商。实现起来虽然不难,但是体力
劳动还是有很多。多亏现在Messenger上的垃圾广告的流行,人们对Messenger的分析都
已经很深入了。google的时候无意中在Full-Disclosure[6]上发现只要把RPC报文中的
标志位Idempotent和NoFack置为1,就不存在conv_who_are_you的协商了。这样一个单独
的UDP报文就可以搞定整个过程(既然是单独的UDP报文就可以搞定,那伪造IP发送消息
... //grin,不过这里用不到),但是考虑到需要根据回应报文判断测试的结果,最后
这个过程就简化为:

Source port1 -> DCE-RPC的Messenger服务报文 -> Target 135
Target 135 -> DCE-RPC Response -> Source port1

根据RPC的协议[7],RPC的PDU分为两种类型,无连接(Connectionless)和有连接的
(Connection-Oriented)。UDP上的RPC自然是无连接的了。
其中RPC头的数据结构为
typedef struct {
unsigned small rpc_vers = 4; /* RPC protocol major version
(4 LSB only)*/
unsigned small ptype; /* Packet type (5 LSB only) */
unsigned small flags1; /* Packet flags */
unsigned small flags2; /* Packet flags */
byte drep[3]; /* Data representation format label */
unsigned small serial_hi; /* High byte of serial number */
uuid_t object; /* Object identifier */
uuid_t if_id; /* Interface identifier */
uuid_t act_id; /* Activity identifier */
unsigned long server_boot;/* Server boot time */
unsigned long if_vers; /* Interface version */
unsigned long seqnum; /* Sequence number */
unsigned short opnum; /* Operation number */
unsigned short ihint; /* Interface hint */
unsigned short ahint; /* Activity hint */
unsigned short len; /* Length of packet body */
unsigned short fragnum; /* Fragment number */
unsigned small auth_proto; /* Authentication protocol
identifier*/
unsigned small serial_lo; /* Low byte of serial number */
} dc_rpc_cl_pkt_hdr_t;

其中需要事先知道的是object和opnum,一种方法就是从ethereal中的报文中构造,另
外一种方法就是使用反汇编msgsvc.dll,使用rpcenum.idc[8]获得这些信息。第二种方法
的输出如下:

------------------------------------
RPC Interface Enum $Revision: 1.8 $, (c) 2003 kkqq
------------------------------------
Length: 68
Interface UUID: 5a7b91f8-ff00-11d0-a9b2-00c04fb6e6fc
Major Version: 1
Minor Version: 0
Transfer UUID: 8a885d04-1ceb-11c9-9fe8-08002b104860
Major Version: 2
Minor Version: 0
Dispatch Table: 76818558
Dispatch Table Count: 1
Dispatch Table Addr: 76818550
DisPatch 1: NdrServerCall2
EndPoint Count: 0
EndPoint: 0
Default Manager: 0
Interpreter Info: 76812988
Flags: 0
------------------------------------

所以object为Interface UUID: "5a7b91f8-ff00-11d0-a9b2-00c04fb6e6fc"。只有
一个Dispatch,opnum从0开始,那么就是0了。其余字段在下一部分介绍。

下来就是紧跟着RPC头的数据部分了。ethereal不愧是最强的协议分析自由软件。直
接从捕获到的报文构造就是了。数据结构大致如下:
typedef struct {
WORD MaxCount;
WORD Offset;
WORD ActualCount;
BYTE Data[ActualCount + ActualCount%4 ? (4 - ActualCount%4) : 0];
} element;
typedef struct {
element Server;
element Client;
element Message;
} data;

之所以用ActualCount + ActualCount%4 ? (4 - ActualCount%4) : 0表达,是因为
RPC中的字符串是要求4字节对齐的,不足的部分补0。另外字符串的长度是计算字符串的
终结符'\0'的。

对应上边的数据结构,消息发送之后弹出的对话框内的文本形式如下:
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ 在2003-11-3 10:16:14从Client.Data到Server.Data的消息 ┃
┃ ┃
┃ Message.Data ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

实际的测试中发现发送一次以后,需要等很长时间第二次发送才能被正确处理。原因
是DCE-RPC为了防止报文重复,一定时间内(似乎要几分钟)之内不再接收重复报文。如果
真是这样的话,几分钟测一个testcase,也真是会等死人的。

测试发现,只要把DCE-RPC报文中的Activity GUID随便换一下,就没有什么事情了。

下来可以开始用SPIKE构造测试脚本了。

--[ 使用spike构造测试框架

之所以挑选SPIKE,是因为SPIKE提供了各种各样的构造函数。例如s_binary可以构造
二进制数据,s_string可以构造字符串,s_unistring可以构造UNICODE字符串。类似这
样的还很多,可以参考源码中的spike.h中s_xxxx之类的函数(SPIKE的文档做的不详细,
想挖什么东西还是看源码来得直接一点)。

SPIKE构造测试集的方法称为Block-Based Protocol Analysis[9]。比如上边我们提
到的RPC Header中有一个字段为len(Length of packet body)。如果让我们自己构造的
话,还需要计算整个Packet的长度。如果在spike中,只需要定义如下的形式

s_block_start("Data")
s_binary("01020304");
s_block_end("Data");

在需要的地方使用以s_binary_block_size开头的函数,例如
s_binary_block_size_intel_halfword("Data");
就可以把标记为Data的Block的长度压到栈里边。

SPIKE的另外一个优势就是Dave Aitel的Fuzz理论,就是构造一些特殊的数字或者
字符串作为程序的输入,检查程序是否能够处理这些异常数据。看过OUSPG[10]对协议进
行安全测试的朋友应该会看到,在测试的过程中有一个异常元素构造(Design of
Exceptional Elements)的过程,这其实就是SPIKE中提供的fuzz机制。只不过SPIKE提供
的是较为常见的一些形式,例如:长字符串,带有格式串的字符串,大整数,负数,其他
各种畸形字符等等(可以看源码中spike.c中的s_init_fuzzing函数)。相比之下,OUSPG
进行的设计是有针对性。

SPIKE里边提供了常见的协议支持,例如SUN RPC和MS RPC。但是SPIKE中的MS RPC是
TCP上的,是有连接的PDU。所以这里我们还需要重新写UDP上的RPC的包构造函数。

下边提供的程序中就使用了SPIKE提供的这种fuzz机制。

-- [ 程序

程序分为三个部分:
1.测试框架rpc_messenger.c; 漏洞原理见[11],在rpc_messenger.c中手动加
入了一行可以引起这个漏洞的代码。(程序中把测试例的长度限制在4000之内)

2.一个简单的编译脚本messenger.sh(因为SPIKE的Makefile是用automake生成
的,怕以后升级之后不好搞,干脆弄一个直接的脚本来编译);

运行:
1.编译spike
2.运行messenger.sh
3.rpc_messenger xxx.xxx.xxx.xxx 135
4.不嫌麻烦的话,一个一个串口点掉吧。可以看看SPIKE中的异常串都是什么
样的格式。:)

结果判断:rpc_messenger.c里边有一个简单的read_packet,判断返回报文的类型。
如果程序停止运行,那么就是说在发送测试报文之后没有收到回应报文。一般来说有三
种情况:测试目标服务关闭;发送的报文有重复,在一定时间内(10分钟)服务器不会对同
样的报文做回应;服务器在上一个报文发送的过程中已经停止响应了。

-- [ rpc_messenger.c

/*
* Copyritht 2003 kkqq
* Covered under GPL v 2.0
* $Id: spike.txt,v 1.8 2003/11/06 11:13:03 yclin Exp $
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <ctype.h>


#include "spike.h"
#include "hdebug.h"
#include "tcpstuff.h"
#include "udpstuff.h"
#include "spike_dcerpc.h"

struct spike * our_spike;

int
s_dce_string1(unsigned char * mystring)
{
unsigned short size;
unsigned int i;

size=strlen(mystring);
for (i=0; i< size; i++)
s_push(mystring+i,1);
s_binary("00");

while ((size + 1) % 4 != 0)
{
s_binary("00");
size++;
}
return size+2; /*2 for intel half word */
}


void
read_packet()
{
unsigned char buffer[5000];
int i;
int size;

s_fd_wait();
memset(buffer,0x00,sizeof(buffer));
printf("Packet:\n");
size=read(our_spike->fd,buffer,1500);
for (i=0; i<size; i++)
{
if(i%16 == 0)
printf("\n");
/* if (isprint(buffer[i]))
printf("%c",buffer[i]);
else
*/
printf("%2.2x",buffer[i]);

}
printf("\n");
if(buffer[size - 1] == 0 && buffer[size - 2] == 0)
{
if(buffer[size - 3] == 0 && buffer[size - 4] == 0)
printf("Test Case Pass: Message OK\n");
else if(buffer[size - 3] == 0x6 && buffer[size - 4] == 0xf7)
printf("Test Case Pass: Invalid Packet\n");
else
printf("Unknow Response\n");
}
else
printf("Unknow Response\n");
}


/*returns 1 on success, 0 on failure*/
/*I think callid is actually ignored by MSRPC servers. Pass something in though.*/

int
my_dce_bind(unsigned int type, char * interface, char * activity,
unsigned int version, unsigned int opnum)
{
unsigned char uuidbuffer[400];
unsigned int uuidlength;

/*version*/
s_binary("04");

/* Type */
s_push(&type, 1);

/* Flags */
s_binary("28");

/*binds are always just one packet*/
s_binary("0x00");

/*now set Data Rep, whatever that is */
s_intelword(0x00000010);

/* Object UUID */
uuidlength=uuid_string_to_buffer(uuidbuffer, "00000000-0000-0000-0000-000000000000");
s_push(uuidbuffer,uuidlength);

/*Interface UUID*/
uuidlength=uuid_string_to_buffer(uuidbuffer, interface);
s_push(uuidbuffer,uuidlength);

/* Activity */
uuidlength=uuid_string_to_buffer(uuidbuffer, activity);
s_push(uuidbuffer,uuidlength);

/* Boot Time */
s_binary("00 00 00 00");

/* Interface Ver */
s_intelword(version);

/* Squence NO. */
s_binary("00 00 00 00");

/* Op Num */
s_intelhalfword(opnum);

/* Interface Hint */
s_binary("ff ff");

/* Activatity Hint */
s_binary("ff ff");


/* Fragement Length */
s_binary_block_size_intel_halfword("DCEFragLength");

/* Fragment NO. */
s_binary("00 00");

/*auth proto*/
s_binary("00");

s_block_start("DCEAuthLength");
s_block_end("DCEAuthLength");

/* Serial NO. */
s_binary("00");

/*why does the DCEFrag start here? - but it does*/
s_block_start("DCEFragLength");
return 1;
}

void
usage()
{
printf("Usage: ./smbmessenger target port\n");
exit(-1);
}

int
main (int argc, char ** argv)
{
char *target;
int port, index = 0;
char guid[50];
char buffer[4000];

if (argc != 3)
{
usage();
}

target = argv[1];
port = atoi(argv[2]);

our_spike = new_spike();

if (our_spike == NULL)
{
fprintf(stderr,"Malloc failed trying to allocate a spike.\r\n");
exit(-1);
}

setspike(our_spike);

/* very important line. don't forget it*/
s_init_fuzzing();

/* test MS-0343 Messenger Buffer Overrun Vul. */
/* memset(buffer, 0, sizeof(buffer));
memset(buffer, 'A', 100);
memset(buffer + 100, 0x14, 3000);
memset(buffer + 2100, 'A', 500);
s_add_fuzzstring(buffer);
*/
/*zeroth fuzz variable is first variable*/
s_resetfuzzvariable();

while (!s_didlastvariable())
{
while(!s_didlastfuzzstring())
{
int len = 0;

i++;
if(i > 5)
exit(-1);
s_setfirstvariable();
spike_clear();
memset(guid, 0, sizeof(guid));

sprintf(guid, "8a885d04-1ceb-11c9-9fe8-08002b1%.5d", index);

/* Messenger Data */
my_dce_bind(0, "5a7b91f8-ff00-11d0-a9b2-00c04fb6e6fc", guid,
1, 0);
s_intelword(5);
s_intelword(0);
s_intelword(5);

s_dce_string1("kkqq");

s_intelword(5);
s_intelword(0);
s_intelword(5);
s_dce_string1("kkqq");

s_binary_block_size_intel_word("MessageData");
s_intelword(0);
s_binary_block_size_intel_word("MessageData");
s_block_start("MessageData");
s_string_variable("");
s_binary("00");
s_block_end("MessageData");

s_block_end("DCEFragLength");
if((len = s_get_size()) < 4100)
{
spike_listen_udp(index + 20000);

printf("fd=%d\n",our_spike->fd);
if(!spike_set_sendto_addr(target, port))
{
printf("Couldn't resolve hostname for spike_set_sendto_addr!\n");
exit(-1);
}

if (spike_send()<0)
{
printf("Couldn't send data!\r\n");
exit(-1);
}

printf("sent packet\n");
read_packet();
s_close_udp();
}
index ++;
s_incrementfuzzstring();
}
s_incrementfuzzvariable();
}

return 0;
}

-- [ messenger.sh

#!/bin/sh
# $Id: spike.txt,v 1.8 2003/11/06 11:13:03 yclin Exp $
rm rpc_messenger
gcc -Wall -funsigned-char -c -fPIC -ggdb -I/usr/local/include -I../include \
-Ilibntlm-0.21/ rpc_messenger.c
gcc -ggdb -o rpc_messenger rpc_messenger.o dlrpc.o dlargs.o spike.o \
listener.o hdebug.o tcpstuff.o spike_dcerpc.o base64.o udpstuff.o \
spike_oncrpc.o -ldl -L. -ldlrpc

-- [ 结束

本文只是给出一个使用SPIKE发掘漏洞的例子,不过这个例子并没有发现什么漏洞,
可以说是正确的方法用在了错误的地方。:),如果要进行真正的黑盒测试,光测试一个
Message字段还是不够的。为了防止这里出现组合爆炸的问题,所以这里只针对Message
字段进行测试。这个程序可以用来在短时间内发送大量Message,希望合适的技术能用
在合适的地方。

感谢Dave Aitel;发现Messenger漏洞的LSD;因为Messenger的漏洞而不高兴的某位
大哥,感谢他对我得帮助;还有我的朋友bladestatn和lgx :)

参考
[1] SPIKE Suite Tools
http://www.immunitysec.com/spike.html

[2] Top 75 Security Tools
http://www.insecure.org/tools.html

[3] atstake
http://www.atstake.com/

[4] #phrack@efnet
http://phrack.efnet.ru
http://phrack.nl/

[5] Ethereal
http://www.ethereal.com/

[6] [Full-Disclosure] Re: Windows Messenger Popup Spam
http://lists.netsys.com/pipermail/full-disclosure/2003-July/006152.html

[7] DCE 1.1: Remote Procedure Call
http://www.opengroup.org/products/publications/catalog/c706.htm

[8] 枚举可执行文件中的RPC接口信息
https://www.xfocus.net/bbs/index.php?act=ST&f=6&t=29860

[9] The Advantages of Block-Based Protocol Analysis for Security Testing
http://www.immunitysec.com/downloads/advantages_of_block_based_analysis.pdf

[10] OUSPG: Oulu University Secure Programming Group
http://www.ee.oulu.fi/research/ouspg/

[11] Proof of concept for Windows Messenger Service overflow
http://lists.netsys.com/pipermail/full-disclosure/2003-October/012347.html

$Id: spike.txt,v 1.8 2003/11/06 11:13:03 yclin Exp $


 
[推荐] [评论(0条)] [返回顶部] [打印本页] [关闭窗口]  
匿名评论
评论内容:(不能超过250字,需审核后才会公布,请自觉遵守互联网相关政策法规。
 §最新评论:
  热点文章
·一句话木马
·samcrypt.lib简介
·教你轻松查看QQ空间加密后的好友
·web sniffer 在线嗅探/online ht
·SPIKE与Peach Fuzzer相关知识
·asp,php,aspx一句话集合
·Cisco PIX525 配置备忘
·用Iptables+Fedora做ADSL 路由器
·检查 Web 应用安全的几款开源免
·Md5(base64)加密与解密实战
·NT下动态切换进程分析笔记
·风险评估中的渗透测试
  相关文章
·探测honeypot的tips
·最佳的75个安全工具
·Snort 用户手册
·搭建一个windows下的蜜罐系统
·玩转ARP
·UNIX系统下的应急响应工具介绍
·Windows Workstation Service远
·Cisco常见路由器密码恢复[原创]
·动网暴力破解密码程序代码
·sniffer技术资料
·深入探索Microsoft SQL Server 2
·Cisco PIX525 配置备忘
  推荐广告
CopyRight © 2002-2022 VFocuS.Net All Rights Reserved