Python渗透测试——一、数据包的编辑工具——Scapy

Python渗透测试——一、数据包的编辑工具——Scapy本文介绍了 Scapy 库在数据包构造 分层结构 常用函数 如发送 接收 抓包 以及伯克利包过滤技术的应用 帮助读者理解如何在 Python 中操作网络数据包并进行网络测试和分析

大家好,欢迎来到IT知识分享网。

一、Scapy简介

提到数据包(这里泛指帧、段和报文等)的构造,我们首先需要了解协议和分层这两个概念。在“互联世界的规则一协议”中,我们提到了协议的概念,简单来说协议就是通信时所有参与者必须遵守的规则集合。这些协议各司其职、各尽其能,它们的不同主要体现在产生的数据包的顺序与格式上。

二、Scapy中的分层结构

首先我们先用几个实例来演示 Scapy 的用法。Scapy 使用了“类+属性”的方法来构造数据包,在 Scapy 中每一个网络协议就是一个类,协议中的字段就对应着属性。只需要实例化一个协议类,就可以创建一个该协议类型的数据包。例如我们要构造一个 IP 数据包,可以使用如下方式。

IP() 

如果要使用 IP 的话,那么首先需要导人 Scapy 库。考虑到目标模块中的属性非常多,反复输人 Scapy 很不方便,这里我们选择“from 模块 import 类”的形式导人,下面给出了一个使用Scapy构造IP 数据包的演示程序

from scapy.all import IP pkt=IP() print(pkt) 

在这里插入图片描述

ip=IP(dst="192.168.217.150") 
from scapy.all import IP,ls pkt=IP() ls (pkt) 
Ether(dst="ff:ff:ff:ff:ff:ff") 

分层是通过符号“/”实现的。如果一个数据包是由多层协议组合而成的,那么这些协议之间就可以使用“/”分开,并按照协议由底而上的顺序从左向右排列。例如我们可以使用Ether()/IP()/TCP()来构造一个TCP数据包。

from scapy.all import pkt=Ether()/IP()/TCP() ls(pkt) 

在这里插入图片描述
在这里插入图片描述
这个程序由于需要导入的模块比较多,因此使用了“import *”。在执行这个程序之后,可以看到我们构造了一个包含 Ether、IP 和TCP 这3 种协议的数据包。
如果要构造一个HTTP 数据包,也可以使用以下这种方法。
在这里插入图片描述



三、Scapy中的常用函数

pkt=IP(src="192.168.1.1",dst="192.168.1.101",ttl=32) 

在这里插入图片描述
刚开始不熟悉 Scapy 有哪些功能的时候,大家可以使用 lsc()函数列出所有可以使用的函数,下面给出了一些经常使用的函数及其使用方法。首先我们使用 pkt=IP()来构造一个数据包然后利用这个 pkt 来演示各种函数。

  • raw()函数表示以字节格式来显示数据包内容。例如我们如果要查看 pkt,就可以使用 print(raw(pkt))。
  • hexdump()函数表示以十六进制数据表示的数据包内容给出了print(hexdump(pkt))的执行结果。
  • summary()函数使用不超过一行的摘要内容来简单描述数据包,pkt.summary()让使用者可以简单明了地知晓数据包的内容。
  • show()函数使用展开视图的方式显示数据包的详细信息,是一种比较常用的方法,使用者可以快速看到每一个属性的值,给出了 pkt,show()的执行结果。
  • show2()函数的作用与 show()的基本相同,区别在于使用 pkt.show2()时会显示数据包的校验和。

如果我们看到了一个数据包,但是不知道如何使用命令来产生相同的数据包时,就可以使用command()函数,它可以显示出构造该数据包的命令。例的就是用 pkt.command()还原 pkt 的构造命令。

有时使用 Scapy 会捕获到大量的数据包,这些数据包需要保存起来,例如在网络取证时就会经常这么做,这时 wrpcap()函数就可以完成这个工作。例如我们在程序中将很多数据包都临时存储在 pkts 中,使用wrpcap("temp.cap",pkts)就可以将pkts 中的数据包写入文件 temp.cap。

同样 Scapy 也提供了读取数据包文件的功能,rdpcap()函数就可以实现这个功能,例如使用pkts =rdpcap("temp.cap")读取 temp.cap文件中的数据包。

四、在Scapy 中发送和接收数据包

除了这些对应着协议的类和它们的属性之外,我们还需要一些可以实现各种功能的函数需要注意的一点是,刚才我们使用 IP()的作用是产生了一个 IP 数据包,但是并没有将其发送出去,因此现在首先需要将产生的数据包发送出去。Scapy 提供了多个用来发送数据包的函数先来看其中的 send()函数和 sendp()函数。这两个函数的区别在于 send()数是用来发送IP数据包的,而sendp()函数是用来发送 Ether 数据包的。我们先来构造一个目标地址为 192.168.1.1的ICMP 数据包,并将其发送出去,可以使用如下程序。

from scapy.all import * pkt=IP(dst="192.168.217.150")/ICMP() send(pkt) 

在这里插入图片描述
在这里插入图片描述
注意,如果这个数据包发送成功,那么下方会有一个“Sent 1 packets”的显示。sendp()函数的使用方法是相同的,下面给出了一个实例。

sendp(Ether(dst="ff:ff:ff:ff:ff:ff")) 

简单来说,当你需要将 MAC 地址作为目标时,就使用 sendp()函数;而当你需要将IP 地址作为目标时,就使用 send()函数。这两个函数的特点是只发不收,也就是说只会将数据包发送出去,但是不会处理该数据包的应答数据包。

在网络的各种应用中,我们需要做的不仅要将创建好的数据包发送出去,也要接收这些数据包的应答数据包,这一点在网络扫描中尤为重要。Scapy 提供了 3 个用来发送和接收数据包的丽数,分别是 sr()函数、sr1()函数和 srp()函数,其中 sr()函数和 sr1()函数主要用于 IP 地址,而srp()丽数用于MAC地址。

这里我们仍然向192.168.217.150发送一个ICMP 数据来了解 sr()函数的使用方法需要注意的是,这里 192.168.217.150 应该是一个可以 ping通的地址。

当产生的数据包被发送出去之后,Scapy 就会监听接收到的数据包,将其中对应的应答数据包筛选出来并显示。为 Reveived 表示收到的数据包个数,answers 表示对应此次发送数据包的应答数据包。

sr()函数是 Scapy 的核心,它的返回值是两个列表,第一个列表包含收到了应答的数据包和对应的应答数据包,第二个列表包含未收到应答的数据包。所以可以使用两个列表来保存sr()函数的返回值。

from scapy.all import * pkt=IP(dst="192.168.217.150")/ICMP() ans,uans=sr(pkt) ans.summary() 

在这里插入图片描述
在这里插入图片描述
这里我们使用ans列表和 uans列表来保存sr()函数的返回值。因为发送出去的是一个ICMP数据包,而且收到了一个应答数据包,所以这个发送的数据包和收到的应答数据包都被保存到了ans列表中使用ans.summary0可以查看两个数据包的内容。unans列表为空。为ans中保存的应答数据包。

srl()雨数跟 sr()丽数作用基本一样,但是只返回一个应答数据包,只需要使用一个列表可以保存这个雨数的返回值。srp()丽数与 srl()函数和 sr()函数的区别在于发送时要使用 MAC地址。

五、Scapy 中的抓包函数

另外,一个十分重要的函数是 snim0。如果你使用过 Tcpdump,那么对这个函数就不会感到陌生。使用这个函数就可以在自己的程序中捕获经过本机网卡的数据包了。

sniff() 

