端口掃描之Scapy模塊的使用


Scapy

知乎:https://zhuanlan.zhihu.com/p/51002301

官方文檔:https://scapy.readthedocs.io/en/latest/introduction.html

中文文檔:https://www.cntofu.com/book/33/1.md

Scapy is a Python program that enables the user to send, sniff and dissect and forge network packets. This capability allows construction of tools that can probe, scan or attack networks.
In other words, Scapy is a powerful interactive packet manipulation program. It is able to forge or decode packets of a wide number of protocols, send them on the wire, capture them, match requests and replies, and much more. Scapy can easily handle most classical tasks like scanning, tracerouting, probing, unit tests, attacks or network discovery. It can replace hping, arpspoof, arp-sk, arping, p0f and even some parts of Nmap, tcpdump, and tshark).
Scapy also performs very well on a lot of other specific tasks that most other tools can’t handle, like sending invalid frames, injecting your own 802.11 frames, combining techniques (VLAN hopping+ARP cache poisoning, VOIP decoding on WEP encrypted channel, …), etc.

Scapy是一個強大的,用Python編寫的交互式數據包處理程序,它能讓用戶發送嗅探解析,以及偽造網絡報文,從而用來偵測掃描和向網絡發動攻擊。Scapy可以輕松地處理掃描(scanning)、路由跟蹤(tracerouting)、探測(probing)、單元測試(unit tests)、攻擊(attacks)和發現網絡(network discorvery)之類的傳統任務。它可以代替hping,arpspoof,arp-sk,arping,p0f 甚至是部分的Nmap,tcpdumptshark 的功能。

Scapy 在大多數其它工具無法完成的特定任務中也表現優異,比如發送無效幀、添加自定義的802.11的偵、多技術的結合(跳躍攻擊(VLAN hopping)+ARP緩存中毒(ARP cache poisoning)、在WEP加密信道(WEP encrypted channel)上的VOIP解碼(VOIP decoding))等等。

image-20200401165632841

Scapy的主要功能是:發送數據包接收響應數據(sending packets and receiving answers)。

一、linux下安裝

官網:https://scapy.readthedocs.io/en/latest/installation.html

pip3 install scapy

注意:

  • 數據包無法發送到 localhost(或你自己的主機上的本機 IP 地址)
  • 可能無法在 Windows 上捕獲 WLAN 流量,原因:wireshark可以嘗試關閉混合模式conf.sniff_promisc = False

二、使用

# 進入scapy
sudo scapy
scapy

進入scapy后,可以用ls()函數來查看scapy支持的網絡協議

除了ls()外,還可以用lsc()函數來查看scapy的指令集(函數)。比較常用的函數包括arpcachepoison(用於arp毒化攻擊,也叫arp欺騙攻擊),arping(用於構造一個ARP的who-has包) ,send(用於發3層報文),sendp(用於發2層報文), sniff(用於網絡嗅探,類似Wireshark和tcpdump), sr(發送+接收3層報文),srp(發送+接收2層報文)等等

還可以用使用ls()的攜帶參數模式,比如ls(IP)來查看IP包的各種默認參數

