1. 概述
1.1 scapy介绍

Scapy是一个功能强大的交互式数据包处理程序,用Python编写。它能让用户发送、嗅探、解析和伪造网络数据包,此外还可以扫描、探测、攻击和发现网络。

Python之scapy(1)基础使用-LMLPHP

根据Scapy官网的描述,它的主要特点包括:

  • 支持大量协议,可以轻松构建任意类型的数据包。
  • 强大的数据包嗅探和注入能力。
  • 可以对网络进行扫描、跟踪路由、probing、单元测试等。
  • 轻量快速,无需再编写底层代码。

Scapy的上述特性使它成为网络安全专业人士和研究人员常用的工具,可以方便地进行数据包捕获与分析、漏洞利用、IDS测试等任务。相比Wireshark等同类工具,Scapy更加灵活和可定制,用户可以通过Python脚本实现自动化的复杂任务。

该项目由Philippe Biondi发起,目前在GPL 2.0许可证下发布,支持Linux、macOS、Windows等主流平台,多年来持续活跃开发和维护,社区用户众多。

1.2 同类C/C++项目

在C/C++中,有一些库提供了类似于Scapy的功能,用于数据包的捕获、构造、发送和分析,以下是几个比较常用的库:

  • Libpcap/WinPcap,一个底层的数据包捕获库,提供了在各种操作系统上捕获网络流量的API。许多网络工具(如Wireshark)的基础,Libpcap用于Unix-like系统,而WinPcap用于Windows。

  • libtins,一个高级的C++网络数据包嗅探和制作库。封装了libpcap/WinPcap,提供了更加面向对象和易于使用的接口。libtins支持多种协议,并且可以在Linux、macOS、Windows等平台上使用。

  • Pcapplusplus,一个基于C++的多平台网络嗅探和数据包处理框架。封装了libpcap/WinPcap/DPDK等底层库,提供了简单易用的API用于捕获、构造和编辑网络数据包。

  • libcrafter,一个C++的高层网络数据包制作库,允许用户容易地创建和解码网络数据包,支持多种协议。libcrafter的目标是提供一个简单直观的接口用于快速网络数据包制作。

  • libnet,提供了构造和注入低层网络数据包的C库API。它支持多种协议,并且可以在多个Unix-like系统上使用。

这些库在功能上与Scapy有一些重叠,可以用于网络数据包的处理和分析,但是通常没有Scapy那样广泛的协议支持和高层次的交互式使用方式。

1.3 scapy优点

scapy作为Python库,使用起来非常方便,相比于GUI发包程序,可操作性更好:

  • 强大的交互式数据包处理能力,Scapy允许用户发送、嗅探、解析和伪造多种协议的网络数据包。用户可以轻松地进行扫描、traceroute、探测、单元测试、攻击或者网络发现等常见任务。它可以替代hping、arpspoof、arp-sk、arping、p0f,甚至部分替代Nmap、tcpdump和tshark的功能。

  • 灵活构建数据包,与其他网络工具不同,Scapy不局限于作者预设的固定功能,而是让用户可以灵活地构建任意类型的数据包。用户可以自由地设置每个字段的值,并按照需要堆叠协议层。Scapy采用Python语法作为数据包描述的DSL,使得描述数据包非常简洁和强大。

  • 丰富的探测信息,使用Scapy进行网络探测时,它会提供探测过程中发送的所有数据包以及收到的所有响应,而不是解释后的结果。这样用户就可以从不同角度来分析这些原始数据,挖掘出所需的信息,同一组数据可以被多次利用,而无需重新探测。

  • 解码而非解释,许多网络工具试图对收到的响应进行解释,而不是仅仅解码呈现事实,这种做法容易带来理解偏差。Scapy坚持对响应解码而不解释,给出事实,把解释的工作留给用户来做,这避免了信息的丢失。

  • 合理的默认值,Scapy为数据包字段提供了合理的默认值,用户可以不必每次都去设置。比如发送IP包时,源地址可以根据路由表自动选择,校验和会被自动计算,MAC地址会根据出口网卡选择,传输层和网络层的协议类型会根据上层协议确定。

1.4 下载和安装

根据Scapy文档的Download and Installation部分,Scapy的下载和安装流程可以总结如下:

(1) 安装Python 3.7+,scapy新版本需要再3.7以上的python版本运行,旧版本支持情况如下:

