Home C/C++ C语言编程来使网卡工作在混杂模式
一 前言

SNIFF真是一个古老的话题,关于在网络上采用SNIFF来获取敏感信息已经不是什么
新鲜事,也不乏很多成功的案例,那么,SNIFF究竟是什么呢? SNIFF就是嗅探器,就是
窃听器,SNIFF静悄悄的工作在网络的底层,把你的秘密全部记录下来。看过威尔史密斯
演的《全民公敌》吗?SNIFF就象里面精巧的窃听器一样,让你防不胜防。

SNIFF可以是软件,也可以是硬件,既然是软件那就要分平台,有WINDOWS下的、UNX
I
下的等,硬件的SNIFF称为网络分析仪,反正不管硬件软件,目标只有一个,就是获取在

络上传输的各种信息。本文仅仅介绍软件的SNIFF。

当你舒适的坐在家里,惬意的享受网络给你带来的便利,收取你的EMAIL,购买你喜

的物品的时候,你是否会想到你的朋友给你的信件,你的信用卡帐号变成了一个又一个

信息包在网络上不停的传送着,你是否曾经这些信息包会通过网络流入别人的机器呢?

的担忧不是没有道理的,因为SNIFF可以让你的担忧变成实实在在的危险。就好象一个人

在你身后偷看一样。。。。。。

二 网络基础知识

“网络基础知识”,是不是听起来有点跑题了?虽然听起来这和我们要谈的SNIFF没什

关系,可是还是要说一说的,万丈高楼平地起,如果连地基都没打好,怎么盖楼?!如
果你
对网络还不是十分清楚的话,最好能静下心来好好看看,要知道,这是基础的基础,在
这里
我只是简单的说一下,免得到时候有人迷糊,详细的最好能够自己去找书看看。

(1)TCP/IP体系结构

开放系统互连(OSI)模型将网络划分为七层模型,分别用以在各层上实现不同的功
能,
这七层分别为:应用层、表示层、会话层、传输层、网络层、数据链路层及物理层。而T
CP/IP
体系也同样遵循这七层标准,只不过在某些OSI功能上进行了压缩,将表示层及会话层合
并入
应用层中,所以实际上我们打交道的TCP/IP仅仅有5层而已,网络上的分层结构决定了在
各层
上的协议分布及功能实现,从而决定了各层上网络设备的使用。实际上很多成功的系统
都是基
于OSI模型的,如:如帧中继、ATM、ISDN等。

TCP/IP的网络体系结构(部分)

———————————–
| SMTP | DNS | HTTP | FTP | TELNET| 应用层

———————————–
|    TCP    |   UDP      |  传输层

———————————–
|  IP  |   ICMP   | ARP RARP | 网络层 

————————
| IEEE 802 以太网 SLIP/PPP PDN etc| 数据链路层

———————————–
|    网卡 电缆 双绞线 etc    | 物理层

———————————–

从上面的图中我们可以看出,第一层物理层和第二层数据链路层是TCP/IP的基础,

TCP/IP本身并不十分关心低层,因为处在数据链路层的网络设备驱动程序将上层的协议

实际的物理接口隔离开来。网络设备驱动程序位于介质访问子层(MAC)。        

(2)网络上的设备                            

中继器:中继器的主要功能是终结一个网段的信号并在另一个网段再生该信号,一句话

就是简单的放大而已,工作在物理层上。      

网 桥:网桥使用MAC物理地址实现中继功能,可以用来分隔网段或连接部分异种网络,

作在数据链路层。

路由器:路由器使用网络层地址(IP,X.121,E.164等),主要负责数据包的路由寻径,也

处理物理层和数据链路层上的工作。

网 关:主要工作在网络第四层以上,主要实现收敛功能及协议转换,不过很多时候网关

被用来描述任何网络互连设备。

(3)TCP/IP与以太网

以太网和TCP/IP可以说是相互相成的,可以说两者的关系几乎是密不可分,以太网

一二层提供物理上的连线,而TCP/IP工作在上层,使用32位的IP地址,以太网则使用48

的MAC地址,两者间使用ARP和RARP协议进行相互转换。从我们上面TCP/IP的模型图中可

清楚的看到两者的关系。

载波监听/冲突检测(CSMA/CD)技术被普遍的使用在以太网中,所谓载波监听是指在

太网中的每个站点都具有同等的权利,在传输自己的数据时,首先监听信道是否空闲,

果空闲,就传输自己的数据,如果信道被占用,就等待信道空闲。而冲突检测则是为了

止发生两个站点同时监测到网络没有被使用时而产生冲突。以太网采用广播机制,所有

网络连接的工作站都可以看到网络上传递的数据。

为了加深你的理解,我们来看看下面的图,一个典型的在以太网中客户与服务器使

TCP/IP协议的通信。

用户进程 FTP客户 <————————-> FTP服务器  应用层
| |
内核中的协议栈 TCP <————————-> TCP  传输层
| |
内核中的协议栈 IP <————————-> IP  网络层
| |
以太网驱动程序 <————————-> 以太网驱动程序  数据链路层

──────——————————- 
以太网

??唆唆了这么多,有人烦了吧?相信我,这是基础的基础,可以说是说得是很简单
拉,
如果需要,拿出个几十万字来说上面的内容,我想也不嫌多,好了,让我们进入下一节

