交换型网络环境嗅探原理及LINUX下的实现

来源:互联网 发布:貂皮能在淘宝上买吗 编辑:程序博客网 时间:2024/04/27 16:02

施聪 (javer@163.com), 程序员

2002 年 12 月 09 日

传统的嗅探器在共享型以太网中可以捕获到所有数据包,但在交换型以太网中却无法工作。本文介绍利用 ARP 欺骗模式,改变其它主机 arp 高速缓存中的记录,使所有数据包都到达本机且由本机转发,从而达到捕获数据包的效果。

1.以太网嗅探原理

以太网环境下的嗅探本身是比较简单的,只要网卡能设置成混杂模式且有数据包到达网卡,则可用多种方法捕获数据包并进行各种协议分析。在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欺骗模式。





回页首

2.相关协议数据包格式

  • 以太数据包格式: 目的MAC地址源MAC地址类型数据66246~1500
    类型0800 :IP数据包
    类型0806 :ARP数据包
  • ARP数据包格式: 目的端 MAC 地址源MAC地址0806硬件类型协议类型硬件地址长度协议地址长度ARP包类型发送端MAC地址发送端IP地址目的端MAC地址目的端IP地址662221126464<------以太网首部--------><------26字节ARP请求/应答-------->
  • ARP数据包简化格式
    为了论述的简洁性,我们把ARP数据包格式做一些简化。 目的端MAC地址源MAC地址ARP包类型发送端MAC地址发送端IP地址目的端MAC地址目的端IP地址




回页首

3.实验环境

为了更清楚的描述交换网络的嗅探原理,我们建立一个虚构的交换网络环境, 在下面的论述中将用到这些数据.

主机编号IP地址MAC地址备注A1.1.1.101:01:01 B2.2.2.202:02:02 C3.3.3.303:03:03 D4.4.4.404:04:04(我)运行嗅探器



回页首

4.ARP协议原理

在以太网中传输的数据包是以太包,而以太包的寻址是依据其首部的物理地址(MAC地址)。仅仅知道某主机的逻辑地址(IP地址)并不能让内核发送一帧数据给此主机,内核必须知道目的主机的物理地址才能发送数据。ARP协议的作用就是在于把逻辑地址变换成物理地址,也既是把32bit的IP地址变换成48bit的以太地址。

每一个主机都有一个ARP高速缓存,此缓存中记录了最近一段时间内其它IP地址与其MAC地址的对应关系。如果本机想与某台主机通信,则首先在ARP高速缓存中查找此台主机的IP和MAC信息,如果存在,则直接利用此MAC地址构造以太包;如果不存在,则向本网络上每一个主机广播一个ARP请求包,其意义是"如果你有此IP地址,请告诉我你的MAC地址",目的主机收到此请求包后,发送一个ARP响应包,本机收到此响应包后,把相关信息记录在ARP高速缓存中,以下的步骤同上。

可以看出,ARP协议是有缺点的,第三方主机可以构造一个ARP欺骗包,而源主机却无法分辨真假。





回页首

5.ARP欺骗原理

假设B(2.2.2.2)要与A(1.1.1.1)通信,且B的ARP高速缓存中没有关于A的MAC信息,则B发出ARP请求包。

FF:FF:FF02:02:02请求02:02:022.2.2.2FF:FF:FF1.1.1.1广播B的MAC B的MACB的IP目的地址A的IP

正常情况下A向B发出ARP应答包:

02:02:0201:01:01应答01:01:011.1.1.102:02:022.2.2.2B的MACA的MAC A的MACA的IPB的MACB的IP

我捕获到B的ARP请求包后,构造ARP欺骗包(欺骗B对A的连接)

02:02:0204:04:04应答04:04:041.1.1.102:02:022.2.2.2B的MAC我的MAC 我的MACA的IPB的MACB的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),则本局域网中所有数据包我都能捕获到!





回页首

