使用 Scapy 构造数据包

网络安全Beginner
立即练习

简介

Scapy 是一个功能强大的交互式数据包处理程序和库,由 Python 编写。它使你能够构造或解码多种协议的数据包,将它们发送到网络上,捕获它们,并匹配请求与回复。

Scapy 的独特之处在于,它允许你在数据包构造层进行操作,而不仅仅是在套接字(socket)或应用层。这意味着你可以显式地控制报头、标志位、字段以及协议组合,而这些细节通常被普通的客户端库所隐藏。

在本实验中,你将学习使用 Scapy 进行数据包构造的基础知识。你将从导入必要的模块开始,然后逐步学习如何逐层构造 ICMP(ping)和 TCP 数据包。最后,你将发送这些自定义数据包并分析网络响应。这种实践经验将使你更深入地理解网络协议的底层工作原理,以及安全专业人员如何测试网络防御。

导入 Scapy 模块

在这一步中,你将设置 Python 环境并导入必要的 Scapy 模块。虽然 Scapy 可以作为交互式控制台使用,但编写脚本可以让你轻松保存、修改和重用你的数据包构造逻辑。

这标志着从「使用协议」到「构造协议」的转变。你不再仅仅是要求现有的应用程序为你发送流量,而是亲自定义流量应该是什么样子。

首先,确保你处于默认的工作目录中。你可以使用 pwd 命令进行验证,但你应该已经位于 ~/project 目录下。

使用 nano 文本编辑器创建一个名为 packet_crafter.py 的新 Python 文件。

nano packet_crafter.py

在该文件中,你需要导入 Scapy 库。在脚本中使用 Scapy 的标准方法是从 scapy.all 模块导入所有函数。将以下代码添加到你的脚本中:

from scapy.all import *

print("Scapy modules imported successfully.")

使用 Ctrl+O 和 Enter 保存文件。如果你想在测试前继续编写脚本,可以留在 nano 中。当你准备返回终端时,请使用 Ctrl+X。

现在,使用 Python 运行你的脚本,以确保没有语法错误且 Scapy 库加载正确。由于构造原始网络数据包需要提升权限,你必须使用 sudo 运行脚本。

sudo python3 packet_crafter.py

你应该看到类似以下的输出,表明成功:

Scapy modules imported successfully.

在某些实验环境中,Scapy 可能会在成功消息之前打印来自 matplotlib 等可选 Python 包的额外警告。只要你看到 Scapy modules imported successfully.,就可以继续下一步。

构造 ICMP 回显请求

在这一步中,你将构造一个 ICMP 回显请求(Echo Request)数据包,通常称为「ping」。网络数据包是按照 OSI 模型分层构建的。在 Scapy 中,你可以使用 / 运算符将这些层堆叠在一起。

分层是这里需要掌握的最重要的概念之一。每一层都添加了自己的字段和职责。Scapy 直接映射了该模型,这就是为什么它的语法使数据包结构更容易理解的原因。

ICMP ping 需要一个 IP 层(网络层)来指定源地址和目标地址,以及一个 ICMP 层来定义消息类型。

如果 packet_crafter.py 仍在 nano 中打开,请继续编辑它。否则,请重新打开它:

nano packet_crafter.py

将以下代码追加到脚本末尾。这段代码创建了一个指向 Google 公共 DNS 服务器(8.8.8.8)的 IP 对象,创建了一个 ICMP 对象,并将它们堆叠在一起。show() 方法将打印数据包结构的详细分解。

## Create an IP layer targeting Google's DNS
ip_layer = IP(dst="8.8.8.8")

## Create an ICMP layer (Echo Request)
icmp_layer = ICMP()

## Stack the layers to form the final packet
icmp_packet = ip_layer / icmp_layer

print("\n--- ICMP Packet Structure ---")
icmp_packet.show()

使用 Ctrl+O 和 Enter 保存文件。如果你想在运行前完成更多脚本内容,可以留在 nano 中并继续下一步。

运行你更新后的脚本,查看你刚刚构造的数据包结构。

sudo python3 packet_crafter.py

你将看到详细的输出,显示了 Scapy 自动为你填充的默认值,例如协议版本、TTL(生存时间)和 ICMP 类型。

--- ICMP Packet Structure ---
###[ IP ]###
  version   = 4
  ihl       = None
  tos       = 0x0
  len       = None
  id        = 1
  flags     =
  frag      = 0
  ttl       = 64
  proto     = icmp
  chksum    = None
  src       = 10.0.2.15
  dst       = 8.8.8.8
  \options   \
###[ ICMP ]###
     type      = echo-request
     code      = 0
     chksum    = None
     id        = 0x0
     seq       = 0x0
     unused    = ''

构造自定义 TCP SYN 数据包

