Программные межсетевые экраны: огненная стена или соломенная ширма? Часть 1

Программные межсетевые экраны: огненная стена или соломенная ширма? Часть 1

Концепция межсетевого экрана (МСЭ) все еще представляется в виде непроницаемой кирпичной стены, непобедимого магического защитника всего хорошего. Но что, если на самом деле МСЭ это не стена, а всего лишь соломенная ширма?

Израэль Дж. Луго и Дон Паркер, перевод Владимир Куксенок

Концепция межсетевого экрана (МСЭ) все еще представляется в виде непроницаемой кирпичной стены, непобедимого магического защитника всего хорошего. Реклама современных производителей только подчеркивает это, обещая полную автоматизированную защиту, стену, способную блокировать все опасности, еще на стадии их возникновения, используя алгоритмы, еще два года назад возможно и не существовавшие. Но что, если на самом деле МСЭ это не стена, а всего лишь соломенная ширма?

Чтобы ответить на этот вопрос, мы должны определиться с несколькими основными понятиями. Прежде всего, чем является программный МСЭ? Его ядро есть не что иное, как фильтр – то, что находится между вашими приложениями и сетевыми компонентами ОС, и решает что можно, а что нельзя. Для этого происходит внедрение данного “фильтра” в ключевые места взаимодействия приложений и сети и анализ всего проходящего трафика на предмет соответствия определенному набору правил. Все, что соответствует этим правилам, пропускается через “фильтр”, остальной трафик блокируется (с опциональной записью в лог, экранным предупреждением и т.д.)

Как это отразится на внутренней архитектуре? По каким критериям производится анализ данных? Итак, два этих вопросы являются основными при создании МСЭ и результаты их решения становятся двумя основными компонентами архитектуры программного межсетевого экрана.

Первый компонент работает на пакетном уровне (уровни 3 и 4 модели OSI). Его задача заключается в обнаружении подозрительных и некорректных пакетов, опознавании сканирования портов и принятии решения о пропуске пакета в стек протокола. Пакеты могут анализироваться в соответствии со следующими критериями: формальная корректность пакета, направление пакета (входящий или исходящий), хост и порт отправителя, наличие установленных флагов (это попытка установления соединения? пакет принадлежит уже установленному соединению? и т.д.).

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

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

Пакетный фильтр

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

Первый способ основан на использовании драйвера NDIS (Network Driver Interface Specification). Этот драйвер будет находиться между драйвером сетевой карты и драйверами протоколов (TCP/IP и т.д.). В сущности, он станет виртуальным адаптером, являясь NIC драйвером для драйверов протокола и наоборот. Так как каждый входящий и исходящий пакет будет проходить через этот промежуточный драйвер, это позволит осуществить атаку “man-in-the-middle - человек посередине” (в данном случае с благой целью).

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

Теперь принцип работы пакетного фильтра должен быть понятен. Он анализирует каждый пакет в соответствии с критериями, указанными в наборе правил МСЭ, сохраненными в некоторой внутренней структуре данных. Осуществляется анализ таких параметров, как хост и порт отправителя и получателя, уровень фрагментации, тип протокола, флаги пакета, действительно ли пакет является частью уже открытого соединения и т.д. Например, если протокол – TCP, и пакет имеет SYN флаг (попытка открыть соединение), фильтр в зависимости от правил разрешит или запретит соединение для данного исходного и целевого хоста. Если все же соединение будет разрешено, фильтр добавит его во внутренний список открытых соединений. Таким способом межсетевой экран следит за текущими соединениями, осуществляя непрерывную инспекцию пакетов. Если пакет удовлетворяет правилам или принадлежит соединению из вышеупомянутого списка открытых соединений, он пропускается. Пакетный фильтр передает пакет на следующий уровень – драйвера протоколов, если пакет входящий или драйвера сетевой карты, если пакет исходящий. Если пакет блокируется правилами, он никогда не будет передан на следующий сетевой уровень. В этом случае, опционально, для обратной связи с пользователем на экране может появиться предупреждение или запись в лог-файле.

Фильтр процессов

Этот драйвер также присутствует во многих программных МСЭ. На уровне рассмотренного выше пакетного фильтра у нас не никакой информации о процессах. Работа происходит только с входящими и исходящими пакетами, вещами, которые с точки зрения прикладного приложения, происходят вне машины. Таким образом, для реализации фильтрации на уровне процессов, нужно создавать фильтр, работающий на более высоком уровне. Данный механизм будет работать на уровне ядра, являясь оберткой над TDI (Transport Driver Interface) и перехватывая функции, которые приложения и/или вспомогательные библиотеки (WinSock) используют для передачи данных между собой и драйверами протоколов.

