Статья Эмуляция прошивок embedded Linux: QEMU, Firmadyne и динамический анализ без устройства

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


Три месяца назад получил прошивку промышленного роутера на MIPS - заказчик хотел проверить веб-интерфейс управления, но само устройство стояло на закрытом объекте за двумя периметрами. Через 40 минут после binwalk -e у меня был работающий lighttpd в QEMU user-mode, а через два часа - command injection в CGI-обработчике на порту 80. Физическое устройство для этого не понадобилось. Эмуляция прошивок embedded Linux - навык, который превращает анализ IoT из задачи «нужно железо» в задачу «нужен образ прошивки и час времени».

Место в цепочке атаки IoT-устройств​

Эмуляция прошивки - не самостоятельная цель, а конкретный этап в kill chain пентеста IoT. Вот куда она встраивается:
  1. Recon и fingerprinting - определяем модель, версию прошивки, открытые порты. Внешний пентест - Shodan/Censys, внутренний - Nmap с баннер-граббингом.
  2. Получение прошивки - скачиваем с сайта вендора, извлекаем через UART/JTAG или перехватываем при обновлении.
  3. Статический анализ - распаковка через binwalk, поиск захардкоженных кредов, анализ бинарей в Ghidra.
  4. Эмуляция и динамический анализ - поднимаем прошивку в эмуляторе, взаимодействуем с сервисами, фаззим интерфейсы. Мы здесь.
  5. Разработка эксплойта - на основе найденных уязвимостей собираем рабочий PoC.
  6. Валидация на устройстве - если физический доступ есть.
Статический анализ покажет подозрительные вызовы system() или strcpy(), но без запуска бинаря подтвердить эксплуатабельность и собрать рабочий payload не получится. Покупать каждое устройство нереально, а удалённый доступ к продакшн-оборудованию заказчик даёт далеко не всегда.

Требования к окружению​

Перед тем как разворачивать эмуляцию - убедитесь, что хост не подведёт:
  • ОС: Ubuntu 20.04/22.04 LTS. Kali тоже работает, но Firmadyne на чистом Ubuntu стабильнее - проверено на трёх разных стендах
  • RAM: 4 ГБ минимум для QEMU user-mode, 8 ГБ для system-mode с Firmadyne. Если параллельно открыта Ghidra - 16 ГБ, иначе всё начинает свопиться
  • Диск: 20+ ГБ свободного места под образы QEMU, распакованные файловые системы и базу данных Firmadyne
  • Зависимости: qemu-system-arm, qemu-system-mips, qemu-utils, binwalksasquatch для SquashFS), python3, postgresql, busybox-static, fakeroot, kpartx, nmap
  • Сеть: интернет нужен только для скачивания прошивок и установки пакетов. Сама эмуляция работает полностью offline
  • Права: большинство операций Firmadyne требуют sudo
Bash:
sudo apt-get install qemu-system-arm qemu-system-mips qemu-utils \
  binwalk busybox-static fakeroot kpartx netcat-openbsd nmap \
  python3-psycopg2 snmp uml-utilities util-linux vlan postgresql

Извлечение файловой системы: binwalk и первый взгляд на прошивку​

Динамический анализ прошивок начинается с извлечения файловой системы. Вендоры упаковывают образы кто во что горазд: .bin, .img, .chk, .trx - внутри обычно ядро Linux и одна или несколько файловых систем (SquashFS, CramFS, JFFS2).

binwalk -e firmware.bin рекурсивно вытаскивает содержимое. Типичный результат для роутерной прошивки на HiSilicon:
Код:
DECIMAL    HEXADECIMAL  DESCRIPTION
0          0x0          uImage header, header size: 64 bytes
64         0x40         Linux kernel ARM boot executable zImage
2464       0x9A0        device tree image (dtb)
16560      0x40B0       LZMA compressed data
4401848    0x432AB8     device tree image (dtb)
Главный приз - каталог squashfs-root с полной файловой системой устройства. Что проверять сразу после распаковки:
  • file bin/busybox - определяет архитектуру: MIPS, ARM, big-endian или little-endian. Без этого не выбрать правильный бинарь QEMU
  • /etc/passwd, /etc/shadow - захардкоженные учётные данные. Встречаются куда чаще, чем хотелось бы
  • CGI-скрипты в /www или /htdocs - точки входа для веб-атак
  • Конфигурационные файлы NVRAM: /etc/nvram.default, /etc/nvram.conf - без них эмуляция может не взлететь
Если binwalk не справляется с проприетарной упаковкой - jefferson для JFFS2, ubi_reader для UBI-разделов. Шифрованные прошивки - это уже реверс загрузчика, отдельная история.

DTB (Device Tree Blob) внутри uImage - кладезь информации о платформе. Утилита dtc превращает его в читаемый DTS-формат с картой памяти, адресами периферии и списком устройств SoC. Когда автоматизированные инструменты ломаются - именно эти данные помогают собрать эмуляцию руками.

QEMU эмуляция IoT: user-mode vs system-mode​

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

Когда что применять​

QEMU user-mode (qemu-mipsel, qemu-arm) запускает отдельный бинарный файл, транслируя системные вызовы в вызовы хостовой ОС. Быстрый старт, не нужны ни ядро, ни образ диска. Годится для отладки конкретного бинаря, работы через chroot в распакованную файловую систему, подключения GDB с gef/pwndbg для пошаговой отладки.

Ограничения: нет сетевого стека устройства, нет эмуляции периферии, init-скрипты не отрабатывают. Бинарь, завязанный на NVRAM или специфические устройства в /dev, упадёт с SIGSEGV или молча зависнет.

QEMU system-mode (qemu-system-mips, qemu-system-arm) поднимает полную виртуальную машину с ядром, виртуальной сетью и дисковым образом. Именно этот режим крутится под капотом Firmadyne. Годится для полносистемного анализа с рабочей сетью: HTTP, SSH, SNMP - всё доступно для пентеста.

Ограничения: нужно совместимое ядро (Firmadyne использует pre-built ядра), возня с TAP-интерфейсами, не загружает out-of-tree модули ядра вендора.

На практике: начинайте с user-mode для быстрого анализа одного бинаря. Нужна полная картина - переходите на system-mode через Firmadyne. Firmadyne не справляется - ручная настройка QEMU system-mode или chroot-подход.

Firmadyne: автоматизированный анализ прошивки​

Firmadyne (представлен на NDSS 2016) - первый фреймворк, который автоматизировал полный пайплайн анализа прошивок: извлечение → определение архитектуры → создание дискового образа → сетевая конфигурация → запуск эмуляции. Поддерживает три комбинации: little-endian ARM, little-endian MIPS, big-endian MIPS. Проект академический, репозиторий на GitHub (firmadyne/firmadyne) - развивается неторопливо (последний значимый коммит - 2020), но для анализа роутеров и IoT инструмент по-прежнему тянет.

Для упрощённой установки есть Firmware Analysis Toolkit (FAT) - обёртка, которая объединяет binwalk и Firmadyne в единый пайплайн с меньшим количеством ручных шагов.

Пайплайн от образа до работающего веб-интерфейса​

Шаг 1: Извлечение. Скрипт extractor.py распаковывает прошивку через binwalk и складывает метаданные в PostgreSQL. На выходе - .tar.gz с файловой системой и Database ID.
Bash:
./sources/extractor/extractor.py -b vendor_name -sql 127.0.0.1 \
  -np -nk "firmware.bin" images/
Шаг 2: Архитектура. getArch.sh смотрит на BusyBox внутри образа. Вывод: mipseb, mipsel или armel - записывается в БД.

Шаг 3: Дисковый образ. makeImage.sh создаёт raw-образ на 1 ГБ, форматирует ext2, копирует файловую систему и патчит окружение: создаёт /etc/TZ, /etc/hosts, /etc/passwd если отсутствуют, выкидывает скрипты сброса настроек, которые помешают загрузке.

Шаг 4: Сетевая конфигурация. inferNetwork.sh - самый интересный этап. Firmadyne запускает прошивку на 60–120 секунд в «обучающем» режиме, перехватывая системные вызовы через kprobes в кастомном ядре. Собирает информацию о сетевых интерфейсах, IP-адресах, мостах и VLAN. Типичный вывод: Interfaces: [('br0', '192.168.0.1')]. Если интерфейсы не обнаружены - в 80% случаев проблема в NVRAM.

Шаг 5: Запуск. run.sh создаёт TAP-устройство на хосте, настраивает маршрутизацию и поднимает QEMU system-mode. После успешного старта сервисы доступны по сети.

NVRAM и аппаратные заглушки​

По наблюдениям авторов Firmadyne (NDSS 2016), значительная часть извлечённых образов обращается к NVRAM через libnvram.so - функции nvram_get() и nvram_set(). Firmadyne подставляет собственную библиотеку через LD_PRELOAD, эмулируя key-value хранилище. Начальные значения берутся из файлов прошивки: /etc/nvram.default, /etc/nvram.conf или из символов router_defaults в libshared.so.

Механизм ломается в трёх случаях:
  • Прошивка вызывает неэмулированные функции NVRAM
  • NVRAM реализован как кастомная структура данных на MTD-разделе, а не key-value
  • Бинарь проверяет наличие конкретного железа через /dev или MMIO
Для первого и третьего - ручной патч бинаря: NOP'ите проверки оборудования в Ghidra, подставляете заглушки в /dev, создаёте фейковые NVRAM-файлы с нужными ключами. Для MTD-зависимостей Firmadyne загружает модуль nandsim для эмуляции MTD-партиций через /dev/mtdX. Процедура не для слабонервных, но когда срабатывает - экономит дни.

Когда Firmadyne ломается: ручная эмуляция роутера через QEMU​

На практике значительная доля прошивок не эмулируется с первого раза: inferNetwork.sh не находит интерфейсы, сервисы падают при старте, ядро паникует из-за отсутствия ожидаемой периферии. Это нормально - было бы странно, если бы академический фреймворк покрывал весь зоопарк embedded-железа.
📚 Часть контента скрыта. Этот материал доступен участникам сообщества с рангом One Level или выше
Получить доступ просто — достаточно зарегистрироваться и проявить активность на форуме


Когда эмуляция невозможна. Прошивки с кастомными RTOS (не Linux), проприетарными сетевыми стеками или глубокой привязкой к SoC (Broadcom с закрытыми блобами) не эмулируются ни одним инструментом. Тут только аппаратный анализ: UART-консоль, JTAG, GDB непосредственно на устройстве. Для bare-metal и RTOS есть Renode - полносистемный эмулятор с описанием периферии на C#, но он требует ручного составления .repl-файла с картой памяти SoC. Задача сама по себе - отдельное исследование.

Динамический анализ прошивок: от эмулятора к уязвимостям​

Эмулятор запущен, сервисы доступны по сети. Дальше - стандартный пентест, но с нюансами embedded-среды.

Веб-интерфейс. Направляете трафик через Burp Suite. Роутерные CGI-скрипты на C любят передавать пользовательский ввод прямо в system() без санитизации. Параметры ping, traceroute, nslookup - классические точки для command injection. На одном проекте нашли инъекцию через поле hostname в настройках DDNS - вендор даже не пытался фильтровать точку с запятой.

Отладка бинарей. Для user-mode: qemu-mipsel -g 1234 ./binary - подключаетесь gdb-multiarch с gef или pwndbg, ставите breakpoint на system(), execve(), strcpy(). Для system-mode: флаг -s -S запускает GDB-сервер на уровне ядра. Трассировка через strace под QEMU user-mode покажет, какие файлы открывает бинарь, к каким сокетам обращается, какие NVRAM-ключи запрашивает - без этого отладка падений превращается в гадание.

Автоматизированное сканирование. Firmadyne включает скрипты для массовой проверки: обход веб-страниц (information disclosure), SNMP-walk, запуск известных эксплойтов через Metasploit-модули с привязкой к конкретным CVE. Kprobes используются в режиме обучения для трассировки сетевых системных вызовов и сбора информации об интерфейсах - не путайте с runtime-анализом.

Сравнение инструментов эмуляции прошивок​

ИнструментПреимуществаОграниченияКогда использоватьКогда не использовать
QEMU user-modeМинимум ресурсов, GDB из коробкиНет сетевого стека, нет периферииОтладка одного бинаря, chrootНужен полный сетевой стек
QEMU system-modeПолная эмуляция, рабочая сетьНужно ядро, ручная настройка TAPПолносистемный анализБыстрый разбор одного CGI
FirmadyneАвтоматизация пайплайна, БД метаданныхARM/MIPS only, академический проектМассовый скрининг прошивокОдна конкретная прошивка
FirmAEУлучшенная совместимостьТе же архитектурные рамкиКогда Firmadyne не справилсяНе-Linux прошивки
QilingPython API, гибкие хукиНет полносистемной эмуляцииПрикладной анализ, хукинг APIНужен полный boot
RenodeПолносистемная эмуляция с периферией на C#Ручное описание платформыBare-metal и RTOSМассовый автоматический анализ

Ограничения эмуляции embedded Linux без устройства​

Тут важно не питать иллюзий - эмуляция закрывает не всё.

Архитектурные рамки. Firmadyne и FirmAE поддерживают только LE ARM, LE MIPS, BE MIPS. Прошивки на AArch64, PowerPC, x86 (NAS, промышленные контроллеры) - мимо. QEMU system-mode поддерживает больше архитектур, но без автоматизации пайплайна.

Привязка к SoC. Бинарь, обращающийся к регистрам конкретного SoC через MMIO (HiSilicon, Realtek, MediaTek), упадёт в эмуляторе. Renode позволяет описать MMIO-периферию, но нужна карта памяти из документации SoC или анализа DTB.

Вендорские модули ядра. Firmadyne использует собственные pre-built ядра и не загружает вендорские модули. Уязвимости в сетевых драйверах или криптографических ускорителях останутся непроверенными.

False negatives. Часть уязвимостей проявляется только при специфическом состоянии NVRAM, которое эмулятор не воспроизводит. CGI-скрипты, требующие аутентификации с нестандартными дефолтными кредами, - ещё одна типичная ловушка.

Не замена аппаратному тестированию. Эмуляция не покрывает: атаки на загрузчик (U-Boot), side-channel через UART/SPI, радиочастотные интерфейсы (Wi-Fi, ZigBee, BLE). Для полноценного пентеста IoT физический доступ рано или поздно понадобится.

Работает, если: прошивка на поддерживаемой архитектуре, сервисы не завязаны на специфичный SoC, файловая система извлекается штатными средствами. Не работает, если: проприетарная RTOS, шифрованная прошивка без ключа, глубокая привязка к нестандартному железу.

Минилаб для отработки​

Для самостоятельной практики анализа embedded Linux прошивок:
  1. Скачайте прошивку D-Link DIR-822 (MIPS, big-endian) или NetGear WN604 с официального сайта вендора - обе стабильно эмулируются через Firmadyne
  2. Установите Firmware Analysis Toolkit (FAT) - обёртку над Firmadyne с упрощённым workflow
  3. Пройдите полный пайплайн: извлечение → getArch.shmakeImage.shinferNetwork.shrun.sh
  4. После успешного запуска - откройте веб-интерфейс в браузере, направьте трафик через Burp, поищите command injection в CGI-параметрах
Эти прошивки - хорошая точка входа: документированы, архитектура поддерживается, сетевые сервисы поднимаются без дополнительных костылей.

На практике статический анализ прошивок нередко заканчивается так: binwalk -e, grep -r password, strings | grep -i admin - и пишут отчёт. Это закрывает процентов тридцать поверхности атаки. Оставшиеся семьдесят - runtime-баги: переполнения буфера в HTTP-парсерах, race conditions в обработчиках аутентификации, command injection через POST-параметры, которые видны только при живом взаимодействии с сервисом. Эмуляция - единственный способ добраться до них без физического устройства.

Инструменты при этом далеки от идеала. Firmadyne - академический проект, который решает задачу массового скрининга, но на единичной нестандартной прошивке регулярно ломается. FirmAE улучшает ситуацию, но не переворачивает её. Qiling перспективен для прикладного анализа, но без полносистемной эмуляции. Renode требует ручного описания платформы, которое само по себе - отдельное исследование. На практике приходится комбинировать: Firmadyne для быстрого скрининга → chroot + QEMU user-mode для конкретных бинарей → Ghidra когда эмулятор не справляется → патч бинаря → повторный запуск. Идеального инструмента нет - есть набор костылей, которые работают вместе.

Скачайте одну из прошивок из минилаба, прогоните через FAT и попробуйте найти что-нибудь в CGI-обработчиках. Если inferNetwork.sh не найдёт интерфейсы - поздравляю, у вас появился повод разобраться с chroot-подходом. На курсе WAPT разбирают похожие цепочки - от распаковки образа до command injection в веб-интерфейсе роутера.
 
Мы в соцсетях:

Взломай свой первый сервер и прокачай скилл — Начни игру на HackerLab

Похожие темы

🚀 Первый раз на Codeby?
Гайд для новичков: что делать в первые 15 минут, ключевые разделы, правила
Начать здесь →
🔴 Свежие CVE, 0-day и инциденты
То, о чём ChatGPT ещё не знает — обсуждаем в реальном времени
Threat Intel →
💼 Вакансии и заказы в ИБ
Pentest, SOC, DevSecOps, bug bounty — работа и проекты от проверенных компаний
Карьера в ИБ →

HackerLab