在这一步中,你将构造一个 TCP SYN 数据包。这种特定类型的数据包常用于网络扫描(例如 Nmap 的隐蔽扫描),用于在不完全建立连接的情况下检查目标机器上的特定端口是否开放。

这是一个很好的例子,说明了微小的报头更改如何产生截然不同的网络行为。你没有更改目标主机或端口,只是更改了标志位和协议字段,但这些细节定义了数据包的含义以及目标将如何解释它。

与 ICMP 数据包类似,TCP 数据包需要一个底层的 IP 层。在此之上,你将添加一个 TCP 层,在其中可以指定目标端口和 TCP 标志位。S 标志代表 SYN(同步)。

如果你仍在同一个 nano 会话中,请继续编辑 packet_crafter.py。否则,请重新打开它:

nano packet_crafter.py

将以下代码追加到你的脚本中。我们将重用你在上一步中创建的 ip_layer,并在其上堆叠一个新的 TCP 层,目标端口为 80(HTTP)。

## Create a TCP layer targeting port 80 with the SYN flag
tcp_layer = TCP(dport=80, flags="S")

## Stack the IP and TCP layers
tcp_packet = ip_layer / tcp_layer

print("\n--- TCP SYN Packet Structure ---")
tcp_packet.show()

使用 Ctrl+O 和 Enter 保存文件。仅当你准备从终端运行脚本时才使用 Ctrl+X 退出,或者继续编辑并进入最后一步。

再次运行脚本以检查你新的 TCP SYN 数据包的结构。

sudo python3 packet_crafter.py

输出现在将包含 TCP 层详细信息,显示目标端口设置为 http(端口 80),标志位设置为 S。

--- TCP SYN Packet Structure ---
###[ IP ]###
  version   = 4
  ihl       = None
  tos       = 0x0
  len       = None
  id        = 1
  flags     =
  frag      = 0
  ttl       = 64
  proto     = tcp
  chksum    = None
  src       = 10.0.2.15
  dst       = 8.8.8.8
  \options   \
###[ TCP ]###
     sport     = ftp_data
     dport     = http
     seq       = 0
     ack       = 0
     dataofs   = None
     reserved  = 0
     flags     = S
     window    = 8192
     chksum    = None
     urgptr    = 0
     options   = []

发送并分析网络响应

在最后一步中,你将实际发送你构造的 ICMP 数据包,并捕获网络响应。

发送数据包完成了整个思维模型:定义层、构建数据包、传输它,然后解释回复。这与许多自定义网络测试工具背后的高层循环是一样的。

Scapy 提供了多种发送数据包的函数。sr1() 函数特别有用,因为它发送一个数据包并等待返回它收到的第一个响应。「s」代表发送(send),「r」代表接收(receive),「1」代表一个数据包。

如果你保持文件打开,请继续编辑。否则,请重新打开 packet_crafter.py:

nano packet_crafter.py

追加以下代码以发送 icmp_packet 并分析回复。我们包含了一个 timeout 参数,这样如果数据包被丢弃或阻塞,脚本就不会无限期挂起。

print("\n--- Sending ICMP Packet ---")
## Send the packet and wait for 1 response, with a timeout of 2 seconds
## verbose=0 hides the default Scapy sending output for cleaner results
response = sr1(icmp_packet, timeout=2, verbose=0)

if response:
    print(f"Response received from: {response[IP].src}")
    print("\n--- Response Packet Structure ---")
    response.show()
else:
    print("No response received. The packet might have been dropped.")

保存文件并退出编辑器。

运行你的脚本,将数据包发送到互联网,并等待 Google 的 DNS 服务器回复。

sudo python3 packet_crafter.py

如果网络允许 ICMP 请求,你将看到响应数据包的结构。注意响应中的 ICMP 类型是 echo-reply。

--- Sending ICMP Packet ---
Response received from: 8.8.8.8

--- Response Packet Structure ---
###[ IP ]###
  version   = 4
  ihl       = 5
  tos       = 0x0
  len       = 28
  id        = 0
  flags     =
  frag      = 0
  ttl       = 114
  proto     = icmp
  chksum    = 0x67d8
  src       = 8.8.8.8
  dst       = 10.0.2.15
  \options   \
###[ ICMP ]###
     type      = echo-reply
     code      = 0
     chksum    = 0xffff
     id        = 0x0
     seq       = 0x0
     unused    = ''
###[ Padding ]###
        load      = '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

总结

你学习了如何使用 Scapy 设置 Python 脚本,使用 / 运算符逐层手动构造 ICMP 和 TCP 数据包,并将这些数据包发送到网络上以分析原始响应。这些基础知识对于理解网络协议如何运行、执行安全评估以及开发自定义网络分析工具至关重要。