Есть также и другие методы. Например, WinSock API, набор функций, использующийся большинством приложений для доступа к сети, основан на многоуровневой модели, позволяющей вставлять расширения (extensions) третьих лиц между интерфейсом приложений и базовым сетевым протоколом. Такое расширение можно добавить, реализовав Layered Service Provider (LSP) и вставив его в LSP-цепочку. LSP – это стандартная Windows DLL, соответствующая некоторой спецификации и имеющая специальную функцию, которая предназначается для вставки в цепочку WinSock протокола. Согласно модели WinSock, все сетевые данные проходят через эту цепочку, в которой каждый LSP принимает решение о пропуске данных на уровень выше (или ниже, в зависимости от того, являются ли конкретные данные входящими или исходящими), предварительно обработав или изменив данные в соответствии со своей функцией. Quality of Service (QoS) является примерно такого расширения, реализованного как LSP. Фильтр процессов может быть реализован в виде LSP, находясь в цепочке протокола и выборочно передавая данные к следующему элементу цепочки или блокируя их, руководствуясь собственными критериями.

Однако, описанный метод - не лучшее решение для реализации фильтра, так как он будет действовать только для приложений, использующих WinSock для передачи данных. Для обхода фильтра процессов, основанного на LSP, нужно всего лишь воспользоваться собственным драйвером для прямой связи через TDI c драйвером протокола, что позволить обойтись без WinSock. Первый способ, основанный на обертке над TDI, является лучшей альтернативой, так как работает на более низком уровне.

Задача фильтра процессов – анализ попыток создание соединений приложениями. Он смотрит на идентификатор (PID) процесса, пытающегося отправлять или получать данные и анализирует его характеристики на соответствие набору правил, используя более или менее сложный набор критериев, в зависимости от качества реализации фильтра процессов МСЭ. Но основной вопрос обычно выглядит так: Разрешено ли приложению, создавшему этот процесс, выполнять те действия, которые оно пытается выполнить? Это задача сводится к проверки целостности файла, создавшего процесс, путем сравнения текущего хэша с известным, поиску файла в наборе правил, а затем проверка разрешения на выполнение соответствующих действий.

Проблемы, связанные с фильтрами процессов

Существует несколько проблем, связанных с реализаций фильтров процессов. Например, неплохо было бы проверять какие DLL присутствуют в адресном пространстве процесса, и действительно ли они должны там находиться? Это имеет смысл, так как код загруженных модулей исполняется в контексте процесса, в адресном пространстве которого они находятся. Таким образом, злонамеренный процесс может загрузить EVIL.DLL в адресное пространство “хорошего” процесса X, и процесс X выполнит код из EVIL.DLL перед своим собственным. Решением этой проблемы будет нахождение всех загруженных модулей, поиск их образов на диске и затем проверка на наличие в таблице модулей, разрешенных для загрузки данным процессом. МСЭ часто осуществляют такую проверку и спрашивают разрешения на загрузку модуля, но очевидно, что это не лучшее решение проблемы. Межсетевой экран не может знать все возможные настоящие и будущие DLL, “плохие” и “хорошие”, поэтому пользователю приходится решать, разрешить ли загрузку данного модуля или нет. Другая проблема – был ли код процесса изменен в памяти (процесс может изменять память другого процесса, с целью изменения его поведения). Такое также возможно, если процесс был создан злонамеренной программой (которая имела бы возможность изменять поведение процесса). Это список продолжать можно долго…

Только некоторые из этих проблем адекватно решаются в современных МСЭ. Правда в том, что существует слишком много путей маскировки злонамеренного кода, которые могут ввести в заблуждение фильтры и простых и сложных межсетевых экранов. Злонамеренный процесс может изменить в памяти код другого процесса. Можно использовать в своих интересах возможности легитимной программы, например, запустив из командной строки браузер, передав ему в аргументах указание загрузить злонамеренную страницу. Даже если фильтр отслеживает отношение родительский-дочерний процесс, можно использовать много уровней косвенности (злонамеренный процесс может запустить cmd.exe, которому приказано запустить другой cmd.exe, который в свою очередь запустит браузер с нужной страницей). Или враждебное приложение может применить агрессивную тактику против МСЭ, вообще его отключив, с помощью эмуляции кликов мыши, закрывающих предупреждения. Помните, все, что может сделать пользователь, может сделать и программа (в пределах контекста пользователя, конечно).

Все что написано выше, фокусируется на введении в заблуждение фильтра процессов. Совсем другие возможности открываются, если атакующему даже не нужно проходить через этот фильтр. Представьте, что информация о процессах, которую использует фильтр процессов, потеряна. Вся информация, которую в этом случае имеет МСЭ это входящий и исходящий трафик, работа с которым ведется на уровне пакетного фильтра. Все что нужно сделать атакующему – это использовать драйвер, который произведет инъекцию пакетов на уровень более низкий, чем уровень фильтра процессов, что даст возможность волноваться только о пакетном фильтре. Пока он будет использовать разрешенные порты (например, 80, 25 и т.п.) пакетный фильтр будет пропускать пакеты атакующего. О возможности работы под уровнем пакетного фильтра даже не будем упоминать…

Заключение

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

Ваш мозг на 60% состоит из жира. Добавьте 40% науки!

Сбалансированная диета для серого вещества

Подпишитесь и станьте самым умным овощем