(2) 下载并安装Scapy,可以选择最新发布版本或当前开发版本,Scapy需要以root权限运行:

  • 最新发布版本可以直接用pip安装:
    $ pip install scapy
    
  • 当前开发版本需要先从GitHub克隆代码仓库,再用pip安装:
    $ git clone https://github.com/secdev/scapy.git
    $ cd scapy
    $ pip install .
    

(3) 根据平台的不同,安装一些依赖:

  • Linux,安装libpcap,确保内核选择了Packet sockets(CONFIG_PACKET)等选项。
  • Mac OS X,建议安装libpcap,可以通过Homebrew或MacPorts安装。
  • OpenBSD,建议安装libpcap。
  • Windows,需要安装Npcap。

(4) (可选)安装一些可选的依赖以启用特殊功能,主要通过pip安装:

(4.1) Matplotlib,用于绘图(plot()),下面是嗅探一段时间内的报文,并且按照报文顺序和长度关系打印图表:

>>> p=sniff(count=100)
>>> p
<Sniffed: TCP:80 UDP:5 ICMP:6 Other:9>
>>> p.plot(lambda x:len(x))
[<matplotlib.lines.Line2D at 0x181881d0c50>]

Python之scapy(1)基础使用-LMLPHP

(4.2) PyX,用于2D图形(psdump()、pdfdump()) ,以PDF格式输出(通过LaTeX实现,需要安装texlive(Unix)和MikTex(Windows)):

>>> p=sniff(count=10)
>>> p.pdfdump(filename="py-test.pdf")

可以生成数据包的十六进制和网络协议字段的对比图,如下(Windows下不要用管理员shell运行,会触发错误):

Python之scapy(1)基础使用-LMLPHP

(4.3) 生成jpg图片,需要安装GraphvizImageMagick,通过官网文档进行安装。

(4.4) 生成3D视图,需要安装VPython-Jupyter,通过pip install vpython直接安装。

(4.4) Cryptography,用于WEP解密和PKI操作等,后续再说。

(4.5) Nmap,用于指纹识别(nmap_fp())

(4.6) SoX,用于VOIP(voip_play())

(5) (可选)可以离线构建文档,包括HTML版本的文档和UML图,需要安装Sphinx和pylint等工具。

2. 使用方法
2.1 进入scapy交互界面

在scapy根目录或者PATH环境变量中含有scapy可执行文件的情况下,直接在命令行下输入以下命令:

ubuntu->~:$ scapy
                                      
                     aSPY//YASa       
             apyyyyCY//////////YCa       |
            sY//////YSpcs  scpCY//Pp     | Welcome to Scapy
 ayp ayyyyyyySCP//Pp           syY//C    | Version 2.5.0
 AYAsAYYYYYYYY///Ps              cY//S   |
         pCCCCY//p          cSSps y//Y   | https://github.com/secdev/scapy
         SPPPP///a          pP///AC//Y   |
              A//A            cyP////C   | Have fun!
              p///Ac            sC///a   |
              P////YCpc           A//A   | Craft packets before they craft
       scccccp///pSP///p          p//Y   | you.
      sY/////////y  caa           S//P   |                      -- Socrate
       cayCyayP//Ya              pY/Ya   |
        sY/PsY////YCc          aC//Yp 
         sc  sccaCY//PCypaapyCP//YSs  
                  spCPY//////YPSps    
                       ccaacs         
                                      
>>> IP()
<IP  |>
>>> _.show()
###[ IP ]### 
  version   = 4
  ihl       = None
  tos       = 0x0
  len       = None
  id        = 1
  flags     = 
  frag      = 0
  ttl       = 64
  proto     = hopopt
  chksum    = None
  src       = 127.0.0.1
  dst       = 127.0.0.1
  \options   \
2.2 构建报文

scapy构建一个报文非常容易,如下所示:

# 通过报文对应类型类实例化构建, 只填写必要参数
>>> a=IP(src="2.2.2.2", ttl=188)
>>> a
<IP  ttl=188 src=2.2.2.2 |>
# 报文字段直接通过成员来访问
>>> a.src
'2.2.2.2'
# 通过dir(a)可以查看支持的成员方法和函数
>> dir(a)
......
# 可以删除对应的成员, 字段就恢复到默认值
>>> del(a.src)
>>> a
<IP  ttl=188 |>
# 多个协议的报文可以按照如下方式拼接
>>> p = Ether()/IP()/TCP()
>>> p
<Ether  type=IPv4 |<IP  frag=0 proto=tcp |<TCP  |>>>

