一,ARP协议简介
ARP的中文名称为“地址解析协议”,位于第三层网络层,主要用在以太网(内网)中。有一点需要明确,所有的主机在互联网中通信的时候使用的是ip地址,而在以太网中通信时使用的确是硬件地址(mac地址)。
这个协议用在只知道目标IP地址的情况下发现物理地址,当所使用的主机只知道目的主机地址(IP地址)却不知道目标的硬件地址时,就需要使用以太网广播包给网络上的每一台主机发送ARP请求.
假设当前以太网环境中有四台主机A,B,C,D
A~ ip:192.168.1.2 mac: 11:11:11:11:11:11, B~ ip:192.168.1.3 mac: 22:22:22:22:22:22
C~ ip:192.168.1.4 mac: 33:33:33:33:33:33, D~ ip:192.168.1.5 mac: 44:44:44:44:44:44
请求格式如下:
协议类型:ARP Request(ARP 请求)
源主机地址:192.168.1.2
目的主机地址:192.168.1.3
源主机Mac地址:11:11:11:11:11:11
目的主机Mac地址:ff:ff:ff:ff:ff:ff (广播)
以太网中其他三台主机在收到这个ARP请求数据包之后,会将自己的IP地址与包头中的目的IP地址进行比较,如果不匹配,则不会做出响应,只有IP地址为192.168.1.3的主机会响应,且将主机A的ip地址和mac地址添加进自己的ARP缓存表中,并回发给192.168.1.2一个ARP回应数据包。
回应格式如下:
协议类型:ARP Reply(ARP回应)
源主机ip地址:192.168.1.3
目的主机ip地址:192.168.1.2
源主机Mac地址:22:22:22:22:22:22
目的主机Mac地址:11:11:11:11:11:11
主机A收到应答包后,同样会将主机B的ip地址和mac地址存进自己的ARP缓存表中
缓存表格式:
IP地址 硬件地址 类型
192.168.1.3 22:22:22:22:22:22 动态
以后当主机A再需要和主机B进行通讯的时候,只需要查询自己的ARP缓存表。找到对应的表项,查询到对应对mac地址就可以发送数据了。
通俗的解释,把以太网比作一个村庄,如果A想要快速找到村里的B在哪(mac地址),最快的方法就是用村委会的广播喊话(以没有手机的时代为背景哈),让村里每个人听到你的声音,你要找的人一听到你叫他的名字(B的IP地址)就会说我在这(B的mac地址),然后你就拿小本本(ARP缓存表)记下了他的位置,方便下次再找。
二,程序执行流程
当目标主机与我们处在同一个以太网中的时候,利用ARP对其进行扫描是最好的选择,因为ARP对其进行扫描是最好的选择,因为这种扫描方式最快,也最为准确。
第一步:向目标主机发送一个ARP请求
第二步:如果目标主机存活,将会返回一个ARP回应
第三步:如果目标主机处于非活跃状态,它将不会给予回应。
三,程序编写
使用scapy模块,没安装模块的可以pip install scapy安装一下。
scapy模块有自己单独的窗口,我们要用到ARP协议,首先先看看ARP包的参数。
参数右面为None的是没有默认值的,这里我们主要关注的是pdst(目标ip地址),其他参数在发包时会自动填补。
另外,发送的是广播数据包,所以需要在ether层(网卡层)进行设置,同样查看ether数据包参数:
其中主要关注dst(目标mac地址),这里因为要发送广播数据包,所以设置为ff:ff:ff:ff:ff:ff,其他自动填补.
命名为arp_host_scan.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from scapy.all import srp,Ether,ARP
dst = "192.168.1.1"
ans,unans = srp(Ether(dst = "ff:ff:ff:ff:ff:ff")/ARP(pdst = dst),timeout=2)
for s,r, in ans:
print("目标主机存活")
print(r.sprintf("%Ether.src%-%ARP.psrc%"))
除了使用scapy库完成扫描外,也可以使用nmap库,
nmap命令合适如下:
nmap -RP -sn [目标主机],-RP表示使用arp扫描,-sn表示只扫描目标主机状态
代码如下:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import nmap
target = "192.168.5.2"
nm = nmap.PortScanner()
nm.scan(target,arguments='-sn -RP')
for host in nm.all_hosts():
print('-'*15)
print('Host:%s(%s)' % (host,nm[host].hostname()))
print('State:%s' % nm[host].state())
nmap库中的PortScanner()类创建实例,使用PortScanner()中的函数scan()进行扫描
scan()函数中target指定扫描IP地址,参数 -RP(进行ARP扫描),-sn(表示只测试主机的状态)