Представь себе фантасмагорию: твоя сетевая карта (или процессор, или
видеокарта) живет отдельной жизнью шизофреника. И дружит она (или все эти
компьютерные потроха сразу) против тебя. Возможно ли такое восстание машин,
инициированное силами хакеров или, скажем, производителей железа? Давай
пофантазируем!

Начнем с того, что любой сетевой пакет, пришедший
из недр сети, прежде чем дойти до твоего браузера или
другого сетевого приложения, в первую очередь будет
обработан твоей сетевой картой, а затем — непосредственно ядром операционной системы. А вдруг этот
самый пакет будет нести вместе с собой некие инструкции, которые тут же подчинят себе всю машину? Ведь для
этого не нужно писать эксплоиты, искать уязвимости, для
того чтобы внедрить зловредный код... Просто… отправь
пакет на какой-либо открытый порт. И — все... Ты уже не
хозяин своему компьютеру. И плакали крокодильими
слезами разработчики антивирусных программ и систем
проактивной защиты – помочь они ничем не смогут.

 

Поехали!

Скажу только одно — есть в сети примеры (внимание!) веб
и SSH-серверов, базирующихся на ресурсах одной лишь
сетевой или графической карты. Да-да, использующих
ресурсы (микропроцессор и оперативную память) этих
самых карт (prooflink:
alchemistowl.org/arrigo/Papers/Arrigo-Triulzi-PACSEC08-Project-Maux-II.pdf, а также
radioradar.net/news/electronics_news/avr_crumb644_net.html).
Если ты до сих пор не понял, о чем речь, повторю: не нужна операционная система, не нужно ядро, все что нужно – это микропроцессор сетевой карты, который будет
обрабатывать приходящие пакеты из сети и что-то там
отсылать обратно. Представь себе мини-Apache, который
реализован вне контроля ядра за самой машиной, ведь
сетевая карта, как железка, висит где-то на PCI-шине и
ей подвластно все ядро операционки.

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

 

Лезем в недра

А теперь представь себе руткит, который живет не
в операционной системе, а, скажем, в той же самой
сетевой карточке. Хотя такое реализовать под силу лишь
разработчикам самого железа, мы попробуем поставить
себя на их место и посмотреть, возможно ли полностью
контролировать железо в твоем компьютере или нет?
Сегодня мы попытаемся рассмотреть эту интересную
тему с точки зрения системного программиста. Мы
попробуем ответить на вопрос, как "глубока кроличья
нора", как глубоко можно залезть в недра операционной
системы. Бороться с руткитами, живущими в firmware
железяк твоего компьютера, наверное, все-таки бессмысленно. Однако ковыряние во внутренностях ядра
и железа, как ты сейчас увидишь, откроет перед тобой
много всяких интересных подробностей.


Так схематично проходит процесс обработки сетевых пакетов на уровне NIC <===>
PCI

Обычный перехват сетевого трафика в современных
файрволах сводится к установкам TDI-NDIS-фильтров
и перехвате важных NDIS-функций, таких, как, скажем,
NdisRegisterProtocol. Есть два подхода к перехвату
сетевого трафика. Первое — это установить, скажем, TDI-фильтр или NDIS IM-драйвер и жить себе спокойно. Но
этот подход не защитит минипорт сетевой карты, который
является своеобразным форпостом, ибо дальше — ресурсы сетевой карты и сеть.

Перехват ключевых функций в структуре NDIS_MINIPORT_BLOCK может гарантировать твоей зверюшке уверенный контроль или модификацию сетевого
трафика, если бы не одно "но" — заполучить указатель на
NDIS_MINIPORT_BLOCK ой как непросто! Один из самых
распространенных способов получить указатель на минипорт — регистрировать свой сетевой протокол в ядре
вызовом NdisRegisterProtocol, но файрволу достаточно
перехватить эту функцию, чтобы обломать все попытки
это сделать.

Как же быть?

Казалось бы, способов контроля сети современному
руткиту остается немного, однако в данной ситуации мало
кто вспоминает о таком волшебном слове, как PCI. Ведь
сетевая карта "сидит" на PCI-шине, взаимодействует
(читай "передает данные") с ядром операционной системы именно посредством тех ресурсов, которые PCI-шина
ей выделяет.

Сетевая карта (физически) состоит из двух блоков — PHY-блок и MAC-блок. Первый отвечает за непосредственное
"переваривание" сигналов с RJ45-кабеля в набор байт,
которые для дальнейшей обработки передаются в MAC-блок. Этот
блок гораздо интереснее, потому что именно он непосредственно отвечает за взаимодействие с драйвером сетевой карты (минипортом).
Он обладает одним или двумя CPU, EEPROM-памятью, собственной
SRAM-памятью и набором регистров, посредством которых управляется "устройство" сетевой карты. В EEPROM, как правило,
содержится информация о производителе, MAC-адрес сетевой карты, образ
прошивки. Структура каждого конкретного EEPROM имеет недокументированный формат и зависит лишь от фантазии разработчиков
самой сетевой карты. SRAM-память содержит копию прошивки
firmware, структуры сетевых пакетов, а также временные буферы
для хранения приходящих/уходящих сетевых пакетов. Регистры, в
свою очередь, позволяют полностью контролировать сетевую карту и
управлять ею. Сколько их, и для чего они служат в каждом конкретном
случае — также зависит от фантазии разработчика, поэтому зачастую
часть из них имеет недокументированный формат.

Главный вопрос статьи — можно ли получить доступ к EEPROM,
SRAM или регистрам? Ответ — да, можно. И сделаем мы это через
PCI-интерфейс. PCI-шина поддерживает метод передачи данных, называемый "linear
burst" (метод линейных пакетов). Этот метод предполагает, что пакет
информации считывается (или записывается) "одним куском", то
есть адрес автоматически увеличивается для следующего байта.
Естественным образом при этом увеличивается скорость передачи
собственно данных за счет уменьшения числа передаваемых адресов.
Шина PCI является той черепахой, на которой стоят слоны, поддерживающие "Землю" — архитектуру Plug and Play (PnP).
Спецификация шины PCI определяет три типа ресурсов: два
обычных ("диапазон памяти" и "диапазон ввода/вывода", как их
называет компания Microsoft) и configuration space — "конфигурационное пространство".

Более подробно о шине PCI ты сможешь прочесть в замечательной книге "PCI Bus Demystified" от товарища Doug Abbott, ее ты сможешь
найти на диске к журналу.

Именно PCI-шина, благодаря своим "фундаментальным" особенностям, позволит нам получить доступ ко всем ресурсам не только
сетевой карты, но и любого другого устройства, которое сидит на
PCI-шине. И при этом мы, находясь в трезвом уме и не совсем трезвой памяти :), не задевая такие уровни сетевой инфраструктуры, как
TDI или NDIS, где сидят сторожа файрволов, сразу залезем в глотку
сетевой карте. И никто нам в этом не помешает: все, что нужно будет
сделать — засандалить драйвер в систему.

Операционная система для взаимодействия с устройствами на PCI-шине задействует механизм ввода-вывода, основанный на проекции
участков памяти (memory-mapped I/O).
Такой участок памяти, как правило, имеет размер в 64 килобайта.
Первые 32 килобайта использованы для проекции регистров устройства, вторые 32 килобайта представляют собой
"окно" с возможностями чтения/записи в SRAM-память сетевой карты. Всего этого
вполне хватит, чтобы получить контроль над любым из устройств,
присутствующих на PCI-шине.

Перечислим все устройства на PCI-шине

for (busNumber = 0; !adapterFound && moreBuses; busNumber++)
{
   
for (deviceNumber = 0;
!adapterFound && deviceNumber < PCI_MAX_DEVICES;
deviceNumber++) {
       
slotNumber.u.bits.Reserved = 0;
       
slotNumber.u.bits.DeviceNumber = deviceNumber;
       
slotNumber.u.bits.FunctionNumber = 0;
       
length = HalGetBusData(PCIConfi guration,
busNumber,
slotNumber.u.AsULONG,
confi gInfo,
sizeof(PCI_COMMON_CONFIG) );
   
}
}

