Для будущих студентов курса «Сетевой инженер» и всех интересующихся подготовили полезную статью.
Также приглашаем на открытый вебинар по теме «NAT — не Firewall». Участники вебинара вместе с экспертом рассмотрят NAT и его использование, почему NAT != firewall, а также различные виды конфигураций для разных ситуаций.
В данной статье будет проведено исследование сетевой подсистемы ОС Windows и Linux, а также предложен план изучения подсистем операционной системы. Основная задача исследования - понять, из чего состоит сетевая подсистема; какие поддерживает протоколы из коробки; какие дополнительные механизмы использует в своей работе.
Disclamer: Статья описывает данные, которые с точки зрения автора помогут понять, как работают операционные системы с моделью TCP/IP, и не претендует на полноту.
Инструментарий и метод исследования
Для исследования операционной системы будем использовать следующие инструменты:
Операционная система Linux:
git;
Visual Studio Code;
Операционная система Windows:
strings.exe;
radare2;
hxD Editor;
Python;
Process Explorer.
Инструменты подобраны таким образом, чтобы можно было охватить максимальное количество форматов файлов, которые можно обнаружить в ОС. Для исходного же кода главный инструмент - редактор, который позволяет удобно переходить от исходника к исходнику для разбора кода.
В нашем исследовании будем руководствоваться двумя правилами:
Используем всю информацию из документации операционных систем;
Проверяем правдивость описанных данных. Для структур данных:
В ОС Windows исследуем соответствующие функционалу dll, sys файлы;
В ОС Linux исследуем исходные коды и отдельные ветки ядра;
Теперь определимся с проблемами, которые вероятно будут нас преследовать на протяжении всего исследования.
Проблемы при исследовании ОС Linux
Основной функционал подсистемы целиком находится в ядре. К счастью, исходный код доступен в сети. Исследование исходного кода таких больших проектов всегда довольно сложная задача. На её сложность может влиять несколько факторов:
Субъективные:
у каждого исследователя разный уровень экспертизы в области языка программирования, который используется в исходном коде;
у каждого исследователя есть свой собственных подход на интерпретацию полученной информации.
Объективные:
ограниченности исследования по времени;
объем исходного кода;
принятые правила кодирования проекта.
Как минимизировать количество действий исследователя, чтобы получить как можно больше полезной и интересной информации? Огромную роль играет правильно настроенное рабочее место. В нашем случае верную настройку определяет набор инструментов, который мы описали в разделе "Инструментарий и метод исследования". Также можно применить небольшой лайфхак и не рассматривать каждую строку исходников ядра, а рассматривать только высокоуровневые элементы. Это сэкономит время на изучение языка программирования и даст возможность разобраться, что к чему. Попробуем применить эту тактику на практике.
Сетевая подсистема Linux
Начнем наше исследование с вот такой интересной картинки:
Картинка представляет собой структуру директорий исходного кода ядра ОС Linux. На ней видно, что сетевая подсистема вовсе не самая большая часть операционной системы. По правде говоря, можно собрать ядро и без этой части. Сегодня это вариант только для embeded
систем, в общем случае без сети представить Linux сложно.
Код, который относится к сетевой подсистеме, находится в директории "net". Посмотрим, из чего он состоит.
Исходный код собран по выполняемым задачам. За базовыми элементами можно обратиться в директорию core:
На картинке выделены названия файлов, которые описывают основные структуры для работы с сетью. Это создание сокетов, хранение пересылаемых данных и работа с фильтрующей подсистемой bfp
. Именно этот код переиспользуется для остальной части сетевой подсистемы.
Оставшиеся файлы в директории "net" описывают работу ядра с различными протоколами. Интересным моментом здесь является то, что фильтрующая подсистема имеет какие-то файлы только в некоторых протоколах и подсистемах:
Прямоугольниками выделены те протоколы и подсистемы, которые содержат файлы netfilter
. Как видно из картинки, механизм фильтрации трафика работает не со всеми протоколами. Также интересно то, что он присутствует не только в протоколах, но и в более высокоуровневой абстракции - bridge. Теперь понятно, почему bridge от Linux можно настроить настолько гибко и контролировать пересылаемые данные.
Что в итоге? Всего по 4м картинкам структуры исходных кодов ядра мы уже обладаем информацией о том, какие поддерживаются протоколы в ядре Linux, какие механизмы интегрированы в протоколы для контроля и фильтрации и где найти базовые элементы, которые позволяют использовать сеть. Попробуем найти эту информацию и в ОС Windows.
ОС Windows: сетевая подсистема
Изучить сетевую подсистему этой ОС так же просто, как в ОС Linux, не получится. Самый большой камень преткновения - закрытый исходный код. Однако давайте попытаемся восстановить информацию о том, как работает сетевая подсистема в рамках этой ОС. В качестве целей будем использовать то, что нашли в Linux:
Где располагается код для создания и работы с сокетами;
Какой механизм используется для фильтрации;
Как имплементированы протоколы.
Сетевая подсистема, согласно документации построена по принципу модели OSI. И также приводится описание того, за счет каких технологий и типов файлов реализуется работа отдельных уровней модели.
Имплементация модели OSI в операционной системе начинается со строго определенных уровней. В данном случае всё начинается на уровне "Канальном" и заканчивается на уровне "Транспортном". Имплементация на каждом уровне своя:
Канальный уровень - состоит из MAC и LLC, соответственно и частей имплементации должно быть две:
MAC - miniportdriver это драйвер, который контролирует сетевой интерфейс;
LLC - protocol driver - драйвер, который используется для обработки данных от сетевых устройств;
Уровень сети - protocol driver - драйвер, который используется для обработки данных от сетевых устройств;
Уровень транспорта - protocol (transport) driver;
Вот и выявилось коренное отличие Windows от Linux - вся логика работы сетевой подсистемы разбита на множество элементов. Каждое устройство, каждый протокол и абстракция имплементированы не в ядре, а в модуле ядра - драйвере, который может быть загружен ядром по запросу. Что это значит для нас? У нас нет исходного кода данных драйверов, а значит мы не можем использовать подход, который использовали при изучении ОС Linux.
Как же быть? При разработке эксплойтов исследователи в качестве отправной точки для восстановления структур внутри ядра Windows используют проект с открытым исходным кодом - ReactOS. Попробуем сделать тоже самое. Давайте найдем части подсистемы и затем спроецируем найденную информацию на реальную ОС Windows.
На экране ниже приведен снимок директории с основными драйверами для сетевой подсистемы:
Попробуем найти такие же файлы в реальной ОС. Заглянем в директорию "%Windows%". В качестве исследуемой системы возьмем Windows 7.
Часть файлов действительно имеет названия файлов, которые присутствуют в реальной ОС.
Один из способов проверки функционала уже скомпилированного приложения - прочитать используемые им строки. Можем для этого воспользоваться утилитой strings.exe для tcpip.sys
:
Похоже, что данные по работе с сетевой подсистемой можно обнаружить именно в этом драйвере. Поищем функции, которые позволяют фильтровать трафик. Как их идентифицировать?
В операционной системе Windows за всё время её существования было 2 технических спецификаций на основании которых создавались драйвера для сетевого взаимодействия: TDI и WinSock. И все эти спецификации использовали отдельный драйвер для того чтобы можно было собирать весь функционал - NDIS. Значит большая часть функций сконцентрирована в этих драйверах:
netio.sys
tcpip.sys
tdi.sys
ndis.sys
Но в них все равно нет функций, которые бы могли фильтровать трафик. Почему так? Дело в том, что до Windows 7 фильтрация трафика как такового была имплементирована в отдельных драйверах, которые настраивались за счет интерфейса Windows. Начиная с Windows 7 была реализована так называемая Windows Filtering Platform, которая определила часть драйверов в специальную категорию, которая и призвана фильтровать трафик.
Часть этих фильтров можно найти по обычному поиску в директориях ОС:
Get-ChildItem "C:\WINDOWS\System32" FWPKCLNT.SYS -Recurse | Select-Object FullName
Get-ChildItem "C:\WINDOWS\System32" wfplwf.sys -Recurse | Select-Object FullName
Используем утилиту strings.exe на файлы FWPKCLNT.SYS
и wfplwf.sys
:
Выше представлена часть строк, которые обнаружились в файле FWPKCLNT.sys
, файл wfplwf.sys
содержал только названия функций. Почему тогда они здесь вместе? Дело в том, что в импортах wfplwf.sys
есть функция, которая берется из файла FWPKCLNT.sy
s:
В итоге:
Имплементация всех объектов и механизмов в ядре для работы с протоколами - файлы из директории
%Windows%\System32\Drivers
. Основные из них - netio.sys, ndis.sys, tdi.sys.Фильтрацией занимаются драйвера WFP:
FWPKCLNT.sys
,wfplwf.sys
.Имплементируются через отдельные одноименные файлы, например:
tcpip.sys
В ОС Linux мы не задумывались о том как приложения получают доступ к структурам ядра и работают с сетью. Там более-менее всё очевидно и только один шаг до функций, но для Windows всё работает по принципу Callback`ов. Поэтому скорее всего будет несколько оберток для взаимодействия. Попробуем найти эти файлы.
Для поиска файлов, которые используются в качестве обертки-библиотеки, можно использовать следующий метод. Для этого создадим мини приложение, которое будет работать с сокетами, принимать и отправлять данные. Исходный код приложения:
import socket
HOST = '127.0.0.1'
PORT = 10000
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((HOST, PORT))
s.listen()
conn, addr = s.accept()
with conn:
print('Connected by', addr)
while True:
data = conn.recv(1024)
if not data:
break
conn.sendall(data)
Запускаем файл в ОС, если не возникло никаких ошибок, то необходимо параллельно запустить инструмент Process Explorer. С помощью этого инструмента мы подсмотрим, чем занимается поток, пока ждет соединения. На картинке ниже отображены все описанные действия:
Слева изображен стек вызовов функций, которые задействованы в процедуре настройки сокета и перевода его в состояние bind. Этот набор файлов - mswinsock.dll
(Win Sock 2 Service) и WS2_32.dll
(Windows Socket 2). Данные библиотеки используются для того, чтобы предоставить приложениям функции по работе с сокетами в ОС Windows.
Стоит отметить, что последовательность функций, которые вызываются для работы сокета в ОС, не виден в Process Explorer`е. Если нужно восстановить и эти данные, то нужно использовать отладчик ядра.
Таким образом, проводить исследование подсистем любых ОС и их механизмов можно с исходным кодом и без — достаточно выбрать необходимый набор инструментов, а также доступные методы, источники знаний.
Узнать подробнее о курсе «Сетевой инженер».
Зарегистрироваться на открытый вебинар по теме «NAT — не Firewall».