Доверяй, но проверяй

7c6hr9cr-axpnbkjusbn9io6wrg.png


Не так давно я считал, что обновление программного обеспечения от производителя на роутерах и подобных им «железках» обязательно, и переход на новую стабильную версию гарантирует временную безопасность. Почитав в интернете мнения пользователей, которые с этим не согласны и были очень убедительны, мои розовые очки разбились, радужных единорогов я больше не увижу, и жизнь стала не такой простой как была. Оказалось, новые прошивки, скачанные у официального производителя «железки», можно считать устаревшими. За точку входа в эту тему предлагаю взять переведённую статью. Помимо интересной и полезной информации о том, как вскрывать бинарники, автор утверждает, что если заглянуть в прошивку, можно обнаружить устаревшую версию ядра Linux. Я решил всё-таки проверить этот довод самостоятельно и вставить свои дилетантские »15 копеек». Заодно провести разведку в области, где я ещё не бывал. Для удовлетворения интереса будет достаточным определить версию ядра прошивки. На время написания статьи последняя версия ядра kernel — 6.0.9 от 16.11.2022. Вскрыть и выгрузить прошивку из приборов, которые описаны в статье, у меня не было возможности. Поэтому воспользуюсь прошивками, скачанными с сайта производителя.

▍ NTP-RG-1402G-W


Первый претендент на вскрытие — абонентский маршрутизатор NTP-RG-1402G-W от ELTEX. На момент написания статьи серийный выпуск данной модели был завершён, но поддержка осуществляется. Поэтому прошивка должна быть свежая. Ссылку на скачивание прошивки можно найти здесь. Мне досталась последняя версия прошивки в версии v3.25.5.165.

Скачиваю и распаковываю:

wget https://eltex-co.ru/upload/iblock/504/ntp-rg-revc-3.25.5.165.fw.zip
&& unzip ntp-rg-revc-3.25.5.165.fw.zip
&& rm ntp-rg-revc-3.25.5.165.fw.zip


Если заглянуть внутрь файла, то можно увидеть метку ELTX — перечисление версий модели, для которых подходит эта прошивка.

cfcib4x2hjz_i6ba7n0-f6pbvyy.png


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

Спросить у binwalk сведения о файле можно следующим способом.

binwalk ntp-rg-revc-3.25.5.165.fw.bin

DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
1043 0x413 JFFS2 filesystem, big endian


Этой информации достаточно, чтобы понять, что файловая система бинарника JFFS2.

Вот что говорит об этом Wikipedia: JFFS2 (Journaling Flash File System version 2 — «Журналируемая файловая система версии 2») — структурированная файловая система, используемая в устройствах флеш-памяти. JFFS2 был включён в ядро Linux, начиная с версии 2.4.10 от 23 сентября 2001 года. JFFS2 также поддерживает несколько загрузчиков операционной системы, таких как Das U-Boot, Open Firmware, eCos RTOS и RedBoot. Также JFFS2 используется в OpenWrt.

Чтобы с этим разобраться, понадобится пакет mtdutils:

sudo apt-get install mtd-utils


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

binwalk -Me ntp-rg-revc-3.25.5.165.fw.bin


У меня появилась папка с названием »_ntp-rg-revc-3.25.5.165.fw.bin.extracted», в ней лежит файл 413.jffs2. Его уже можно конвертировать.

jffs2dump -b -eimage.bin 413.jffs2

Wrong bitmask at 0x01047f80, 0x0000
Wrong bitmask at 0x01047f84, 0x0000
Wrong bitmask at 0x01047f88, 0x0000
Wrong bitmask at 0x01047f8c, 0x0000
Wrong bitmask at 0x01047f90, 0x0000
Wrong bitmask at 0x01047f94, 0x0000
Wrong bitmask at 0x01047f98, 0x0000
Wrong bitmask at 0x01047f9c, 0x0000
Wrong bitmask at 0x01047fa0, 0x0000
Wrong bitmask at 0x01047fa4, 0x0000
Wrong bitmask at 0x01047fa8, 0x0000


Исправить неприятность «Wrong bitmask» предлагают так.

Дальше монтируем образ и добираемся до данных.

mkdir mount_dir
sudo modprobe mtdram total_size=24576 erase_size=128
sudo modprobe mtdblock
sudo dd if=image.bin of=/dev/mtdblock0
sudo mount -t jffs2 /dev/mtdblock0 mount_dir


jcn2b94wo4dpwkburj9lbjlksae.png


На этом этапе уже можно определить версию linux, заглянув в каталог lib/modules/2.6.30. Если посмотреть на дату модификации всех файлов образа, то можно предположить, что сформирована эта прошивка 17.08.2020. Но для уверенности лучше заглянуть в ядро.

binwalk -Me vmlinux.lz

DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
2220124 0x21E05C Certificate in DER format (x509 v3), header length: 4, sequence length:4
3035152 0x2E5010 Linux kernel version 2.6.30
3112032 0x2F7C60 DES SP2, big endian
3112544 0x2F7E60 DES SP1, big endian
3137904 0x2FE170 CRC32 polynomial table, little endian
3155688 0x3026E8 CRC32 polynomial table, big endian

3544627 0x361633 Neighborly text, "neighbor %.2x%.2x.%.2x:%.2x:%.2x:%.2x:%.2x:%.2x lost on port %d(%s)(%s)"


Linux kernel version 2.6.30 соответствует каталогу с модулями lib/modules/2.6.30. Там же можно найти дату выпуска версии — 2.6.30, которая обозначена как 10.06.2009.

После распаковки данных binwalk оставил файл с именем «C». Если выполнить следующую команду, можно получить немного больше информации, например версию компилятора, и не гадать с датой сборки прошивки.

strings C | grep "Linux version"

Linux version 2.6.30 (user@86671791164b) (gcc version 4.4.2 (Buildroot 2010.02-git) ) #1 SMP PREEMPT Mon
 Aug 17 12:49:01 NOVT 2020


Всё сходится, прошивка была собрана чуть больше двух лет назад.

▍ M4300–52G-PoE+ (GSM4352PB)


В этом случае рассмотрим прошивку на коммутатор от NETGEAR, M4300–52G-PoE+ (GSM4352PB).

wget https://www.downloads.netgear.com/files/GDC/M4300/GSM_XSM4300_V12.0.17.10.zip
&& unzip GSM_XSM4300_V12.0.17.10.zip
&& rm GSM_XSM4300_V12.0.17.10.zip


Появится файл с именем m4300v12.0.17.10.stk. Посмотрим, что представляет из себя этот файл.

binwalk m4300v12.0.17.10.stk

DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
116 0x74 Flattened device tree, size: 43857977 bytes, version: 17 344 0x158 LZMA compressed data, properties: 0x5D, dictionary size: 8388608 bytes, uncompressed size: -1 bytes
2044644 0x1F32E4 LZMA compressed data, properties: 0x5D, dictionary size: 8388608 bytes, uncompressed size:
 -1 bytes
4334548 0x4223D4 LZMA compressed data, properties: 0x5D, dictionary size: 8388608 bytes, uncompressed size:
 -1 bytes
6785752 0x678AD8 LZMA compressed data, properties: 0x5D, dictionary size: 8388608 bytes, uncompressed size:
 -1 bytes
9044804 0x8A0344 LZMA compressed data, properties: 0x5D, dictionary size: 8388608 bytes, uncompressed size:
 -1 bytes
11303856 0xAC7BB0 gzip compressed data, from Unix, last modified: 1970-01-01 00:00:00 (null date)
38409620 0x24A1594 Zlib compressed data, compressed
42333777 0x285F651 Certificate in DER format (x509 v3), header length: 4, sequence length: 1284
42333901 0x285F6CD Certificate in DER format (x509 v3), header length: 4, sequence length: 1288
42458920 0x287DF28 CRC32 polynomial table, little endian
42462540 0x287ED4C CRC32 polynomial table, little endian
42464208 0x287F3D0 LZO compressed data
42521356 0x288D30C gzip compressed data, maximum compression, from Unix, last modified: 2013-04-09
 21:31:53
43046116 0x290D4E4 CRC32 polynomial table, little endian
43053216 0x290F0A0 CRC32 polynomial table, little endian
43054884 0x290F724 LZO compressed data

43134420 0x2922DD4 gzip compressed data, maximum compression, from Unix, last modified: 2013-04-09 
21:31:53
43721552 0x29B2350 CRC32 polynomial table, little endian
43728716 0x29B3F4C CRC32 polynomial table, little endian
43730384 0x29B45D0 LZO compressed data
43812756 0x29C8794 gzip compressed data, maximum compression, from Unix, last modified: 2013-04-09 21:31:53
43855988 0x29D3074 Executable script, shebang: "/bin/sh"


Много информации. Похоже на то, что в этом бинарнике находятся файлы с разными типами сжатия. Предоставим с этим разобраться binwalk.

binwalk -Me m4300v12.0.17.10.stk


После распаковки появилось шесть каталогов и несколько бинарников. С помощью binwalk удалось найти версию ядра в трёх файлах:

binwalk 1F32E4: Linux kernel version 3.6.5
binwalk 158: Linux kernel version 3.6.5
binwalk 4223D4: Linux kernel version 3.6.5

Версию компилятора можно определить, например, вот так:

strings _m4300v12.0.17.10.stk.extracted/_8A0344.extracted/cpio-root/lib |grep GCC

GCC: (Broadcom Linux 3.6) 4.8.2


▍ ASUS RT-AX55


Двухдиапазонный беспроводной маршрутизатор от ASUS, RT-AX55.

wget https://dlcdnets.asus.com/pub/ASUS/wireless/RT-AX55/FW_RT-AX55_300438650460.zip
&& unzip GSM_XSM4300_V12.0.17.10.zip
&& rm GSM_XSM4300_V12.0.17.10.zip

binwalk -Me RT-AX55_combo_3.0.0.4_386_50460-g5174ed0_puresqubi.w


Появится каталог »_RT-AX55_combo_3.0.0.4_386_50460-g5174ed0_puresqubi.w.extracted», и если заглянуть сюда «squashfs-root/lib/modules/», можно увидеть каталог с именем версии ядра. У меня он 4.19.183.

▍ Dahua DH_IPC-HX2×4X


Для разнообразия можно рассмотреть регистратор фирмы Dahua. Название прошивки — DH_IPC-HX2×4X-Taylor_MultiLang_PN_V2.840.0000000.7.R.221110. В этом случае бинарник можно
распаковать с помощью zip-архиватора.

unzip DH_IPC-HX2X4X-Taylor_MultiLang_PN_V2.840.0000000.7.R.221110.bin

Archive: DH_IPC-HX2X4X-Taylor_MultiLang_PN_V2.840.0000000.7.R.221110.bin
file #1: bad zipfile offset (local header sig): 0
inflating: Install
inflating: kernel.img
inflating: dhboot.bin.img
inflating: dhboot-min.bin.img
inflating: romfs-x.squashfs.img
inflating: web-x.squashfs.img
inflating: dhdtb.bin.img
inflating: partition-x.cramfs.img
inflating: check.img
extracting: sign.img


Чтобы определить ядро прошивки, на данном этапе достаточно применить binwalk.

binwalk kernel.img

DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
0 0x0 uImage header, header size: 64 bytes, header CRC: 0x6F27594A, created: 2022-11-10 13:43:13, 
image size: 2313680 bytes, Data Address: 0x1D00000, Entry Point: 0x2300000, data CRC: 0x47CC5A2D, 
OS: Linux, CPU: ARM, image type: Firmware Image, compression type: none, image name: "kernel"

64 0x40 uImage header, header size: 64 bytes, header CRC: 0x359DB3A3, created: 2022-10-28 04:08:13, 
image size: 2309152 bytes, Data Address: 0x8000, Entry Point: 0x8000, data CRC: 0xFAC624BD, OS: 
Linux, CPU: ARM, image type: OS Kernel Image, compression type: none, image name: "Linux-4.19.91"

128 0x80 Linux kernel ARM boot executable zImage (little-endian)

18432 0x4800 LZMA compressed data, properties: 0x5D, dictionary size: 67108864 bytes, uncompressed 
size: -1 bytes

2311536 0x234570 uImage header, header size: 64 bytes, header CRC: 0x3C52A920, created: 
2022-11-10 13:43:13, image size: 2311448 bytes, Data Address: 0x1D00000, Entry Point: 0x2300000, 
data CRC: 0xBDDC7DE8, OS: Linux, CPU: ARM, image type: Firmware Image, compression type: none, 
image name: "kernel"


Версия ядра у этой прошивки — Linux-4.19.91, создана 28.10.2022.

▍ Личное мнение


С первого взгляда может показаться, что все производители оборудования не заботятся об обновлении ядра, и поэтому уровень безопасности остаётся неизменным. Я считаю, что дело обстоит следующим образом:

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


Конечно, было бы правильнее спросить у самих производителей, что я и сделал. Но ни один из них не ответил на моё письмо. Ещё бы, кто я такой — обычный пользователь. Так что придётся жить в догадках и относиться с недоверием к разработчикам, которые скрывают исходники, а так и до паранойи недалеко.

▍ Итог


В итоге — что мы имеем, и как с этим жить. Не думаю, что стоит паниковать из-за старой версии ядра. А вот если последняя версия прошивки собрана года два назад (что не всегда можно выявить), то следует искать другие способы обновления. Например, такие:

  • купить самое новое оборудование;
  • выбрать прошивку с открытым исходным кодом.


Лучше всех дела обстоят с роутерами. В подавляющих случаях покупать прибор не целесообразно. А вот прошивка с открытым исходным кодом подойдёт. Главное не превратить прибор в кирпич.

Автор статьи, которую я упоминал в начале, предлагает OpenWrt, есть и другие варианты прошивок. Также можно выбрать роутер с открытым исходным кодом (если бы все производители делали именно так). Я слышал о двух таких, это MikroTik (github) и Turris Omnia (github). В остальных случаях «кушаем», что дают.

Играй в нашу новую игру прямо в Telegram!

sz7jpfj8i1pa6ocj-eia09dev4q.png

© Habrahabr.ru