zoukankan      html  css  js  c++  java
  • tcp/ip协议学习 第四章 ARP:地址解析协议

    派猴子来的救兵

    关于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协议详解

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

  • 相关阅读:
    连接查询
    分组查询
    【转载】C语言 构建参数个数不固定函数
    【转载】vc编译exe的体积最小优化
    VC6微软正则表达式greta使用案例
    MultiByteToWideChar和WideCharToMultiByte
    【转载】VC操作剪切板
    VC/MFC分割字符串(SplitString)返回CStringArray
    【转载】实现UTF8与GB2312编码格式相互转换(VC)已经验证!
    VC6配置sqlite数据库
  • 原文地址:https://www.cnblogs.com/morningchilde/p/4149864.html
Copyright © 2011-2022 走看看