Socket Raw e encapsulamento de Dados 0xc7
Introdução a Socket Raw
A ideia ou conceito básico de se usar o socket de baixo nível (low level), é basicamente enviar um pacote por vez, usando os socket raw podemos preencher o nosso pacote da maneira que desejar, cabeçalhos de protocolos e ou invés de deixar o kernel fazer tudo, no Unix podemos usar dois tipos de socket's o SOCK_PACKET que já vimos em artigos passados, e o SOCK_RAW que é nosso modo Hardcore na verdade. sem falar que com eles podemos fazer spoof de IP, attack dos,sniffers em texto plano (veremos e breve),etc... irei falar mais sobre eles na conclusão. mas antes de começamos a por a mão na massa, vamos entender um pouco sobre o modelo das camadas OSI Open Systems Interconnection -> Sistemas de interconexão aberta;
OSI Open Systems Interconnection
O Modelo OSI (acrônimo do inglês Open System Interconnection) é um modelo de rede de computador referência da ISO dividido em camadas de funções, criado em 1971 e formalizado em 1983, com objetivo de ser um padrão.(Wiki) Esse padrão foi constituido para funcionar dessa forma com 7 camadas.,vamos lá cada uma delas;
Camada aplicação 7
Essa é a camada que resume nosso tutorial, a camada responsável por criar pacotes, tudo relacionado a solicitação de conexão. exemplos browers, firefox,chrome,iexplorer(feito para instalar os outros navegadores) . quando você faz um request para um servidor qualquer você está criando um pacote com header e tudo mais veremos isso em breve, Nela é que atuam o DNS, o Telnet, o FTP, etc.
Camada de Apresentação 6
Essa camada prepara os dados que serão enviados, é como entregar para o correio enviar seu pacote. ela converte os dados para um formato compatível para o procedimento de transporte.por outras palavras essa camada já é inserida na camada TCP/IP e ela é a camada responsável por fazer com que duas redes diferentes (por exemplo, uma TCP/IP e outra IPX/SPX) se comuniquem, ?traduzindo? os dados no processo de comunicação.
Camada de Sessão 5
Camada responsável por estabelecer uma conexão entre dois hosts, a camada de seção têm que se preocupar com a sincronização entre hosts, para que a sessão aberta entre eles se mantenha funcionando. novamente varemos isso em C :D, na parte do header do pacote, aguarde... Esta camada também é responsável pelo CONTROLE da comunicação entre as aplicações que estão em execução nas maquinas. No TCP/IP esta camada já é inserida nas aplicações de rede.
Camada de Transporte 4
A camada de transporte é responsável pela qualidade na entrega/recebimento dos dados. Após os dados já endereçados virem da camada 3, é hora de começar o transporte dos mesmos. definimos como o nosso pacote vai ser 'guiado' pelo protocolo IP (Protocolo responsável pelo roteamento de pacotes na internet). Uma determinada aplicação (Software's) poderia utilizar o UDP ou poderia utilizar o famoso TCP.
Camada de Rede 3
A camada 3 é responsável pelo tráfego no processo de internet. Nesta camada que é inserido ao header TCP ou UDP do pacote, um header com o protocolo IP que vai ser o encarregado de transportar os dados. costumamos dizer que essa camada é dos sonhos pois nela podemos fazer coisas um pouco malignas na rede, só mais uma informação ela endereça os dados pelas redes, e gerencia suas tabelas de roteamento.:D tem muita coisa a falar dessa camada como classes de IPs, Broadcast da uma olhada ai na net. não vamos fugir do assunto;
Camada de Enlace 2
Camada responsável pela comunicação entre duas interfaces de rede em uma LAN (Local Area Network). O trabalho de receber e entregar o pacote para uma determinada interface de rede, Após a camada física ter formatado os dados de maneira que a camada de enlace os entenda, inicia-se a segunda parte do processo. Um aspecto interessante é que a camada de enlace já entende um endereço, o endereço físico (MAC Address ? Media Access Control ou Controle de acesso a mídia)DNS spoof,DNS Posion, MTIM, etc... :D
Camada Física
É a camada onde se inicia o todo processo. a camada física identifica como 0 sinal elétrico com ?5 volts e 1 como sinal elétrico com +5 volts. Diz respeito a parte fisica da rede, quando digo física pode pensar em eth0 (Ethernet) e tals. em fim, não irei abortar nada dessa camada por enquanto :D.
Encapsulamento de dados
Agora que já sabemos como funciona as camadas do modelo OSI, vamos para prática, primeiro o que temos que ter em mente é que quando o pacote é entregue para o host remoto acontece o inverso do encapsulamento, segundo quando a comunicação se dar em uma rede Ehternet, o pacote vai se chamar 'Frame Ethernet'. Quando a camada de transporte diz que o pacote vai ser enviado se utilizando de UDP ai chamamos o pacote de datagrama. Modulo nada mais eh que um software que se comunica diretamente com o drive de dispositivo (da interface de rede) que age no kernel traduzindo instruções do periférico para o OS.O modulo também se comunica com aplicativos de rede e outros módulos. Podemos dizer então que o que faz as coisas acontecerem no encapsulamento de dados são os tais módulos. Não se esqueça que os módulos também se comunicam com aplicativos de rede, que nada mais são que programas que fazem as requisições de conexão, como browsers, clientes de FTP, POP, clientes de trojans, etc....:) Lembrando que as aplicações não apenas fazem requisições, também ficam esperando as tais...Sacou? =) Os aplicativos de rede se comunicam com os modulos apenas para lhes entregar as requisições ou para receber as requisições que são trazidas pelos modulos no caso do recebimento. não entendeu ainda ? queria deixar isso para parte da programação, porém sei que vai ajudar a visualizar na sua mente como é mais ou menos esse encapsulamento outra coisa, que pena que esse artigo não é direcionado para quem curti a linguagem python, pois só com ela podemos ver esse processo e analizar cada frame, cada pedaço do header, cada fragmento de bytes,isso tudo por causa do interpretador e ruby também podemos fazer isso, mas deixa isso para um outro paper irei fazer em breve python é só alegria. vamos lá então.Suponhamos que enviamos uma mensagem com seguinte conteúdo, "Vem monstro, Pode vim monstro", na camada de aplicação é claro, logo seguida vem nosso buffer é coloca dentro de um segmento TCP, no segmento TCP pode ser divido em duas partes o header e os dados, lógico depois de codificada pela aplicação veremos isso melhor em breve keep me calm rapaz, fica mais ou menos assim:
Exemplo 1
DATA Dump IP Header 45 20 00 89 8B 38 40 00 33 06 D4 7D AE 8F 77 5B E ...8@.3..}..w[ C0 A8 01 06 .... TCP Header 1A 0B 95 79 49 BF 5F 41 03 E5 5E 37 50 18 25 B0 ...yI._A..^7P.%. B6 87 00 00 .... Data Payload 3A 6B 61 74 65 60 21 7E 6B 61 74 65 40 75 6E 61 :kate`!~kate@una 66 66 69 6C 69 61 74 65 64 2F 6B 61 74 65 2F 78 ffiliated/kate/x 2D 30 30 30 30 30 30 31 20 50 52 49 56 4D 53 47 -0000001 PRIVMSG 20 23 23 63 20 3A 69 20 6E 65 65 64 20 65 78 61 ##c :i need exa 63 74 6C 79 20 74 68 65 20 72 69 67 68 74 20 6E ctly the right n 75 6D 62 65 72 20 6F 66 20 73 6F 63 6B 73 21 0D umber of socks!. 0A .
Exemplo 2
DATA Dump IP Header 45 20 00 BA DC EC 00 00 30 06 59 73 4A 7D 47 93 E ......0.YsJ}G. C0 A8 01 06 .... TCP Header 00 50 C0 DE BA EC 43 51 94 54 B9 19 50 18 AE DD .P....CQ.T..P... 3A E6 00 00 :... Data Payload 48 54 54 50 2F 31 2E 31 20 33 30 34 20 4E 6F 74 HTTP/1.1 304 Not 20 4D 6F 64 69 66 69 65 64 0D 0A 58 2D 43 6F 6E Modified..X-Con 74 65 6E 74 2D 54 79 70 65 2D 4F 70 74 69 6F 6E tent-Type-Option 73 3A 20 6E 6F 73 6E 69 66 66 0D 0A 44 61 74 65 s: nosniff..Date 3A 20 54 68 75 2C 20 30 31 20 44 65 63 20 32 30 : Thu, 01 Dec 20 31 31 20 31 33 3A 31 36 3A 34 30 20 47 4D 54 0D 11 13:16:40 GMT. 0A 53 65 72 76 65 72 3A 20 73 66 66 65 0D 0A 58 .Server: sffe..X 2D 58 53 53 2D 50 72 6F 74 65 63 74 69 6F 6E 3A -XSS-Protection: 20 31 3B 20 6D 6F 64 65 3D 62 6C 6F 63 6B 0D 0A 1; mode=block.. 0D 0A
quase iria esquecendo do Header, nos cabeçalhos um é do IP header que já diz tudo e outro é o TCP header , vai por mim na parte programação explicarei cada um deles, só estou mostrando no intuito de memorizar a leitura associando aos texto as imagens que não deixa de ser um texto kkkk. um professor meu falava sempre no ensino médio. em fim, fica assim os dois:
IP Header
|-IP Version : 4 |-IP Header Length : 5 DWORDS or 20 Bytes |-Type Of Service : 32 |-IP Total Length : 186 Bytes(tamanho do pacote) |-Identification : 56556 |-TTL : 48 |-Protocol : 6 |-Checksum : 22899 |-Source IP : 192.168.0.100 |-Destination IP : 192.168.0.102
TCP Header
|-Source Port : 80 |-Destination Port : 49374 |-Sequence Number : 3136045905 |-Acknowledge Number : 2488580377 |-Header Length : 5 DWORDS or 20 BYTES |-Urgent Flag : 0 |-Acknowledgement Flag : 1 |-Push Flag : 1 |-Reset Flag : 0 |-Synchronise Flag : 0 |-Finish Flag : 0 |-Window : 44765 |-Checksum : 15078 |-Urgent Pointer : 0
o cabeçalho com 20 bytes, isso aplicação vai fazer tudo, claro se você usar o socket normal no modo Noob, já no modo l33t já muda tudo é por nossa conta heheeheh, voltando para entender precisamos saber que Destination IP é que vai analisar a mensagem é muito importante, que é representado em 16 bit vai uma imagem ai pra não chorar:

Com todos os requisitos setando com sucesso, o segmento é encaminhado de Rede, mas não estávamos na camada de aplicação ? é que esqueci de um detalhe o modulo TCP já passa tudo isso, deixando o pacote já pronto para camada de rede, ao chamar na camada de rede o primeiro passo é encapsular o segmento TCP dentro da unidade de dados da camada de rede, e nessa camada onde se verifica tudo aquilo que nós colocamos no header, nesse caso o pacote identifica a origem e o destino, verifica o TTP,flag, protocolo(muito importante), tipo do serviço, versão e etc... ou seja as informações do header TCP, se liga na imagem:

O protocolo é muito importante, ele permite ao host destino quando receber o pacote identificar qual tipo de protocolo se tiver um 6 esse protocolo vai ser TCP como vimos no exemplo citado acima,se for 1 quer dizer que o protocolo vai ser ICMP (ping), caso for = 2 será IGMP Protocol e 17 para UDP, o Source IP é o IP que está enviando a requisição, apenas dessa forma com socket l33t podemos colocar o IP que quisermos, ou seja, podemos colocar que a requisição foi enviada pelo google.com.br, isso já abre o leck de possibilidades de attack como DOS, os flood em geral e etc... e logo em seguida chegamos na camada de enlace, depois de tudo verificado chegamos na camada de enlace e codificamos com a interface de rede wlan0, e for fim ehhehee chega na camada de física que será codificada em onda eletromagnéticas no caso wifi.
Socket Raw na Prática :D Wellcome a Selva l33t Wilsoooooooon
Depois de resumir o encapsulamento de dados, iremos para parte prática da coisa... lembrando que python seria, mas interessante pois iriamos ver o pacote ao vivo sendo capturado, mas quem sabe um serie sobre python em breve. let's Go
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <errno.h>
#include <unistd.h>
#include <arpa/inet.h> //operações de internet
#include <net/ethernet.h> // ether_header
#include <netinet/in.h> //Internet Protocol family
#include <netinet/ip.h> // declaração ip header
#include <netinet/tcp.h> // declaração para TCP header
// struct do IP HEADER
struct headerTCP {
u_int32_t src_addr;
u_int32_t dst_addr;
u_int8_t padding;
u_int8_t proto;
u_int16_t length;
};
struct data_checksum {
struct headerTCP pshd;
struct tcphdr tcphdr;
char payload[1024];
};
unsigned short comp_chksum(unsigned short *addr, int len) {
long sum = 0;
while (len > 1) {
sum += *(addr++);
len -= 2;
}
if (len > 0)
sum += *addr;
while (sum >> 16)
sum = ((sum & 0xffff) + (sum >> 16));
sum = ~sum;
return ((u_short) sum);
}
primeiro de tudo declaramos os header's, até comentei alguns deles, logo seguida vem duas estruturas para o ip header e tcp header, calma ficará tudo claro em breve, o checksum é a soma de verificação, é usado para detectar a corrupção de dados através de uma conexão isso quer dizer que qualquer erro que ocorrer na soma, Se um bit é invertida, um byte mutilado, ou alguma outra maldade acontece com um pacote, ele provavelmente vai ser quebrado e não conseguirá entrar os dados para o destino, qual motivo da criação dessa medida, então o checksum é uma garantia que o fluxo de dados está correto. No IPV4 essa soma verificação para detectar a corrupção de cabeçalhos dos pacotes. ou seja, a origem, o destino e outras meta-dados. isso tudo para proteger o payload. há e outra coisa o algoritmo de verificação do checksum é o mesmo tanto para TCP e IPV4. também temos lá em cima a definição de uma estrutura que se você comparar com uma das imagens que citei acima como exemplo vera que nada mais é que a estrutura do nela temos o endereço de origem e o endereço de destino, u_int32_t src_addr; u_int32_t dst_addr; , ainda temos o padding né que é opcional nem irei usa-lo, tá mas pra que serve ? então o padding no cabeçalho TCP é usado para garantir que as extremidades do cabeçalho TCP e dados começa num limite de 32 bits. O Padding ou preenchimento não vamos generalizar mas quase sempre consiste em apenas zeros para assegurar a parte do pacote de dados não está perdida. Proto já diz tudo onde definimos que tipo de protocolo vai ser usado.
int main(int argc, char *argv[]) {
// bloco 1
int sock, bytes, nivel = 1;
char buffer[1024];
struct iphdr *ip;
struct tcphdr *tcp;
struct sockaddr_in to;
struct headerTCP p_tcp_header;
struct data_checksum checksum_tcp_calc;
// bloco 2
if (argc != 2) {
fprintf(stderr, "Usage: %s ", argv[0]);
fprintf(stderr, "\n");
return 1;
}
sock = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
if (sock == -1) {
perror("socket() failed");
return 1;
}else{
printf("socket() ok\n");
}
if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, &nivel, sizeof(nivel)) == -1) {
perror("setsockopt() failed");
return 2;
}else{
printf("setsockopt() ok\n");
}
// Apenas para exemplo do comentário abaixo
//int setsockopt( int s,
// int level,
// int optname,
// const void * optval,
// socklen_t optlen );
//bloco 3
ip = (struct iphdr*) buffer;
tcp = (struct tcphdr*) (buffer + sizeof(struct tcphdr));
int iphdrlen = sizeof(struct iphdr);
int tcphdrlen = sizeof(struct tcphdr);
int datalen = 0;
// bloco 1
ip->frag_off = 0;
ip->version = 4;
ip->ihl = 5;
ip->tot_len = htons(iphdrlen + tcphdrlen);
ip->id = 0;
ip->ttl = 40;
ip->protocol = IPPROTO_TCP;
ip->saddr = inet_addr("192.168.1.135"); // IP Spoof :D
ip->daddr = inet_addr(argv[1]); // Destiny IP, lembrei do jogo muito loko Destiny
ip->check = 0;
//bloco 2
tcp->source = htons(12345);
tcp->dest = htons(80);
tcp->seq = random();
tcp->doff = 5;
tcp->ack = 0;
tcp->psh = 0;
tcp->rst = 0;
tcp->urg = 0;
tcp->syn = 1;
tcp->fin = 0;
tcp->window = htons(65535);
//bloco 3
p_tcp_header.src_addr = ip->saddr;
p_tcp_header.dst_addr = ip->daddr;
p_tcp_header.padding = 0;
p_tcp_header.proto = ip->protocol;
p_tcp_header.length = htons(tcphdrlen + datalen);
checksum_tcp_calc.pshd = p_tcp_header;
checksum_tcp_calc.tcphdr = *tcp;
int checksum = comp_chksum((unsigned short*) &checksum_tcp_calc,
sizeof(struct headerTCP) + tcphdrlen + datalen);
tcp->check = checksum;
printf("TCP Checksum: %i\n", checksum);
printf("Destination : %i\n", ntohs(tcp->dest));
printf("Source: %i\n", ntohs(tcp->source));
// bloco 1
to.sin_addr.s_addr = ip->daddr;
to.sin_family = AF_INET;
to.sin_port = tcp->dest;
// bloco 2
bytes = sendto(sock, buffer, ntohs(ip->tot_len), 0, (struct sockaddr*) &to,
sizeof(to));
if (bytes == -1) {
perror("sendto() failed");
return 1;
}
recv(sock, buffer, sizeof(buffer), 0);
printf("TTL= %d\n", ip->ttl);
printf("Window= %d\n", tcp->window);
printf("ACK= %d\n", tcp->ack);
printf("%s:%d\t --> \t%s:%d \tSeq: %d \tAck: %d\n",
inet_ntoa(*(struct in_addr*) &ip->saddr), ntohs(tcp->source),
inet_ntoa(*(struct in_addr *) &ip->daddr), ntohs(tcp->dest),
ntohl(tcp->seq), ntohl(tcp->ack_seq));
return 0;
}
// Extra ;D
struct icmpheader {
unsigned char icmp_type;
unsigned char icmp_code;
unsigned short int icmp_cksum;
unsigned short int icmp_id;
unsigned short int icmp_seq;
}; / * icmp: 8 bytes (= 64 bits) * /
struct udpheader {
unsigned short int uh_sport;
unsigned short int uh_dport;
unsigned short int uh_len;
unsigned short int uh_check;
}; / * Comprimento total cabeçalho udp: 8 bytes (= 64 bits) * /
Simples Pacote Sniffer
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <linux/if_ether.h>
#include <net/if.h>
#include <linux/filter.h>
#include <sys/ioctl.h>
#include <string.h>
// by: pokerbirch
int main(int argc, char **argv) {
int sock, i;
unsigned char buffer[2048];
unsigned char *iphead, *ethhead;
struct ifreq ethreq;
// NOTE: use TCPDUMP to build the filter array.
// set filter to sniff only port 443
// $ sudo tcpdump -dd port 443
struct sock_filter BPF_code[] = {
{ 0x28, 0, 0, 0x0000000c },
{ 0x15, 0, 8, 0x000086dd },
{ 0x30, 0, 0, 0x00000014 },
{ 0x15, 2, 0, 0x00000084 },
{ 0x15, 1, 0, 0x00000006 },
{ 0x15, 0, 17, 0x00000011 },
{ 0x28, 0, 0, 0x00000036 },
{ 0x15, 14, 0, 0x000001bb },
{ 0x28, 0, 0, 0x00000038 },
{ 0x15, 12, 13, 0x000001bb },
{ 0x15, 0, 12, 0x00000800 },
{ 0x30, 0, 0, 0x00000017 },
{ 0x15, 2, 0, 0x00000084 },
{ 0x15, 1, 0, 0x00000006 },
{ 0x15, 0, 8, 0x00000011 },
{ 0x28, 0, 0, 0x00000014 },
{ 0x45, 6, 0, 0x00001fff },
{ 0xb1, 0, 0, 0x0000000e },
{ 0x48, 0, 0, 0x0000000e },
{ 0x15, 2, 0, 0x000001bb },
{ 0x48, 0, 0, 0x00000010 },
{ 0x15, 0, 1, 0x000001bb },
{ 0x6, 0, 0, 0x00000060 },
{ 0x6, 0, 0, 0x00000000 }
};
struct sock_fprog Filter;
Filter.len = sizeof(BPF_code) / 8;
Filter.filter = BPF_code;
if ((sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP))) == -1) {
perror("socket");
exit(1);
}
// set network card to promiscuos
strncpy(ethreq.ifr_name, "eth0", IFNAMSIZ);
if (ioctl(sock,SIOCGIFFLAGS, ðreq) == -1) {
perror("ioctl");
close(sock);
exit(1);
}
ethreq.ifr_flags |= IFF_PROMISC;
if (ioctl(sock, SIOCSIFFLAGS, ðreq) == -1) {
perror("ioctl");
close(sock);
exit(1);
}
// attach filter to socket
if(setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &Filter, sizeof(Filter)) == -1) {
perror("setsockopt");
close(sock);
exit(1);
}
while (1) {
printf("----------------------\n");
i = recvfrom(sock, buffer, sizeof(buffer), 0, NULL, NULL);
printf("%d bytes read\n", i);
// check header size: Ethernet = 14, IP = 20, TCP = 8 (sum = 42)
if (i < 42) {
perror("recvfrom():");
printf("Incomplete packet (errno is %d)\n", errno);
close(sock);
exit(0);
}
ethhead = buffer;
iphead = buffer + 14; // (skip ethernet header)
if (*iphead == 0x45) {
printf("Source Address: %d.%d.%d.%d, Port: %d\n",
iphead[12], iphead[13], iphead[14], iphead[15], (iphead[20] << 8) + iphead[21]);
printf("Dest Address: %d.%d.%d.%d, Port: %d\n",
iphead[16], iphead[17], iphead[18], iphead[19], (iphead[22] << 8) + iphead[23]);
}
}
// clean up
close(sock);
}
Conclusão
O objetivo desse artigo foi tentar de uma forma interativa como tudo funciona na criação e encapsulamento de dados. além disso, aliando a programação fica mais interessante ainda, pois podemos desenvolver outros pacotes com tipos de protocolos diferentes, lembrando que isso não é tudo tem muita coisa que deixei passar para não perder o foco, detalhei apenas as coisas mais importante para um conhecimento prévio sobre socket raw, também aprendendo a inserir qualquer datagrama baseada em protocolo IP para o tráfego de rede. Isto é útil, por exemplo, para construir scanners como nmap, falsificar ou para realizar operações que precisam enviar pacotes simples. Basicamente, você pode enviar qualquer pacote a qualquer momento, enquanto utilizando as funções de interface para seus sistemas que você não tem controle direto sobre os pacotes. O conceito básico de socket raw de baixo nível é para enviar um único pacote de uma só vez, com todos os cabeçalhos de protocolo preenchidos pelo programa (ao invés de o kernel).Unix fornece dois tipos de tomadas que permitem o acesso directo à rede. há algumas funções que detalhei é exatamente porque vamos usa-las em outros artigos que irei escrever, assim não preciso perder muito tempo explicando cada uma delas. hope i helped you , see you next paper...Referências: http://pt.wikipedia.org/wiki/TCP/IP http://www.opennet.ru/base/sec/p49-15.txt.html http://ubuntuforums.org/showthread.php?t=954426 https://dl.packetstormsecurity.net/mag/vipercorp/vcc-0x01.txt http://nunix.fr/index.php/programmation/1-c/58-rawsocket-to-forge-udp-packets http://jkolb.com.br/wp-content/uploads/2016/06/modelo-osi2.png