6.程序设计思路

  • 使用到的函数包
    libpcap : 捕获ARP数据包。
    libnet : 获得本机的MAC地址和IP地址;构造和发送ARP欺骗包。
    这两个的函数包的使用在网上资料很多,本文中不介绍。
  • 主要数据结构
    程序中有两个全局变量,MYIP代表本机的IP地址,MYMAC代表本机的MAC地址。
    程序中维护一个存放主机信息的链表:
    typedef struct host HOST;
    struct host
    {
    unsigned long ip; // IP地址
    unsigned char mac[6]; // MAC地址
    int mac_flag; // 0:MAC为空,1:MAC不为空
    HOST * next;
    };

  • 掌握本局域网中每一台主机的IP地址和MAC地址信息。
    利用libpcap捕获网络中的ARP请求/应答包,最大限度的提取相关信息。如在第五节中的B对A的ARP请求包,我们可以提取出关于B的完整信息(2.2.2.2,02:02:02),也获得了关于A的部分信息(1.1.1.1,null)。在知道网络中有主机A的情况下,我们可以构造并发送对A的ARP请求包,捕获A的ARP应答包,从而完整掌握A的信息。同理,我们也可以捕获TCP/UDP等数据包,从中提取信息。
    创建一个向链表增加主机信息的函数:add_host(ip,mac), 每收到一个ARP请求/应答包,都执行add_host( )两次:add_host(发送端IP,发送端MAC),add_host(目的端IP,目的端MAC)。
    在收到ARP应答包时,首先检查发送端的IP和MAC,如果IP不是自己的,但MAC是自己的,则说明此应答包是本机构造的ARP欺骗包,程序忽略。
    对于正常的ARP请求包和应答包,add_host(ip, mac )中IP或MAC只要有一个是自己的(ip == MYIP || mac ==MYMAC),则程序忽略。显然,没有必要自己欺骗自己。
    add_host(ip,mac)遍历主机链表,如果IP存在,且MAC不空,则把MAC地址写入;如果不存在,则增加一个HOST节点,写入IP地址,如果MAC不空,则也把MAC地址写入。注意到这样一个情况:在ARP请求包中,目的MAC地址是没有意义的,所以我们只写入IP地址,而MAC地址用NULL来表示。这是我们收集网络拓朴结构的一种被动方法。

    函数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;
    }

  • 周期性的向局域网中每一台主机发送ARP欺骗包。
    创建一个发送ARP欺骗包的函数send_fake_arp_packet(),遍历主机链表的每一个IP地址,如果此IP地址的MAC地址已知,则遍历主机链表中其它IP地址,以其它IP地址和本机的MAC地址为发送端,以选中的IP地址和MAC地址为目的端,构造并发送ARP应答欺骗包;如果此IP地址的MAC地址未知,则以本机IP地址和MAC地址为发送端,以选中的IP地址为目的端,构造并发送正常的ARP请求包。注意,这是我们收集网络拓朴结构的一种主动方法。
    ARP高速缓存中的记录都有过期时间,不同的操作系统有不同的设置.在实施中,我们只需以较短的时间周期性的发ARP欺骗包,则可解决这个问题.
    代码如下:
    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");
    }
    }
    }

  • 正确处理一个以太包实际被捕获两次的情况。例如:捕获到B发向A的以太包,第一次为(2.2.2.2,02:02:02)->(1.1.1.1,04:04:04),第二次为(2.2.2.2,04:04:04)->(1.1.1.1,01:01:01)。区分这两次捕获的规则很简单:目标IP不为本IP且目标MAC为本MAC就是第一次;源IP不为本IP且源MAC为本MAC就是第二次。在实际处理中,可任取一种包并把源/目的MAC改写,对另一种包忽略即可。




回页首

7.相关说明

  • 这种ARP欺骗是以主机的ARP高速缓存可以动态改变为前提的,如果ARP高速缓存中某一IP的MAC地址被设为静态(static),则对关于此IP的欺骗是显然不成立的。
  • 为了尽快的掌握网络中主机的地址信息,应至少对ARP请求包和ARP应答包都处理。如果只处理ARP请求包,则在此刻只能掌握发端主机的信息,并只能欺骗发端主机。在实际的IP包捕获中,就会看到单边数据包。当然,在程序运行一段时间后,所有主机信息也能全部掌握,但效率显然是不高的。如果再加上对未知MAC的IP的主动请求,则捕获所有数据包可在较短时间内完成。(在实际的C类网中测试,不到一分钟)


参考资料

本文的样码 在此下载。

dsniff: http://naughty.monkey.org/~dugsong/dsniff/

http://sunsite.uba.ar/download/pub/OpenBSD/snapshots/packages/i386/

http://www.cpress.cz/knihy/tcp-ip-bezp/Download/dsniff/

angst: http://sourceforge.net/project/showfiles.php?group_id=14044&release_id=23186

http://www.zone-h.org/en/download/category=52/

《交换网络嗅探》:作者:Sumit Dhar < sumit.dhar@slmsoft.com>

翻译:coolfrog < coolfrog@usa.com>

《TCP/IP详解 卷一》:作者 W.Richard Stevens



关于作者


施聪,成都人,程序员。长期从事基于UNIX/LINUX下的c/c++程序设计。近期学习和研究的方向为J2EE,设计模式,软件工程。可通过 javer@163.com或 shicong1973@163.com和他联系。

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 孕39周羊水过多怎么办 生完孩子腿关节疼怎么办 手指上长了倒刺怎么办 肥肉吃多了恶心怎么办 大便粘稠怎么回事还便秘怎么办 狗狗大便次数多怎么办 宝宝拉白色稀便怎么办 5个月宝宝流鼻涕怎么办 5个月婴儿流鼻涕怎么办 五个月宝宝流鼻涕鼻塞怎么办 4个月宝宝流鼻涕怎么办 大便经常是稀的怎么办 拉黑色的稀大便怎么办 孕晚期半夜饿了怎么办 肠胃不好大便不成型怎么办 螃蟹吃多了过敏怎么办 吃螃蟹过敏很痒怎么办 吃螃蟹喝啤酒了怎么办 1个月宝宝拉肚子怎么办 被雨林蝎子蛰了怎么办 在家被蜈蚣咬了怎么办 宝宝被蝎子蜇了怎么办 仓鼠只吃面包虫怎么办 套装但是装等低怎么办 被香港人骗了钱怎么办 被红头蛇咬了怎么办 爸妈吵架闹离婚怎么办 包包用酒精擦了怎么办 灰色泰迪毛发白怎么办 手被野猫抓伤了怎么办 想去香港玩两天怎么办 受凉了一直想吐怎么办 受寒后头晕想吐怎么办 肚子受凉了想吐怎么办 想吐但吐不出来怎么办 抽烟抽的牙黄怎么办 借了大耳窿的钱怎么办 5岁左眼视力不好怎么办 老公才30性不行怎么办 老婆出轨跑了怎么办啊 海螺吃多了头晕怎么办