Pull to refresh

Что-то не так с IDS сигнатурой

Reading time12 min
Views9.5K


Имена Snort и Suricata IDS знакомы каждому, кто работает в сфере сетевой безопасности. Системы WAF и IDS — это те два класса защитных систем, которые анализируют сетевой трафик, разбирают протоколы самого верхнего уровня и сигнализируют о злонамеренной или нежелательной сетевой активности. Если первая система помогает веб-серверам обнаружить и избегать атак, специфичных только для них, то вторая, IDS, способна обнаружить атаки во всем сетевом трафике.

Многие компании устанавливают IDS для контроля трафика внутри корпоративной сети. Благодаря механизму DPI они собирают транспортные потоки, заглядывают внутрь пакетов от IP до HTTP и DCERPC, а также выявляют как эксплуатацию уязвимостей, так и сетевую активность вредоносных программ.

Сердце и тех и других систем — наборы сигнатур для выявления известных атак, разрабатываются экспертами сетевой безопасности и компаниями по всему миру. Мы, команда @attackdetection, также занимаемся разработкой сигнатур для обнаружения сетевых атак и вредоносной активности. Далее в статье речь пойдет о обнаруженном нами новом подходе, который позволяет нарушить работу систем IDS Suricata и скрыть такую активность.

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


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



Первым делом входящий трафик разбивается на TCP, UDP или другие транспортные потоки, после чего парсеры маркируют их и разбивают на высокоуровневые протоколы и их поля — нормализуя, если требуется. Полученные декодированные, разжатые и нормализованные поля протоколов затем проверяются наборами сигнатур, которые выявляют, есть ли среди сетевого трафика попытки сетевых атак или пакеты, присущие вредоносной активности.

Наборы сигнатур, к слову, это продукт многих индивидуальных исследователей и компаний. Среди поставщиков вы найдете такие имена, как Cisco Talos, Emerging Threats, а в открытом наборе правил сейчас насчитывается более 20 000 активных сигнатур.

Общие способы обхода IDS


Несовершенство IDS и ошибки в их ПО позволяют находить условия, при которых они не способны обнаружить атаку в сетевом трафике. Среди достаточно давно известных техник обхода стадии разбора стримов можно перечислить и такие:

  • Нестандартная фрагментация пакетов на уровнях IP, TCP или, например, DCERPC, с которой IDS порой не способна справиться.
  • Пакеты с пограничными или некорректными значениями TTL или MTU также могут обрабатываться IDS некорректно.
  • Неоднозначность восприятия накладывающихся TCP-фрагментов (номеров TCP SYN) может трактоваться IDS иначе, чем на сервере или клиенте, которому этот TCP-трафик предназначался.
  • Подставной пакет TCP FIN, например с неверной контрольной суммой (т. н. TCP un-sync), может быть воспринят как конец сессии вместо игнорирования.
  • Разное время таймаута TCP-сессии между IDS и клиентом также может послужить инструментом для сокрытия атак.

Что касается этапа разбора протоколов и нормализации полей, многие техники обхода WAF могут быть позаимствованы и для IDS. Их число значительно больше, поэтому приведем лишь некоторые из них:

  • HTTP double encoding.
  • Gzip-сжатие HTTP-пакета без соответствующего заголовка Content-Encoding может так и остаться неразжатым на стадии нормализации, такой прием можно порой встретить в трафике вредоносных программ.
  • Использование редких кодировок, как, например, Quoted-Printable для протоколов POP3/IMAP, также может сделать некоторые сигнатуры бессильными.

Не стоит забывать и про баги, специфичные для каждого вендора IDS или сторонних библиотек в их составе, которые можно найти на публичном багтрекере.
Одну из таких специфичных баг, позволявшую отключать проверки сигнатур при определенных условиях, нашла команда @attackdetection в Suricata IDS, и эта ошибка могла быть проэксплуатирована для сокрытия таких атак, как, например, BadTunnel.

Во время этой атаки уязвимый клиент открывает сгенерированную злоумышленником HTML-страницу и тем самым устанавливает UDP-тоннель сквозь сетевой периметр до сервера злоумышленника для портов 137 с обеих сторон. После установления тоннеля злоумышленник получает возможность спуфить имена внутри сети уязвимого клиента, посылая поддельные ответы на NBNS-запросы. Несмотря на то, что к серверу злоумышленника уходило три пакета, ему было достаточно ответить лишь на один из них для установления тоннеля.

Найденная ошибка состояла в том, что если ответом на первый UDP-пакет от клиента был ICMP-пакет, например ICMP Destination Unreachable, то из-за неточного алгоритма отныне этот стрим проверялся сигнатурами только для ICMP-протокола. Любые дальнейшие атаки, в том числе и спуфинг имен, оставались незамеченными для IDS, так как осуществлялись поверх UDP-тоннеля. Несмотря на отсутствие номера CVE для этой уязвимости, она приводила к обходу защитных функций IDS.



Названные выше техники байпаса известны давно и устранены в современных и долго развивающихся IDS, а специфичные баги и уязвимости работают лишь для непропатченных версий.

Поскольку наша команда работает над исследованием сетевой безопасности и сетевых атак и непосредственно разрабатывает и тестирует сетевые сигнатуры, мы не могли не обратить внимания на способы обхода, связанные с самими сигнатурами и их несовершенством.

Уклоняемся от сигнатур


Постойте, как вообще сигнатуры могут быть проблемой?

Исследователи изучают появляющиеся угрозы и формируют свое понимание того, как та или иная атака может быть обнаружена на сетевом уровне за счет особенностей эксплуатации или других сетевых артефактов, а затем переводят полученное представление в одну или множество сигнатур на понятном для IDS языке. Из-за ограниченных возможностей системы или ошибки исследователя остаются непокрытые способы эксплуатации уязвимостей.

Если протокол и формат сообщений среди одного семейства вредоносных программ и их поколения остается неизменным и сигнатуры для них работают замечательно, то при эксплуатации уязвимостей чем выше сложность протокола и его вариативность, тем проще атакующей стороне изменить эксплойт без потери функциональности — и обойти сигнатуры.
Хотя для наиболее опасных и громких уязвимостей вы найдете целое множество качественных сигнатур от разных вендоров, некоторые другие сигнатуры можно обойти простыми приемами. Приведу в пример весьма распространенную ошибку сигнатур для протокола HTTP: порой достаточно лишь изменить порядок аргументов HTTP GET, чтобы обойти проверку сигнатурой.


И вы будете правы, если подумаете, что в сигнатурах встречаются проверки подстрок с фиксированным порядком аргументов, например “?action=checkPort” или “action=checkPort&port=”. Требуется лишь внимательно изучить сигнатуру и проверить, нет ли в ней такого же хардкода.

Другими и не менее сложными для проверок протоколами и форматами являются, например, DNS, HTML или DCERPC, вариативность которых чрезвычайно высока. Поэтому для покрытия сигнатурами всех вариаций атак и разработки не только качественных, но и быстрых сигнатур, разработчику необходимо обладать широким спектром умений и твердым знанием сетевых протоколов.

О несовершенстве IDS-сигнатур говорят давно, и вы можете найти мнения других авторов в их докладах: 1, 2, 3.

Сколько весит сигнатура


Как уже было сказано, скорость работы сигнатуры лежит в зоне ответственности разработчика, и естественно, что большему количеству сигнатур требуется больше вычислительных ресурсов для проверок. Правило золотой середины советует добавлять один CPU для каждой тысячи сигнатур или каждой половины гигабита сетевого трафика в случае Suricata IDS.


Тут зависимость и от количества сигнатур, и от объема сетевого трафика. Хоть эта формула и выглядит полной, она не учитывает того факта, что сигнатуры могут быть быстрыми или медленными, а трафик — самым разнообразным. Так что же произойдет, если медленная сигнатура попадет на плохой трафик?