这个函数完整的格式为sniff(filter="",iface="any”,prn=function,count=N)。第1个参数是filter,可以用来对数据包进行过滤。例如我们指定只捕获与 192.168.217.150有关的数据包,就可以使用host 192.168.217.150″

sniff(filter="host 192.168.1.1") 

但是这种仅依靠IP地址来过滤的方法有很大的局限性,下面我们介绍一种功能更加完善的方法。1993年史蒂文·麦卡内(Steven McCanne)与范·雅各布森( Van Jacobson)在USENIX93会议上提出了一种机制一伯克利包过滤(Berkeley Packet Filter,BPF)它采用了一种与自然语言很接近的语法,利用这种语法构成的字符串可以确定保留哪些数据包以及忽略哪些数据包。

这种语法很容易理解。例如最简单的空字符串,表示的就是匹配所有数据包,也就是保留所有的数据包。如果这个字符串不为空,那么只有那些使字符串表达式值为“真”的数据包才会被保留。这种字符串通常由一个或者多个原语所组成,每个原语又由一个标识符(名称或者数字)组成,后面跟着一个或者多个限定符。

伯克利包过滤中的限定符有下面3种:

  • Type:这种限定符表示指代的对象,例如 IP 地址子网或者端口等。常见的有 host(用来表示主机名和 IP 地址)、net(用来表示子网)、port(用来表示端口)。如果没有指定,默认为 host。
  • Dir:这种限定符表示数据包传输的方向,常见的有 src(源地址)和 dst(目的地)如果没有指定,则默认为“src or dst”。例如 192.168.217.151表示的就是匹配源地址或者目标地址为 192.168.217.150的数据包。
  • Proto:这种限定符表示与数据包匹配的协议类型,常见的就是 Ether、IP、TCP、ARP这些协议。
  • host 192.168.1.1:当数据包的目标地址或者源地址为 192.168.1.1 时,过滤语句为真。
  • dst host 192.168.1.1:当数据包的目标地址为 192.168.1.1时,过滤语句为真
  • src host 192.168.1.1:当数据包的源地址为 192.168.1.1 时,过滤语句为真。
  • ether host 11:22:33:44:55:66:当数据包的以太网源地址或者目标地址为 11:22:33:44:55:66时,过滤语句为真。
  • ether dst 11:22:33:44:55:66:当数据包的以太网目标地址为 11:22:33:44:55:66 时,过语句为真。
  • ether src 11:22:33:44:55:66:当数据的以太网源地址为11:22:33:44:55:66 时过滤语句为真
  • dst net 192.168.1.0/24:当数据包的IP4/IPv6 的目标地址的网络号为192.168.1.0/24时过滤语句为真。
  • src net 192.168.1.0/24:当数据包的IPV4/IPv6 的源地址的网络号为/24时过滤语句为真。
  • net 192.168.1.0/24:当数据包的IPV4/IPV6 的源地址或目标地址的网络号为192.168.1.0/24时,过滤语句为真。
  • dst port 8080:当数据是TCP 或者UDP 数据包且目标端口号为8080时过滤语为真。
  • src port 8080:当数据包是TCP 或者UDP 数据包且源端口号为 8080 时,过滤语句为真。
  • port 8080:当数据包的源端口或者目标端口为 8080 时,过滤语句为真。所有的 port前面都可以加上关键字TCP或者UDP。
sniff(filter="icmp", prn=lambda x:x.summary()) 

如果这个函数比较长,也可以定义成回调函数。这个回调函数以接收到的数据包对象作为唯一的参数,最后再调用 sniff()函数。

def packet_callback(pkt): print (pkt,summary) sniff(prn=packet.callback) 

第4个参数 count 用来指定监听到数据包的数量,达到指定的数量就会停止监听。例如我们只希望监听到 10 个数据包就停止。

sniff(count=10) 

我们来设计一个综合性的监听器,它会在网卡 eth0 上监听源地址或者目标地址为 192.168.1.1 的1CMP 数据包并输出,当收到了3个这样的数据包之后,就会停止监听。建的监听器如下:

sniff(filter="icmp and host 192,168,1,1",prn=lambda x:x,summary(),count=3) 

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/121962.html

(0)
上一篇 2025-10-20 12:26
下一篇 2025-10-20 12:45

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信