Платформа фильтрации ip пакетов windows разрешила подключение

Обновлено: 03.07.2024

Начиная с Server 2008 и Vista в винду был встроен механизм WFP,
представляющий собой набор API и системных сервисов. С помощью него стало можно
запрещать и разрешать соединения, управлять отдельными пакетами. Эти
нововведения были предназначены для упрощения жизни разработчиков различных
защит. Внесенные в сетевую архитектуру изменения затронули как kernel-mode, так
и user-mode части системы. В первом случае необходимые функции экспортируются
fwpkclnt.sys, во втором — fwpuclnt.dll (буквы "k" и "u" в названиях библиотек
означают kernel и user соответственно). В этой статье мы расскажем о применении
WFP для перехвата и фильтрации трафика, а после ознакомления с основными
определениями и возможностями WFP мы напишем свой простой фильтр.

Основные понятия

Перед началом кодинга нам совершенно необходимо ознакомиться с терминологией
Microsoft — и для понимания статьи будет полезно, и дополнительную литературу
читать будет проще :). Итак, поехали.

Классификация — процесс определения того, что нужно делать с пакетом.
Из возможных действий: разрешить, блокировать или вызвать callout.

Callouts — это набор функций в драйвере, которые проводят инспекцию
пакетов. Они имеют специальную функцию, выполняющую классификацию пакетов. Эта
функция может принять следующее решение:

  • разрешить (FWP_ACTION_PERMIT);
  • блокировать (FWP_ACTION_BLOCK);
  • продолжить обработку;
  • запросить больше данных;
  • прервать соединение.

Фильтры (Filters) — правила, указывающие, в каких случаях вызывается
тот или иной callout. Один драйвер может иметь несколько callout’ов, а
разработкой драйвера с callout’ом мы и займемся в этой статье. Кстати, колауты
есть и встроенные, например, NAT-callout.

Layer — это признак, по которому объединяются различные фильтры (или,
как говорят в MSDN, "контейнер").

По правде говоря, документация от Microsoft, выглядит достаточно мутно, пока
не заглянешь в примеры в WDK. Поэтому, если вдруг надумаешь разрабатывать что-то
серьезное, нужно непременно с ними ознакомиться. Ну что ж, теперь плавно
перейдем к практике. Для успешной компиляции и тестов тебе потребуется WDK (Windows
Driver Kit), VmWare, виртуальная машина с установленной Вистой и отладчик WinDbg.
Что касается WDK, то у меня лично установлена версия 7600.16385.0 — там есть все
необходимые либы (поскольку мы будем разрабатывать драйвер, нам нужны только
fwpkclnt.lib и ntoskrnl.lib) и примеры использования WFP. Ссылки на весь
инструментарий уже неоднократно приводились, поэтому повторяться не будем.

Coding

Для инициализации callout’а я написал функцию BlInitialize. Общий алгоритм
создания callout и добавления фильтра таков:

  1. FWPMENGINEOPEN0 осуществляет открытие сеанса;
  2. FWPMTRANSACTIONBEGIN0 — начало операции с WFP;
  3. FWPSCALLOUTREGISTER0 — создание нового callout;
  4. FWPMCALLOUTADD0 — добавление объекта callout’а в систему;
  5. FWPMFILTERADD0 — добавление нового фильтра(ов);
  6. FWPMTRANSACTIONCOMMIT0 — сохранение изменений (добавленных
    фильтров).

Обрати внимание, что функции оканчиваются на 0. В Windows 7 некоторые из этих
функций были изменены, например, появилась FwpsCalloutRegister1 (при
сохраненной FwpsCalloutRegister0). Отличаются они аргументами и, как следствие,
прототипами классифицирующих функций, но для нас это сейчас неважно — 0-функции
универсальны.

FwpmEngineOpen0 и FwpmTransactionBegin0 не особо нам интересны — это
подготовительный этап. Самое интересное начинается с функции
FwpsCalloutRegister0:

Прототип FwpsCalloutRegister0

NTSTATUS NTAPI FwpsCalloutRegister0
(
__inout void *deviceObject,
__in const FWPS_CALLOUT0 *callout,
__out_opt UINT32 *calloutId
);

Я уже говорил, что callout — это набор функций, теперь пришло время
рассказать об этом подробнее. Структура FWPS_CALLOUT0 содержит указатели на три
функции — классифицирующую (classifyFn) и две уведомляющие (о
добавлении/удалении фильтра (notifyFn) и закрытии обрабатываемого потока (flowDeleteFn)).
Первые две функции являются обязательными, последняя нужна только в случае, если
ты хочешь мониторить сами пакеты, а не только соединения. Также в структуре
содержится уникальный идентификатор, GUID колаута (calloutKey).