Suricata IDS умеет выводить данные о производительности сигнатур в журнал. Туда попадают данные о самых медленных сигнатурах, формируя топ с указанием времени их выполнения, выраженного в ticks — времени CPU и количестве их проверок.
Наверху журнала — самые медленные сигнатуры.



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

Что бывает, если мощность IDS подобрана неправильно и она не справляется с проверкой всего сетевого трафика? Как правило, если нагрузка ядер CPU составляет в среднем больше 80%, то IDS уже начинает пропускать проверку некоторых пакетов. Чем выше нагрузка на ядра, тем больше непроверенных мест появляется в сетевом трафике и тем выше шанс, что зловредная активность останется незамеченной.

Что, если попытаться усилить этот эффект, когда сигнатура осуществляет проверку сетевых пакетов слишком долго? Такая схема эксплуатации должна вывести IDS из игры, заставив пропускать пакеты и атаки. Начнем с того, что у нас уже есть топ горячих сигнатур на живом трафике, и попытаемся усилить эффект на них.

Эксплуатируем


Одна из таких сигнатур выявляет в трафике попытку эксплуатации уязвимости CVE-2013-0156 RoR YAML Deserialization Code Execution.



Весь HTTP-трафик по направлению к корпоративным веб-серверам подвергается проверке на наличие трех строк в строгой последовательности — “ type”, “yaml” и “!ruby” — и проверке регулярным выражением.

Прежде чем мы приступим к генерации «плохого» трафика, я приведу некоторые гипотезы, которые нам в этом помогут:

  • Найти совпадение подстроки легче, чем доказать, что такого совпадения нет.
  • Проверка регулярным выражением для IDS Suricata медленнее, чем поиск подстроки.

Это значит, что если мы хотим от сигнатуры долгих проверок, то проверки эти должны быть безуспешными и использовать регулярные выражения.

Для того чтобы дойти до проверки регулярным выражением, три подстроки должны присутствовать в пакете друг за другом.

Пробуем соединить их в таком порядке и запустить IDS для проверки. Для конструирования файлов с HTTP-трафиком в формате Pcap из текста я использовал инструмент Cisco Talos file2pcap:



Еще один журнал keyword_perf.log помогает нам увидеть, что цепочка проверок успешно дошла (content matches — 3) до регулярного выражения (PCRE) и завершилась неудачей (PCRE matches — 0). Если далее мы хотим извлечь пользу из дорогих PCRE-проверок, то нам необходимо полностью его разобрать и подобрать эффективный трафик.



Задача обратной разработки регулярного выражения хоть и легко выполняется вручную, но плохо автоматизируется из-за таких конструкций, как, например, backreferences или named capture groups: способов автоматически подобрать строку для успешного прохождения регулярного выражения любого вида я не нашел.

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

<a type="yaml" !ruby : 32 steps, match
<a type="yaml" !rub  : 57 steps, no match

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

Другой занимательный факт открылся при дальнейшем изучении этого регулярного выражения. Если мы неоднократно продублируем минимальную необходимую строку без последнего символа, то разумно ожидать увеличения числа шагов для окончания проверки, однако зависимость такого роста совершенно взрывная:

2 x (<a type="yaml" !rub) : 209 steps
10 x (<a type="yaml" !rub) : 9885 steps
100 x (<a type="yaml" !rub) : timeout

Время проверки нескольких десятков таких строк составляет уже около секунды, и повышая их количество, мы упираемся в timeout error. Этот эффект в регулярных выражениях называется Catastrophic Backtracking и ему посвящено немало статей, в том числе и на Хабре. Такие ошибки можно встретить в популярных продуктах и по сей день; например, недавно такую нашли во фреймворке Apache Struts.