sniff的原理。

三 SNIFF的原理

要知道在以太网中,所有的通讯都是广播的,也就是说通常在同一个网段的所有网络

口都可以访问在物理媒体上传输的所有数据,而每一个网络接口都有一个唯一的硬件地
址,
这个硬件地址也就是网卡的MAC地址,大多数系统使用48比特的地址,这个地址用来表示

络中的每一个设备,一般来说每一块网卡上的MFC地址都是不同的,每个网卡厂家得到一

地址,然后用这段地址分配给其生产的每个网卡一个地址。在硬件地址和IP地址间使用A
RP
和RARP协议进行相互转换。

在正常的情况下,一个网络接口应该只响应这样的两种数据帧:

1.与自己硬件地址相匹配的数据帧。                       
                               2.发向所有机器的广播数据
帧。 

在一个实际的系统中,数据的收发是由网卡来完成的,网卡接收到传输来的数据,网

内的单片程序接收数据帧的目的MAC地址,根据计算机上的网卡驱动程序设置的接收模式

断该不该接收,认为该接收就接收后产生中断信号通知CPU,认为不该接收就丢掉不管,

以不该接收的数据网卡就截断了,计算机根本就不知道。CPU得到中断信号产生中断,操

系统就根据网卡的驱动程序设置的网卡中断程序地址调用驱动程序接收数据,驱动程序
接收
数据后放入信号堆栈让操作系统处理。而对于网卡来说一般有四种接收模式:

广播方式:该模式下的网卡能够接收网络中的广播信息。            
组播方式:设置在该模式下
的网卡能够接收组播数据。                               
            直接方式:在这种模式下,只有目的网卡才能接收该数据。
混杂模
式:在这种模式下的网卡能够接收一切通过它的数据,而不管该数据是否是传给它的。

好了,现在我们总结一下,首先,我们知道了在以太网中是基于广播方式传送数据的
,也
就是说,所有的物理信号都要经过我的机器,再次,网卡可以置于一种模式叫混杂模式
(promiscuous),在这种模式下工作的网卡能够接收到一切通过它的数据,而不管实际
上数
据的目的地址是不是他。这实际上就是我们SNIFF工作的基本原理:让网卡接收一切他所
能接
收的数据。

(图一)

我们来看一个简单的例子,如图一所示,机器A、B、C与集线器HUB相连接,集线器HUB

过路由器Router访问外部网络。这是一个很简单也很常见的情况,比如说在公司大楼里
,我
所在的网络部办公室里的几台机器通过集线器连接,而网络部、开发部、市场部也是同
样如
此,几个部门的集线器通过路由器连接。还是回到我们的图一上来,值得注意的一点是
机器
A、B、C使用一个普通的HUB连接的,不是用SWITCH,也不是用ROUTER,使用SWITCH和ROU
TER
的情况要比这复杂得多。

我们假设一下机器A上的管理员为了维护机器C,使用了一个FTP命令向机器C进行远程
登陆,
那么在这个用HUB连接的网络里数据走向过程是这样的。首先机器A上的管理员输入的登
陆机
器C的FTP口令经过应用层FTP协议、传输层TCP协议、网络层IP协议、数据链路层上的以
太网
驱动程序一层一层的包裹,最后送到了物理层,我们的网线上。接下来数据帧送到了HUB
上,
现在由HUB向每一个接点广播由机器A发出的数据帧,机器B接收到由HUB广播发出的数据
帧,
并检查在数据帧中的地址是否和自己的地址相匹配,发现不是发向自己的后把这数据帧
丢弃,
不予理睬。而机器C也接收到了数据帧,并在比较之后发现是发现自己的,接下来他就对
这数
据帧进行分析处理。

在上面这个简单的例子中,机器B上的管理员如果很好奇,他很想知道究竟登陆机器C
上FTP
口令是什么?那么他要做的很简单,仅仅需要把自己机器上的网卡置于混杂模式,并对
接收到
的数据帧进行分析,从而找到包含在数据帧中的口令信息。

四 做一个自己的sniff

在上一节里,我们已经知道了SNIFF的基本原理是怎么一回事,这一节我们来亲自动手
做一个
自己的sniff,毕竟,用程序代码来说话比什么都要来得真实,也容易加深理解。

回头想一想我们上面说的原理,我们要做的事情有几件:

1. 把网卡置于混杂模式。                            
2. 捕获数据包。    

3. 分析数据包。

注:下面的源代码取至Chad Renfro的<< Basic Packet-Sniffer Construction from
the Ground Up>>
一文中
/************************Tcp_sniff_2.c********************/
1.#i nclude  
2.#i nclude  
3.#i nclude
4.#i nclude
5.#i nclude
6.#i nclude
7.#i nclude  
8.#i nclude
9.#i nclude “headers.h”

#define INTERFACE “eth0”

/*Prototype area*/

10.int Open_Raw_Socket(void); 
11.int Set_Promisc(char *interface, int sock); 
12.int main() {  
13.int sock, bytes_recieved, fromlen;  
14.char buffer[65535];
15.struct sockaddr_in from; 
16.struct ip *ip;
17.struct tcp *tcp;  
18.sock = Open_Raw_Socket();
19. Set_Promisc(INTERFACE, sock);

20. while(1)
22. {
23. fromlen = sizeof from;
24. bytes_recieved = recvfrom(sock, buffer, sizeof buffer, 0, (struct
sockaddr *)&from, &fromlen);
25. printf(“\nBytes received ::: %5d\n”,bytes_recieved);
26. printf(“Source address ::: %s\n”,inet_ntoa(from.sin_addr));
27. ip = (struct ip *)buffer;
/*See if this is a TCP packet*/
28. if(ip->ip_protocol == 6) {
29. printf(“IP header length ::: %d\n”,ip->ip_length);
30. printf(“Protocol ::: %d\n”,ip->ip_protocol);
31. tcp = (struct tcp *)(buffer + (4*ip->ip_length));
32. printf(“Source port ::: %d\n”,ntohs(tcp->tcp_source_port));
33. printf(“Dest port ::: %d\n”,ntohs(tcp->tcp_dest_port));
34. }

35. }
36.}
37.int Open_Raw_Socket() {    
38. int sock;
39. if((sock = socket(AF_INET, SOCK_RAW, IPPROTO_TCP)) < 0) {
/*Then the socket was not created properly and must die*/
40. perror(“The raw socket was not created”);
41. exit(0);
42. };  
43. return(sock);  
44. }

45.int Set_Promisc(char *interface, int sock ) {  
46. struct ifreq ifr;      
47. strncpy(ifr.ifr_name, interface,strnlen(interface)+1);
48. if((ioctl(sock, SIOCGIFFLAGS, &ifr) == -1)) {  
/*Could not retrieve flags for the interface*/
49. perror(“Could not retrive flags for the interface”);
50. exit(0);
51. } 
52. printf(“The interface is ::: %s\n”, interface);  
53. perror(“Retrieved flags from interface successfully”);
54. ifr.ifr_flags |= IFF_PROMISC;  
55. if (ioctl (sock, SIOCSIFFLAGS, &ifr) == -1 ) {  
/*Could not set the flags on the interface */  
56. perror(“Could not set the PROMISC flag:”);
57. exit(0);    
58. }
59. printf(“Setting interface ::: %s ::: to promisc”, interface);
60. return(0);
61. }

/***********************EOF**********************************/

上面这段程序中有很详细的注解,不过我想还是有必要说一说,首先
第10行–int Open_Raw_Socket(void); 是我们的自定义函数,具体内容如下:

37.int Open_Raw_Socket() {    
38. int sock;
39. if((sock = socket(AF_INET, SOCK_RAW, IPPROTO_TCP)) < 0) {
/*Then the socket was not created properly and must die*/
40. perror(“The raw socket was not created”);
41. exit(0);
42. };  
43. return(sock);  
44. }

第39行 if((sock = socket(AF_INET, SOCK_RAW, IPPROTO_TCP)) < 0) {

这里我们调用了socket函数,使创建了了一个原始套接口,使之收到TCP/IP信息包。

接下来第11行-int Set_Promisc(char *interface, int sock),这也是我们的自定
义函数,
目的是把网卡置于混杂模式,具体内容如下:
45.int Set_Promisc(char *interface, int sock ) {  
46. struct ifreq ifr;      
47. strncpy(ifr.ifr_name, interface,strnlen(interface)+1);
48. if((ioctl(sock, SIOCGIFFLAGS, &ifr) == -1)) {  
/*Could not retrieve flags for the interface*/
49. perror(“Could not retrive flags for the interface”);
50. exit(0);
51. } 
52. printf(“The interface is ::: %s\n”, interface);  
53. perror(“Retrieved flags from interface successfully”);
54. ifr.ifr_flags |= IFF_PROMISC;  
55. if (ioctl (sock, SIOCSIFFLAGS, &ifr) == -1 ) {  
/*Could not set the flags on the interface */  
56. perror(“Could not set the PROMISC flag:”);
57. exit(0);    
58. }
59. printf(“Setting interface ::: %s ::: to promisc”, interface);
60. return(0);
61. }

首先 struct ifreq ifr; 定一了一个ifrreg的结构ifr,接下来
strncpy(ifr.ifr_name, interface,strnlen(interface)+1);,就是把我们网络设备的
名字填
充到ifr结构中,在这里 #define INTERFACE “eth0” ,让我们再往下看,
ioctl(sock, SIOCGIFFLAGS, &ifr),SIOCGIFFLAGS请求表示需要获取接口标志,现在到

第54行,在我们成功的获取接口标志后把他设置成混杂模式,
ifr.ifr_flags |= IFF_PROMISC;ioctl (sock, SIOCSIFFLAGS, &ifr)。OK,现在我们所
说的
第一步已经完成——–把网卡置于混杂模式。

现在进入第二步,捕获数据包。从第20行开始,我们进入了一个死循环,while(1)
,在
第24行,recvfrom(sock, buffer, sizeof buffer, 0, (struct sockaddr *)&from,
&fromlen),
这个函数要做的就是接收数据,冰把接收到的数据放入buffer中。就是这么简单,已经
完成了我
们要捕获数据包的任务。

到了第三步,分析数据包。27行,ip = (struct ip *)buffer,使我们在头文件中
的IP结
构对应于所接收到的数据,接下来判断在网络层中是否使用的是TCP协议,
if(ip->ip_protocol == 6) ,如果答案是,tcp信息包从整个IP/TCP包 buffer +
(4*ip->ip_length)
地址处开始,所以31行 tcp = (struct tcp *)(buffer + (4*ip->ip_length)),然后对

结构把你所需要的信息输出。
/*************************headers.h**************************/
/*structure of an ip header*/ 
struct ip {   
unsigned int ip_length:4; /*little-endian*/ 
unsigned int ip_version:4;
unsigned char ip_tos; 
unsigned short ip_total_length;  
unsigned short ip_id;  
unsigned short ip_flags;
unsigned char ip_ttl;
unsigned char ip_protocol;
unsigned short ip_cksum;
unsigned int ip_source; unsigned int ip_dest;  
};

/* Structure of a TCP header */
struct tcp {
unsigned short tcp_source_port;
unsigned short tcp_dest_port;
unsigned int tcp_seqno;  
unsigned int tcp_ackno;
unsigned int tcp_res1:4, /*little-endian*/
tcp_hlen:4,
tcp_fin:1,
tcp_syn:1,
tcp_rst:1,
tcp_psh:1,
tcp_ack:1,
tcp_urg:1,
tcp_res2:2;
unsigned short tcp_winsize;
unsigned short tcp_cksum;
unsigned short tcp_urgent;
};
/*********************EOF***********************************/

从上面的分析我们可以清楚的认识到,认识一个SNIFF需要对TCP/IP协议有着详细的了
解,
否则你根本无法找到你需要的信息。有了上面的基础,你可以自己来做一个你需要的SNI
FF了。

五 常用的SNIFF

很少有原因会让你自己亲自动手来做一个自己的SNIFF,除非你是想了解他的原理,或
者是
其他一些特别的原因,比如你要在某个特殊的环境拦截一些特殊的数据包。下面我们就
来看
看一些在网络上经常使用的SNIFF。

(1)windows环境下

windows环境下当然是大名鼎鼎的netxray以及sniffer pro了,实际上很多人都是用
他在
windows环境下抓包来分析,不过我想很少有人笨到去在别人的机器上安装一个图形界面
的SNIFF,
除非他和管理员很熟悉…….. netxray的使用就不多说了,反正windows下的东西就是

click,click,click,非常的方便用户。

(2)UNUX环境下

UNUX环境下的sniff可以说是百花齐放,一抓就是一大把,如sniffit,snoop,tcpdump
,dsniff
等都是比较常见的,他们都有一个好处就是发布源代码,可以让你研究,当然也都是免
费的:)