Код регистрации callout

FWPS_CALLOUT sCallout = ;
sCallout.calloutKey = *calloutKey;
sCallout.classifyFn = BlClassify;
// классифицирующая функция
sCallout.notifyFn = (FWPS_CALLOUT_NOTIFY_FN0)BlNotify;
// функция, уведомляющая о добавлении/удалении фильтра
// создаем новый колаут
status = FwpsCalloutRegister(deviceObject, &sCallout, calloutId);

Далее нужно добавить объект-callout в систему и присоединить его к
определенному уровню (layer) с помощью функции FwpmCalloutAdd0:

DWORD WINAPI FwpmCalloutAdd0(
__in HANDLE engineHandle,
__in const FWPM_CALLOUT0 *callout,
__in_opt PSECURITY_DESCRIPTOR sd,
__out_opt UINT32 *id
);
typedef struct FWPM_CALLOUT0_ GUID calloutKey;
FWPM_DISPLAY_DATA0 displayData; // описание callout
UINT32 flags;
GUID *providerKey;
FWP_BYTE_BLOB providerData;
GUID applicableLayer;
UINT32 calloutId;
> FWPM_CALLOUT0;

В структуре FWPM_CALLOUT0 нам интересно поле applicableLayer — уникальный
идентификатор уровня, на который добавляется callout. В нашем случае это
FWPM_LAYER_ALE_AUTH_CONNECT_V4. "v4" в названии идентификатора означает версию
протокола Ipv4, есть также FWPM_LAYER_ALE_AUTH_CONNECT_V6 для Ipv6. Учитывая
малую распространенность Ipv6 на настоящий момент, работать мы будем только с
Ipv4. CONNECT в названии означает, что мы контролируем только установку
соединения, о входящих и исходящих на этот адрес пакетах речи не идет! Вообще
уровней, помимо использованного нами, много — они объявлены в заголовочном файле
fwpmk.h из WDK.

Добавление объекта-callout в систему

// название callout
displayData.name = L"Blocker Callout";
displayData.description = L"Blocker Callout";
mCallout.calloutKey = *calloutKey;
mCallout.displayData = displayData;
// описание callout
//FWPM_LAYER_ALE_AUTH_CONNECT_V4
mCallout.applicableLayer = *layerKey;
status = FwpmCalloutAdd(gEngineHandle, &mCallout, NULL, NULL);

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

В FWPM_FILTER0 есть одна или несколько структур FWPM_FILTER_CONDITION0 (их
число определяется полем numFilterConditions). Поле layerKey заполняется GUID’ом
уровня (layer), к которому мы хотим присоединиться. В данном случае указываем
FWPM_LAYER_ALE_AUTH_CONNECT_V4.

Теперь подробнее рассмотрим заполнение FWPM_FILTER_CONDITION0. Во-первых, в
поле fieldKey нужно явно указать, что мы хотим контролировать — порт, адрес,
приложение или что-то еще. В данном случае WPM_CONDITION_IP_REMOTE_ADDRESS
указывает системе, что нас интересует IP-адрес. Значение fieldKey определяет,
значения какого типа будут в структуре FWP_CONDITION_VALUE, входящей в
FWPM_FILTER_CONDITION0. В данном случае в ней содержится ipv4-адрес. Идем
дальше. Поле matchType определяет, каким образом будет производиться сравнение
значения в FWP_CONDITION_VALUE с тем, что пришло по сети. Тут вариантов много:
можно указать FWP_MATCH_EQUAL, что будет означать полное соответствие условию, а
можно — FWP_MATCH_NOT_EQUAL, то есть, фактически, мы можем добавить таким
образом исключение фильтрации (адрес, соединение с которым не отслеживается).
Еще есть варианты FWP_MATCH_GREATER, FWP_MATCH_LESS и другие (см. энум
FWP_MATCH_TYPE). В данном случае у нас стоит FWP_MATCH_EQUAL.

Я не стал сильно заморачиваться и просто написал условие на блокирование
одного выбранного IP-адреса. В случае, когда какое-то приложение попытается
установить соединение с выбранным адресом, будет вызвана классифицирующая
функция нашего callout’а. Код, обобщающий сказанное, ты можешь посмотреть на
врезке "Добавление фильтра в систему".

Добавление фильтра в систему