Бежим с найденными строками обратно к Suricata IDS и проверяем их:

  Keyword    Ticks  	Checks    Matches
  --------   --------   -------   --------
  content    19135  	4         3   	
  pcre       1180797	1         0

Однако вместо фанфар и Catastrophic Backtracking мы получаем едва ощутимую для IDS нагрузку — всего 1 миллион ticks. Это история о том, как после отладки, изучения исходного кода Suricata IDS и используемой внутри библиотеки libpcre я наткнулся на PCRE-лимиты, а именно:

  • MATCH_LIMIT DEFAULT = 3500
  • MATCH_LIMIT_RECURSION_DEFAULT = 1500


Эти лимиты и ограничивают регулярные выражения от попадания в катастрофы во многих библиотеках регулярных выражений. Те же лимиты можно встретить и в WAF, где преобладают проверки регулярных выражений. Эти лимиты, конечно, могут быть изменены в конфигурации IDS, но распространяются по умолчанию и не рекомендуются к изменению.

Эксплуатация только лишь регулярного выражения не поможет нам достичь желаемого результата. Но что, если проверить при помощи IDS сетевой пакет с таким контентом?


В таком случае мы получим следующие значения в журнале:

Keyword		Avg. Ticks  Checks	Matches
--------	----------  -------     --------
content		3338        7     	6   	
pcre		12052       3     	0

Количество проверок было равно 4, а стало 7 лишь из-за дублирования изначальной строки. Хоть механизм и остался неясным, стоит ожидать лавинообразного увеличения числа проверок, если мы продублируем строки еще. В конце концов я смог добиться следующих значений:

Keyword		Avg. Ticks  Checks	Matches
--------	----------  -------     --------
content			    1508  	1507      
pcre			    1492  	0 

Суммарно число проверок подстрок и регулярных выражений не превышает 3000, какой бы контент ни проверялся сигнатурой. Очевидно, в самой IDS также присутствует внутренний ограничитель, который на этот раз носит название inspection-recursion-limit и равняется по умолчанию как раз 3000. При всем количестве лимитов в PCRE, IDS и ограничений на единовременный размер контента, попадающего под проверку, если видоизменить контент и использовать лавинообразные проверки регулярных выражений, то результат получится что надо:

Keyword		Avg. Ticks  Checks	Matches
--------	----------  -------     --------
content		3626	    1508	1507      
pcre		1587144	    1492	0 

Несмотря на то, что сложность одной проверки регулярного выражения не поменялась, число таких проверок значительно выросло и достигло полутора тысяч. Перемножив число проверок на среднее количество тактов, затраченных на каждую проверку, получим заветные 3 миллиарда тиков.

Num  	 Rule     	Avg Ticks
-------- ------------   -----------
1    	 2016204  	3302218139

И это более чем тысячекратное усиление! Для эксплуатации потребуется лишь утилита curl для составления минимального запроса HTTP POST. Выглядеть он будет примерно так:



Минимальный набор HTTP-полей и HTTP body с повторяющимся паттерном.
Такой контент не может быть бесконечно большим и заставлять IDS тратить громадное количество ресурсов на его проверку, так как несмотря на то, что внутри TCP-сегменты и соединяются в единый поток-стрим, — стрим и собранные HTTP-пакеты не проверяются целиком, какими бы большими они ни были. Вместо этого они проверяются небольшими кусочками размером около 3-4 килобайт. Этот размер сегментов для проверки, как и глубина проверок, задаются в конфиге (ровно как и все в IDS). Размер сегмента слегка «дрожит» от запуска к запуску во избежание атак на границу фрагментации таких сегментов — когда атакующий, зная размер сегментов по умолчанию, может дробить сетевые пакеты таким образом, чтобы атака разделилась на два соседних сегмента и не могла быть обнаружена сигнатурой.

Итак, в наших руках оказалось мощное оружие, загружающее IDS на более чем 3 000 000 000 тиков CPU за одно применение. Что это вообще значит?
Фактически полученная цифра это примерно 1 секунда работы среднестатистического CPU. Простая взаимосвязь состоит в том, что послав один HTTP-запрос размером 3 КБ, мы загружаем IDS работой на целую секунду. Чем больше ядер у IDS, тем больше потоков данных она способна обрабатывать одновременно.



Не стоит забывать, что IDS не стоит без дела и, как правило, занимает часть своих ресурсов проверкой фонового сетевого трафика, тем самым снижая порог для этой атаки.

Проводя измерения на рабочей IDS-конфигурации с 8/40 ядрами CPU Intel Xeon E5-2650 v3 2.30 Ghz без фонового трафика, пороговым значением, после которого все 8 CPU-ядер оказываются на 100% загруженными, стали всего лишь 250 килобит в секунду. И это для системы, предназначенной для переработки многих гигабит сетевого потока, то есть в тысячи раз больше.

Для эксплуатации именно этой сигнатуры атакующему достаточно лишь посылать около 10 HTTP-запросов в секунду на защищаемый веб-сервер для постепенного заполнения очереди сетевых пакетов у IDS. После исчерпания буфера пакеты начнут проходить мимо IDS и с этого самого момента атакующий может использовать любые инструменты или проводить произвольные атаки и оставаться незамеченным для систем обнаружения. Постоянный уровень зловредного трафика позволит отключить IDS до тех пор, пока этот трафик не перестанет бомбардировать внутреннюю сеть, а для кратковременных атак атакующий может послать короткий спайк из таких пакетов и также добиться слепоты у системы обнаружения, но на короткий период.

Эксплуатация медленных сигнатур не может быть обнаружена существующими механизмами: хоть IDS и обладает профилирующим кодом, она не умеет отличать просто медленную сигнатуру от катастрофически медленной и автоматически об этом сигнализировать. Стоит заметить, что сигнализация о срабатывании сигнатуры также не происходит — вследствие отсутствия подходящего контента.

Помните тот невыясненный рост числа проверок? Ошибка IDS действительно имела место быть и приводила к росту числа излишних проверок. Уязвимость получила наименование CVE-2017-15377 и в данный момент устранена в ветках Suricata IDS 3.2 и 4.0.

Описанный выше подход хорошо работает для одного конкретного экземпляра сигнатуры. Она распространяется в составе открытого набора сигнатур и, как правило, включена по умолчанию, но на вершине топа самых горячих сигнатур то и дело всплывают новые, а другие еще ждут своего трафика. Язык описания сигнатур для IDS Snort и Suricata предлагает разработчику множество удобных инструментов, таких как декодирование base64, прыжки по контенту и математические операции. Другие комбинации проверок могут также вызывать взрывообразный рост потребляемых для проверки ресурсов. Внимательное наблюдение за данными о производительности может стать отправной точкой для эксплуатации. После того, как проблема CVE-2017-15377 была устранена, мы снова запустили Suricata IDS проверять наш сетевой трафик и увидели точно такую же картину: топ самых горячих сигнатур на вершине журнала, но уже с другими номерами. Это говорит о том, что таких сигнатур, равно как и подходов к их эксплуатации, множество.

Не только IDS, но еще и антивирусы, WAF и многие другие системы основаны на сигнатурном поиске. Следовательно, подобный подход может быть применен для поиска слабых мест в их производительности. Он способен незаметно прекратить обнаружение зловредной активности системами обнаружения. Связанная с ним сетевая активность не может быть обнаружена защитными средствами и детекторами аномалий. Ради эксперимента включите профилирующую настройку в своей системе обнаружения — и понаблюдайте за вершиной журнала производительности.



Автор: Кирилл Шипулин из команды @attackdetection, Twitter | Telegram
Tags:
Hubs:
Total votes 12: ↑11 and ↓1+10
Comments2

Articles

Information

Website
www.ptsecurity.com
Registered
Founded
2002
Employees
1,001–5,000 employees
Location
Россия