前言
我们在信息网络中,常通过发送与接受数据包来完成通信,今天我们来学习这些数据包是如何构造的、各类数据包有什么功能与差异?我们能利用数据包做什么?初出茅庐,如有错误望各位不吝赐教。
2.1 概念
数据包是网络通信中的基本单位,它是一段二进制数据,包含了从源到目标的传输信息。数据包通常由几个部分组成,包括头部、数据和尾部,其中头部包含了一些关键信息,如源地址、目标地址、协议类型、校验和等等。
在互联网中,数据包是通过协议栈的层次化结构传输的。在每一层次中,数据包被添加上该层次的头部信息以标识该层次的功能和需求,然后再发送到下一层。在接收端,数据包按照相同的顺序从下往上逐层解包,并按照相应的协议处理和分发。
数据包的大小通常受限于网络的带宽和MTU(最大传输单元),如果数据包太大超过了MTU,则需要进行分片,将其分解为多个较小的数据包,以便传输和重新组装。
2.2 Scapy基本用法
Scapy,目前许多优秀的网络扫描和攻击工具都使用到了这个模块。它可以实现对网络数据包的发送、监听和解析。我们先来学习一下构造所有数据包都要使用的方法:
1、创建一个数据包
在Scapy中创建一个数据包非常简单。只需要使用Packet()函数或者自定义一个继承自Packet的类:
from scapy.all import *
packet = IP(dst="8.8.8.8")/ICMP()
创建一个目的地址为“8.8.8.8”的IP数据包,并将其与ICMP数据包合并。
2、发送一个数据包
发送一个数据包可以使用send()函数:
send(packet)
发送创建的IP/ICMP数据包。
3、接收一个数据包
接收一个数据包可以使用sr()或sr1()函数。sr()函数将返回接收到的数据包列表,而sr1()函数将返回第一个接收到的数据包:
response = sr1(packet)
发送创建的IP/ICMP数据包,并返回响应数据包。
4、解析一个数据包:
解析一个数据包可以使用Python的切片操作或Scapy提供的函数来访问数据包的每个字段。例如:
print(packet[IP].dst)
这将打印IP数据包的目的地址。
修改一个数据包:
可以使用Python的切片操作或Scapy提供的函数来修改数据包的每个字段:
packet[IP].dst = "1.1.1.1"
将IP数据包的目的地址更改为“1.1.1.1”。
2.3 IP数据包
IP数据包是在互联网协议(IP)中传输数据的基本单位。它是一种在网络上进行通信的数据包,其中包含了源IP地址、目标IP地址和数据负载等信息。注意:IP数据包是通过传输控制协(TCP)或用户数据报协议(UDP)等协议在网络上进行传输的。正因如此我们就需要用到scapy中一个非常重要的概念——多层协议组合。
scapy中的分层通过符号“/”实现,如下我们构建一个设置了IP与TCP确定参数的数据包:
from scapy.all import *
# 构建IP和TCP协议层
ip_pkt = IP(src="192.168.0.1", dst="192.168.0.2")
tcp_pkt = TCP(sport=1234, dport=80)
# 组合多个协议层
pkt = ip_pkt/tcp_pkt/Raw(b"Hello, World")
# 发送数据包
send(pkt)
但要是如果不需要确定的TCP参数,还能发送IP数据包吗?当然也是可以的:
from scapy.all import *
# 创建IP数据包
ip_packet = IP(src='192.168.1.1', dst='192.168.1.2')
# 显示IP数据包头信息
print(ip_packet.show())
# 发送IP数据包
send(ip_packet)
2.4 HTTP数据包
HTTP(Hyper Text Transfer Protocol)数据包是一种用于在Web服务器和Web浏览器之间传输数据的协议。HTTP数据包由两部分组成:请求和响应。
请求由以下组成:
- 请求行:包含请求方法(GET、POST、PUT、DELETE等)、请求URI(Uniform Resource Identifier)和HTTP协议版本号。
- 请求头部:包含一些元数据,如请求的主机、语言、缓存等。
- 请求正文:包含具体的数据(如表单提交的数据、上传的文件等)。
响应由以下组成:
- 状态行:包含HTTP协议版本号、状态码和状态短语。
- 响应头部:包含一些元数据,如服务器版本、响应的类型、长度等。
- 响应正文:包含具体的数据,如HTML文档、图片等。
HTTP数据包是通过TCP/IP协议进行传输的,可以用一些抓包工具(如Wireshark)进行捕获和分析。接下来我们来学习使用scapy来构造HTTP数据包:
使用Scapy构造HTTP数据包需要以下步骤:
1、导入Scapy库
from scapy.all import *
2、构造IP和TCP数据包
ip = IP(dst="www.example.com")
tcp = TCP(dport=80, sport=RandShort())
3、构造HTTP请求数据包
http_request = "GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n"
4、将HTTP请求数据包添加到TCP负载中
pkt = ip/tcp/http_request
5、发送数据包
send(pkt)
完整代码示例:
from scapy.all import *
ip = IP(dst="www.example.com")
tcp = TCP(dport=80, sport=RandShort())
http_request = "GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n"
pkt = ip/tcp/http_request
send(pkt)
2.5 ICMP数据包
ICMP (Internet Control Message Protocol) 数据包是用于在互联网上发送错误消息和操作控制消息的协议。 ICMP 数据包通常用于网络故障排除和网络管理。它包含以下字段:
- 类型 (Type):用于标识 ICMP 数据包的类型,例如差错报告或操作控制消息。
- 代码 (Code):用于提供与类型字段相关的详细信息。
- 校验和 (Checksum):用于检测 ICMP 数据包是否损坏。
- 其他 (其他):包含与 ICMP 数据包类型和代码相关的其他信息,例如差错报告中的 IP 报头。
构造ICMP数据包的示例代码:
from scapy.all import *
icmp_packet = IP(dst="192.168.1.1")/ICMP()/"Hello World!"
send(icmp_packet)
创建一个ICMP数据包,并将其发送到目标IP地址为“192.168.1.1”的主机上。ICMP数据包中包含了一个字符串消息“Hello World!”。构造ICMP数据包的过程包括创建一个IP层和一个ICMP层,使用“/”运算符将它们连接起来,并使用send()函数将数据包发送出去。
也可以通过添加其他数据包头来构造不同类型的ICMP数据包:
icmp_packet = IP(dst="192.168.1.1")/ICMP(type=8,code=0)/Raw(load="Ping!")
这个代码片段创建了一个类型为8、代码为0的ICMP数据包,并将一个原始数据载荷添加到其中。原始数据载荷使用Raw类来表示,并使用load属性设置其内容。
在构造ICMP数据包时,还可以添加其他选项和参数:
icmp_packet = IP(dst="192.168.1.1")/ICMP(type=8,code=0)/Raw(load="Ping!")
icmp_packet.show()
这个代码片段使用show()函数来显示ICMP数据包的详细信息,包括各个字段的值和选项。可以使用这些信息来检查和调试生成的数据包。
2.6 Ether
Ether类是Scapy中的一个重要类,用于处理以太网帧(Ethernet Frame)。
下面是Ether类的一些常用属性和方法:
属性:
- dst:目的MAC地址
- src:源MAC地址
- type:以太网类型,常用类型有0x0800(IPv4)、0x0806(ARP)、0x86dd(IPv6)
方法:
- show():显示以太网帧的信息
- summary():显示以太网帧的摘要信息
- str():以字符串形式打印以太网帧的详细信息
下面是一个使用Ether类创建以太网帧的示例:
from scapy.all import *
ether = Ether(dst='00:11:22:33:44:55', src='aa:bb:cc:dd:ee:ff', type=0x0800)
packet = ether/IP(dst='192.168.1.1')/TCP(dport=80)
send(packet)
我们首先创建了一个以太网帧对象,指定目的MAC地址、源MAC地址和以太网类型,然后创建了一个IP数据包对象,指定目的IP地址和TCP端口号,最后将IP数据包封装在以太网帧中并发送。
实战训练
学了这么多,我们来综合练习一下吧,解决开头我们问到的最后一个问题:我们能利用数据包做什么?
1、监控网络流量并打印出所有数据包的源地址和目标地址:
from scapy.all import *
def print_packet(packet):
print("Source: {}, Destination: {}".format(packet[IP].src, packet[IP].dst))
sniff(prn=print_packet)
2、仅监控指定源地址或目标地址的数据包:
from scapy.all import *
def print_packet(packet):
if packet[IP].src == '192.168.1.1' or packet[IP].dst == '192.168.1.1':
print("Source: {}, Destination: {}".format(packet[IP].src, packet[IP].dst))
sniff(prn=print_packet)
3、监控所有数据包并劫持HTTP请求:
from scapy.all import *
def process_packet(packet):
if packet.haslayer(HTTPRequest):
url = packet[HTTPRequest].Host + packet[HTTPRequest].Path
print("[+] HTTP Request => " + url)
sniff(filter="port 80", prn=process_packet, store=False)
4、监控所有数据包并劫持DNS请求:
from scapy.all import *
def process_packet(packet):
if packet.haslayer(DNSQR):
query = packet[DNSQR].qname
print("[+] DNS Request => " + query)
sniff(filter="udp port 53", prn=process_packet, store=False)
就是这样!将它们综合,这里的sniff()函数进行数据包嗅探,可以指定嗅探的网卡、嗅探的数据包数量、过滤条件等参数。
以后我们将一起来制作第一款渗透工具(在将要用到的技术学习完后)让我们拭目以待吧!