filter.flags = FWPM_FILTER_FLAG_NONE;
filter.layerKey = *layerKey;
filter.displayData.name = L"Blocker Callout";
filter.displayData.description = L"Blocker Callout";
filter.action.type = FWP_ACTION_CALLOUT_UNKNOWN;
filter.action.calloutKey = *calloutKey;
filter.filterCondition = filterConditions;
// одно условие фильтрации
filter.numFilterConditions = 1;
//filter.subLayerKey = FWPM_SUBLAYER_UNIVERSAL;
filter.weight.type = FWP_EMPTY; // auto-weight.
// добавляем фильтр на удаленный адрес
filterConditions[0].fieldKey = FWPM_CONDITION_IP_REMOTE_ADDRESS;
filterConditions[0].matchType = FWP_MATCH_EQUAL;
filterConditions[0].conditionValue.type = FWP_UINT32;
filterConditions[0].conditionValue.uint32 = ntohl(BLOCKED_IP_ADDRESS);
// добавляем фильтр
status = FwpmFilterAdd(gEngineHandle, &filter, NULL, NULL);

Вообще, конечно, фильтрующих условий может быть много. Например, можно
указать блокирование соединений с определенным удаленным или локальным портом (FWPM_CONDITION_IP_REMOTE_PORT
и FWPM_CONDITION_IP_LOCAL_PORT соответственно). Можно вылавливать все пакеты
определенного протокола или определенного приложения. И это еще не все! Можно,
например, заблокировать трафик определенного пользователя. В общем, есть где
разгуляться.

Впрочем, вернемся к фильтру. Классифицирующая функция в нашем случае просто
блокирует соединение с указанным адресом (BLOCKED_IP_ADDRESS), возвращая
FWP_ACTION_BLOCK:

Код нашей classify-функции

void BlClassify(
const FWPS_INCOMING_VALUES* inFixedValues,
const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
VOID* packet,IN const FWPS_FILTER* filter,
UINT64 flowContext,FWPS_CLASSIFY_OUT* classifyOut)
// заполняем структуру FWPS_CLASSIFY_OUT0
if(classifyOut) < // блокируем пакет
classifyOut->actionType =
FWP_ACTION_BLOCK;
// при блокировании пакета нужно
сбрасывать FWPS_RIGHT_ACTION_WRITE
classifyOut->rights&=

На практике функция классификации также может установить FWP_ACTION_PERMIT,
FWP_ACTION_CONTINUE и др.

И в заключение при выгрузке драйвера нужно удалить все установленные
callout’ы (угадай, что будет, если система попытается вызвать callout
выгруженного драйвера? Правильно, BSOD). Для этого существует функция
FwpsCalloutUnregisterById. В качестве параметра ей передается 32-битный
идентификатор callout’а, возвращенный функцией FwpsCalloutRegister.

Завершение работы callout’а

NTSTATUS BlUninitialize() NTSTATUS ns;
if(gEngineHandle) FwpmEngineClose(gEngineHandle);

>
if(gBlCalloutIdV4) ns =FwpsCalloutUnregisterById(gBlCalloutIdV4);
>
return ns;
>

Как видишь, программирование WFP-фильтра — не такая сложная задача, поскольку
MS предоставили нам весьма удобный API. Кстати, в нашем случае мы устанавливали
фильтр в драйвере, но это можно делать и из юзермода! Например, семпл из wdk
msnmntr (монитор трафика MSN Messenger-а) так и поступает — это позволяет не
перегружать kernel-mode часть фильтра.

Свой GUID

Для регистрации callout ему нужен уникальный идентификатор. Для того, чтобы
получить свой GUID (Globally Unique Identifier), используй guidgen.exe, входящий
в Visual Studio. Лежит тулза в (VS_Path)\Common7\Tools. Вероятность коллизии
очень мала, поскольку длина GUID составляет 128 бит, и всего доступно 2^128
идентификаторов.

Отладка фильтра

Для отладки дров удобно использовать связку Windbg+VmWare. Для этого нужно
настроить как гостевую систему (в виде которой выступает Vista), так и отладчик
WinDbg. Если у WinXP для удаленной отладки нужно было редактировать boot.ini, то
для Vista+ есть консольная утилита bcdedit. Как обычно, нужно включить отладку:

BCDedit /dbgsettings SERIAL DEBUGPORT:1 BAUDRATE:115200 BCDedit /debug
ON (или BCDedit /set debug ON)

Далее нужно настроить последовательный порт удаленной системы (см.
соответствующую иллюстрацию).


Теперь все готово! Запускаем батник с нижеприведенным текстом:

start windbg -b -k com:pipe,port=\\.\pipe\com_1,resets=0