Осталась самая малость — разобраться, в смысле, отреверсить
EEPROM сетевой карты, потому что в нашем случае EEPROM — это все.
Что тут надо иметь в виду? Во-первых, EEPROM содержит в себе
non-volatile-данные. Во-вторых, эти данные доступны для чтения и
записи через набор регистров сетевой карты. Ну и в-третьих, надо
помнить, что формат EEPROM практически никем из производителей сетевых карт не документируется. Что мы знаем о EEPROM? Он
содержит в себе, как правило, заголовок загрузчика, метаданные "устройства" сетевой карты, данные о конфигурации сетевой карты,
такие как MAC-адрес, и самое главное — набор firmware-имиджей,
то есть: код загрузчика, дефолтный имидж, PXE (Preboot eXecution
Environment, хрень для возможности "загрузки компьютера с использованием сетевого интерфейса") и много всего прочего.

Теперь надо ответить на вопрос, как имидж frimware загружается из
EEPROM в память? Очень просто — надо перегрузить сетевую карту
и остановить процессор как можно скорее! Разумеется, делать это
надо с использованием ПО, поддерживающего эмуляцию физических устройств :). Что в результате? В результате можно увидеть,
что каждый раз, когда происходит подключение сетевой карты (или
перезагрузка PCI-шины):

а. Процессор инициализирует EEPROM и и загружает загрузчик
firmware (простите за тавтологию) из EEPROM.

б. Выполняет код загрузчика firmware, то есть конфигурирует ядро сетевой карты, настраивая часы, потребление энергии и прочее; после чего
загружает на исполнение "вторую очередь" firmware, которая является
дефолтным основным имиджем сетевой карты; после чего настраивает
все остальное — MAC-адрес и прочие особенности сетевой карточки.

Вот, в принципе, и все, что нужно знать и процессе загрузки имиджа
сетевой карты. И наконец, отвечу на вопрос, который, наверное, давно вертится у тебя в голове: можно ли сделать такой руткит, который
сможет заразить сетевую или графическую карту? Ответ прост: да,
это можно сделать, хотя и очень-очень непросто. Несмотря на то,
что такой руткит будет весьма опасным и живучим, он сможет жить
лишь на конкретной марке сетевой карты от одного производителя.
Для разработки такого руткита нужно сдампить firmware, отреверсить его, разобраться в принципах работы регистров...

А затем
написать свое собственное firmware, которое и будет заменено
на оригинальное. Сделать это крайне сложно, хотя и возможно. В
сети, если хорошенько поискать, можно найти реальные примеры
программулек, которые могут заставить сетевую карту жить двойной
жизнью. Однако, повторюсь, это всего лишь PoC, который привязан к
конкретной модели сетевой карты.

А что насчет контроля за сетевыми картами без варианта инсталляции
руткита? Ненамного проще! Универсального способа, который бы
позволил нагнуть все сетевые карты разом, не существует. Производителей множество, и запилить программу, которая будет контролировать
все сетевые карты подряд, невозможно. Для этого, как ты уже понял,
нужно знать конкретные особенности конкретной сетевой карты —
ведь сколько разработчиков, столько и разных форматов EEPROM,
регистров, ну и, разумеется, firmware. Нужно хорошо разбираться в
принципах действия шины PCI и самой операционной системы.

 

Вместо заключения

Согласен: выбирать путь заражения или контроля за PCI-based-устройствами таким вот способом — удел немногих извращенцев.
Нет, я отнюдь не призываю тебя присоединяться к извращенцам, однако системный кодинг в этом направлении поможет тебе понять, как
работает система на уровне аппаратного железа. Поверь, это крайне
увлекательное занятие :). Удачного компилирования, и да пребудет с
тобой Сила!

 

Links

Рекомендую к посещению —
alchemistowl.org/arrigo/index.html,
сайт Arrigo Triulzi,
там есть немало вкусностей на тему нагиба
всяких операционных
систем.

  • Подпишись на наc в Telegram!

    Только важные новости и лучшие статьи

    Подписаться

  • Подписаться
    Уведомить о
    2 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии