网络攻防-假消息攻击2-TCP攻击,涉及实验:SEED Labs – TCP/IP Attack Lab,代码见:https://github.com/Seanxz401/seed-labs
理论
传输控制协议(TCP)为应用程序提供主机到主机的通信服务。(可靠且有序)
TCP通信代码
客户端:1.创建套接字;2.设置目的地相关信息;3.连接目标服务器;4.发送数据
1 | int sockfd=socket(AF_INET,SOCK_STREAM,0); |
服务器端:1.创建套接字;2.绑定到端口;3.监听连接;4.接受连接请求;5.发送和接收数据
1 | int sockfd=socket(AF_INET,SOCK_STREAM,0); |
要接受多个连接可以采用fork多进程、pthread多线程、select轮询等方法。以fork为例:
1 | while(1){ |
TCP报文
- seq序列号,如果设置了SYN位,则为初始序列号
- ack确认号,等于发送方期望的下一个序列号的值
TCP三次握手
![image-20221231152310873](http://hexo-git.oss-cn-beijing.aliyuncs.com/img/image-20221231152310873.png)
- SYN包,客户端使用随机生成的数字x作为序列号
- SYN+ACK,服务器端使用随机生成的数字y作为序列号
- ACK,客户端确认,结束握手
SYN Flooding
当服务器接收到初始SYN数据包时,它使用TCB(传输控制块)存储有关连接的 信息。服务器将TCB存储在仅用于半开放连接的队列中。在服务器获得ACK数据包后,它将把这个TCB从队列中取出并存储在另一个地方 。如果ACK没有到达,服务器将重新发送SYN+ACK数据包。一段时间后,TCB最终将 被丢弃。
攻击原理:持续向服务器发送大量 SYN数据包。这会通过插入TCB记录来消耗队列 中的空间。最终服务器端没有空间为任何新的半开放连接存储TCB,导致无法接收新的客户端连接请求。
ps.使用随机的源IP
防范:syncookies。在服务器接收到SYN数据包后,它使用只有服务器知道的密钥从数据包中的信息 计算密钥散列(H)。此哈希(H)作为初始序列号从服务器发送到客户端。服务器不会将半开放连接存储在其队列中。服务器通过重新计算cookie来检查确认字段中的数字是否有效。
TCP重置攻击
断开TCP连接:
FIN四次挥手
RST:通信一方发送RST立刻断开连接
伪造RST数据包需要正确设置序列号和确认号
TCP会话劫持攻击
在已建立连接中注入数据。伪造数据包需要正确设置序列号和确认号,具体见实验。
反向shell
劫持连接后运行的最佳命令是运行反向shell命令。
防御
- 使攻击者难以伪造数据包
- 随机化源端口号
- 随机化初始序列号
- 对本地攻击无效
- 加密有效载荷
实验
Task1 SYN
1.1 synflooding.py
1 | from scapy.all import * |
以容器10.9.0.5
的23端口作为目标,通过telnet判断是否成功。
第一次尝试,容器中通过netstat -nat
可以看到23端口收到了很多的SYN包,但是telnet远程登录还是成功了。
改进1:提高受害者的tcp重传阈值
1 | sysctl -w net.ipv4.tcp_synack_retries=10 |
改进2:减小队列中能容纳的syn包的数量
1 | sysctl -w net.ipv4.tcp_max_syn_backlog=80 |
在容器中清除受害者与攻击者的成功连接记录:
1 | ip tcp_metrics show #查看 |
再次发起攻击,等待一分钟后尝试登录,无法连接成功:
查看受害者的队列中有多少个半连接:(前面设置的队列大小的四分之三用于存放半连接,三分之一用来存放已成功连接,因此有效容量为80*3/4=60)
1 | netstat -tna | grep SYN_RECV | wc -l |
可以看出来队列已满
1.2 synflooding.c
首先将受害者的相关参数恢复为修改前。
1 | sysctl -w net.ipv4.tcp_synack_retries=5 |
编译执行synflood.c,等待一分钟后尝试telnet连接受害者,无法成功登录,查看半连接数量97>(128*0.75=96):
1.3 syncookie
开启syncookie保护机制,此机制能够检测syn洪水攻击
1 | sysctl -w net.ipv4.tcp_syncookies=1 |
开启syncookie后再次攻击,攻击无效,远程登录能成功。查看此时设置的队列值tcp_max_syn_backlog无效,因为连接并没有存在队列中。tcp_syncookies 半连接 - silyvin - 博客园 (cnblogs.com)
Task2 RST
开启wireshark监听telnet包,用10.9.0.5
向10.9.0.6
发起telnet远程连接,成功登录后,查看最后一个telnet数据包,从中获取源IP、目的IP、源端口、目的端口、next seq等重要信息:
根据这些信息构造RST包,伪装成上面那个最后一个telnet包的下一个包:
1 | from scapy.all import * |
执行代码后查看连接已被中断,wireshark也捕获到了对应的RST包:
Task3 session.py
从远端(10.9.0.6)发来的最后一个telnet包中获得重要信息
攻击者假装是10.9.0.5在与10.9.0.6通信,seq和ack与上图中的交换,data中保存想要执行的命令,注意以\n\0结尾,\n表示回车执行,\0表示字符串结尾
1 | from scapy.all import * |
wireshark抓到攻击者发出的会话劫持包,并成功接收到来自10.9.0.6的对应命令的回复,此时10.9.0.5的远程连接终端已经锁死。
Task4
大概过程与Task3类似,只是将传递的一条命令内容改为reverse shell。根据最后一个telnet包填充内容,代码:
1 | ip=IP(src='10.9.0.5',dst='10.9.0.6') |
攻击机开启9090端口监听:
1 | nc -lnv 9090 |
发送构造的包,成功获取到shell: