参考网络嗅探器设计与实现.docx
《参考网络嗅探器设计与实现.docx》由会员分享,可在线阅读,更多相关《参考网络嗅探器设计与实现.docx(26页珍藏版)》请在冰豆网上搜索。
参考网络嗅探器设计与实现
JIANGSUUNIVERSITY
入侵检测技术课程报告
--网络嗅探器的设计与实现
学院名称:
计算机学院
专业班级:
研1101
学生姓名:
朱锋
教师姓名:
周莲英
2012年5月12日
网络嗅探器的设计与实现
Designandimplementationofnetworksniffer
目录
1网络嗅探概述3
1.1网络嗅探的简介3
1.2相关的网络知识4
1.3基于网卡混杂模式的嗅探原理6
1.4基于arp欺骗的嗅探原理7
1.5网络嗅探的安全威胁7
1.6网络嗅探的防范8
2基于原始套接字的嗅探程序9
2.1嗅探实现9
2.2嗅探运行结果25
3网络嗅探工具应用----WinSniffer使用方法27
3.1WinSniffer简介27
3.2WinSniffer嗅探功能使用方法27
1网络嗅探概述
1.1网络嗅探的简介
网络嗅探器又称为网络监听器,简称为Sniffer子系统,放置于网络节点处,对网络中的数据帧进行捕获的一种被动监听手段,是一种常用的收集有用数据的方法,这些数据可以是用户的账号和密码,可以是一些商用机密数据等等。
Sniffer是利用计算机的网络接口截获目的地为其他计算机的数据报文的一种工具。
Sniffer的正当用处主要是分析网络的流量,以便找出所关心的网络中潜在的问题。
例如,假设网络的某一段运行得不是很好,报文的发送比较慢,而我们又不知道问题出在什么地方,此时就可以用嗅探器截获网络中的数据包,分析问题的所在。
而嗅探器也可作为攻击工具被黑客所利用为其发动进一步的攻击提供有价值的信息。
1.2相关的网络知识
1.2.1 交换基础
交换发生网络的第二层,即数据链路层。
谈到交换的问题,从广义上讲,任何数据的转发都可以称作交换。
当然,现在我们指的是狭义上的交换,仅包括数据链路层的转发。
1.2.1.1 交换原理
所谓交换,就是将分组(或帧)从一个端口移到另一个端口的简单动作。
交换机在操作过程当中会不断的收集资料去建立它本身的一个地址表,MAC地址表显示了主机的MAC地址与以太网交换机端口映射关系,指出数据帧去往目的主机的方向。
当以太网交换机收到一个数据帧时,将收到数据帧的目的MAC地址与MAC地址表进行查找匹配。
如果在MAC地址表中没有相应的匹配项,则向除接收端口外的所有端口广播该数据帧,有人将这种操作翻译为泛洪。
在我们测试过的交换机中,有的除了能够对广播帧的转发进行限制之外,也能对泛洪这种操作进行限制。
而当MAC地址表中有匹配项时,该匹配项指定的交换机端口与接收端口相同则表明该数据帧的目的主机和源主机在同一广播域中,不通过交换机可以完成通信,交换机将丢弃该数据帧。
否则,交换机将把该数据帧转发到相应的端口。
1.2.1.2 交换技术
局域网交换技术是作为对共享式局域网提供有效的网段划分的解决方案而出现的,它可以使每个用户尽可能地分享到最大带宽。
交换技术是在OSI七层网络模型中的第二层,即数据链路层进行操作的,因此交换机对数据包的转发是建立在MAC地址基础上的,对于IP网络协议来说,它是透明的,即交换机在转发数据包时,不知道也无须知道信源机和目标机的IP地址,只需知其物理地址。
从网络交换产品的形态来看,交换产品大致有三种:
端口交换、帧交换和信元交换。
1.2.2 路由基础
所谓路由就是指通过相互连接的网络把信息从源地点移动到目标地点的过程。
1.2.2.1 路由原理
当IP子网中的一台主机发送IP分组给同一IP子网的另一台主机时,它将直接把IP分组送到网络上,对方就能收到。
而要送给不同IP子网上的主机时,它要选择一个能到达目的子网上的路由器,把IP分组送给该路由器,由路由器负责把IP分组送到目的地。
如果没有找到这样的路由器,主机就把IP分组送给一个称为“缺省网关”的路由器上。
“缺省网关”是每台主机上的一个配置参数,它是接在同一个网络上的某个路由器端口的IP地址。
路由器转发IP分组时,只根据IP分组目的IP地址的网络号部分,选择合适的端口,把IP分组送出去。
同主机一样,路由器也要判定端口所接的是否是目的子网,如果是,就直接把分组通过端口送到网络上,否则,也要选择下一个路由器来传送分组。
路由器也有它的缺省网关,用来传送不知道往哪儿送的IP分组。
这样,通过路由器把知道如何传送的IP分组正确转发出去,不知道的IP分组送给“缺省网关”路由器,这样一级一级的传送,IP分组最终将送到目的地,送不到目的地的IP分组则被网络丢弃了。
1.2.2.2 路由技术
路由器不仅负责对IP分组的转发,还要负责与别的路由器进行联络,共同确定“网间网”的路由选择和维护路由表。
路由包含两个基本的动作:
选择最佳路径和通过网络传输信息。
在路由的过程中,后者也称为(数据)交换。
交换相对来说比较简单,而选择路径很复杂。
1.2.2.3 路径选择
路径选择是判定到达目的地的最佳路径,由路由选择算法来实现。
由于涉及到不同的路由选择协议和路由选择算法,要相对复杂一些。
为了判定最佳路径,路由选择算法必须启动并维护包含路由信息的路由表,其中路由信息依赖于所用的路由选择算法而不尽相同。
metric是路由算法用以确定到达目的地的最佳路径的计量标准,如路径长度。
为了帮助选路,路由算法初始化并维护包含路径信息的路由表,路径信息根据使用的路由算法不同而不同。
1.2.3网卡的工作原理
发送数据时,网卡首先侦听介质上是否有载波,如果有,则认为其他站点正在传送信息,继续侦听介质。
一旦通信介质在一定时间段内是安静的,即没有被其他站点占用,则开始进行帧数据发送,同时继续侦听通信介质,以检测冲突。
在发送数据期间。
如果检测到冲突,则立即停止该次发送,并向介质发送一个“阻塞”信号,告知其他站点已经发生冲突,从而丢弃那些可能一直在接收的受到损坏的帧数据,并等待一段随机时间。
在等待一段随机时间后,再进行新的发送。
如果重传多次后(大于16次)仍发生冲突,就放弃发送。
接收时,网卡浏览介质上传输的每个帧,如果其长度小于64字节,则认为是冲突碎片。
如果接收到的帧不是冲突碎片且目的地址是本地地址,则对帧进行完整性校验,如果帧长度大于1518字节或未能通过CRC校验,则认为该帧发生了畸变。
通过校验的帧被认为是有效的,网卡将它接收下来进行本地处理。
接受到报文的计算机的网卡处理报文的过程如下图所示:
1.3基于网卡混杂模式的嗅探原理
在网络中,嗅探器接收所有的分组,而不发送任何非法分组。
它不会妨碍网络数据的流动,因此很难对其进行检测。
不过,处于混杂模式网卡的状态很显然和处于普通模式下不同。
在混杂模式下,应该被硬件过滤掉的分组文会进入到系统的内核。
是否回应这种分组完全依赖与内核。
下面我举一个现实世界中的例子,说明我们检测处于混杂模式网络节点的方法。
设想一下,在一个会议室中正在举行一个会议。
某个人把耳朵放在会议室就可以进行窃听。
当她进行窃听时,会屏住呼吸,安静地聆听会议室内所有的发言。
然而,如果此时会议室内有人忽然叫窃听者的名字:
“太太”,她就可能答应“唉”。
这听起来有点好笑,但是完全可以用于网络嗅探行为的检测。
网络进行网络嗅探的节点会接收网络的所有报文,因此其内核可能对某些本该被硬件过滤的分组作出错误回应。
根据这个原理,我们可以通过检查节点对ARP报文的响应来检测网络的嗅探行为。
1.4基于arp欺骗的嗅探原理
所谓ARP欺骗,就是利用广播地址上主机保持周边计算机信息方式的固有安全弱点,使用伪造的MAC地址和IP地址伪装成ARP高速缓存中的另一台主机的技术。
根据交换机的工作原理,有以下两种基于ARP欺骗的网络嗅探方法。
(1)基于交换机的MAC-端口映射表修改的嗅探。
(2)基于中间人攻击的嗅探。
1.5网络嗅探的安全威胁
实际应用中的嗅探器分软、硬两种。
软件嗅探器便宜易于使用,缺点是往往无法抓取网络上所有的传输数据,也就可能无法全面了解网络的故障和运行情况;硬件嗅探器的通常称为协议分析仪,它的优点恰恰是软件嗅探器所欠缺的,但是价格昂贵。
目前主要使用的嗅探器是软件的。
嗅探器捕获真实的网络报文。
嗅探器通过将其置身于网络接口来达到这个目的--例如将以太网卡设置成杂收模式。
数据在网络上是以帧的单位传输的。
帧通过特定的称为网络驱动程序的软件进行成型,然后通过网卡发送到网线上。
通过网线到达它们的目的机器,在目的机器的一端执行相反的过程。
接收端机器的以太网卡捕获到这些帧,并告诉操作系统帧的到达,然后对其进行存储。
就是在这个传输和接收的过程中,每一个在LAN上的工作站都有其硬件地址。
这些地址唯一地表示着网络上的机器。
当用户发送一个报文时,这些报文就会发送到LAN上所有可用的机器。
在一般情况下,网络上所有的机器都可以"听"到通过的流量,但对不属于自己的报文则不予响应。
如果某在工作站的网络接口处于杂收模式,那么它就可以捕获网络上所有的报文和帧,如果一个工作站被配置成这样的方式,它就是一个嗅探器。
这也是嗅探器会造成安全方面的问题的原因。
通常使用嗅探器的入侵者,都必须拥有基点用来放置嗅探器。
对于外部入侵者来说,能通过入侵外网服务器、往内部工作站发送木马等获得需要,然后放置其嗅探器,而内部破坏者就能够直接获得嗅探器的放置点,比如使用附加的物理设备作为嗅探器(例如,他们可以将嗅探器接在网络的某个点上,而这个点通常用肉眼不容易发现。
除非人为地对网络中的每一段网线进行检测,没有其他容易方法能够识别出这种连接。
嗅探器可能造成的危害:
(1)嗅探器能够捕获口令.
(2)能够捕获专用的或者机密的信息.
(3)可以用来危害网络邻居的安全,或者用来获取更高级别的访问权限.
(4)分析网络结构,进行网络渗透。
1.6网络嗅探的防范
1.6.1检测嗅探器
检测嗅探器可以采用检测混杂模式网卡的工具。
由于嗅探器需要将网络中入侵的网卡设置为混杂模式才能工作,能够检测混杂模式网卡的AntiSniff是一个工具。
证明你的网络有嗅探器有两条经验:
(1)网络通讯丢包率非常高:
通过一些网管软件,可以看到信息包传送情况,最简单是ping命令。
它会告诉你掉了百分之多少的包。
如果你的网络结构正常,而又有20%-30%数据包丢失以致数据包无法顺畅的流到目的地。
就有可能有人在监听,这是由于嗅探器拦截数据包导致的。
(2)网络带宽出现反常:
通过某些带宽控制器,可以实时看到目前网络带宽的分布情况,如果某台机器长时间的占用了较大的带宽,这台机器就有可能在监听。
应该也可以察觉出网络通讯速度的变化。
1.6.2将数据隐藏,使嗅探器无法发现
嗅探器非常难以被发现,因为它们是被动的程序一个老练的攻击者可以轻易通过破坏日志文件来掩盖信息。
它们并不会给别人留下进行核查的尾巴.。
完全主动的解决方案很难找到,我们可以采用一些被动的防御措施:
(1)安全的拓扑结构。
(2)会话加密。
(3)用静态的ARP或者IP-MAC对应表代替动态的。
除了以上三点另外还要重视重点区域的安全防范。
这里说的重点区域,主要是针对嗅探器的放置位置而言。
入侵者要让嗅探器发挥较大功效,通常会把嗅探器放置在数据交汇集中区域,比如网关、交换机、路由器等附近,以便能够捕获更多的数据。
因此,对于这些区域就应该加强防范,防止在这些区域存在嗅探器。
2基于原始套接字的嗅探程序
2.1嗅探实现
下面通过c语言实现基于原始套接字的嗅探程序,代码以及代码分析如下:
#include
#include
#include#include
#include
#pragmacomment(lib,"ws2_32.lib")
#defineSIO_RCVALL_WSAIOW(IOC_VENDOR,1)
#defineMAX_PACK_LEN65535//最大包长度
#defineMAX_ADDR_LEN16//最大地址长度
#defineMAX_PROTO_TEXT_LEN16//子协议名称最大长度
#defineMAX_PROTO_NUM12//子协议数量
#defineMAX_HOSTNAME_LEN255//最大主机名长度
上面程序主要包含了工程所需的头文件和进行了相关的宏定义。
其中,SIO_RCVALL表示套接字接收所有的数据包。
//定义IP首部格式
typedefstruct_IPHeader
{
unsignedcharh_verlen;//版本和首部长度
unsignedchartos;//服务类型
unsignedshorttotal_len;//总长度
unsignedshortident;//标识号
unsignedshortfrag_and_flags;//段偏移量
unsignedcharttl;//生存时间
unsignedcharproto;//协议
unsignedshortchecksum;//首部校验和
unsignedintsourceIP;//源IP地址
unsignedintdestIP;//目的地址
}IPHEADER;
//定义TCP首部格式
typedefstruct_TCPHeader
{
unsignedshortth_sport;//源端口号
unsignedshortth_dport;//目的端口号
unsignedintth_seq;//SEQ序号
unsignedintth_ack;//ACK序号
unsignedcharth_lenres;//首部长度
unsignedcharth_flag;//控制位
unsignedshortth_win;//窗口大小
unsignedshortth_sum;//校验和
unsignedshortth_urp;//紧急指针
}TCPHEADER;
上面程序定义了IP数据包和TCP数据包的首部格式,以便进行数据包的解析。
//定义UDP首部格式
typedefstruct_UDPHeader
{
unsignedshortuh_sport;//16位源端口
unsignedshortuh_dport;//16位目的端口
unsignedshortuh_len;//16位长度
unsignedshortuh_sum;//16位校验和
}UDPHEADER;
//定义ICMP首部格式
typedefstruct_ICMPHeader
{
BYTEi_type;//8位类型
BYTEi_code;//8位代码
unsignedshorti_cksum;//16位校验和
unsignedshorti_id;//识别号
unsignedshorti_seq;//报文序列号
unsignedlongtimestamp;//时间戳
}ICMPHEADER;
上面程序定义了UDP数据包和ICMP数据包的首部格式,以便进行数据包的解析。
//定义子协议映射表
typedefstruct_protomap
{
intProtoNum;
charProtoText[MAX_PROTO_TEXT_LEN];
}PROTOMAP;
//为子协议映射表赋值
PROTOMAPProtoMap[MAX_PROTO_NUM]={
{IPPROTO_IP,"IP"},
{IPPROTO_ICMP,"ICMP"},
{IPPROTO_IGMP,"IGMP"},
{IPPROTO_GGP,"GGP"},
{IPPROTO_TCP,"TCP"},
{IPPROTO_PUP,"PUP"},
{IPPROTO_UDP,"UDP"},
{IPPROTO_IDP,"IDP"},
{IPPROTO_ND,"ND"},
{IPPROTO_RAW,"RAW"},
{IPPROTO_MAX,"MAX"},
{NULL,""}
};
上面程序定义了子协议映射表并对映射表进行了赋值。
SOCKETSockRaw;//全局套接字
charTcpFlag[6]={'F','S','R','P','A','U'};//TCP标志位
boolparamAll=false;//嗅探所有的数据包
boolparamTcp=false;//嗅探TCP数据包
boolparamUdp=false;//嗅探UDP数据包
boolparamIcmp=false;//嗅探ICMP数据包
intparamkeyword=0;//是否进行关键字查询
intpacket_totallen=0;//数据包总长度
charparamHostAddr_A[20];//嗅探的主机A
charparamHostAddr_B[20];//嗅探的主机B
charkeyword[100];//嗅探的关键信息
//IP数据包解析函数
intDecodeIpPack(char*);
//TCP数据包解析函数
intDecodeTcpPack(char*);
//UDP数据包解析函数
intDecodeUdpPack(char*);
//ICMP数据包解析函数
intDecodeIcmpPack(char*);
//显示数据包信息
voidShowPackInfo(char*buf,intiProtocol,char*szSoueceIP,char*szDestIP,char*szProtocol);
//显示子协议数据包函数
voidShowSubPackInfo(char*,int);
//错误检测函数
voidCheckSockError(int,char*);
//协议检测函数
char*CheckProtocol(int);
//设置嗅探器参数函数
boolSetSnifferParam();
上面程序主要定义了相关的全部变量和声明了相关函数。
变量SockRaw是负责接收数据包的原始套接字。
变量TcpFlag定义了TCP的标识位,以便进行TCP的数据包解析。
变量paramAll表示是否对所有类型数据包进行嗅探。
变量paramTcp表示是否对TCP数据包进行嗅探。
变量paramUdp表示是否对UDP数据包进行嗅探。
变量paramIcmp表示是否对ICMP数据包进行嗅探。
变量paramKeyword表示是否进行关键字搜索。
变量Keyword表示关键字。
变量packet_totallen表示嗅探到的每个数据包的总长度,变量aramHostAddr_A和aramHostAddr_B表示通信双方的IP地址。
//SOCK错误处理函数
voidCheckSockError(intiErrorCode,char*pErrorMsg)
{
if(iErrorCode==SOCKET_ERROR)
{
printf("%sError:
%d",pErrorMsg,GetLastError());
closesocket(SockRaw);
exit(0);
}
}
上面程序是实现SOCK错误的功能函数。
参数iErrorCode是输入的校验码;参数pErrorMsg是输入的错误信息。
程序流程是:
如果校验码表示的是错误码SOCKET_ERROR,则调用GetLastError函数将具体的错误信息输出。
//协议识别函数
char*CheckProtocol(intiProtocol)
{
for(inti=0;i{//如果找到对应的子协议,则返回名称
if(ProtoMap[i].ProtoNum==iProtocol)
{
returnProtoMap[i].ProtoText;
}
}
return"";
}
上面程序是实现根据输入的协议编号到协议映射表中查找对应的功能函数。
参数iProtocol是输入的协议编号。
程序流程是:
对映射表进行循环查找,找到对应的协议编号后,输出协议名称。
//TCP解包函数
intDecodeTcpPack(char*TcpBuf)
{
TCPHEADER*pTcpHeader;
chardata[MAX_PACK_LEN];
inti;
//转换成TCP首部格式
pTcpHeader=(TCPHEADER*)TcpBuf;
//输出源端口和目的端口
printf("Port:
%d-->%d",ntohs(pTcpHeader->th_sport),ntohs(pTcpHeader->th_dport));
unsignedcharFlagMask=1;
//输出标志位
for(i=0;i<6;i++)
{
if((pTcpHeader->th_flag)&FlagMask)
{
printf("%c",TcpFlag[i]);
}
else
{
printf("-");
}
FlagMask=FlagMask<<1;
}
printf("\n");
上面程序是实现解析TCP数据包函数的部分代码。
参数TcpBuf是输入的TCP首部和数据段的头指针。
程序流程是:
首先将TcpBuf转换成TCP首部格式。
然后输出TCP首部中的源端口号th_sport和目的端口号th_dport。
最后采用循环与位的方法输出TCP首部中的标志位。
//求数据段长度
inttotalheadlen=sizeof(IPHEADER)+sizeof(TCPHEADER);
inttcpheadlen=sizeof(TCPHEADER);
memcpy(data,TcpBuf+tcpheadlen,packet_totallen-totalheadlen);
//进行关键字寻求和输出
if(paramkeyword==1)
{
//如果找到关键字,则输出数据段
if(strstr(data,keyword))
{
printf("\n************************DATA******************************\n");
for(i=0;i{
printf("%c",data[i]);
}
printf("\n************************DATA******************************\n");