以下是Scapy支持的常见报文类型总结(实际支持的协议更多,无法完整列出):

Scapy有个特性被称为"层间组合"或"层间重载",允许使用 / 操作符将两个或多个层组合在一起,形成一个新的复合报文。

当使用 / 操作符组合两个层时,上层可以覆盖下层的一个或多个默认字段。这意味可以在组合层时,根据上层的信息来自动填充或修改下层的某些字段,而无需手动设置。

例如,当组合 IP 层和 TCP 层时,可以这样写:

packet = IP(dst="10.0.0.1")/TCP(dport=80)

在这个例子中,创建了一个 IP 报文,目标地址为 “10.0.0.1”,然后在其上叠加了一个 TCP 报文,目标端口为 80。这里,TCP 层的源端口字段会自动根据 IP 层的源地址进行计算和填充。

还可以在组合层时手动指定字段的值,覆盖默认的行为,例如:

packet = IP(dst="10.0.0.1")/TCP(sport=1024, dport=80)

这里,手动指定了 TCP 层的源端口为 1024,而不是使用默认的自动计算值。

除了使用 Scapy 内置的协议层,还可以使用字符串作为原始层(raw layer),原始层允许在报文中添加任意的字节序列,例如:

packet = IP(dst="10.0.0.1")/TCP(dport=80)/"GET /index.html HTTP/1.1\r\n\r\n"

在这个例子中,在 TCP 层之后添加了一个原始层,其中包含了一个 HTTP GET 请求的字节序列。

2.3 序列化和反序列化

scapy可以在字节流和报文实例类之间流畅切换,如下所示:

>>> ip = IP(src="2.2.2.2", ttl=188)
# 生成原始字节流
>>> raw(ip)
b'E\x00\x00\x14\x00\x01\x00\x00\xbc\x00{\xe4\x02\x02\x02\x02\x7f\x00\x00\x01'
# 从原始字节流生成IP报文实例
>>> IP(_)
<IP  version=4 ihl=5 tos=0x0 len=20 id=1 flags= frag=0 ttl=188 proto=ip chksum=0x7be4 src=2.2.2.2 dst=127.0.0.1 |> 

下面是一个更加复杂的实例展示:

>>> a=Ether()/IP(dst="www.slashdot.org")/TCP()/"GET /index.html HTTP/1.0 \n\n"                                            
>>> hexdump(a)
0000  6C B1 58 61 54 AA 02 11 11 11 11 11 08 00 45 00  l.XaT.........E.
0010  00 43 00 01 00 00 40 06 2D 54 C0 A8 00 66 68 12  .C....@.-T...fh.
0020  24 40 00 14 00 50 00 00 00 00 00 00 00 00 50 02  $@...P........P.
0030  20 00 70 51 00 00 47 45 54 20 2F 69 6E 64 65 78   .pQ..GET /index
0040  2E 68 74 6D 6C 20 48 54 54 50 2F 31 2E 30 20 0A  .html HTTP/1.0 .        
0050  0A                                               .                                                                  
>>> b=raw(a)
>>> b
b'l\xb1XaT\xaa\x02\x11\x11\x11\x11\x11\x08\x00E\x00\x00C\x00\x01\x00\x00@\x06-T\xc0\xa8\x00fh\x12$@\x00\x14\x00P\x00\x00\x00\x00\x00\x00\x00\x00P\x02 \x00pQ\x00\x00GET /index.html HTTP/1.0 \n\n'
>>> c=Ether(b)
>>> c
<Ether  dst=6c:b1:58:61:54:aa src=02:11:11:11:11:11 type=IPv4 |<IP  version=4 ihl=5 tos=0x0 len=67 id=1 flags= frag=0 ttl=64 proto=tcp chksum=0x2d54 src=192.168.0.102 dst=104.18.36.64 |<TCP  sport=ftp_data dport=http seq=0 ack=0 dataofs=5 reserved=0 flags=S window=8192 chksum=0x7051 urgptr=0 |<Raw  load=b'GET /index.html HTTP/1.0 \n\n' |>>>>
2.4 读取pcap文件

scapy可以非常方便的读取和写入pcap文件,如下:

