ab网络应用层
命令行构造
构建二层包
注意这里的MAC_ADDRESS,如果IP不在局域网内,填网关ip,如果在局域网内,直接填写网关
packet_2 = Ether(dst="${MAC_ADDRESS}") / IP(dst="${IP}") / ICMP(id=0x1,seq=0x2)
使用sendp(packet_2)发送
构建三层包
构建命令
packet_3 = IP(dst="${IP}") / ICMP(id=0x1,seq=0x2)
使用sr(packet_3)发送
程序构建
二层包
packet_2.py
from scapy.all import *
packet_2 = Ether(dst="${MAC_ADDRESS}") / IP(dst="${IP}") / ICMP(id=0x1,seq=0x2)
sendp(packet_2)
三层包
from scapy.all import *
packet_3 = IP(dst="${IP}") / ICMP(id=0x1,seq=0x2)
sr(packet_3)
完整TCP三次握手+HTTP请求
TCP三次握手原理解释
源IP 源端口 目标IP 目标端口
sourceIP sou PORT des IP des PORT
A浏览器 Bweb服务器
A-IP 随机端口 B-IP 80 syn(问) flags=S 直接构造会收到SA回包
B-IP 80 A-IP 随机端口 ACK(答)+SYN flags=SA 直接构造会收到RST回包
A-IP 随机端口 B-IP 80 ack flags=A 直接构造会收到RST回包
A-IP 随机端口 B-IP 80 TCP(HTTP REQUEST)
B-IP 80 A-IP 随机端口 TCP (HTTP REPLY)
三次握手过程
客户端 → 服务器 :发送 SYN 包
→ 表示请求建立连接
→ 携带:SYN=1, seq=x (x 是客户端随机初始化的序列号)
服务器 → 客户端 :发送 SYN-ACK 包
→ 表示同意建立连接
→ 携带:SYN=1, ACK=1, seq=y (服务端也生成自己的随机 seq),ack=x+1(确认客户端的 seq)
客户端 → 服务器 :发送 ACK 包
→ 表示确认收到了服务端的 SYN-ACK
→ 携带:ACK=1, seq=x+1, ack=y+1
代码如下
from scapy.all import * # 导入Scapy网络包处理库
import random # 导入随机数生成模块
target_ip = "47.117.47.208" # 设置目标服务器IP地址
target_port = 80 # 设置HTTP服务默认端口
source_port = random.randint(1024, 65535) # 随机生成客户端源端口
ip = IP(dst=target_ip) # 创建IP层数据包,目标地址为target_ip
syn = ip / TCP(sport=source_port, dport=target_port, flags="S", seq=1000) # 构造SYN包,flags="S"表示SYN标志,seq设置初始序列号
syn_ack = sr1(syn, timeout=2, verbose=0) # 发送SYN包并等待响应,timeout设置2秒超时,verbose=0关闭输出
server_seq = syn_ack[TCP].seq # 从服务端响应包中提取序列号
server_ack = syn_ack[TCP].ack # 从服务端响应包中提取确认号
ack = ip / TCP(sport=source_port, dport=target_port, flags="A", seq=server_ack, ack=server_seq + 1) # 构造ACK包,确认服务端序列号+1
send(ack, verbose=0) # 发送ACK包完成三次握手
http_get = "GET / HTTP/1.1\r\nHost: example.com\r\nConnection: close\r\n\r\n" # 构造HTTP GET请求
http_payload = raw(http_get.encode("UTF-8")) # 将HTTP请求编码为字节流
get_request = ip / TCP(sport=source_port, dport=target_port, flags="PA", seq=server_ack, ack=server_seq + 1) / http_payload # 构造带PSH+ACK标志的HTTP请求包
response = sr1(get_request, timeout=5, verbose=0) # 发送HTTP请求并等待响应
丢弃RST命令:sudo iptables -A OUTPUT -p tcp --tcp-flags RST RST -j DROP
UDP构造
rom scapy.all import *
# 指定目标mac,目标ip,udp源端口和目的端口,如果是外网,mac改成网关mac
packet = Ether(dst="00:0c:29:4b:f2:6b") / IP(dst="192.168.17.128") / UDP(sport=1029,dport=1030,checksum=0x0)
packet.show()
# 发送
srp1(packet)
老师的查询DNS服务器
from scapy.all import *
import random
# 1.目标 DNS 服务器
dns_server = "114.114.114.114"
dns_port = 53 # DNS 服务默认端口
# 2.要查询的域名
domain = "www.baidu.com"
# 3.随机源端口(DNS 客户端端口通常是随机的)
src_port = random.randint(1024, 65535)
# 4. 构造 DNS 查询包(核心,如果单独写domain,注意修改为具体网址)
dns_query = IP(dst=dns_server) /UDP(sport=src_port, dport=dns_port) / DNS(rd=1,qd=DNSQR(qname=domain, qtype="A"))
#rd=1 表示希望 DNS 服务器进行递归查询(Recursive)
#qtype="A" 表示查询 A 记录(IPv4 地址)
#qname="www.baidu.com" 是要解析的域名
#5.发送 DNS 查询并等待响应(超时设为 5 秒)(核心)
dns_query.show()
print(f"[*] 正在向 DNS 服务器 {dns_server} 查询域名:{domain} …")
response = sr1(dns_query, timeout=5, verbose=0)
#6. 处理响应
if response:
if response.haslayer(DNS):
dns_layer = response.getlayer(DNS)
if dns_layer and dns_layer.an: # dns_layer.an 是 Answer Section
for answer in dns_layer.an:
if answer.type == 1: # type=1 表示 A 记录(IPv4)
ip = answer.rdata
print(f"[+] 域名 {domain} 的 IP 地址是:{ip}")
else:
print("[-] 响应中未找到有效的 DNS Answer 记录")
else:
print("[-] 收到响应,但不是 DNS 响应")
else:
print("[-] 未收到 DNS 服务器的响应(可能超时、被阻、或 DNS 服务器无响应)")
核心这两句
# dns_query = IP(dst=dns_server) /UDP(sport=src_port, dport=dns_port) / DNS(rd=1,qd=DNSQR(qname=domain, qtype="A"))
#response = sr1(dns_query, timeout=5, verbose=0)
反向解析PTR
from scapy.all import *
# 1. 请求 www.baidu.com 的 A 记录(正向解析)
A_query="www.baidu.com"
dns_a_query = (
IP(dst="114.114.114.114") /
UDP(sport=RandShort(), dport=53) /
DNS(rd=1, qd=DNSQR(qname=A_query, qtype="A"))
)
print("\n===DNS A记录请求包为: "+str(A_query))
dns_a_query.show()
# 2. 请求 PTR 记录(反向解析)
# 反向解析需要将 IP 转换为 in-addr.arpa 格式,也就是转向
ip_reversed = "180.101.51.73".split('.')[::-1]
ptr_name = ".".join(ip_reversed) + ".in-addr.arpa"
dns_ptr_query = (
IP(dst="114.114.114.114") /
UDP(sport=RandShort(), dport=53) /
DNS(rd=1, qd=DNSQR(qname=ptr_name, qtype="PTR"))
)
print("\n=== DNS PTR记录请求: "+str(ptr_name))
dns_ptr_query.show()
# 3.第一步A请求的回应
print("第一步A请求的回应为")
a_response = sr1(dns_a_query, timeout=3, verbose=0)
if a_response:
a_response.show()
# 4.第二步PTR请求的回应
print("第二步PTR请求的回应为")
ptr_response = sr1(dns_ptr_query, timeout=3, verbose=0)
if ptr_response:
ptr_response.show()
RIP
VRRP
- (简答题) A 计算机VRID 学号 VRRP虚拟IP地址为192.168.100.学号,构造eth/ip/vrrp包,目标地址和MAC地址设置正确,B计算机收到并提示
这里虚拟MAC最后两位16进制是VRID的数值回家处理
10.1广播通告其他路由器,192.168.10.0是我的直连网段
RIP目标地址有2种,如果用RIP V1,不需要mask值,无子网掩码,目标地址就是255.255.255.255,广播方式通信
如果用RIP V2,需要mask值,无子网掩码,目标地址就是224.0.0.9,组播方式通信,
A发RIP包
V1:
send(IP(dst="255.255.255.0")/UDP(dport=520)/RIP(cmd=2,version=1)/RIPEntry(ip="192.168.1.0",metric=1))
V2:
send(IP(dst="224.0.0.9")/UDP(dport=520)/RIP(cmd=2,version=2)/RIPEntry(ip="192.168.1.0",mask="255.255.255.0",metric=1))
B收RIP包
sniff(filter="udp port 520", prn=lambda p: p.show() if p.haslayer(RIP) else None, store=0)
sniff 这是 Scapy 的抓包函数,用于监听网络数据包。
filter="udp port 520"过滤520UDP端口
prn=lambda p: p.show() if p.haslayer(RIP) else None, 打印RIP数据内容
store=0不存储
一、实验目的
掌握 VRRP(Virtual Router Redundancy Protocol)协议的基本原理;
使用 Scapy 构造并发送 VRRP 报文;
模拟主备路由器之间的 VRRP 通告与监听过程;
理解 VRRP 在高可用网关中的作用。
二、VRRP 协议简介
VRRP 是一种容错协议,用于在多个路由器之间提供虚拟网关冗余。当主路由器故障时,备份路由器可自动接管,保障网络连通性。
关键特性
项目 说明
协议号 IP 协议号 112
组播地址 IP: 224.0.0.18
虚拟 MAC 00:00:5E:00:01:XX(XX = VRID 十六进制)
默认通告间隔 1 秒
优先级范围 0~255(255 = Master,0 = 释放主控)
网络拓扑:两台主机 A、B 处于同一局域网
四、实验步骤
4.1 A 机:模拟主路由器(Master)
定期发送 VRRP Advertisement 报文。
vrrp_master.py
from scapy.all import *
import time
vip = "192.168.100.17"
vrid = 17
vrrp = VRRP(
version=2,
vrid=vrid,
priority=255, # Master
ipcount=1,
authtype=0,
adv=1,
addrlist=[vip]
)
pkt = IP(dst="224.0.0.18", proto=112, ttl=255) / vrrp
print("【Master】开始发送 VRRP 通告...")
try:
while True:
send(pkt, verbose=0)
time.sleep(1)
except KeyboardInterrupt:
print("\n停止发送。")
二层构建
from scapy.all import *
import time
vip = "192.168.100.17"
vrid = 17
vrrp = VRRP(
version=2,
vrid=vrid,
priority=255, # Master
ipcount=1,
authtype=0,
adv=1,
addrlist=[vip]
)
pkt = Ether(dst="00:00:5E:00:01:11") / IP(dst="224.0.0.18", proto=112, ttl=255) / vrrp
print("【Master】开始发送 VRRP 通告...")
try:
while True:
sendp(pkt, verbose=0)
time.sleep(1)
except KeyboardInterrupt:
print("\n停止发送。")
4.2 B 机:模拟备份路由器(Backup)
监听 VRRP 报文并解析内容。
vrrp_backup.py
from scapy.all import *
def vrrp_handler(pkt):
if pkt.haslayer(VRRP):
v = pkt[VRRP]
vip = v.addrlist[0] if v.addrlist else 'N/A'
print(f"[VRRP] 收到通告: VRID={v.vrid}, 优先级={v.priority}, VIP={vip}")
print("【Backup】监听 VRRP 通告中...")
sniff(filter="ip proto 112", prn=vrrp_handler, store=0)
4.3 运行流程
1.在 B 机终端运行:sudo python3 vrrp_backup.py
2.在 A 机终端运行:sudo python3 vrrp_master.py
3.观察 B 机是否持续输出 VRRP 通告信息。
4.(可选)停止 A 机脚本,B 机可构造高优先级包模拟“抢主”。
五、预期结果
B 机终端应持续输出:
[VRRP] 收到通告: VRID=10, 优先级=255, VIP=192.168.1.100
[VRRP] 收到通告: VRID=10, 优先级=255, VIP=192.168.1.100
...
提示:可用 tcpdump -i eth0 proto 112 -nn 验证底层报文是否正确发送。
六、注意事项
VRRP 报文 TTL 必须为 255,否则接收方会丢弃;
防火墙或交换机 ACL 可能阻止协议 112,需确保网络通畅;
七、思考题
1.若将 A 机的优先级设为 200,B 机设为 150,谁会成为 Master?
2.如何通过 Scapy 模拟主路由器故障后备份路由器接管的过程?
3.VRRP v3 与 v2 有何区别?Scapy 是否支持 v3?
八、附录:VRRP 虚拟 MAC 地址计算
VRID = 10(十进制) → 十六进制为 0A → 虚拟 MAC 为:
00:00:5E:00:01:0A
STP
from scapy.all import *
from scapy.layers.l2 import LLC, SNAP, STP
import time
# ===== 配置参数 ===== INTERFACE = "eth0" # 替换为你的网卡名(如 ens33)
INTERFACE = "ens33"
ROOT_PRIORITY = 0x0000 # 最高优先级(0),确保成为根桥
BRIDGE_PRIORITY = 0x0000 #优先级
ROOT_MAC = "00:00:00:00:00:01" # 伪造的根桥 MAC
BRIDGE_MAC = "00:00:00:00:00:01"
COST = 0 # 到根桥开销为 0
PORT_ID = 0x8001 # 端口 ID
print(f"[🔍] 正在使用网卡: {INTERFACE}")
print(f"[🎯] 构造高优先级 BPDU: 优先级={ROOT_PRIORITY}, MAC={ROOT_MAC}")
# ===== 构造完整的 STP BPDU 帧 =====
pkt = Ether(
dst="01:80:c2:00:00:00", src=BRIDGE_MAC,type=0x0000 ,) / LLC(dsap=0xaa,ssap=0xaa,ctrl=0x03) / SNAP(OUI=0x00000c,code=0x010b) / STP(bpdid=0x00, rootid=ROOT_PRIORITY << 48 | int(ROOT_MAC.replace(":", ""), 16),rootpcost=COST,bridgeid=BRIDGE_PRIORITY << 48 | int(BRIDGE_MAC.replace(":", ""), 16),portid=PORT_ID,msg_age=0,max_age=20,hello=2,forward_delay=15)
# ===== 发送 BPDU =====
print(f"[🚀] 开始发送伪造 STP BPDU(每 2 秒一次)...")
print("按 Ctrl+C 停止...")
try:
while True:
sendp(pkt, iface=INTERFACE, verbose=0)
print(f"[📤] 已发送 BPDU: Root={ROOT_MAC}, Cost={COST}")
time.sleep(2)
except KeyboardInterrupt:
print("\n[🛑] 发送停止。")
老师给的网页
五、使用 Scapy 模拟不同场景的 BPDU
📌 前提准备
$ sudo scapy
确保你的网卡已连接实验网络。
✅ 命令 1:发送最优 BPDU(抢占根桥)
sendp(Ether(dst="01:80:c2:00:00:00")/LLC(dsap=0x42, ssap=0x42, ctrl=3)/STP(rootid=0), iface="eth0")
📌 参数解释
字段 值 说明
dst="01:80:c2:00:00:00" 组播 MAC STP 专用地址,交换机不会泛洪
dsap=0x42 目的服务访问点 0x42 表示桥接协议(IEEE 802.1D)
ssap=0x42 源服务访问点 同上,表示这是桥接控制帧
ctrl=3 控制字段 UI 帧(无连接信息)
STP(rootid=0) 根桥 ID = 0 优先级为 0,MAC 为 0 → 最优根桥
iface="eth0" 网卡名 替换为你的实际网卡名
作用:模拟一台“超级交换机”宣告自己为根桥
结果:其他交换机会认为这是最优路径,可能重新选举根桥
✅ 命令 2:发送普通优先级 BPDU(模拟普通交换机)
sendp(Ether(dst="01:80:c2:00:00:00")/LLC(dsap=0x42, ssap=0x42, ctrl=3)/STP(rootid=32768 << 48 | 0x001122334455, rootpcost=19), iface="eth0")
📌 参数解释
字段 值 说明
rootid=32768 << 48 | ... 32768 + MAC 根桥优先级为默认值 32768,MAC 为 00:11:22:33:44:55
rootpcost=19 路径开销 表示通过百兆链路连接到根桥
其他字段 同上 LLC 封装不变
作用:模拟普通交换机行为
观察:若已有更优根桥,此 BPDU 不会影响选举
✅ 命令 3:发送高开销 BPDU(模拟远端交换机)
sendp(Ether(dst="01:80:c2:00:00:00")/LLC(dsap=0x42, ssap=0x42, ctrl=3)/STP(rootid=32768 << 48 | 0x001122334455, rootpcost=38), iface="eth0")
📌 参数解释
字段 值 说明
rootpcost=38 路径开销 表示经过两段百兆链路(19+19)
其他字段 同上 LLC 封装不变
作用:模拟距离根桥更远的交换机
结果:交换机会选择开销更小的路径,阻塞高开销端口
✅ 命令 4:连续发送 BPDU(模拟稳定状态)
for i in range(10):
sendp(Ether(dst="01:80:c2:00:00:00")/LLC(dsap=0x42, ssap=0x42, ctrl=3)/STP(rootid=0), iface="eth0", verbose=0)
time.sleep(2)
📌 参数解释
字段 说明
for i in range(10) 循环 10 次
time.sleep(2) 每 2 秒发送一次,符合 STP 默认 Hello 时间
verbose=0 不显示发送日志,保持界面整洁
作用:模拟交换机持续发送 BPDU 的行为
观察:Wireshark 中应看到周期性 BPDU
✅ 命令 5:发送拓扑变更通知(TCN)BPDU
sendp(Ether(dst="01:80:c2:00:00:00")/LLC(dsap=0x42, ssap=0x42, ctrl=3)/STP(bpdid=0x80), iface="eth0")
📌 参数解释
字段 值 说明
bpdid=0x80 TCN BPDU 表示这是“拓扑变更通知”
其他字段 同上 LLC 封装不变
作用:通知网络中其他交换机“拓扑变了”
结果:根桥会泛洪更新,所有交换机刷新 MAC 地址表
实用命令
from scapy.all import *
from scapy.layers.inet import IP, TCP
from scapy.layers.l2 import Ether, ARP, getmacbyip
from scapy.config import conf # 用于获取当前系统的网络配置
My_Mac = get_if_hwaddr(conf.iface) # 获取自己的MAC地址
My_Ip = get_if_addr(conf.iface) # 获取自己IP地址
Target_Mac = getmacbyip("ip地址") # 根据ip获取对方mac地址
posted on 2025-09-17 09:17 suiseiseki 阅读(17) 评论(1) 收藏 举报
浙公网安备 33010602011771号