1 scapy簡介
scapy是一個python語言寫的,用來操作TCP/IP數據包的庫,基本涵蓋了wireshark的主要功能,例如抓包、ping、traceroute、嗅探、掃描,但由於其可以按照自己的意願來拼接和“無中生成”TCP/IP數據包中的內容,因此還可以實現attack的部分功能,並可以移植到任意平臺運行。
2 安裝和運行scapy
scapy官網上有安裝教程,不再贅述。建議在venv的虛擬環境下安裝Scapy的basic包,不影響主python環境。本文是在windows10+python3.7環境下,安裝的scapy2.4.3 basic包。另在windows下使用scapy需要安裝npcap軟件。
運行venv\Scripts下運行activate進入虛擬環境,再運行scapy。
圖中INFO錯誤是scapy的附加功能,需要依賴一些三方包,不安裝也不影響scapy核心功能的使用。
scapy的默認主題太暗,建議改成亮色,conf.color_theme=BrightTheme()
conf.color_theme=BrightTheme()
默認主題效果:
BrightTheme主題效果:
3 查看當前網絡配置
venv/Lib/site-packages/scapy/config.py下有一個Conf類,主要存儲了scapy最主要的一些配置,比如scapy版本、主題顏色、網卡、路由、是否使用npcap、可以在scapy交互環境中使用哪些命令等。在scapy交互環境中可以直接輸入conf來查看相應的內容。
3.1 conf概覽
命令 | 作用 |
---|---|
conf | 顯示conf所有配置 |
conf.iface | 主網卡 |
conf.route | 獲取主路由 |
conf.commands | 可在交互環境中使用的命令集合 |
lsc() | 同conf.commands |
詳解:
conf本質是Conf類的實例:
>>> type(conf)
scapy.config.Conf
Conf類中包含有大量配置,部分配置如下:
>>> conf
ASN1_default_codec = <ASN1Codec BER[1]>
AS_resolver = <scapy.as_resolvers.AS_resolver_multi object at 0x0000029E42AC...
BTsocket = <BluetoothRFCommSocket: read/write packets on a connected L2CAP...
L2listen = <L2pcapListenSocket: read packets at layer 2 using libpcap>
L2socket = <L2pcapSocket: read/write packets at layer 2 using only libpcap>
L3socket = <L3pcapSocket: read/write packets at layer 3 using only libpcap>
L3socket6 = functools.partial(<L3pcapSocket: read/write packets at layer 3 ...
USBsocket = None
auto_crop_tables = True
auto_fragment = True
bufsize = 65536
當前主網卡conf.iface
>>> conf.iface
<NetworkInterface [Intel(R) Ethernet Connection (5) I219-V #2] {XXXX}>
當前路由表conf.route(部分)
>>> conf.route
Network Netmask Gateway Iface Output IP Metric
0.0.0.0 0.0.0.0 25.255.255.254 ZeroTier One Virtual Port 172.28.33.102 10034
0.0.0.0 0.0.0.0 10.11.91.254 Intel(R) Ethernet Connection (5) I219-V #2 10.11.91.161 25
10.11.91.0 255.255.255.0 0.0.0.0 Intel(R) Ethernet Connection (5) I219-V #2 10.11.91.161 281
10.11.91.161 255.255.255.255 0.0.0.0 Intel(R) Ethernet Connection (5) I219-V #2 10.11.91.161 281
10.11.91.255 255.255.255.255 0.0.0.0 Intel(R) Ethernet Connection (5) I219-V #2 10.11.91.161 281
127.0.0.0 255.0.0.0 0.0.0.0 Npcap Loopback Adapter 127.0.0.1 281
127.0.0.1 255.255.255.255 0.0.0.0 Npcap Loopback Adapter 127.0.0.1 281
可在交互環境中使用的命令conf.commands(或者輸入lsc() )
>>> conf.commands
IPID_count : Identify IP id values classes in a list of packets
arpcachepoison : Poison target's cache with (your MAC,victim's IP) couple
arping : Send ARP who-has requests to determine which hosts are up
arpleak : Exploit ARP leak flaws, like NetBSD-SA2017-002.
bind_layers : Bind 2 layers on some specific fields' values.
bridge_and_sniff : Forward traffic between interfaces if1 and if2, sniff and return
chexdump : Build a per byte hexadecimal representation
computeNIGroupAddr : Compute the NI group Address. Can take a FQDN as input parameter
corrupt_bits : Flip a given percentage or number of bits from a string
corrupt_bytes : Corrupt a given percentage or number of bytes from a string
defrag : defrag(plist) -> ([not fragmented], [defragmented],
defragment : defragment(plist) -> plist defragmented as much as possible
dhcp_request : Send a DHCP discover request and return the answer
dyndns_add : Send a DNS add message to a nameserver for "name" to have a new "rdata"
dyndns_del : Send a DNS delete message to a nameserver for "name"
etherleak : Exploit Etherleak flaw
explore : Function used to discover the Scapy layers and protocols.
fletcher16_checkbytes: Calculates the Fletcher-16 checkbytes returned as 2 byte binary-string.
fletcher16_checksum : Calculates Fletcher-16 checksum of the given buffer.
fragleak : --
fragleak2 : --
fragment : Fragment a big IP datagram
fuzz :
getmacbyip : Return MAC address corresponding to a given IP address
getmacbyip6 : Returns the MAC address corresponding to an IPv6 address
hexdiff : Show differences between 2 binary strings
hexdump : Build a tcpdump like hexadecimal view
hexedit : Run hexedit on a list of packets, then return the edited packets.
hexstr : Build a fancy tcpdump like hex from bytes.
import_hexcap : Imports a tcpdump like hexadecimal view
is_promisc : Try to guess if target is in Promisc mode. The target is provided by its ip.
linehexdump : Build an equivalent view of hexdump() on a single line
ls : List available layers, or infos on a given layer class or name.
neighsol : Sends and receive an ICMPv6 Neighbor Solicitation message
overlap_frag : Build overlapping fragments to bypass NIPS
promiscping : Send ARP who-has requests to determine which hosts are in promiscuous mode
rdpcap : Read a pcap or pcapng file and return a packet list
report_ports : portscan a target and output a LaTeX table
restart : Restarts scapy
send : Send packets at layer 3
sendp : Send packets at layer 2
sendpfast : Send packets at layer 2 using tcpreplay for performance
sniff :
split_layers : Split 2 layers previously bound.
sr : Send and receive packets at layer 3
sr1 : Send packets at layer 3 and return only the first answer
sr1flood : Flood and receive packets at layer 3 and return only the first answer
srbt : send and receive using a bluetooth socket
srbt1 : send and receive 1 packet using a bluetooth socket
srflood : Flood and receive packets at layer 3
srloop : Send a packet at layer 3 in loop and print the answer each time
srp : Send and receive packets at layer 2
srp1 : Send and receive packets at layer 2 and return only the first answer
srp1flood : Flood and receive packets at layer 2 and return only the first answer
srpflood : Flood and receive packets at layer 2
srploop : Send a packet at layer 2 in loop and print the answer each time
tcpdump : Run tcpdump or tshark on a list of packets.
tdecode :
traceroute : Instant TCP traceroute
traceroute6 : Instant TCP traceroute using IPv6
traceroute_map : Util function to call traceroute on multiple targets, then
tshark : Sniff packets and print them calling pkt.summary().
wireshark :
wrpcap : Write a list of packets to a pcap file
3.2 查看網卡及路由
3.2.1 查看網卡
命令 | 作用 |
---|---|
get_windows_if_list() | 獲取所有網卡 |
IFACES / ifaces | get_windows_if_list() 的全局變量 |
IFACES.reload() / ifaces.reload() | 網卡發生變化時,刷新IFACES |
詳解:
venv/Lib/site-packages/scapy/arch/windows/__init__.py文件get_windows_if_list()用來獲取網卡列表:
>>> get_windows_if_list()
[{'name': '有線網',
'win_index': 27,
'description': 'Intel(R) Ethernet Connection (5) I219-V #2',
'guid': '{XX}',
'mac': 'xx:xx:xx:xx:xx:xx',
'ipv4_metric': 25,
'ipv6_metric': 25,
'ips': ['fe80::XXXX:XXXX:XXXX:XXXX', '10.11.91.161']},
{'name': 'Npcap Loopback Adapter',
'win_index': 22,
'description': 'Npcap Loopback Adapter',
'guid': '{XX}',
'mac': 'xx:xx:xx:xx:xx:xx',
'ipv4_metric': 25,
'ipv6_metric': 25,
'ips': ['fe80::XXXX:XXXX:XXXX:XXXX', '169.254.140.26']},
{'name': 'Wifi',
'win_index': 31,
'description': 'Intel(R) Dual Band Wireless-AC 8265 #2',
'guid': '{XX}',
'mac': 'xx:xx:xx:xx:xx:xx',
'ipv4_metric': 25,
'ipv6_metric': 25,
'ips': ['fe80::XXXX:XXXX:XXXX:XXXX', '169.254.62.191']}]
NetworkInterfaceDict中,用NetworkInterface將get_windows_if_list()進行了封裝,並在windows/__init__.py中進行了如下初始化,因此可使用IFACES或者ifaces查看網卡列表:
IFACES = ifaces = NetworkInterfaceDict() #NetworkInterfaceDict的無參構造函數不包含任何有用信息
IFACES.load() #這裏是真正加載本地網卡的,因此如果網卡列表發生了變化,需要手工重新調用下ifaces.reload()
>>> ifaces
INDEX IFACE IP MAC
27 Intel(R) Ethernet Connection (5) I219-V #2 10.11.91.161 XXX
22 Npcap Loopback Adapter 127.0.0.1 00:00:00:00:00:00
18 SVN Adapter V1.0 169.254.112.118 XXX
29 Microsoft Wi-Fi Direct Virtual Adapter #3 169.254.173.211 XXX
6 Microsoft Wi-Fi Direct Virtual Adapter #4 169.254.192.230 XXX
21 Bluetooth Device (Personal Area Network) #2 169.254.227.190 XXX
17 TAP-Windows Adapter V9 169.254.26.68 XXX
31 Intel(R) Dual Band Wireless-AC 8265 #2 169.254.62.191 XXX
14 ZeroTier One Virtual Port 172.28.33.102 XXX
10 VMware Virtual Ethernet Adapter for VMnet8 192.168.15.1 XXX
23 VMware Virtual Ethernet Adapter for VMnet1 192.168.220.1 XXX
-2 [Unknown] NdisWan Adapter None ff:ff:ff:ff:ff:ff
-3 [Unknown] NdisWan Adapter None ff:ff:ff:ff:ff:ff
-1 [Unknown] NdisWan Adapter None ff:ff:ff:ff:ff:ff
如果在使用過程中網卡列表發生了變化,需要手動調用ifaces.reload()
class NetworkInterfaceDict(UserDict):
def reload(self):
"""Reload interface list"""
self.restarted_adapter = False
self.data.clear()
if conf.use_pcap:
# Reload from Winpcapy
from scapy.arch.pcapdnet import load_winpcapy
load_winpcapy()
self.load() # reload函數實際上最後也是通過調用load重新加載網卡列表
# Reload conf.iface
conf.iface = get_working_if() #reload函數會同時刷新默認網卡,這裏目前有點問題,詳見3.2.3節
3.2.2 查看路由
命令 | 作用 |
---|---|
read_routes() | 查看ipv4路由 |
Route() | 對read_routes()的封裝 |
conf.route | Route的全局對象 |
conf.route.route(dst=“www.baidu.com”) | 獲取去百度的路由,如果dst=None的話返回默認路由 |
conf.route.resync() | 如果網絡發生了變化,用來刷新conf.route |
venv/Lib/site-packages/scapy/arch/windows/__init__.py中,read_routes()用來獲取ipv4路由
>>> read_routes()
[(0, //dest 以十進制顯示
0, //netmask 以十進制顯示
'10.11.91.254', //nexthop
<NetworkInterface [Intel(R) Ethernet Connection (5) I219-V #2] {XXX}>, //iface
'10.11.91.161', //ip
25), //metric
(0,
0,
'25.255.255.254',
<NetworkInterface [ZeroTier One Virtual Port] {XXX}>,
'172.28.33.102',
10034),
(168516352,
4294967040,
'0.0.0.0',
<NetworkInterface [Intel(R) Ethernet Connection (5) I219-V #2] {XXX}>,
'10.11.91.161',
281)]
在venv/Lib/site-packages/scapy/route.py文件中對ipv4的route命令進行了封裝成了Route類
class Route:
def __init__(self):
self.resync()
def resync(self):
from scapy.arch import read_routes
self.invalidate_cache()
self.routes = read_routes()
>>> Route()
Network Netmask Gateway Iface Output IP Metric
0.0.0.0 0.0.0.0 10.11.91.254 Intel(R) Ethernet Connection (5) I219-V #2 10.11.91.161 25
0.0.0.0 0.0.0.0 25.255.255.254 ZeroTier One Virtual Port 172.28.33.102 10034
10.11.91.0 255.255.255.0 0.0.0.0 Intel(R) Ethernet Connection (5) I219-V #2 10.11.91.161 281
10.11.91.161 255.255.255.255 0.0.0.0 Intel(R) Ethernet Connection (5) I219-V #2 10.11.91.161 281
conf.route初始化時=Route(),如果網絡發生變化,需要手動調用conf.route.resync()刷新路由
conf.route = Route()
3.3.3 查看默認網卡
命令 | 作用 |
---|---|
conf.route.resync() | 刷新路由 |
conf.iface | conf.iface = conf.route.route(‘0.0.0.0’)[0] ,默認路由對應的網卡 |
詳解:
conf.iface被初始化爲conf.iface = iface = conf.route.route(None, verbose=0)[0],之後如果網卡發生了變化,需要手動指定
conf.route.resync() #這一步不可少,必須先刷新conf.route
conf.route.route(None, verbose=0)[0] # 從conf.route中獲取默認路由對應的接口
或者使用ifaces的dev_from_index(INDEX)方法手動指定:
>>> ifaces
INDEX IFACE IP MAC
27 Intel(R) Ethernet Connection (5) I219-V #2 10.11.91.161 XXX
22 Npcap Loopback Adapter 127.0.0.1 00:00:00:00:00:00
18 SVN Adapter V1.0 169.254.112.118 XXX
29 Microsoft Wi-Fi Direct Virtual Adapter #3 169.254.173.211 XXX
6 Microsoft Wi-Fi Direct Virtual Adapter #4 169.254.192.230 XXX
21 Bluetooth Device (Personal Area Network) #2 169.254.227.190 XXX
17 TAP-Windows Adapter V9 169.254.26.68 XXX
31 Intel(R) Dual Band Wireless-AC 8265 #2 169.254.62.191 XXX
14 ZeroTier One Virtual Port 172.28.33.102 XXX
10 VMware Virtual Ethernet Adapter for VMnet8 192.168.15.1 XXX
23 VMware Virtual Ethernet Adapter for VMnet1 192.168.220.1 XXX
-2 [Unknown] NdisWan Adapter None ff:ff:ff:ff:ff:ff
-3 [Unknown] NdisWan Adapter None ff:ff:ff:ff:ff:ff
-1 [Unknown] NdisWan Adapter None ff:ff:ff:ff:ff:ff
>>> conf.iface=ifaces.dev_from_index(27)
PS:
scapy有一個函數get_working_if()
也可以返回網卡,大多數情況下是正常的,但在有多個route的mask爲0.0.0.0時有可能返回錯誤的結果,原因是該函數調用的路由表中netmask最小的網卡,如下獲取到Zerotier虛擬網卡,原因詳見win10下scapy get_working_if()不能獲得正確的網卡原因分析
>>> Route()
Network Netmask Gateway Iface Output IP Metric
0.0.0.0 0.0.0.0 10.11.91.254 Intel(R) Ethernet Connection (5) I219-V #2 10.11.91.161 25
0.0.0.0 0.0.0.0 25.255.255.254 ZeroTier One Virtual Port 172.28.33.102 10034
10.11.91.0 255.255.255.0 0.0.0.0 Intel(R) Ethernet Connection (5) I219-V #2 10.11.91.161 281
10.11.91.161 255.255.255.255 0.0.0.0 Intel(R) Ethernet Connection (5) I219-V #2 10.11.91.161 281
>>> get_working_if()
<NetworkInterface [ZeroTier One Virtual Port] {XXX}>
def get_working_if():
try:
iface = min(conf.route.routes, key=lambda x: x[1])[3] #這裏有點問題,詳見https://blog.csdn.net/austin1000/article/details/100775993