>>> a=rdpcap("/spare/captures/isakmp.cap")
>>> a
<isakmp.cap: UDP:721 TCP:0 ICMP:0 Other:0>
2.5 单个报文查看命令

scapy支持以下的命令,可以方便的查看报文情况:

2.6 报文集合

scapy也可以使用范围表达式,快速构建具有指定规律的报文集合:

# 构建连续报文集合
>>> s = IP(ttl=(32,36))
>>> s
<IP  ttl=(32, 36) |>
>>> [p for p in s]
[<IP  ttl=32 |>,
 <IP  ttl=33 |>,
 <IP  ttl=34 |>,
 <IP  ttl=35 |>,
 <IP  ttl=36 |>]
#构建指定报文集合
>>> s = IP(ttl=[32,36])
>>> s
<IP  ttl=[32, 36] |>
>>> [p for p in s]
[<IP  ttl=32 |>,
 <IP  ttl=36 |>]
# 可以转换为报文列表
>>> p = PacketList(s)
>>> p
<PacketList: TCP:0 UDP:0 ICMP:0 Other:2>
>>> p.nsummary()
0000 127.0.0.1 > 127.0.0.1 ip
0001 127.0.0.1 > 127.0.0.1 ip

常见的报文列表有如下的操作方法:

2.7 报文发送方法(lsc()查看)

通过lsc可以查看scapy常见的函数方法,如下:

>>> lsc()
IPID_count            : Identify IP id values classes in a list of packets
arp_mitm              : ARP MitM: poison 2 target's ARP cache
arpcachepoison        : Poison targets' ARP cache
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.
...

下面是 Scapy 中几个常用的发包函数及其描述,这些函数可以根据不同的需求来选择使用,例如是否需要等待响应、是否在第二层发送报文等。

Scapy 的 sr 函数族是发送和接收数据包的核心功能,其中最常用的是 srsr1srp 等函数。它们可以发送数据包并接收响应,返回一个由两个列表组成的元组:第一个列表包含成功收到响应的数据包对(发送的数据包和对应的响应),第二个列表包含未收到响应的数据包。

sr 函数用于发送第三层数据包(如 IP、ARP 等),并返回所有收到的响应。sr1 函数是 sr 的变体,只返回第一个收到的响应数据包。类似地,srp 函数用于发送第二层数据包(如 Ethernet、802.3 等)。如果在超时时间内没有收到响应,相应的响应数据包将被设置为 None

这些 “send’n’receive” 函数返回的两个列表被封装在一个对象中,以提供更好的表示和一些常用的方法。通过这个对象,可以方便地访问发送的数据包、收到的响应以及未响应的数据包。

在发送数据包时,可以通过设置 inter 参数来指定两个数据包之间的发送间隔(以秒为单位),以限制发送速率。如果出现数据包丢失或发送间隔不足的情况,可以通过设置 retry 参数来重新发送未响应的数据包。例如,retry=3 表示 Scapy 将尝试重新发送未响应数据包 3 次。如果设置 retry=-3,则表示 Scapy 将不断重新发送未响应数据包,直到连续 3 次没有收到同一组未响应数据包的响应为止。timeout 参数用于指定发送完最后一个数据包后等待响应的时间。

下面是一个使用 srp 函数发送 ARP 请求的示例:

from scapy.all import *

# 构造 ARP 请求数据包
arp_request = Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(pdst="192.168.1.0/24")

# 发送 ARP 请求并接收响应
ans, unans = srp(arp_request, timeout=2, retry=2)

# 处理响应结果
for sent, received in ans:
    print(f"收到 {received.psrc} 的 ARP 响应")

print(f"未收到响应的 IP 地址:{unans.summary()}")

在这个例子中,构造了一个 ARP 请求数据包,目标地址为 “192.168.1.0/24” 网段的所有主机。然后,使用 srp 函数发送 ARP 请求并接收响应,设置超时时间为 2 秒,重试次数为 2 次。

通过遍历 ans 列表,可以获取每个收到响应的 IP 地址。同时,通过访问 unans 列表,可以获取未收到响应的 IP 地址。

2.8 模糊字段报文

Scapy 的 fuzz() 函数是一个用于对数据包进行模糊测试的强大工具。它可以自动将指定层中的默认字段值替换为随机生成的值,同时保持字段的类型和约束条件。这使得我们能够方便地构造出大量的随机测试数据包,并将其发送到目标系统,以测试其鲁棒性和安全性。

