本秘籍簡介:
Scapy 是一種工具,允許用戶製作並向網絡中注入自定義數據包。 此工具可以用於構建 ICMP 協議請求,並將它們注入網絡來分析響應。 這個特定的秘籍演示瞭如何使用 Scapy 在遠程主機上執行第3層發現。
準備
使用 Scapy 執行第三層發現不需要實驗環境,因為 Internet 上的許多系統都將回復ICMP 回顯請求。 但是,強烈建議你只在您自己的實驗環境中執行任何類型的網絡掃描,除非你完全熟悉您受到任何管理機構施加的法律法規。 如果你希望在實驗環境中執行此技術,你需要至少有一個響應 ICMP 請求的系統。
操作步驟
為了使用 Scapy 發送 ICMP 回顯請求,我們需要開始堆疊層級來發送請求。 堆疊數據包時的一個好的經驗法則是,通過 OSI 按照的各層進行處理。 你可以通過使用斜槓分隔每個層級來堆疊多個層級。 為了生成 ICMP 回顯請求,IP 層需要與 ICMP請求堆疊。 為了開始,請使用 scapy 命令打開 Scapy 交互式控制檯,然後將 IP 對象賦給變量:
root@kali:~# scapy
INFO: Can't import PyX. Won't be able to use psdump() or pdfdump().
WARNING: No route found for IPv6 destination :: (no default route?)
WARNING: IPython not available. Using standard Python shell instead.
AutoCompletion, History are disabled.
aSPY//YASa
apyyyyCY//////////YCa |
sY//////YSpcs scpCY//Pp | Welcome to Scapy
ayp ayyyyyyySCP//Pp syY//C | Version 2.4.0
AYAsAYYYYYYYY///Ps cY//S |
pCCCCY//p cSSps y//Y | [url=https://github.com/secdev/scapy]https://github.com/secdev/scapy[/url]
SPPPP///a pP///AC//Y |
A//A cyP////C | Have fun!
p///Ac sC///a |
P////YCpc A//A | We are in France, we say Skappee.
scccccp///pSP///p p//Y | OK? Merci.
sY/////////y caa S//P | -- Sebastien Chabal
cayCyayP//Ya pY/Ya |
sY/PsY////YCc aC//Yp
sc sccaCY//PCypaapyCP//YSs
spCPY//////YPSps
ccaacs
>>> ip=IP()
>>> ip.display()
###[ IP ]###
version= 4
ihl= None
tos= 0x0
len= None
id= 1
flags=
frag= 0
ttl= 64
proto= hopopt
chksum= None
class="lazy" src="//p2.ttnews.xyz/loading.gif" data-original= 127.0.0.1
dst= 127.0.0.1
\options\
將新值賦給目標地址屬性後,可以通過再次調用 display() 函數來驗證更改。 請注意,當目標 IP 地址值更改為任何其他值時,源地址也會從回送地址自動更新為與默認接口關聯的 IP 地址。 現在 IP 對象的屬性已經適當修改了,我們將需要在我們的封包棧中創建第二層。 要添加到棧的下一個層是 ICMP 層,我們將其賦給單獨的變量:
>>> ping=ICMP()
>>> ping.display()
###[ ICMP ]###
type= echo-request
code= 0
chksum= None
id= 0x0
seq= 0x0
在所提供的示例中,ICMP 對象使用 ping 變量名稱初始化。 然後可以調用 display() 函數來顯示 ICMP 屬性的默認配置。 為了執行 ICMP 回顯請求,默認配置就足夠了。 現在兩個層都已正確配置,它們可以堆疊來準備發送。 在Scapy 中,可以通過使用斜槓分隔每個層級來堆疊層級。 看看下面的命令集:
>>> ip.dst="172.16.155.1"
>>> ping_request=(ip/ping)
>>> ping_request.display()
###[ IP ]###
version= 4
ihl= None
tos= 0x0
len= None
id= 1
flags=
frag= 0
ttl= 64
proto= icmp
chksum= None
class="lazy" data-original= 172.16.155.150
dst= 172.16.155.1
\options\
###[ ICMP ]###
type= echo-request
code= 0
chksum= None
id= 0x0
seq= 0x0
一旦堆疊層級被賦給一個變量, display() 函數可以顯示整個棧。 以這種方式堆疊層的過程通常被稱為數據報封裝。 現在已經堆疊了層級,並已經準備好發送請求。 這可以使用 Scapy 中的 sr1() 函數來完成:
>>> ping_reply=sr1(ping_request)
Begin emission:
...........................*Finished sending 1 packets.
Received 28 packets, got 1 answers, remaining 0 packets
>>> ping_reply.display()
###[ IP ]###
version= 4
ihl= 5
tos= 0x0
len= 28
id= 47924
flags=
frag= 0
ttl= 64
proto= icmp
chksum= 0x30f4
class="lazy" data-original= 172.16.155.1
dst= 172.16.155.150
\options\
###[ ICMP ]###
type= echo-reply
code= 0
chksum= 0xffff
id= 0x0
seq= 0x0
###[ Padding ]###
load= '\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00'
在提供的示例中, sr1() 函數賦給了 ping_reply 變量。 這將執行該函數,然後將結果傳遞給此變量。 在接收到響應後,在 ping_reply 變量上調用 display() 函數來查看響應的內容。 請注意,此數據包是從我們發送初始請求的主機發送的,目標地址是 Kali 系統的 IP 地址。 另外,注意響應的 ICMP 類型是回應應答。 基於此示例,使用 Scapy 發送和接收 ICMP 的過程看起來很有用,但如果你嘗試對非響應的目標地址使用相同的步驟,你會很快注意到問題:
>>> ip.dst="172.16.155.100"
>>> ping_request=(ip/ping)
>>> ping_reply=sr1(ping_request)
Begin emission:
..............................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................WARNING: Mac address to reach destination not found. Using broadcast.
Finished sending 1 packets.
......................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................^C
Received 4340 packets, got 0 answers, remaining 1 packets
示例輸出被截斷,但此輸出應該無限繼續,直到你使用 Ctrl + C 強制關閉。 不向函數提供超時值, sr1() 函數會繼續監聽,直到接收到響應。 如果主機不是活動的,或者如果 IP 地址沒有與任何主機關聯,則不會發送響應,並且該功能也不會退出。 為了在腳本中有效使用此函數,應定義超時值:
>>> ping_reply=sr1(ping_request,timeout=1)
Begin emission:
....................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................WARNING: Mac address to reach destination not found. Using broadcast.
Finished sending 1 packets.
................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................
Received 2340 packets, got 0 answers, remaining 1 packets
>>>
通過提供超時值作為傳遞給 sr1() 函數的第二個參數,如果在指定的秒數內沒有收到響應,進程將退出。 在所提供的示例中, sr1() 函數用於將 ICMP 請求發送到無響應地址,因為未收到響應,會在 1 秒後退出。 到目前為止提供的示例中,我們將函數賦值給變量,來創建持久化和可操作的對象。 但是,這些函數不必複製給變量,也可以通過直接調用函數生成。
>>> answer=sr1(IP(dst="172.16.155.1")/ICMP(),timeout=1)
Begin emission:
..................................................................Finished sending 1 packets.
*
Received 67 packets, got 1 answers, remaining 0 packets
>>> answer.display()
###[ IP ]###
version= 4
ihl= 5
tos= 0x0
len= 28
id= 2141
flags=
frag= 0
ttl= 64
proto= icmp
chksum= 0xe3cb
class="lazy" data-original= 172.16.155.1
dst= 172.16.155.150
\options\
###[ ICMP ]###
type= echo-reply
code= 0
chksum= 0xffff
id= 0x0
seq= 0x0
###[ Padding ]###
load= '\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00'
在這裡提供的示例中,之前使用四個單獨的命令完成的所有工作,實際上可以通過直接調用函數的單個命令來完成。 請注意,如果在超時值指定的時間範圍內,ICMP 請求沒有收到 IP 地址的回覆,調用對象會產生異常。 由於未收到響應,因此此示例中賦值為響應的應答變量不會初始化:
>>> answer=sr1(IP(dst="172.16.155.100")/ICMP(),timeout=1)
Begin emission:
....................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................WARNING: Mac address to reach destination not found. Using broadcast.
...Finished sending 1 packets.
.....................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................
Received 2348 packets, got 0 answers, remaining 1 packets
>>> answer.dislay()
Traceback (most recent call last):
File "
", line 1, in AttributeError: 'NoneType' object has no attribute 'dislay'
有關這些不同響應的知識,可以用於生成在多個 IP 地址上按順序執行 ICMP 請求的腳本。 腳本會循環遍歷目標 IP 地址中最後一個八位字節的所有可能值,併為每個值發送一個 ICMP 請求。 當從每個 sr1() 函數返回時,將評估響應來確定是否接收到應答的響應:
#!/usr/bin/python3
import logging
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
from scapy.all import *
if len(sys.argv)!=2:
print("Usage - ./ping.py [/24 network address]")
print("Exameple - ./pinger.py 172.16.155.1")
print("Exameple will perform an ICMP scan of the 172.16.155.0/24 range")
sys.exit()
address=str(sys.argv[1])
prefix=address.split(".")[0]+'.'+address.split(".")[1]+'.'+address.split(".")[2]+'.'
for addr in range(1,255):
answer=sr1(IP(dst=prefix+str(addr))/ICMP(),timeout=1,verbose=0)
if answer==None:
pass
else:
print(prefix+str(addr))
腳本的第一行標識了 Python 解釋器所在的位置,以便腳本可以在不傳遞到解釋器的情況下執行。 然後腳本導入所有 Scapy 函數,並定義 Scapy 日誌記錄級別,以消除腳本中不必要的輸出。 還導入了子過程庫,以便於從系統調用中提取信息。 第二個代碼塊是條件測試,用於評估是否向腳本提供了所需的參數。 如果在執行時未提供所需的參數,則腳本將輸出使用情況的說明。 該說明包括工具的用法,示例和所執行任務的解釋。
在這個代碼塊之後,有一個單獨的代碼行將所提供的參數賦值給 interface 變量。 下一個代碼塊使用 check_output() 子進程函數執行 ifconfig 系統調用,該調用也使用 grep 和 cut 從作為參數提供的本地接口提取 IP 地址。 然後將此輸出賦給 ip 變量。 然後使用 split 函數從 IP 地址字符串中提取 / 24 網絡前綴。 例如,如果 ip 變量包含 192.168.11.4 字符串,則值為 192.168.11 。 它將賦給 prefix 變量。
最後一個代碼塊是一個用於執行實際掃描的 for 循環。 for 循環遍歷介於 0 和254 之間的所有值,並且對於每次迭代,該值隨後附加到網絡前綴後面。 在早先提供的示例的中,將針對 192.168.11.0 和 192.168.11.254 之間的每個 IP 地址發送 ICMP 回顯請求。 然後對於每個回覆的活動主機,將相應的 IP 地址打印到屏幕上,以表明主機在 LAN 上活動。 一旦腳本被寫入本地目錄,你可以在終端中使用句號和斜槓,然後是可執行腳本的名稱來執行它。 看看以下用於執行腳本的命令:
root@kali:~# ./ping.py
Usage - ./ping.py [/24 network address]
Exameple - ./pinger.py 172.16.155.1
Exameple will perform an ICMP scan of the 172.16.155.0/24 range
root@kali:~# ./ping.py 172.16.155.0
172.16.155.1
172.16.155.2
如果在沒有提供任何參數的情況下執行腳本,則會將使用方法輸出到屏幕。 使用方法輸出表明,此腳本需要用於定義要掃描的 / 24 網絡的單個參數。 提供的示例使用 172.16.155.0 網絡地址來執行腳本。 該腳本然後輸出在 / 24 網絡範圍上的活動 IP 地址的列表。 此輸出也可以使用尖括號重定向到輸出文本文件,後跟輸出文件名。 一個例子如下:
root@kali:~# ./ping.py 172.16.155.0 > output.txt
root@kali:~# ls output.txt
output.txt
root@kali:~# cat output.txt
172.16.155.1
172.16.155.2
然後可以使用 ls 命令來驗證輸出文件是否已寫入文件系統,或者可以使用 cat 命令查看其內容。 也可以修改此腳本,來接受 IP 地址列表作為輸入。 為此,必須更改 for 循環來循環遍歷從指定的文本文件讀取的行。 一個例子如下:
#!/usr/bin/python3
import logging
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
from scapy.all import *
if len(sys.argv)!=2:
print("Usage - ./ping.py [filename]")
print("Exameple - ./pinger.py iplist.txt")
print("Exameple will perform an ICMP scan of the IP addresses in iplist.txt")
sys.exit()
filename=str(sys.argv[1])
file1=open(filename,"r")
for addr in file1:
answer=sr1(IP(dst=addr.strip())/ICMP(),timeout=1,verbose=0)
if answer==None:
pass
else:
print(str(addr.strip()))
與之前的腳本唯一的主要區別是,它接受一個輸入文件名作為參數,然後循環遍歷此文件中列出的每個 IP 地址進行掃描。 與其他腳本類似,生成的輸出包括響應ICMP 回顯請求的系統的相關 IP 地址的簡單列表,其中包含 ICMP 回顯響應:
root@kali:~# ./ping2.py
Usage - ./ping.py [filename]
Exameple - ./pinger.py iplist.txt
Exameple will perform an ICMP scan of the IP addresses in iplist.txt
root@kali:~# ./ping2.py iplist.txt
172.16.155.1
172.16.155.2
此腳本的輸出可以以相同的方式重定向到輸出文件。 使用作為參數提供的輸入文件來執行腳本,然後使用尖括號重定向輸出,後跟輸出文本文件的名稱。 一個例子如下:
root@kali:~# ./ping2.py iplist.txt > output.txt
root@kali:~# ls output.txt
output.txt
root@kali:~# cat output.txt
172.16.155.1
172.16.155.2
工作原理
此處使用 Scapy 通過構造包括 IP 層和附加的 ICMP 請求的請求來執行 ICMP 第三層發現。 IP 層能夠將封包路由到本地網絡之外,並且 ICMP 請求用於從遠程系統請求響應。 在 Python 腳本中使用此技術,可以按順序執行此任務,來掃描多個系統或整個網絡範圍。
閱讀更多 Web安全陪跑團 的文章