и лицезреем отладочный вывод в окне windbg (см. картинку).


Заключение

Как видишь, область применения WFP довольно широка. Тебе решать, как
применить эти знания — во зло или во благо 🙂

Windows Платформа фильтрации (WFP) позволяет независимым поставщикам программного обеспечения (ISVs) фильтровать и изменять пакеты TCP/IP, отслеживать или авторизовать подключения, фильтровать трафик, защищенный протоколом Интернета (IPsec) и фильтровать удаленные вызовы процедур (RPCs).

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

Объем событий: High.

Тип компьютера Общий успех Общий сбой Более сильный успех Более сильный сбой Комментарии
Контроллер домена Нет Да IF Да Аудит успешности для этой подкатегории обычно создает очень большой объем событий, например одно событие для каждого подключения к системе. Гораздо важнее аудит событий сбоя (например, заблокированных подключений). Рекомендации по использованию и анализу собираемой информации см. в разделах Мониторинг безопасности Рекомендации.
IF . Включить аудит успешности в случае необходимости отслеживать успешные исходящие или входящие подключения к неоправданым IP-адресам на компьютерах или устройствах с высоким значением.
Сервер участника Нет Да IF Да Аудит успешности для этой подкатегории обычно создает очень большой объем событий, например одно событие для каждого подключения к системе. Гораздо важнее аудит событий сбоя (например, заблокированных подключений). Рекомендации по использованию и анализу собираемой информации см. в разделах Мониторинг безопасности Рекомендации.
IF . Включить аудит успешности в случае необходимости отслеживать успешные исходящие или входящие подключения к неоправданым IP-адресам на компьютерах или устройствах с высоким значением.
Workstation Нет Да IF Да Аудит успешности для этой подкатегории обычно создает очень большой объем событий, например одно событие для каждого подключения к системе. Гораздо важнее аудит событий сбоя (например, заблокированных подключений). Рекомендации по использованию и анализу собираемой информации см. в разделах Мониторинг безопасности Рекомендации.
IF . Включить аудит успешности в случае необходимости отслеживать успешные исходящие или входящие подключения к неоправданым IP-адресам на компьютерах или устройствах с высоким значением.

Список событий:

5031(F): служба Windows брандмауэра заблокировала прием входящих подключений в сети.

5150(-): Платформа фильтрации Windows блокировала пакет.

5151(-): Более Windows фильтр платформы фильтрации заблокировал пакет.

5154(S): Платформа Windows фильтрации разрешила приложению или службе прослушивать в порту для входящих подключений.

5155(F): платформа Windows фильтрации заблокировала прослушивание приложения или службы в порту для входящих подключений.

5156(S): платформа Windows фильтрации разрешила подключение.

5157(F): платформа Windows фильтрации заблокировала подключение.

5159(F): Платформа Windows фильтрации заблокировала привязку к локальному порту.

Я пытаюсь настроить брандмауэр Windows в режиме повышенной безопасности для входа в систему и сообщить мне, когда программы пытаются выполнить исходящие запросы. Я ранее пробовал установить ZoneAlarm, который работал с моими чудесами в Windows XP. Но теперь я не могу установить ZoneAlarm в Windows 7.

Возможно ли каким-либо образом отслеживать журнал или получать уведомления, когда программа пытается это сделать, если я установил все исходящие соединения для автоматического блокирования, чтобы затем создать определенное правило для программы и заблокировать его?

Обновление
Я включил все параметры ведения журнала, доступные через окна свойств брандмауэра Windows с помощью Advanced Security Console. Но я вижу только журналы в файле %systemroot%\system32\LogFiles\Firewall\pfirewall.log , а не в средстве просмотра событий, в качестве первого ответа.

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

4 ответа

Вы можете увидеть это в Средстве просмотра событий . Сначала вам нужно настроить параметры ведения журнала в Консоль дополнительных настроек :

alt text

В левой панели «Просмотр событий» разверните узел Журнал приложений и сервисов -> Microsoft -> Windows -> Брандмауэр Windows с повышенной безопасностью :

alt text

Здесь вы можете создать собственное представление и фильтровать журнал только для исходящих попыток подключения.

В Windows 7 & 8 необходимо сначала включить аудит неудачных подключений.

Локальная политика компьютера (Run: GPEdit.msc )> Конфигурация компьютера> Настройки Windows> Настройки безопасности> Локальные политики> Политика аудита> Доступ к объекту аудита: Отказ

Теперь сброшенные соединения вместе с соответствующим исполняемым именем должны отображаться по адресу:

