ARP協議
地址解析協議,即ARP(Address Resolution Protocol),是根據IP地址獲取物理地址的一個TCP/IP協議。主機發送信息時將包含目標IP地址的ARP請求廣播到網絡上的所有主機,並接收返回消息,以此確定目標的物理地址;
OP
操作類型:
- 1 ARP請求
- 2 ARP應答
- 3 RARP請求
- 4 RARP應答
數據包分析
ping局域網中的一個地址
抓包,可以看到在尋找10.35.68.1
是誰,並做出了答覆
封裝爲Ether/ARP
Ether
源MAC
爲本機MAC
目的MAC
爲廣播地址ff:ff:ff:ff:ff:ff
(ARP特性)
ARP:
op
爲1
(ARP請求)源MAC
和源IP
爲本機MAC
和本機IP
目的MAC
和目的IP
爲00:00:00:00:00:00
和目標機IP,
答覆包
ARP:
-
獲取到
10.35.68.1
的MAC
並判斷它存活 -
op
爲2
(ARP答覆)
編寫腳本
1.Scapy中ARP的請求和答覆
>>> ls(ARP)
hwtype : XShortField = (1)
ptype : XShortEnumField = (2048)
hwlen : FieldLenField = (None)
plen : FieldLenField = (None)
op : ShortEnumField = (1)
hwsrc : MultipleTypeField = (None)
psrc : MultipleTypeField = (None)
hwdst : MultipleTypeField = (None)
pdst : MultipleTypeField = (None)
>>> arp = (Ether(dst='FF:FF:FF:FF:FF:FF')/ARP(op=1, pdst='10.35.68.1'))
>>> arp.show()
###[ Ethernet ]###
dst= FF:FF:FF:FF:FF:FF
src= a0:8c:fd:1b:cb:90
type= 0x806
###[ ARP ]###
hwtype= 0x1
ptype= 0x800
hwlen= None
plen= None
op= who-has
hwsrc= a0:8c:fd:1b:cb:90
psrc= 10.35.71.205
hwdst= None
pdst= 10.35.68.1
>>> pkt = srp1(arp) #srp1() 發送二層包並接受第一個答覆包
Begin emission:
Finished sending 1 packets..
.*
Received 3 packets, got 1 answers, remaining 0 packets
>>> pkt.show() #查看答覆包
###[ Ethernet ]###
dst= a0:8c:fd:1b:cb:90
src= 34:96:72:8a:6e:a2
type= 0x806
###[ ARP ]###
hwtype= 0x1
ptype= 0x800
hwlen= 6
plen= 4
op= is-at
hwsrc= 34:96:72:8a:6e:a2
psrc= 10.35.68.1
hwdst= a0:8c:fd:1b:cb:90
pdst= 10.35.71.205
###[ Padding ]###
load= '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
>>> pkt.getlayer('ARP').fields['hwsrc'] #獲取目標MAC地址
'34:96:72:8a:6e:a2'
2.demo
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
from scapy.all import (
Ether,
ARP,
srp1)
def arp_request(ip_dst):
pkt = Ether(dst='FF:FF:FF:FF:FF:FF')/
ARP(op=1,hwdst='00:00:00:00:00:00',pdst=ip_dst)
arp_rep = srp1(pkt,,timeout=3,verbose=False)
if arp_rep:
print('[+]',ip_dst,'-->MAC: ',arp_rep.hwsrc,'\n') ##掃描出的MAC地址
if __name__ == '__main__':
arp_request('10.35.68.1')
運行結果
[+] 10.35.68.1 -->MAC: 34:96:72:8a:6e:a2
3.完善代碼
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
from scapy.all import (
Ether,
ARP,
srp1)
import ipaddress
import time
import threading
import argparse
import os
import sys
hwdst = '00:00:00:00:00:00'
dst= 'FF:FF:FF:FF:FF:FF'
def arp_request(ip_dst):
hwdst = '00:00:00:00:00:00'
mac_broad = 'FF:FF:FF:FF:FF:FF' #廣播地址
pkt = Ether(dst=mac_broad)/ARP(op=1, hwdst=hwdst, pdst=ip_dst)
arp_rep = srp1(pkt,timeout=3, verbose=False)
if arp_rep:
print('[+]'+ip_dst,'-->MAC: ',arp_rep.hwsrc) ##掃描出的MAC地址
def arp_scan(network):
begin = time.time()
threads = []
length = len(network)
for ip in network:
scan = threading.Thread(target=arp_request,args=(str(ip),))
threads.append(scan)
for i in range(length):
threads[i].start()
for i in range(length):
threads[i].join()
stop = time.time()
print('[+]complete scan time cost:%.3fs'%(stop-begin)) #計算運行時間
def main():
# Windows下注釋掉這段
# 判斷是否爲root
if os.getegid() != 0:
print('[-]Need root user to run')
sys.exit(1)
parser = argparse.ArgumentParser()
parser.add_argument('network',help='eg: 192.168.1.0/24')
args = parser.parse_args()
try:
network = list(ipaddress.ip_network(args.network))
arp_scan(network)
except ValueError:
parser.print_help()
except KeyboardInterrupt:
print('[-]Stop scan')
if __name__ == '__main__':
main()
運行演示