>>> a=fuzz(IP())
>>> a
<IP  |>
>>> a.show()
###[ IP ]###
  version   = <RandNum>           
  ihl       = None
  tos       = <RandByte>
  len       = None
  id        = <RandShort>
  flags     = 2
  frag      = <RandNum>
  ttl       = <RandByte>                 
  proto     = <RandByte>                 
  chksum    = None                 
  src       = 127.0.0.1
  dst       = 127.0.0.1
  \options   \

>>> a.show2()
###[ IP ]###
  version   = 4                
  ihl       = 5                
  tos       = 0x55                 
  len       = 20                 
  id        = 51216                
  flags     =
  frag      = 2557
  ttl       = 248
  proto     = 122
  chksum    = 0xf20a
  src       = 127.0.0.1
  dst       = 127.0.0.1
  \options   \

>>> a.show2()
###[ IP ]###
  version   = 4
  ihl       = 5
  tos       = 0x4f
  len       = 20
  id        = 16737
  flags     = evil
  frag      = 1849
  ttl       = 122                
  proto     = 168                
  chksum    = 0x7956
  src       = 127.0.0.1
  dst       = 127.0.0.1
  \options   \

fuzz() 函数的主要特点包括:

  1. 自动随机化指定层中的默认字段值,同时保持字段的类型和约束条件。
  2. 智能处理特殊字段,如校验和字段,确保生成的测试数据包在语法和格式上正确。
  3. 可以对数据包的特定层或字段进行部分模糊处理,灵活控制随机化的范围。
  4. 在 IP 层使用 fuzz() 函数时,源地址和目标地址字段默认不会被随机化,可以使用 RandIP() 函数来生成随机的 IP 地址。

通过合理使用 fuzz() 函数,可以快速构建大量的随机测试数据包,并全面评估目标系统的可靠性和安全性,发现潜在的漏洞和问题。

2.9 注入原始字节序列

Scapy 提供了一个名为 RawVal 的特性,用于在数据包中注入任意字节序列,而无需考虑字段的类型限制。这在开发概念验证(PoC)或测试非标准行为时非常有用。

通常,数据包中的每个字段都有特定的类型,例如 IP 数据包的长度字段 len 期望接收一个整数值。然而,在某些情况下,可能需要注入一些不符合该类型的值。这时,就可以使用 RawVal 来实现。

RawVal 允许将任意的字节序列作为字段的值,绕过 Scapy 的类型检查和自动转换机制。这样就可以灵活地构造出包含特定字节序列的数据包,用于测试目标系统对非标准或异常输入的处理能力。

使用 RawVal 非常简单,只需将目标字节序列作为参数传递给 RawVal 函数,然后将返回的对象赋值给相应的字段即可。Scapy 会将该字节序列原样插入到数据包中,不做任何类型转换或检查。

>>> pkt = IP(len=RawVal(b"NotAnInteger"), src="127.0.0.1")
>>> bytes(pkt)
b'H\x00NotAnInt\x0f\xb3er\x00\x01\x00\x00@\x00\x00\x00\x7f\x00\x00\x01\x7f\x00\x00\x01\x00\x00'
2.10 路由表配置

scapy有自己的路由表,可以自行配置路由,从将报文发送给目标接口和主机:

# 查看当前scapy路由表
>>> conf.route
Network         Netmask         Gateway         Iface
127.0.0.0       255.0.0.0       0.0.0.0         lo
192.168.8.0     255.255.255.0   0.0.0.0         eth0
0.0.0.0         0.0.0.0         192.168.8.1     eth0
# 删除路由
>>> conf.route.delt(net="0.0.0.0/0",gw="192.168.8.1")
# 添加路由
>>> conf.route.add(net="0.0.0.0/0",gw="192.168.8.254")
>>> conf.route.add(host="192.168.1.1",gw="192.168.8.1")
# 查看路由
>>> conf.route
Network         Netmask         Gateway         Iface
127.0.0.0       255.0.0.0       0.0.0.0         lo
192.168.8.0     255.255.255.0   0.0.0.0         eth0
0.0.0.0         0.0.0.0         192.168.8.254   eth0
192.168.1.1     255.255.255.255 192.168.8.1     eth0
# 重新同步路由
>>> conf.route.resync()
>>> conf.route
Network         Netmask         Gateway         Iface
127.0.0.0       255.0.0.0       0.0.0.0         lo
192.168.8.0     255.255.255.0   0.0.0.0         eth0
0.0.0.0         0.0.0.0         192.168.8.1     eth0
3. 具体使用实例
3.1 SYN扫描

通过TCP扫描80端口:

>>> sr1(IP(dst="72.14.207.99")/TCP(dport=80,flags="S"))

通过TCP扫描440~443之间的TCP端口:

>>> sr(IP(dst="192.168.1.1")/TCP(sport=666,dport=(440,443),flags="S"))

显示时,可以使用lambda表达式自定义打印,如下:

>>> ans.summary( lambda s,r: r.sprintf("%TCP.sport% \t %TCP.flags%") )
440      RA
441      RA
442      RA
https    SA

还可以制作表格打印:

>>> ans.make_table(
   lambda s,r: (s.dst, s.dport,
   r.sprintf("{TCP:%TCP.flags%}{ICMP:%IP.src% - %ICMP.type%}")))
    66.35.250.150                192.168.1.1 216.109.112.135
22  66.35.250.150 - dest-unreach RA          -
80  SA                           RA          SA
443 SA                           SA          SA

也可以使用过滤函数从大量数据中挑选关键数据:

>>> ans.filter(lambda s,r: TCP in r and r[TCP].flags&2).make_table(lambda s,r:
            (s.dst, s.dport, "X"))
    66.35.250.150 192.168.1.1 216.109.112.135
80  X             -           X
443 X             X           X
3.2 TCP traceroute路由追踪

下面是一个典型的TCP路由追踪操作:

>>> ans, unans = sr(IP(dst="baidu.com", ttl=(1,20),id=RandShort())/TCP(flags=0x2))
Begin emission:
Finished sending 20 packets.
...*...*.....*...........*...........................
Received 53 packets, got 4 answers, remaining 16 packets
>>> for snd,rcv in ans:
...:     print(snd.ttl, rcv.src, isinstance(rcv.payload, TCP))
...: 
1 192.168.0.1 False
2 192.168.1.1 False
3 100.64.0.1 False
4 39.156.27.1 False
3.3 sniff嗅探

scapy可以非常简单的去抓取报文,就像tcpdump和wireshark一样:

>>> a = sniff(filter="icmp", count=2)
>>> a
<Sniffed: TCP:0 UDP:0 ICMP:2 Other:0>
>>> a.nsummary()
0000 Ether / IP / ICMP 192.168.0.102 > 47.112.110.79 echo-request 0 / Raw
0001 Ether / IP / ICMP 47.112.110.79 > 192.168.0.102 echo-reply 0 / Raw
3.4 ACK扫描

TCP ACK扫描的原理是向目标主机的端口发送带有ACK标志的TCP数据包,通过分析目标主机的响应,可以判断端口的状态:

  • 如果收到RST响应,说明端口是关闭的。
  • 如果没有收到任何响应或收到ICMP不可达错误,说明端口可能被防火墙过滤。
  • 如果收到其他响应(如SYN/ACK),则表明端口可能处于打开状态。

使用Scapy进行TCP ACK扫描的基本步骤如下:

  • 创建一个IP数据包,目标地址为要扫描的主机。
  • 在IP数据包上叠加一个TCP数据包,设置ACK标志位,目标端口为要测试的端口。
  • 发送构造的数据包,并捕获响应。
  • 根据收到的响应判断端口状态。
from scapy.all import *

def ack_scan(host, port):
    ack_pkt = IP(dst=host)/TCP(dport=port, flags='A')
    resp = sr1(ack_pkt, timeout=1, verbose=0)
    
    if resp is None:
        print(f"{host}:{port} is filtered or silently dropped.")
    elif resp.haslayer(TCP) and resp.getlayer(TCP).flags == 0x4: 
        print(f"{host}:{port} is closed.")
    else:
        print(f"{host}:{port} is open or unfiltered.")

# 扫描192.168.1.1的80端口
ack_scan('192.168.1.1', 80)
3.5 wireshark和scapy联动

在安装了wireshark的设备上,可以直接将scapy捕捉的报文在wireshark上展示,如下:

# First, generate some packets...
>>> packets = IP(src="192.0.2.9", dst=Net("192.0.2.10/30"))/ICMP()

# Show them with Wireshark
>>> wireshark(packets)






Python之scapy(1)基础使用-LMLPHP

06-21 08:28