Журнал событий> Журналы Windows> Безопасность:

  1. Платформа фильтрации Windows заблокировала пакет: [Идентификатор события: 5152]
  2. Платформа фильтрации Windows заблокировала соединение: [Идентификатор события: 5157]

Здесь вы найдете:

Имя приложения: \ device \ harddiskvolume2 \ program files \ xyz.exe

Я искал одну и ту же проблему, и ни Event Viewer (без событий), ни опция pfirewall.log (без имени нарушающей программы) помогли мне определить, что происходит.

Оглядываясь вокруг, я люблю Брандмауэр Windows , который даже предоставляет графический интерфейс, который показывает программу-нарушитель и позволяет создавать правила исключения (вам нужно, чтобы все WFN создавали правила, а не исключения при вызове в первый раз).

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

WFP - это универсальная технология фильтрации сети, охватывающая все основные
уровни, от транспортного (TCP/UDP) до канального (Ethernet), и дающая разработчикам
массу интересных возможностей.

Почему WFP ?

До WFP разработчики фаерволов, спам-фильтров, родконтролей и других программ
такого плана были вынуждены использовать сложные, разрозненные, а часто просто
недокументированные способы, которые во многих отношениях не давали нужного
эффекта или требовали высокой квалификации и учета многочисленных деталей, с
которыми то и дело возникали проблемы при переносе на другие версии Windows.
Пример таких технологий - TDI, LSP, NDIS, а также старые Filter-Hook Drivers и
Firewall-Hook Drivers. В WFP многие типовые проблемы этих технологий были учтены,
некоторые решения вообще не имеют аналогов, либо тяжелореализуемы в TDI/LSP/NDIS.
Сама технология имеет достаточно простую и понятную объектную модель, хорошо
документирована и при желании ее может освоить человек весьма средней квалификации.

Добавлю, что WFP - единственная на сегодняшний день технология, позволяющая
полноценно фильтровать трафик от modern-приложений на Windows 8 и выше.
И не только. Например, TDI и LSP в настоящее время уже не справляются даже с
Internet Explorer 11 на Windows 7. Поэтому при выборе технологии для нового проекта
следует в первую очередь рассматривать WFP, и только потом (если есть причины,
например совместимость с XP или отсутствие каких-то важных функций WFP на
целевых версиях Windows) другие.

Краткая история.

Появилась в Windows Vista, с тех пор постепенно развивается и дополняется.
В Windows 7 появилась возможность фильтрации на уровне Ethernet, возможность
делать редиректы соединений (как исходящих, так и входящих), а также разные
вспомогательные функции, например для своевременной очистки ресурсов.
В Windows 8 появилось то, чего так долго ждали некоторые разработчики -
возможность многократно перекидывать соединение с одного прокси на другой.
Раньше из-за отсутствия этой возможности было почти нереальным иметь в системе,
к примеру, параллельно работающий фаервол и какой-нибудь спам-фильтр от
разных производителей. Есть и другие изменения, все они описаны в MSDN.

Ложка дегтя.

Лично для меня ложкой дегтя в WFP является то, что наиболее "вкусные" вещи в
ней появились только в Windows 7 - Windows 8 и для того, чтобы сделать
коммерческий продукт, реально совместимый со всей современной линейкой Windows,
не списывая со счетов XP и Vista, все равно приходится использовать TDI/LSP
вместе с WFP. Также я замечал, что документация местами недостаточно детальная, а
кое-где содержит ошибки. В итоге приходилось иногда закапываться надолго в
отладчик, чтобы узнать, в чем дело. И в WFP, как и в любой технологии, есть
недочеты и даже ошибки. Сам я с ними на практике не сталкивался, но не раз
слышал о проблемах с Teredo, например, в результате чего система выпадает в
синий экран (BSOD).

Документация и исходники.

Главный источник информации по WFP - конечно же, MSDN.
Обращаю внимание, что WFP имеет функции как в kernel mode, так и в user mode,
поэтому одну часть документации следует искать в разделе о программировании
драйверов, а вторую - в разделе "network programming" из WinAPI:

Аналогично, исходники примеров для WFP есть как в Windows SDK Samples (diagevents и
msnfilter) и в Windows Driver Kit Samples (ddproxy, inspect, msnmntr и stmedit).
Вероятно, на MSDN Gallery можно найти и другие исходники, а где-нибудь на codeproject,
sourceforge и других опенсорсных хостингах - исходники проектов с использованием WFP.

В следующей части: Архитектура WFP, объектная модель, принципы работы.

Читайте также: