Приветствую вас, дорогие читатели! Сегодня хочу рассказать вам о том, как я получил интерфейс командной оболочки Linux у wi-fi роутера Mi Router 4A Giga Version:
![Рисунок 1 – wi-fi роутер Рисунок 1 – wi-fi роутер](https://habrastorage.org/getpro/habr/upload_files/5e6/fe3/5e7/5e6fe35e7b73440201aac3ccd58c1673.png)
Разбор роутера и подключение к ноутбуку
Для начала я разберу роутер, чтобы определить какие порты, чипы и т. д. расположены на его плате:
![Рисунок 2 - Материнская плата с компонентами wi-fi роутера Рисунок 2 - Материнская плата с компонентами wi-fi роутера](https://habrastorage.org/getpro/habr/upload_files/71a/571/81d/71a57181d1418395828c9d6f3e2fc890.png)
Из интересного было обнаружено:
После внимательного изучения платы я подключил роутер к ноутбуку, используя UART порт, чтобы определить, какая информация по нему передается. Для этого я припаял провода к UART порту:
![Рисунок 5 - Припаянные провода к UART порту Рисунок 5 - Припаянные провода к UART порту](https://habrastorage.org/getpro/habr/upload_files/dff/eff/402/dffeff402349b58a483b378dcd79da35.png)
а другой конец подключил к PL2303:
![Рисунок 6 - Подключение проводов к PL2303 Рисунок 6 - Подключение проводов к PL2303](https://habrastorage.org/getpro/habr/upload_files/87f/b84/eb3/87fb84eb382d9d79ccf473d3cd5f6a75.png)
Затем установил на Windows 7 драйвер PL2303 и Putty:
![Рисунок 7 - Драйвер и Putty Рисунок 7 - Драйвер и Putty](https://habrastorage.org/getpro/habr/upload_files/8a8/f33/317/8a8f333179b880d21b267d6444ffe438.png)
Далее подключился к wi-fi роутеру с помощью Putty. Для этого необходимо проделать следующие шаги:
Включить wi-fi роутер.
-
Подключить PL2303 к ноутбуку:
Рисунок 8 - Подключение PL2303 к ноутбуку -
Выбрать параметры в Putty и нажать "Open":
Рисунок 9 - Выбор параметров Serial line = COM3(От компьютера к компьютеру может отличаться COM* порт), Speed = 115200, Connection type = Serial в Putty и нажатие "Open" После нажатия кнопки "Open" в Putty, можно увидеть процесс загрузки прошивки wi-fi роутера но есть проблема - нет возможности передать информацию с помощью Putty. В следствие чего я не могу повлиять на процесс загрузки прошивки, выбрав один из пунктов меню (Рисунок 10), а также нет интерфейса командной оболочки после завершения загрузки прошивки (Рисунок 11).
Рисунок 10. Пункты меню Рисунок 11. Конец загрузки прошивки
Дамп прошивки
Чтобы решить проблему передачи информации с помощью Putty и последующего выбора одного из пунктов меню, я сделал дамп прошивки и изучил его. Итак, для дампа прошивки я подключил прищепку-коннектор к чипу 25Q127CSIG (SPI), как изображено на рисунке, красный провод к первой ноге чипа. Первая нога чипа там, где изображен круг на чипе 25Q127CSIG (SPI):
![Рисунок 12 - Подключение прищепке-коннектор Рисунок 12 - Подключение прищепке-коннектор](https://habrastorage.org/getpro/habr/upload_files/01b/20d/0c0/01b20d0c057e29ea9eb878c6c53f8ad2.png)
а другой конец прищепки-коннектора подключил к программатору EZP2019+ через переходник:
![Рисунок 13 - Подключение другого конца прищепки-коннектора к EZP2019+ Рисунок 13 - Подключение другого конца прищепки-коннектора к EZP2019+](https://habrastorage.org/getpro/habr/upload_files/ded/baf/c87/dedbafc87d17bda97b0ab6603c2f0533.png)
а сам EZP2019+ к ноутбуку:
![Рисунок 14 - Подключение EZP2019+ к ноутбуку Рисунок 14 - Подключение EZP2019+ к ноутбуку](https://habrastorage.org/getpro/habr/upload_files/e8e/e18/5bb/e8ee185bbe9308746f991cfa398121d2.png)
Далее установил на Windows 7 драйвер для EZP2019+ и EZP2019+.exe:
![Рисунок 15 - Драйвер и EZP2019+.exe Рисунок 15 - Драйвер и EZP2019+.exe](https://habrastorage.org/getpro/habr/upload_files/3d5/e11/0d2/3d5e110d2acb595fdbba179ba96717d6.png)
Затем запустил EZP2019+.exe и выбрал чип 25Q127C. Но так как его нет в списке, я взял ближайший к нему по характеристикам, под номером 25Q128C:
![Рисунок 16 - Выбор чипа в EZP2019+.exe Рисунок 16 - Выбор чипа в EZP2019+.exe](https://habrastorage.org/getpro/habr/upload_files/527/4f2/1a0/5274f21a0a6a454e468a88e49a97714b.png)
Потом нажал на кнопку "READ" в программе EZP2019+.exe, дождался, когда прошивка считается, и сохранил в файл spi.bin.
Исследование прошивки
После получения дампа прошивки, я приступил к его исследованию. Начал с поиска места проверки вводимого через консоль числа, так как есть предположение, что пункт “3: Boot system code via Flash (default)” имеет константное значение, из-за чего я не могу выбрать любой другой пункт меню (Рисунок 17).
![Рисунок 17 - Пункты меню Рисунок 17 - Пункты меню](https://habrastorage.org/getpro/habr/upload_files/dd5/f48/5c9/dd5f485c933dba7bf39937aad16a81db.png)
Когда я открыл файл spi.bin с помощью binwalk, меня заинтересовала строка “U-Boot version string, ‘U-Boot 1.1.3 (Aug 18 2020 – 11:10:29)’” (Рисунок 18) по смещению 0x17DA0 от начала файла spi.bin. Эта строка указывает на то, что секция загрузчика в этой прошивке U-Boot.
![Рисунок 18 – Открытие файла spi.bin с помощью binwalk Рисунок 18 – Открытие файла spi.bin с помощью binwalk](https://habrastorage.org/getpro/habr/upload_files/5fe/7dd/462/5fe7dd46216cecf83101392ed09aceca.png)
Далее нашел начало секции загрузчика U-Boot в файле spi.bin. Эту информацию я узнал, посмотрев на процессе загрузки прошивки wi-fi роутера в Putty. В момент загрузки прошивки wi-fi роутера, я увидел, что U-Boot от компании Ralink версии 5.0.0.0 (Ralink UBoot Version: 5.0.0.0). Поискав в интернете данную версию, я нашел проект на github (https://github.com/cidermole/ralink-uboot), в котором есть описание начала секции загрузчика U-Boot. Сверив свое начало файла с проектом на github, я пришел к выводу, что они совпадают (Рисунок 19). Значит это — начало секции загрузчика U-Boot в файле spi.bin по смещению 0x00000000.
![Рисунок 19 - Начало секции Рисунок 19 - Начало секции](https://habrastorage.org/getpro/habr/upload_files/074/c86/0f3/074c860f32b6c7498a2e2d0179c687bc.png)
Следом я открыл файл spi.bin в IDA Pro, но перед тем, как это сделать, определил архитектуру (x86, x64, ARM, MIPS) файла spi.bin. Это можно сделать, взяв любой бинарный файл из файла spi.bin. Для этого воспользовался binwalk с параметрами –Me:
-M - рекурсивное сканирование извлеченных файлов.
-
-e - автоматическое извлечение известных типов файлов.
Рисунок 20 - binwalk
После выполнения команды binwalk –Me создается директория _spi.bin.extracted, в которой можно найти исполняемые файлы операционной системы Linux, одним из которых является wpad:
![Рисунок 21 - wpad Рисунок 21 - wpad](https://habrastorage.org/getpro/habr/upload_files/32a/d7b/113/32ad7b1134c298a9975cf5024c790bc2.png)
Этот файл я открыл с помощью IDA Pro x86 и посмотрел, какие параметры выбирает IDA Pro:
![Рисунок 22 - Открытие wpad в IDA Pro Рисунок 22 - Открытие wpad в IDA Pro](https://habrastorage.org/getpro/habr/upload_files/960/f3f/2d6/960f3f2d63da1a33d3c8907f991a4e5d.png)
Узнав, какие параметры выбирает IDA Pro в момент открытия файла wpad, я могу открыть файл spi.bin в IDA Pro x86 с такими же параметрами (Рисунок 23).
![Рисунок 23 - Открытие spi.bin в IDA Pro Рисунок 23 - Открытие spi.bin в IDA Pro](https://habrastorage.org/getpro/habr/upload_files/415/596/a3e/415596a3e13a27dc5a3294b5478831f6.jpg)
После того как я открыл файл spi.bin в IDA Pro, его необходимо разметить (преобразовать из байт кода в читабельный ассемблерный (assembler) код). Во-первых, я отсчитал от начала файла 0x1000 байт, чтобы не наткнуться на служебную область. Во-вторых, выделил несколько тысяч байт, например, с 0x1000 до 0x4000. Это необходимо для того, чтобы IDA Pro могла автоматически преобразовать из байт кода в ассемблерный код (Рисунок 24):
![Рисунок 24 – Начало и конец выделенного участка Рисунок 24 – Начало и конец выделенного участка](https://habrastorage.org/getpro/habr/upload_files/8c3/9dc/2e6/8c39dc2e66ca2ec79315b569eb88d7df.png)
И нажал на клавиатуре “C”, чтобы появилось диалоговое окно, и следом нажал на кнопку “Analyze”:
![Рисунок 25 - Analyze Рисунок 25 - Analyze](https://habrastorage.org/getpro/habr/upload_files/4f2/e13/707/4f2e1370762506632ede16523dbbe843.png)
В результате получил ассемблерный код:
![Рисунок 26 - Assembler code Рисунок 26 - Assembler code](https://habrastorage.org/getpro/habr/upload_files/368/90c/36d/36890c36dbeb6c2a157ed016d4892fe4.png)
Дальше необходимо понять, какой Imagebase (это базовый адрес загрузки программы) для того, чтобы IDA Pro могла создать перекрёстные ссылки (это информация о том, где в коде используется функция или строка), относящиеся к строкам и функциям. Это можно сделать, посмотрев на dword (Рисунок 27) или посмотреть в hex-rays (это функциональная возможность IDA Pro, позволяющая конвертировать assembler code в псевдо-код, наподобие языка программирования С) (Рисунок 28). Чтобы перейти в hex-rays, необходимо нажать на клавиатуре "F5".
![Рисунок 27 – Поиск Imagebase в dword Рисунок 27 – Поиск Imagebase в dword](https://habrastorage.org/getpro/habr/upload_files/88c/e2e/94f/88ce2e94f1748f200537b77bf3a72256.png)
![Рисунок 28 - Поиск Imagebase в hex-rays Рисунок 28 - Поиск Imagebase в hex-rays](https://habrastorage.org/getpro/habr/upload_files/fe1/c30/e21/fe1c30e219b99686673b00cb559f67c2.png)
Из вышесказанного (Рисунок 27, Рисунок 28), можно сделать вывод, что Imagebase начинается с 0xBFC*, а вот четвертый байт я нашел перебором от 0 до 9. Правильный байт можно определить, посмотрев на строки, они должны преобразоваться в следующий вид и иметь перекрестные ссылки (Рисунок 29).
![Рисунок 29 – Корректные строки Рисунок 29 – Корректные строки](https://habrastorage.org/getpro/habr/upload_files/f82/07c/b04/f8207cb0452e59972667a2c78b678ae3.png)
Теперь необходимо изменить Imagebase в IDA Pro. Для этого я перешёл в Edit -> Segments -> Rebase program... и изменил Imagebase на 0xBFC10000:
![Рисунок 30 - Rebase program Рисунок 30 - Rebase program](https://habrastorage.org/getpro/habr/upload_files/579/ac4/843/579ac484398ab258274b9e87670acbc1.png)
Далее приступил к решению проблемы в передаче информации с помощью Putty и последующем выборе одного из пунктов меню. Начал я с поиска строки “3: Boot system code via Flash (default)” в файле spi.bin с помощью IDA Pro:
![Рисунок 31 – Найденная строка в IDA Pro Рисунок 31 – Найденная строка в IDA Pro](https://habrastorage.org/getpro/habr/upload_files/df1/98c/4b4/df198c4b4e39744537c42900407adf8c.png)
Затем я нажал на aDBootSystemCod (Рисунок 32).
![Рисунок 32 - Нажатие на aDBootSystemCod Рисунок 32 - Нажатие на aDBootSystemCod](https://habrastorage.org/getpro/habr/upload_files/c0d/860/814/c0d86081460f4caa3825b2cf24105cde.png)
и следом нажал на клавиатуре "X", затем появляется окно, в котором можно увидеть, где используется данная строка.
![Рисунок 33 - Место использования строки "Boot system code via Flash (default)." Рисунок 33 - Место использования строки "Boot system code via Flash (default)."](https://habrastorage.org/getpro/habr/upload_files/11e/a3f/5a8/11ea3f5a82669869e63c64ac127be9c3.png)
Потом нажал на строчку sub_BFC028C0+6C (Рисунок 33) и провалился в функцию sub_BFC028C0:
![Рисунок 34 - Функция sub_BFC028C0 Рисунок 34 - Функция sub_BFC028C0](https://habrastorage.org/getpro/habr/upload_files/49e/941/1ba/49e9411baf1f006323beb3e6cd78cb73.png)
Дальше нажал на функцию sub_BFC028C0 (Рисунок 34), затем на клавиатуре “X” и посмотрел, куда ведёт эта функция. Она привела в место проверки введённого числа (Рисунок 35). Также из документации по U-Boot следует, что bootdelay – это количество секунд, данное на ввод числа, для выбора одного из пунктов. А вот описания boot_wait в документации не обнаружено.
![Рисунок 35 - Место проверки введённого числа Рисунок 35 - Место проверки введённого числа](https://habrastorage.org/getpro/habr/upload_files/0f6/52a/77d/0f652a77d3776941d952c6b32f1e581e.png)
Вернемся к проблеме, описанной выше. Я не мог передать информацию с помощью Putty и выбрать пункт меню, так как в коде есть константное значение (Рисунок 35 – строка 259) и нет возможности передачи информации роутеру с помощью Putty, потому что переменная v33 равна “off” (Рисунок 35 – строка 239). Исходя из этого есть два варианта: изменить константное значение на необходимое мне, или удалить “off”. Я выбрал второй вариант, так как он позволит более гибко выбирать пункты меню (Рисунок 10) и удалил “off” в файле spi.bin:
![Рисунок 36 - Удаление “off” в файле spi.bin Рисунок 36 - Удаление “off” в файле spi.bin](https://habrastorage.org/getpro/habr/upload_files/a2a/9dc/fcd/a2a9dcfcddc291b1f3c6c0d6cc92d088.png)
Перепрошивка роутера и получение командной оболочки Linux
Следом перепрошил wi-fi роутер полученным дампом прошивки. Для этого подключил прищепку-коннектор к чипу 25Q127CSIG (SPI), как было описано выше. Затем запустил EZP2019+.exe и выбрал чип 25Q128C. Потом нажал на кнопку "OPEN", выбрал файл spi_fix.bin. Далее нажал на кнопку “WRITE” и дождался, когда прошивка загрузится:
![Рисунок 37 – Перепрошивка роутера Рисунок 37 – Перепрошивка роутера](https://habrastorage.org/getpro/habr/upload_files/ae2/ea3/fe3/ae2ea3fe37139c799d8b866755a1d80b.png)
После загрузки прошивки я подключился к wi-fi роутеру с помощью Putty.exe и выбрал пункт “4: Entr boot command line interface” (Рисунок 38). Пункт 4 позволяет зайти в интерфейс командной оболочки загрузчика и используя командную оболочку загрузчика попасть в интерфейс командной оболочки Linux.
![Рисунок 38 - Выбор пункта 4 Рисунок 38 - Выбор пункта 4](https://habrastorage.org/getpro/habr/upload_files/c2e/314/16c/c2e31416ca2d6823c94cd5d16483180d.png)
Теперь необходимо разобраться, как из командной оболочки U-Boot, получить командную оболочку Linux. Я начал с чтения документации по U-Boot, поскольку в ней есть описание переменной bootargs. В документации сказано, что содержимое этой переменной передается ядру Linux в качестве параметра загрузки. Далее я посмотрю в IDA Pro, где используется эта переменная:
![Рисунок 39 - Код заполнения bootargs Рисунок 39 - Код заполнения bootargs](https://habrastorage.org/getpro/habr/upload_files/cfd/feb/92f/cfdfeb92f43f695b1d19e0a0f8f9946f.png)
После изучения кода, отвечающего за содержимое переменной bootargs, меня заинтересовали переменные (Рисунок 40), описание которых я не обнаружил в документации.
![Рисунок 40 - Неизвестные переменные Рисунок 40 - Неизвестные переменные](https://habrastorage.org/getpro/habr/upload_files/2e6/da7/a68/2e6da7a687fc34c32f24441e3f8a7377.png)
Названия этих переменных наталкнули меня на мысль, что они отвечают за включение и отключение определенного функционала у роутера. Чтобы проверить эту гипотезу, я зашёл в командную оболочку U-Boot и посмотрел, чему равняются эти переменные (Рисунок 41), и поменял содержимое этих переменных на противоположные (Рисунок 42). Затем перезагрузил роутер командой “bootm”.
![Рисунок 41 - Содержимое переменных Рисунок 41 - Содержимое переменных](https://habrastorage.org/getpro/habr/upload_files/bd5/173/efa/bd5173efa1825b8c2f50e4f55624b6ec.png)
![Рисунок 42 - Изменение переменных Рисунок 42 - Изменение переменных](https://habrastorage.org/getpro/habr/upload_files/667/a87/e69/667a87e6912a8d0e2708cb5e2d718cc4.png)
При загрузке прошивки wi-fi роутера я выбрал пункт “3: Boot system code via Flash (default)” и после окончания загрузки прошивки получил командную оболочку Linux:
![Рисунок 43 - Выбор пункта 3 и получение командной оболочки Linux Рисунок 43 - Выбор пункта 3 и получение командной оболочки Linux](https://habrastorage.org/getpro/habr/upload_files/7de/8c5/d7d/7de8c5d7dbd3bdf884b7fe06afd5d1ca.png)
Если кому-то стала интересна данная тема, то предлагайте свои идеи в комментариях, что можно посмотреть в прошивке или сделать с ней. Например, я мог бы посмотреть какую информацию отправляет роутер на сервера производителя, поискать бинарные уязвимости или уязвимости, связанные с web частью.
Комментарии (14)
VVitaly
05.04.2023 12:49+3Работа проделана большая, но... Может проще было разобрать образ прошивки? (Даже не из SPI flash, а тупо из образа поставляемого вендором для обновления роутера, хотя конечно стоковая прошивка и шифрованная м.б., это уже смотреть нужно).
И после поиска и нахождения всех разделов flash (в прошивке или дампе flash) варианты -
1) Поправить переменные загрузки в том разделе flash где они хранятся. (он обычно мелкий и в нем перечислены байт значений переменных загрузки).
2) Поправить root раздел (обычно init скрипты) где проверяются boot переменные или же явным образом в этих init скриптах стартовать демоны ssh/telnet/консоли
3) Использовать uboot этой версии от этой платформы без блокировки ввода с клавиатуры. Риск этих экспериментов замены в прошивке, и что можно "окирпичить" роутер, нивелируется возможностью восстановить оригинальную прошивку spi flash программатором.sh0r Автор
05.04.2023 12:49Конечно Ваши решения упрощают, но мне было интересно разобраться более детально, как все устроено)
eisaev
05.04.2023 12:49+3А вы пробовали получить доступ к шеллу более простыми способами прежде, чем вскрывать пациента и паять? Вот здесь говорят, что широко известный эксплоит работает на этом роутере: https://openwrt.org/inbox/toh/xiaomi/xiaomi_mi_router_4a_gigabit_edition#notes_on_firmware_exploit_procedure
Я то и сам непрочь пошалить программатором и паяльником (см. Xiaomi AC2350 например, которому я стоковую прошивку пересобирал, добавляя плюшек, и куда я в итоге портировал OpenWRT). Но я обычно иду по пути наименьшего сопротивления и прибегаю к более агрессивным действиям только в случае, если простые пути недоступны.
В любом случае благодарю за статью!
Xobotun
05.04.2023 12:49Емнип, я на двух таких роутерах openwrt и поставил через уязвимость веб-морды. Кажется, по этому туториалу.
Емнип, самой большой проблемой было перевести китайские иероглифы, будучи подключённым к этому роутеру, когда выход в интернет осуществляется через другой. Приходилось фоткать экран телефоном и пихать в гуглопереводчик.
RolexStrider
05.04.2023 12:49Судя по версиям U-Boot и ядра похоже на старые ZyXEL Keenetic. Там тоже mipsel, кажется Ralink 3052
MinimumLaw
05.04.2023 12:49Ну, если есть человек с SPI-программатором, то система беззащитна. Ну хорошо, не всякая и не совсем.
Есть задокументированный формат области переменных окружения U-Boot, что позволяет (при наличии программатора) менять их как заблагорассудится. Хуже когда загрузчик собран без возможности сохранения переменных - но это скорее планшетно-телефонное, чем роутерное.
И еще - консоль хорошо, но особого смысла в этом нет. Разве что DTB декомпилировать или через /proc/device-tree восстановить и попытаться на современные ядра насадить... И то нужно, чтобы ядро чип поддерживало. Тогда можно попробовать OpenWRT насадить или вообще кастомную систему с каким-нить BuildRoot'ом сварганить... Но это уже тема совсем других разговоров... Хотя... Я б взял на работу того, кто это сможет.
event1
05.04.2023 12:49Ну, если есть человек с SPI-программатором, то система беззащитна. Ну хорошо, не всякая и не совсем.
К сожалению нет. У меня в одном устройстве процессор включается при подаче питания на spi флешку. И тоже начинает читать флешку.
Есть задокументированный формат области переменных окружения U-Boot, что позволяет (при наличии программатора) менять их как заблагорассудится
Их можно зашифровать. Или разрешить менять в заданном диапазоне. Хотя конечно, в данном случае автор стреляет из пушек по воробьям.
Хуже когда загрузчик собран без возможности сохранения переменных - но это скорее планшетно-телефонное, чем роутерное
В планшето-телефонах обычно стоит андрюша на плечах LK. У которого нет переменных вообще
MinimumLaw
05.04.2023 12:49Android'ный boot.img (kernel+ dtb + initrd) тоже кто-то прочитать должен. Бывает по разному. Бывает вендорский код, а бывает и самый настоящий U-Boot.
И шуточки с питанием - это не страшно. Страшна криптография и подписи. Вот тут появляется несколько вариантов, но ни одного хорошего.
hierarchical
Есть прогресс?
dartraiden
Скорее всего, количество отправляемой информации напрямую зависит от версии прошивки.
Прошивки, предназначенные для китайского рынка, содержат больше специфических для Китая приложений.
sh0r Автор
Еще не двигался в этом направление, мне пока интересно, кому-то понравится эта статья )