(https://img2020.cnblogs.com/blog/1461466/202006/1461466-20200602205510241-1955828266.png)

" style="zoom: 80%;" />

(一)構造數據包

1、一層數據包

>>> a=IP(ttl=1)
>>> a
<IP  ttl=1 |>

>>> a.src
'127.0.0.1'
>>> a.dst='10.1.1.10'
>>> a
<IP  ttl=1 dst=10.1.1.10 |>

>>> ls(a)
version    : BitField (4 bits)                   = 4               (4)
ihl        : BitField (4 bits)                   = None            (None)
tos        : XByteField                          = 0               (0)
len        : ShortField                          = None            (None)
id         : ShortField                          = 1               (1)
flags      : FlagsField (3 bits)                 = <Flag 0 ()>     (<Flag 0 ()>)
frag       : BitField (13 bits)                  = 0               (0)
ttl        : ByteField                           = 1               (64)
proto      : ByteEnumField                       = 0               (0)
chksum     : XShortField                         = None            (None)
src        : SourceIPField                       = '10.0.2.58'     (None)
dst        : DestIPField                         = '10.1.1.10'     (None)
options    : PacketListField                     = []              ([])

2、多層數據包

/ 操作符在兩層之間起到一個組合的作用

>>> a=IP(dst='192.168.10.1')/TCP(sport=RandShort(),dport=80)
>>> a
<IP  frag=0 proto=tcp dst=192.168.10.1 |<TCP  sport=<RandShort> dport=http |>>
>>> ls(a)
version    : BitField (4 bits)                   = 4               (4)
ihl        : BitField (4 bits)                   = None            (None)
tos        : XByteField                          = 0               (0)
len        : ShortField                          = None            (None)
id         : ShortField                          = 1               (1)
flags      : FlagsField (3 bits)                 = <Flag 0 ()>     (<Flag 0 ()>)
frag       : BitField (13 bits)                  = 0               (0)
ttl        : ByteField                           = 64              (64)
proto      : ByteEnumField                       = 6               (0)
chksum     : XShortField                         = None            (None)
src        : SourceIPField                       = '10.0.2.58'     (None)
dst        : DestIPField                         = '192.168.10.1'  (None)
options    : PacketListField                     = []              ([])
--
sport      : ShortEnumField                      = <RandShort>     (20)
dport      : ShortEnumField                      = 80              (80)
seq        : IntField                            = 0               (0)
ack        : IntField                            = 0               (0)
dataofs    : BitField (4 bits)                   = None            (None)
reserved   : BitField (3 bits)                   = 0               (0)
flags      : FlagsField (9 bits)                 = <Flag 2 (S)>    (<Flag 2 (S)>)
window     : ShortField                          = 8192            (8192)
chksum     : XShortField                         = None            (None)
urgptr     : ShortField                          = 0               (0)
options    : TCPOptionsField                     = []              (b'')

>>> IP()
<IP |>
>>> IP()/TCP()
<IP frag=0 proto=TCP |<TCP |>>
>>> Ether()/IP()/TCP()
<Ether type=0x800 |<IP frag=0 proto=TCP |<TCP |>>>
>>> IP()/TCP()/"GET / HTTP/1.0\r\n\r\n"
<IP frag=0 proto=TCP |<TCP |<Raw load='GET / HTTP/1.0\r\n\r\n' |>>>
>>> Ether()/IP()/IP()/UDP()
<Ether type=0x800 |<IP frag=0 proto=IP |<IP frag=0 proto=UDP |<UDP |>>>>
>>> IP(proto=55)/TCP()
<IP frag=0 proto=55 |<TCP |>>
命令 效果
str(pkt) 組裝數據包
hexdump(pkt) 十六進制轉儲
ls(pkt) 顯示出字段值的列表
pkt.summary() 一行摘要
pkt.show() 針對數據包的展開視圖
pkt.show2() 顯示聚合的數據包(例如,計算好了校驗和)
pkt.sprintf() 用數據包字段填充格式字符串
pkt.decode_payload_as() 改變payload的decode方式
pkt.psdump() 繪制一個解釋說明的PostScript圖表
pkt.pdfdump() 繪制一個解釋說明的PDF
pkt.command() 返回可以生成數據包的Scapy命令

3、一組數據包

傳入的是數據段,就會生成一組數據包

>>> a=IP(dst="www.slashdot.org/30")    # 該網段中的子網的ip,4個
>>> [i for i in a]
[<IP  dst=216.105.38.12 |>, <IP  dst=216.105.38.13 |>, <IP  dst=216.105.38.14 |>, <IP  dst=216.105.38.15 |>]
>>> b=TCP(dport=[3,(600,610)])     # (a, b)表示從a到b范圍內所有數據
>>> [i for i in b]
[<TCP  dport=3 |>, <TCP  dport=600 |>, <TCP  dport=601 |>, <TCP  dport=602 |>, <TCP  dport=603 |>, <TCP  dport=604 |>, <TCP  dport=605 |>, <TCP  dport=606 |>, <TCP  dport=nqs |>, <TCP  dport=608 |>, <TCP  dport=609 |>, <TCP  dport=npmp_local |>]

>>> c= IP(dst="www.slashdot.org/30")/TCP(dport=[3,(600,603)])
>>> [i for i in c]
[<IP  frag=0 proto=tcp dst=216.105.38.12 |<TCP  dport=3 |>>, <IP  frag=0 proto=tcp dst=216.105.38.12 |<TCP  dport=600 |>>, <IP  frag=0 proto=tcp dst=216.105.38.12 |<TCP  dport=601 |>>, <IP  frag=0 proto=tcp dst=216.105.38.12 |<TCP  dport=602 |>>, <IP  frag=0 proto=tcp dst=216.105.38.12 |<TCP  dport=603 |>>, <IP  frag=0 proto=tcp dst=216.105.38.13 |<TCP  dport=3 |>>, <IP  frag=0 proto=tcp dst=216.105.38.13 |<TCP  dport=600 |>>, <IP  frag=0 proto=tcp dst=216.105.38.13 |<TCP  dport=601 |>>, <IP  frag=0 proto=tcp dst=216.105.38.13 |<TCP  dport=602 |>>, <IP  frag=0 proto=tcp dst=216.105.38.13 |<TCP  dport=603 |>>, <IP  frag=0 proto=tcp dst=216.105.38.14 |<TCP  dport=3 |>>, <IP  frag=0 proto=tcp dst=216.105.38.14 |<TCP  dport=600 |>>, <IP  frag=0 proto=tcp dst=216.105.38.14 |<TCP  dport=601 |>>, <IP  frag=0 proto=tcp dst=216.105.38.14 |<TCP  dport=602 |>>, <IP  frag=0 proto=tcp dst=216.105.38.14 |<TCP  dport=603 |>>, <IP  frag=0 proto=tcp dst=216.105.38.15 |<TCP  dport=3 |>>, <IP  frag=0 proto=tcp dst=216.105.38.15 |<TCP  dport=600 |>>, <IP  frag=0 proto=tcp dst=216.105.38.15 |<TCP  dport=601 |>>, <IP  frag=0 proto=tcp dst=216.105.38.15 |<TCP  dport=602 |>>, <IP  frag=0 proto=tcp dst=216.105.38.15 |<TCP  dport=603 |>>]  #len()=4*5=20

命令 效果
summary() 顯示一個關於每個數據包的摘要列表
nsummary() 同上,但規定了數據包數量
conversations() 顯示一個會話圖表
show() 顯示首選表示(通常用nsummary())
filter() 返回一個lambda過濾后的數據包列表
hexdump() 返回所有數據包的一個hexdump
hexraw() 返回所以數據包Raw layer的hexdump
padding() 返回一個帶填充的數據包的hexdump
nzpadding() 返回一個具有非零填充的數據包的hexdump
plot() 規划一個應用到數據包列表的lambda函數
make table() 根據lambda函數來顯示表格

(二)發送數據包

1、send——發送IP報文

構造IP報文

ip = IP(dst='120.78.120.251')

查看IP報文

ls(ip)        # ip的src變為本機,dst變為120.78.120.251

.png)