1. sniffit

sniffit可以运行在Solaris、SGI和Linux等平台上,由Lawrence Berkeley
Laboratory 实验
室开发的一个免费的网络监听软件。最近Sniffit 0.3.7也推出了NT版本,并也支持WIND
OWS2000.

使用方法:
-v 显示版本信息
-a 以ASCII形式将监听的结果输出。
-A 在进行记录时,所有不可打印的字符都用代替
-b 等同于同时使用参数-t & -s。    
-d 将监听所得内容以十六进制方式显示在当前终端 
-p 记录连接到的包,0为所有端口。缺省为0。   
-P protocol 选择要检查的协议,缺省为TCP。可能的选择有IP、TCP、ICMP、UDP和他们
的组合。
-s 指定sniffer 检查从 发送的数据包。 -t 指定sniffer 检查发送到的数据包。
-i 进入交互模式   
-l 设定数据包大小,default是300字节   
注:参数可以用@来表示一个IP范围,比如 -t 192.168.@ -t和-s 只适用于TCP/UDP数据
包,对
于ICMP和IP也进行解释。但如果只选择了-p参数,则只用于TCP和UDP包。

举例说明:

#sniffit -a -p 21 -t xxx.xxx.xxx.xxx

监听流向机器xxx.xxx.xxx.xxx的21端口(FTP)的信息,并以ASCII显示

#sniffit -d -p 23 -b xxx.xxx.xxx.xxx

监听所有流出或流入机器xxx.xxx.xxx.xxx的23端口(telnet)的信息,并以16进制显示

你可以在这里找到sniffit http://reptile.rug.ac.be/~coder/sniffit/sniffit.html

2. snoop

snoop默认情况安装在Solaris下,是一个用于显示网络交通的程序,不过SNIFF是把
双刃剑,
既然管理员能用他来监视自己的网络,当然一个心怀恶意的入侵者也可以用他来SNIFF自
己感兴
趣的内容。值得一提的是, SNOOP被发现存在一个缓冲区溢出漏洞,当以导致入侵者以
运行
snoop(通常为root)的身份远程进入系统。这是题外话,暂且就此打住。

使用方法:
[ -a ] # Listen to packets on audio
[ -d device ] # settable to le?, ie?, bf?, tr?
[ -s snaplen ] # Truncate packets
[ -c count ] # Quit after count packets
[ -P ] # Turn OFF promiscuous mode
[ -D ] # Report dropped packets
[ -S ] # Report packet size
[ -i file ] # Read previously captured packets
[ -o file ] # Capture packets in file
[ -n file ] # Load addr-to-name table from file
[ -N ] # Create addr-to-name table
[ -t r|a|d ] # Time: Relative, Absolute or Delta
[ -v ] # Verbose packet display
[ -V ] # Show all summary lines
[ -p first[,last] ] # Select packet(s) to display
[ -x offset[,length] ] # Hex dump from offset for length
[ -C ] # Print packet filter code

例如:

#snoop -o saved A B

监听机器A与B的谈话,并把内容存储于文件saved中

3. tcpdump

tcpdmp也算是一个很有名气的网络监听软件,FREEBSD还把他附带在了系统上,是一
个被
很多UNIX高手认为是一个专业的网络管理工具。

使用方法:
tcpdump采用命令行方式,它的命令格式为:
tcpdump [ -adeflnNOpqStvx ][ -c 数量 ][ -F 文件名 ][ -i 网络接口 ][ -r 文件名
]
[ -s snaplen ][ -T 类型 ][ -w 文件名 ][表达式 ]
1. tcpdump的选项介绍
-a    将网络地址和广播地址转变成名字;
-d    将匹配信息包的代码以人们能够理解的汇编格式给出;
-dd    将匹配信息包的代码以c语言程序段的格式给出;
-ddd   将匹配信息包的代码以十进制的形式给出;
-e    在输出行打印出数据链路层的头部信息;
-f    将外部的Internet地址以数字的形式打印出来;
-l    使标准输出变为缓冲行形式;
-n    不把网络地址转换成名字;
-t    在输出的每一行不打印时间戳;
-v    输出一个稍微详细的信息,例如在ip包中可以包括ttl和服务类型的信息;
-vv    输出详细的报文信息;
-c    在收到指定的包的数目后,tcpdump就会停止;
-F    从指定的文件中读取表达式,忽略其它的表达式;
-i    指定监听的网络接口;
-r    从指定的文件中读取包(这些包一般通过-w选项产生);
-w    直接将包写入文件中,并不分析和打印出来;
-T    将监听到的包直接解释为指定的类型的报文,常见的类型有rpc和snmp

2. tcpdump的表达式介绍

表达式是一个正则表达式,tcpdump利用它作为过滤报文的条件,如果一个报文满足表
达式
的条件,则这个报文将会被捕获。如果没有给出任何条件,则网络上所有的信息包将会
被截获。

在表达式中一般如下几种类型的关键字,一种是关于类型的关键字,主要包括host,n
et,
port, 例如 host 210.27.48.2,指明 210.27.48.2是一台主机,net 202.0.0.0 指明
202.0.0.0
是一个网络地址,port 23 指明端口号是23。如果没有指定类型,缺省的类型是host.

第二种是确定传输方向的关键字,主要包括src , dst ,dst or src, dst and src
,这些关
键字指明了 传输的方向。举例说明,src 210.27.48.2 ,指明ip包中源地址是210.27.48
.2 ,
dst net 202.0.0.0 指明目的网络地址是202.0.0.0 。如果没有指明方向关键字,则缺
省是
src or dst关键字。    

第三种是协议的关键字,主要包括fddi,ip ,arp,rarp,tcp,udp等类型。Fddi指明是

FDDI(分布式光纤数据接口网络)上的特定的网络协议,实际上它是”ether”的别名,fddi
和ether
具有类似的源地址和目的地址,所以可以将fddi协议包当作ether的包进行处理和分析。
其他的
几个关键字就是指明了监听的包的协议内容。如果没有指定任何协议,则tcpdump将会监
听所有
协议的信息包。   

除了这三种类型的关键字之外,其他重要的关键字如下:
gateway, broadcast,less,greater,还有三种 逻辑运算,取非运算是 ‘not ‘ ‘! ‘, 与
运算
是’and’,’&&’;或运算 是’or’ ,’||’。

举例使用:

#tcpdump host AAA.BBB.CCC.DDD

将监听IP地址为AAA.BBB.CCC.DDD的机器的通话

#tcpdump tcp port 23 host AAA.BBB.CCC.DDD

将监听IP地址为AAA.BBB.CCC.DDD的机器的23端口的通话

4. dsniff

之所以要谈谈dsniff,是因为他不仅仅是一个sniff,在他的整个套件包中,包含了很

其它有用的工具,如arpspoof,dnsspoof,macof,tcpkill等等,SNIFF的手段更加的多
样和
复杂化。dsniff是由DugSong开发的你可以在他的主页上找到这个工具。 目前dsniff支

OpenBSD (i386), Redhat Linux (i386), 和Solaris (sparc). 并且在FreeBSD,
Debian Linux,
Slackware Linux, AIX, 和HP-UX上也能运转得很好。但是dsniff需要几个其他的第三方
软件进
行支持,他们分别是,Berkeley DB ,OpenSSL, libpcap, libnet, libnids。如果
条件允
许的话,你最好能够亲自读一读dsniff的源代码,你可以在
http://naughty.monkey.org/~dugsong/找到dsniff。

六 深入sniff

单纯的sniff的功能始终是局限的,所以在大多数的情况下,sniff往往和其他手段结
合起来使
用,sniff和spoof已及其他技术手段结合在一起对网络构成的危害是巨大的。单纯的sni
ff好比缺
了一只腿,无法发挥大的作用,例如在sniff原理一节中我们讨论的例子里,我一再的强
调我们使
用的是一个普通的HUB进行连接是有原因的,如果我们把在图一中的HUB用一个switch代
替,那情况
就要复杂一些了,如图二所示:

图(二)

在图二中,我们的机器A、B、C与Switch相连接,而Switch通过路由器Router访问外部
网络。我
们先来了解Switch的工作原理:

在我们图一中的 HUB 只是简单地把所接收到的信号通过所有端口(除了信号来的那
个口)重复
发送出去不同,而图二中的Switch却可以检查每一个收到的数据包,并对数据包进行相
应的处理。
在Switch内保存着每一个网段上所有节点的物理地址,只允许必要的网络流量通过Switc
h。举例来
说,当Switch接收到一个数据包之后,根据自身保存的网络地址表检查数据包内包含的
发送和接收
方地址。如果接收方位于发送方网段,该数据包就会被Switch丢弃,不能通过交换机传
送到其它的
网段;如果接收方和发送方位于两个不同的网段,该数据包就会被Switch转发到目标网
段。这样,
通过交换机的过滤和转发,可以有效避免网络广播风暴,减少误包和错包的出现。顺便
说一句,现在
Switch和HUB的价格相去无几,所以hub正逐渐被网络交换机取代。

现在回到我们的例子中来,在图二中仍然和图一一样,我们假设机器A上的管理员为了
维护机器C,
使用了一个FTP命令向机器C进行远程登陆,那么在这里,数据是这样走的:首先机器A上
的管理员输入
的登陆机器C的FTP口令经过应用层FTP协议、传输层TCP协议、网络层IP协议、数据链路
层上的以太网
驱动程序一层一层的包裹,最后送到了物理层,我们的网线上。接下来数据帧送到了Swi
tch上,而
Switch检查数据帧中的目的地址,并在他自身保存的网络地址表中知道了他应该把这数
据帧发到机器
C那里,于是,接下来机器C接收到了从A发来的信息,发现他是发给自己的信息,于是进
行分析处理。

OK,现在我们机器B上的管理员的好奇心只能深深的埋藏在心里了,因为数据包根本
就没有经过他,
就算他把自己的网卡设置成混杂模式也是有力无处使。

在了解在一个Switch环境下原理后,我们结合一些手段去设法sniff,是的,我们可以
做到这一点,
有许多的手段可以让管理员B满足他的好奇心,在下面我会提出几个办法,当然只是其中
的一些办法
而已。

1 ARP Spoof

在基于IP通信的内部网中,我们可以使用 ARP Spoof 的手段,了解什么是ARP
Spoof的前提你先
要明白一下什么是ARP和RARP协议,什么是MAC地址,什么又是IP地址。ARP协议是地址转
换协议,
RARP被称为反向地址转换协议,他们负责把IP地址和MAC地址进行相互转换对应。

ARP Spoof 攻击的根本原理是因为计算机中维护着一个 ARP 高速缓存,并且这个ARP
高速缓存是
随着计算机不断的发出ARP请求和收到ARP响应而不断的更新的,ARP 高速缓存的目的是
把机器的IP地
址和MAC地址相互映射。你可以使用 arp 命令来查看你自己的 ARP 高速缓存。现在设想
一下,一个
Switch工作在数据链路层,他根据MAC地址来转发他所接收的数据包,而计算器维护的
ARP 高速缓存
却是动态的……你想到什么了吗?

为了加深理解,现在给我们的机器编上号,机器A:IP地址为 10.0.0.1 ,MAC地址为
20-53-52-43-00-01 ,机器B:IP地址为 10.0.0.2 ,MAC地址为 20-53-52-43-00-02,机器
C:IP地址
为 10.0.0.3 ,MAC地址为 20-53-52-43-00-03 。现在机器B上的管理员是个聪明的家伙
,他向机器
A发出一个 ARP Reply (协议没有规定一定要等ARP Request出现才 能发送ARP Reply,
也没有
规定一定要发送过ARP Request才能接收ARP Reply),其中的目的IP地址为10.0.0.1,
目的MAC
地址为 20-53-52-43-00-01 ,而源IP地址为10.0.0.3,源MAC地址为
20-53-52-43-00-02 ,好了,
现在机器A更新了他的 ARP 高速缓存,并相信了IP地址为10.0.0.3的机器的MAC地址是
20-53-52-43-00-02 。当机器A上的管理员发出一条FTP命令时—ftp 10.0.0.3,数据包
被送到了
Switch,Switch查看数据包中的目的地址,发现MAC为 20-53-52-43-00-02 ,于是,他
把数据包
发到了机器B上。再设想一下,如果不想影响A和C之间的通信该怎么办?你可以同时欺骗
他们双方,
来一个 man-in-middle 。

当然,在实际的操作中你还需要考虑到一些其他的事,比如某些操作系统在会主动的
发送ARP请
求包来更新相应的ARP入口等。

2. MAC Flooding

在上面我们曾经提到过,Switch之所以能够由数据包中目的MAC地址判断出他应该把数
据包发送到
那一个端口上是根据他本身维护的一张地址表。这张地址表可能是动态的也可能是静态
的,这要看
Switch的厂商和Switch的型号来定,对于某些Switch来说,他维护的是一张动态的地址
表,并且地
址表的大小是有上限的,比如 3com Superstack Switch 3300 (3c16981 Hardware
v.1 Software v.2.10)
就是这样一种Switch,我们可以通过发送大量错误的地址信息而使SWITCH维护的地址
表“溢出”,
从而使他变成广播模式来达到我们要 sniff 机器A与机器C之间的通信的目的。

3. Fake the MAC address

伪造MAC地址也是一个常用的办法,不过这要基于你网络内的Switch是动态更新其地址
表,这实
际上和我们上面说到的 ARP Spoof 有些类似,只不过现在你是想要Switch相信你,而不
是要机器A
相信你。因为Switch是动态更新其地址表的,你要做的事情就是告诉Switch:HI,我是机
器C。换成
技术上的问题你只不过需要向Switch发送伪造过的数据包,其中源MAC地址对应的是机器
C的MAC地址,
现在Switch就把机器C和你的端口对应起来了。不过其中存在一个问题,现在机器C也会
说了:
HI,Switch老大,我才是机器C呢!,现在你该怎么办?切,还用问!让他说不了话就可
以了,
DOS还是其他什么,随便你了……

4. ICMP Router Advertisements

这主要是由ICMP路由器发现协议(IRDP)的缺陷引起的,在Windows 95、98、2000及Su
nOS、
Solaris 2.6等系统中,都使用了IRDP协议,SunOS系统只在某些特定的情况下使用该协
议,而
Windows95 ,Windows95b, Windows98, Windows98se, 和 Windows2000都是默认的使用IR
DP协议。
IRDP协议的主要内容就是告诉人们谁是路由器,设想一下,一个HACK利用IRDP宣称自己
是路由器的
情况会有多么的糟糕!所有相信HACK的请求的机器把他们所有的数据都发送给HACK所控
制的机器………

5. ICMP Redirect

所谓ICMP重定向,就是指告诉机器向另一个不同的路由发送他的数据包,ICMP重定向
通常使
用在这样的场合下,假设A与B两台机器分别位于同一个物理网段内的两个逻辑子网内,
而A和B都
不知道这一点,只有路由器知道,当A发送给B的数据到达路由器的时候,路由器会向A送
一个ICMP
重定向包裹,告诉A:HI,别再送数据给我转交了,你就直接送到B那里就可以了。设想
一下,
一个hack完全可以利用这一点,使得A发送给B的数据经过他。

上面提到的这些方法只不是其中的一些,为了配合sniff能够工作得更有效率,还有其
他许多
的办法,其实sniff的目的说穿了只有一个,就是抓包,从抓包这个概念上引伸下去,所
有为了能
够抓到网络上的信息包而采用的技术都可以归入sniff,单纯的sniff是没有什么效率的
。你还能
想到什么吗?进攻路由器,在路由器上放置sniff……,在系统内核中植入sniff…..
.等等。

七 如何防止SNIFF

防止sniff最有效的手段就是进行合理的网络分段,并在网络中使用交换机和网桥,在
理想的情
况下使每一台机器都拥有自己的网络段,当然这会使你的网络建设费用增加很多,所以
你可以尽量
使相互信任的机器属于同一个网段,使他们互相之间不必担心sniff的存在。并在网段于
网段间进
行硬件屏障。你也可以使用加密技术对你在网络中传送的敏感数据如户ID或口令,你的
银行帐号,
商业机密等进行加密,你可以选用SSH等加密手段。为了防止ARP欺骗,你可以使用永
久的ARP
缓存条目,反正上面的攻击手段和原理你也看了,你就反过来想想该怎么办好了。不过
有盾必有矛,
平时的安全意识才是最重要的。

(注:以下关于AntiSniff的介绍取至backend翻译整理的L0pht AntiSniff 技术文档
一文)

当你做做层层保护后,你还是怀疑自己的网络上存在sniff该怎么办? L0pht 小组为
了探测
sniff专门发布了一个软件 AntiSniff,当然这个软件不是免费的:),AntiSniff 工具
用于检测局
域网中是否有机器处于混杂模式,AntiSniff Version 1.x被设计为运行在以太网的Wind
ows系统中,
提供了简单易用的图形用户界面,AntiSniff Version 1.x 主要工作在非交换环境下的
本地网段中,
如果运行在交换环境下其功能将大打折扣。AntiSniff Ver 2.0 将不但能在本地网段中
,而且能够穿
过路由器和交换机进行工作。

◆ 操作系统类特殊测试

Linux 内核测试

旧版本的Linux内核存在一个奇怪的特性,可被用于确定机器是否处于混杂模式。在正
常情形下,
网卡会过滤和丢弃那些目标地址不是本机MAC地址或以太网广播地址的数据包。如果数据
包的目标地
址为本机以太网地址或广播地址,将传送给内核进行处理,因为其认为该以太网数据帧
包含了本机
的正确IP地址或该网络广播地址。如果网卡处于混杂模式,则每个数据包都会传递给操
作系统进行
分析或处理。许多版本的 Linux内核只检查数据包中的IP地址以确定是否存放到IP堆栈
中进行处理。
为了利用这一点,AntiSniff构造一个无效以太网地址而IP地址有效的数据包。对于使用
了这些内核
版本和处于混杂模式的Linux系统,由于只检查到IP地址有效而将其接收并存放到相应堆
栈中。通过
在这个伪造的以太网数据帧中构造一个ICMP ECHO请求,这些系统会返回响应包(如果处
于混杂模式)
或忽略(如果不处于混杂模式),从而暴露其工作模式。当伪造的以太网数据帧中的IP地
址设置为网络
广播地址时这个测试非常有效。 AntiSniff的使用者可以修改伪造的以太网址,缺省值
为66:66:66:66:66:66。

NetBSD

许多NetBSD内核具有与上述Linux内核相同的特性,不过伪造以太网数据帧中的 IP地
址必须设为广
播地址。

Windows 95/98/NT

根据对网络驱动程序头文件的了解,可以知道当处于混杂模式时,Microsoft的操作系
统会确切地检
查每个包的以太网地址。如果与网卡的以太网地址匹配,将作为目标IP地址为本机的数
据包存放到相应
堆栈中处理。可以被利用的一点是系统对以太网广播包的分析。在正常情形下,例如机
器工作在非混
杂模式下,网卡只向系统内核传输那些目标以太网址与其匹配或为以太网广播地址(ff:f
f:ff:ff:ff:ff)
的数据包。如果机器处于混杂模式下,网络驱动程序仍然会检查每个数据包的以太网地
址,但检查是否
为广播包时却只检查头8位地址是否为0xff。因此,为了使处于混杂模式的系统返回响应
信息,
AntiSniff构造以太网地址为ff:00:00:00:00:00且含有正确目标IP 地址的数据包,当Mi
crosoft的操
作系统接收到这个数据包时,将根据网络驱动程序检查到的细微差别而返回响应包(如果
处于混杂模式)
或丢弃这个数据包(如果处于非混杂模式)。

需要注意的是,这个检查与使用的网络驱动程序有关。Microsoft缺省的网络驱动程序
具有以上特性,
大多数的厂商为了保持兼容性也继承了这些特性。不过有些网卡会在其硬件层中检查以
太网地址的头8位,
所以可能会无论系统真正的状态是什么都总是返回正值。关于这类网卡和驱动程序请访

AntiSniff Ver 1.x的web网站。

◆ DNS 测试

进行DNS测试的原因是许多攻击者使用的网络数据收集工具都对IP地址进行反向 DNS解
析,因为他们
希望根据域名寻找更有价值的主机。例如joepc1.foo.bar对攻击者的吸引力往往不如pay
roll.foo.bar
这种商业域名。此时这些工具就由被动型网络工具变为主动型网络工具了。而不监听网
络通讯的机器
不会试图反向解析数据包中的 IP地址。为了利用这一点,AntiSniff Ver 1.x使自身处
于混杂模式下,
向网络发送虚假目标IP地址的数据包,然后监听是否有机器发送该虚假目标IP地址的反
向DNS查询。
伪造数据包的以太网地址、检查目标、虚假目标IP地址可由用户定制。

◆ 网络和主机响应时间测试

这种测试已被证明是最有效的。它能够发现网络中处于混杂模式的机器,而不管其操
作系统是什么。
警告,这个测试会在很短的时间内产生巨大的网络通讯流量。进行这种测试的理由是不
处于混杂模式
的网卡提供了一定的硬件底层过滤机制。也就是说,目标地址非本地(广播地址除外)的
数据包将被网卡
的固件丢弃。在这种情况下,骤然增加、但目标地址不是本地的网络通讯流量对操作系
统的影响只会
很小。而处于混杂模式下的机器则缺乏此类底层的过滤,骤然增加、但目标地址不是本
地的网络通讯
流量会对该机器造成较明显的影响(不同的操作系统/内核/用户方式会有不同)。这些变
化可以通过网
络通讯流量工具监视到。

根据以上要点,AntiSniff Ver 1.x 首先利用ICMP ECHO请求及响应计算出需要检测
机器的响应时间
基准和平均值。在得到这个数据后,立刻向本地网络发送大量的伪造数据包。与此同时
再次发送测试
数据包以确定平均响应时间的变化值。非混杂模式的机器的响应时间变化量会很小,而
混杂模式的机
器的响应时间变化量则通常会有 1-4个数量级。为了对付攻击者和入侵者们最常用的多
种工具,
AntiSniff进行了三种网络饱和度测试:SIXTYSIX、TCPSYN和THREEWAY。

* SIXTYSIX测试构造的数据包数据全为0x66。这些数据包不会被非混杂模式的
机器接收,同时
方便使用常见的网络监听/分析工具(如tcpdump和snoop等)记录和捕获。

* TCPSYN测试构造的数据包包含有效的TCP头和IP头,同时TCP标志域的SYN位被
设置。

* THREEWAY测试采取的原理基本上与TCPSYN一样,但更复杂些。在这种测试中两
个实际不存在
的机器间多次建立完整的TCP三方握手通讯。它能够更好地欺骗那些骇客工具。

AntiSniff Ver 1.x 中能够通过以上三种数据包测试发现正处于混杂模式机器的测试
方法最好周
期性地进行和与以前的数据比较。响应时间测试第一次运行的数据还能够用于分析一个
大型网络在
flooding和非flooding状态时的性能,并帮助工程师调整网络性能。一旦确信本地网络
已运行在正
常(没有未经允许而处于混杂模式的机器) 状态,就应该设置AntiSniff工具周期性运行
。只要发现
某台机器性能(响应时间)发生数量级的变化,一般就能确定其正处于混杂模式。这种方
法不需比较
两台独立系统间的性能数据,而只需比较同一台机器不同时候的数据就能确定该机器是
否处于混杂模式。

打赏
0 comment

You may also like

Leave a Comment

*

code

error: Alert: Content is protected !!