• 热门专题

tcp/ip协议学习 第四章 ARP:地址解析协议

作者:heychilde  发布日期:2014-12-08 20:27:04
Tag标签:地址  
  • 派猴子来的救兵

    关于ARP的RFC文档在此!

    ARP干嘛的

    曾经有段时间, 六七年前了吧. 本科的时候, 流行了一阵子ARP病毒攻击, 导致整个局域网都不能上网了. 当时只听说这个东西防不住, 只要有一个人中毒, 就导致所有人上不了网. 现在也终于知道这是怎么回事了, 也能手工让某个同学上不了网了, 咳咳.

    大家应该也都知道ARP是干嘛的, 我再啰嗦一下.. 比如我访问了百度, 百度回了包给我, 百度只知道我的IP是什么,不知道我的MAC地址. 这个包到网关的时候, IP这一层再把数据交给下一层的链路层, 链路层不知道IP是什么东西的, 它只认MAC地址. 所以就需要把IP转成MAC地址, ARP请求就是做这个的.

    就是说, 我可以通过这个协议广播问一下所有机器 , 谁的IP是XXX.XXX.XXX.XXX, 请把你的MAC地址告诉我. 这个IP是XXX.XXX.XXX.XXX的机器收到请求之后, 就会告诉我, XXX.XXX.XXX.XXX的MAC地址是啥啥啥.

    不幸这个是基于互相信任的, 理论上大家都会相信别人说的是正确的. 但是, 我可以撒谎说, XXX.XXX.XXX.XXX是我, 我的MAC是啥啥啥. 然后本来应该到 XXX.XXX.XXX.XXX那里的数据包就到我这里来了. XXX.XXX.XXX.XXX不仅仅是断网了, 我还能窃听他的数据.

    协议格式

    要想伪造, 啊,不, 发送一个ARP请求或者应答, 一定要了解协议格式. 从RFC文件抄了一份.

    To communicate mappings from <protocol, address> pairs to 48.bit
    Ethernet addresses, a packet format that embodies the Address
    Resolution protocol is needed.  The format of the packet follows.
    
        Ethernet transmission layer (not necessarily accessible to
             the user):
            48.bit: Ethernet address of destination
            48.bit: Ethernet address of sender
            16.bit: Protocol type = ether_type$ADDRESS_RESOLUTION
        Ethernet packet data:
            16.bit: (ar$hrd) Hardware address space (e.g., Ethernet,
                             Packet Radio Net.)
            16.bit: (ar$pro) Protocol address space.  For Ethernet
                             hardware, this is from the set of type
                             fields ether_typ$<protocol>.
             8.bit: (ar$hln) byte length of each hardware address
             8.bit: (ar$pln) byte length of each protocol address
            16.bit: (ar$op)  opcode (ares_op$REQUEST | ares_op$REPLY)
            nbytes: (ar$sha) Hardware address of sender of this
                             packet, n from the ar$hln field.
            mbytes: (ar$spa) Protocol address of sender of this
                             packet, m from the ar$pln field.
            nbytes: (ar$tha) Hardware address of target of this
                             packet (if known).
            mbytes: (ar$tpa) Protocol address of target.
    

    这个还是TCP/IP协议详解书里面的图好看一些, 且等我截个图来, 呃,截歪了.

    arp协议,截取自是TCP/IP协议详解arp协议,截取自是TCP/IP协议详解

    其实里面有些值, 像”硬件地址长度”什么的, 是个变量, 后面的”发送端以太网地址”就是根据这个而变化 .就我们目前的应用和环境来说, 拿这个图就可以啦.
    这里的长度单位是字节, 不是上一篇IP协议里面的bit了.

    详细解释我也copy一下吧. 也是出自TCP/IP协议详解一书.

    以太网报头中的前两个字段是以太网的源地址和目的地址。目的地址为全 1的特殊地址是 广播地址。电缆上的所有以太网接口都要接收广播的数据帧。

    两个字节长的以太网帧类型表示后面数据的类型。对于 ARP请求或应答来说,该字段的 值为0x0806。

    形容词hardware(硬件)和protocol(协议)用来描述 ARP分组中的各个字段。例如,一个 ARP 请求分组询问协议地址(这里是 IP地址)对应的硬件地址(这里是以太网地址)。

    硬件类型字段表示硬件地址的类型。它的值为 1即表示以太网地址。协议类型字段表示要 映射的协议地址类型。它的值为 0x0800即表示 IP地址。它的值与包含 IP数据报的以太网数据 帧中的类型字段的值相同,这是有意设计的(参见图 2–1)。

    接下来的两个 1字节的字段,硬件地址长度和协议地址长度分别指出硬件地址和协议地址 的长度,以字节为单位。对于以太网上 IP地址的 ARP请求或应答来说,它们的值分别为 6和4。 操作字段指出四种操作类型,它们是 ARP请求(值

    (值为3)和RARP应答(值为4)(我们在第5章讨论RARP)。这个字段必需的,因为 ARP请求 和ARP应答的帧类型字段值是相同的。

    接下来的四个字段是发送端的硬件地址(在本例中是以太网地址)、发送端的协议地址 (IP地址)、目的端的硬件地址和目的端的协议地址。注意,这里有一些重复信息:在以太网的数据帧报头中和 ARP请求数据帧中都有发送端的硬件地址。

    对于一个 ARP请求来说,除目的端硬件地址外的所有其他的字段都有填充值。当系统收到一份目的端为本机的 ARP请求报文后,它就把硬件地址填进去,然后用两个目的端地址分 别替换两个发送端地址,并把操作字段置为 2,最后把它发送回去。

    来段程序吧

    其它也没啥好说的了, 先来段程序吧.

    广播一个ARP请求, 问一下网关的MAC地址是多少. 运行环境是ubuntu12.04. osx上面是不行的. 据说windows也不行. 搜索了好久, 也不知道mac上面怎么搞.

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    '''
    广播一个ARP请求, 问一下网关的MAC地址是多少.
    运行环境是ubuntu12.04.
    osx上面是不行的. 据说windows也不行.  搜索了好久, 也不知道mac上面怎么搞.
    '''
    
    import socket
    import struct
    
    
    def main():
        st = struct.Struct('!6s 6s h h h b b h 6s 4s 6s 4s')
    
        GATEWAY = '192.168.1.1'
        MYIP = '192.168.1.8'
        MYMAC = '20:c9:d0:88:96:3f'
    
        dst_ethernet_addr = ''.join(
            [chr
             (int(e, 16))
             for e in 'FF:FF:FF:FF:FF:FF'.split(':')])
        protocol_type = 0x0806
        hw_addr_space = 1
        protocol_addr_space = 0x800
        hw_addr_length = 6
        protocol_addr_length = 4
        op = 1
        my_mac = ''.join([chr(int(e, 16)) for e in MYMAC.split(':')])
        my_ip = socket.inet_aton(MYIP)
        target_hw_addr = ''.join(
            [chr
             (int(e, 16))
             for e in '00:00:00:00:00:00'.split(':')])
        des_ip = socket.inet_aton(GATEWAY)
        data = (
            dst_ethernet_addr,
            my_mac,
            protocol_type,
            hw_addr_space,
            protocol_addr_space,
            hw_addr_length,
            protocol_addr_length,
            op,
            my_mac,
            my_ip,
            target_hw_addr,
            des_ip,
            )
        packed_data = st.pack(*data)
    
        s = socket.socket(socket.PF_PACKET, socket.SOCK_RAW, socket.SOCK_RAW)
        s.bind(('eth0', socket.SOCK_RAW))
    
        # 下面这样也行, 不知道区别.
        #http://sock-raw.org/papers/sock_raw 这个应该可以参考
        #s = socket.socket(socket.PF_PACKET, socket.SOCK_RAW)
        #s.bind(('eth0',0))
    
        r = s.send(packed_data)
        print r
        return
    
    if __name__ == '__main__':
        main()
    

    抓包结果, 这里已经忽略了以太网首部的14个字节. 是从上图中的“硬件类型”开始的.

    % sudo tcpdump -nn -vvv -x -c1 arp   
    tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
    19:28:43.209235 ARP, Ethernet (len 6), IPv4 (len 4), Request who-has 192.168.1.1 tell 192.168.1.8, length 28
        0x0000:  0001 0800 0604 0001 20c9 d088 963f c0a8
        0x0010:  0108 0000 0000 0000 c0a8 0101
    1 packet captured
    1 packet received by filter
    0 packets dropped by kernel
    

    ARP攻击

    上面的代码简单改一下就可以做ARP攻击了.

    对网关做一个ARP应答.
    op改为2, 代表ARP应答. 然后把 “以太网源地址”和“发送端以太网地址”都写自己的. IP地址写要攻击的人.

    OVER

About IT165 - 广告服务 - 隐私声明 - 版权申明 - 免责条款 - 网站地图 - 网友投稿 - 联系方式
本站内容来自于互联网,仅供用于网络技术学习,学习中请遵循相关法律法规