發送報文

send(ip,iface=80)

2、sendp——發送ARP報文

send(),sendp()函數,兩者的區別是前者是發送三層報文,后者則是發送二層報文

用sendp()配合Ether()和arp()函數來構造一個ARP報文

sendp(Ether(dst='ff:ff:ff:ff:ff:ff') / ARP(hwsrc = '00:0c:29:72:b2:b5', psrc = '192.168.2.1', hwdst = 'ff:ff:ff:ff:ff:ff', pdst = '120.78.120.251') / 'abc', iface='80')
# 這里我們構造了一個源MAC地址為00:0c:29:72:b2:b5, 源IP地址為192.168.2.1, 目標MAC地址為ff:ff:ff:ff:ff:ff,目標IP地址為120.78.120.251,payload為abc的ARP報文

3、sr——發送接收3層報文

  • send()和sendp()函數只能發送報文,而不能接收返回的報文

  • 查看返回的3層報文,需要用到sr()函數

用sr()向S1發一個ICMP包,可以看到返回的結果是一個tuple(元組),該元組里的元素是兩個列表,其中一個列表叫Results(響應),另一個叫Unanswered(未響應)。

sr(IP(dst = '192.168.2.11') / ICMP())
  • 如果向一個不存在的IP,由於沒有響應,所以你能看到Unanswered后面的ICMP:顯示了1

  • 使用兩個變量接收返回的元組

ans, unans = sr(IP(dst = '192.168.2.11') / ICMP())

for sent,received in ans:
    if received.haslayer(TCP) and str(received[TCP].flags) == "SA":
        pass

  • 用show(), summary(), nsummary()等方法來查看ans的內容
ans.show()
ans.summary()
ans.nsummary()
  • 查看更多ans信息,ans實為一個SndRcvList列表
ans[0]     # (send數據包, recv數據包)
  • 可以看到ans[0]本身又是一個包含了兩個元素的元組,我們可以繼續用ans[0][0]和ans[0][1]查看這兩個元素
ans[0][0]
ans[0][1]    # sr1的返回值,recv數據包

4、sr1——發送接收3層報文

sr1sr的一種變體,返回的是應答(ans[0][1])數據包,即sr返回值中接收的數據包

srcport = RandShort()
received = sr1(IP(dst = target)/TCP(sport=srcport, dport = port, flags = "S"), timeout=1) # Send SYN and recieve RST-ACK or SYN-ACK

# received ==> ans[0][1]

if str(received.getlayer(TCP).flags)=="SA":
    pass

5、srp——發送接收2層報文

6、tcp——發送接收4層TCP SYN報文

  • 在scapy上使用ip()和tcp()函數來構造一個目的地IP為192.168.2.11,源端口(sport)為30,目的端口(dport)為80的TCP SYN報文
ans, unans = sr(IP(dst = "192.168.2.11") / TCP(sport = 30, dport = 80, flags = "S"))
  • TCP端口號除了手動指定外,還可以使用RandShort(), RandNum()Fuzz()這幾個函數來自動生成一個隨機的端口號

    • 隨機生成一個1-65535之間的端口號,

      ans, unans = sr(IP(dst = "192.168.2.11") / TCP(sport = RandShort(), dport = 80, flags = "S"))

    • 在指定范圍內自動生成一個端口號,RandNum(100-50000)

      ans, unans = sr(IP(dst = "192.168.2.11") / TCP(sport = RandNum(100-50000), dport = 80, flags = "S"))

    • Fuzz()檢查sport是否漏寫,漏寫會自動生成一個sport

      ans, unans = sr(IP(dst = "192.168.2.11") / fuzz(TCP(dport = 80, flags = "S"))

三、TCP SYN掃描

當發送端的TCP SYN包發出后,大致會有下面四種情況發生:

  • 目的端口在接收端打開,收到SYN包的接收端回復SYN/ACK包給發送端,收到SYN/ACK包的發送端此時知道目的端口是打開的(open)。
  • 目的端口在接收端被關閉,收到SYN包的接收端回復RST包給發送端,告知發送端該目的端口已經被關閉了(closed)。
  • 如果發送端和接收端之間有防火牆或者使用ACL進行包過濾的路由器,那么SYN包在到達接收端之前就被防火牆或路由器攔截下來,此時防火牆或路由器會回復一個類型3(Unreachable,不可達)的ICMP包(注意不再是TCP包)給發送端告知該目的端口已經被過濾了(filtered)。
  • 如果ICMP在防火牆或路由器上被關閉了,這時SYN包會被防火牆、路由器"靜悄悄"地丟棄,路由器和防火牆不會發送類型3的ICMP包告知發送端。此時發送端收不到任何回應(no response),這里我們同樣可以判斷該目的端口已經被過濾了(filtered)。

端口掃描方式及代碼實現

四、Sniff

[wireshark BPF過濾規則](/home/up/文檔/markdown文檔/wireshark BPF過濾規則.md)

sniff(filter="tcp port 80 and src host 192.168.88.3",iface="any", prn=function, count=N)

# filter
指定scapy嗅探的數據包,一個 BPF(wireshark類型)的過濾器,空表示嗅探所有數據包

# iface
設置所需要嗅探的網卡,留空嗅探所有網卡

# prn
指定嗅探到符合過濾器條件的數據包時所調用的回調函數,這個回調函數以接受到的數據包對象作為唯一的參數。

# count
指定嗅探的數據包的個數,留空則默認為嗅探無限個
>>> lsc()
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


免責聲明!

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



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