Исследуем Wisenet (Samsung) HRX-1620

c32dc9e3d0f0316b1d97fb8c991c0135.jpg

Приветствую!

В этот раз я хотел бы рассказать о своём первом проекте в компании BI.ZONE. Дело было давно, девайс (Wisenet HRX-1620) уже не выпускается и не обслуживается, поэтому за давностью лет можно и поделиться. Заодно это предостережёт вас от использования этого устройства на объектах и поможет защититься.

Где-то на третий день работы мне вручили «посылку» с надписью »Wisenet». Внутри лежало несколько камер видеонаблюдения и одна большая коробочка:

Красивая коробочка, люблю такие

Красивая коробочка, люблю такие

Загуглив название железки, я нашёл сайт с прошивками, скачал самую свежую и полез распаковывать.

Содержимое прошивки

Основной файл с расширением .img на деле оказался обычным .tar.gz. Если его распаковать, вашему взору предстанут следующие файлики:

Содержимое архива

Содержимое архива

Содержимое каталога uptools

Содержимое каталога uptools

Большая часть файлов зашифрована (пока непонятно как), но вы обязательно заметите один интересный ELF-файл: swupgrader.

Такая схема схема достаточно часто используется во всяких файлах обновлений: в архив кладутся какие-то бинари, а с ними — программа или скрипт для установки.

Конечно, первым делом я открыл этот самый swupgrader в надежде найти ключ, которым была зашифрована прошивка.

Ключей там не нашлось, но обнаружилась очень подробная система логирования (классика), где у всех важных функций были указаны имена:

Приятно, когда разработчики всё логируют

Приятно, когда разработчики всё логируют

Формирование команды запуска protector

Формирование команды запуска protector

Таким образом мне удалось найти функции, которые назывались DecryptFile и DecryptImageFiles. В последнюю, кстати, передавалось имя какого-то странного бинаря protector, в сочетании с которым во второй функции формировалась команда следующего вида:

protector bin_file 1

Судя по всему, этот скрипт или программа как раз таки и расшифровывали все нужные файлы. Но, очевидно, доступа к «протектору» у меня не имелось (пока что).

Раз уж в swupgrader больше ловить нечего… Так, стоп! А как же классическая тема с подменой бинаря на свой с целью его запуска? Да, это сработало, но не сразу — процесс апгрейда почему-то падал.

Причину падения удалось выяснить немного позже (спойлер: криво собирался армовский «эльф»), поэтому я решил пойти немного другим путём: попробовать расшифровать бинари по-тупому —, а вдруг там простейший XOR?

Цикличность данных - один из основных признаков блочного шифрования с помощью XOR

Цикличность данных — один из основных признаков блочного шифрования с помощью XOR

Шестнадцатеричное представление

Шестнадцатеричное представление

Внимательный реверсер обнаружит здесь повторяющийся паттерн, который может говорить только об одном: да, используется тупой XOR с одним и тем же ключом для каждого блока. Длина ключа оказалась 16 байт. Далее я сделал предположение, что в конце прошивки идут либо нули, либо FF. Соответственно, чтобы получить сам ключ, нужно поксорить повторяющиеся байты на 0xFF или взять как есть. Оказалось, первое. Так я и получил файлы прошивок.

Ну, а дальше дело техники: замаунтить обнаруженную внутри JFFS2 (Journaling Flash File System version 2) и другие файлы (ext2), извлечь содержимое и провести полноценный анализ.

Что обнаружилось внутри

Конечно же, первым делом я полез смотреть, что из себя представляет protector и насколько плохо он расшифровывает файлы (спойлер: очень плохо!).

Попробуйте найти здесь ошибку:

Что-то здесь не так

Что-то здесь не так

Далее нужно было получить persistence (закрепиться на системе), чтобы отлаживать встроенные приложения в динамике и баловаться с возможными переполнениями (да, они тут тоже есть). Казалось бы, достаточно просто добавить в автостарт нужные telnet и GDB (я использовал IDA debug server), запаковать и зашифровать всё обратно — да и готово. Но нет. В самом начале, при распаковке .tar.gz, архиватор сообщил мне, что в конце архива имеются неиспользуемые данные. Посмотрим на них:

Структура завершающего блока .tar.gz

Структура завершающего блока .tar.gz

Видим структуру, которая начинается на AA CC BC BB и заканчивается на BC CA AB BC, и каких-то два дворда: 0x012A и 0x059F29D5. С первым удалось определиться достаточно быстро — это количество блоков по 0x80000. Ну, а второе, как можно уже догадаться, — это контрольная сумма CRC32 (полином удалось подобрать — 0x04C11DB7).

Затем я написал пересобиралку, включил необходимые мне FTP, Telnet и отладку, после чего залил на устройство в надежде, что оно после этого заведётся. Завелось!

Ну, а дальше начинается исключительно пентестерская тема. Нам понадобятся знания реверс-инжиниринга и написания ROP-цепочек, так как реверсить придётся не простой скриптец на JS, PHP или ещё на чём, а нормальный такой ELF-CGI.

Реверсим веб

Настройки доступа по HTTP(s)

Настройки доступа по HTTP (s)

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

Выяснилось, что всё в железке работает на CGI-скриптах, которые общаются между собой посредством линуксовых очередей сообщений. Я не буду сильно вдаваться во взаимодействие сервисов на устройстве, а сразу перейду к тому, как мне удалось найти уязвимость.

Уязвимость номер 1

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

А 80 байт точно хватит?

А 80 байт точно хватит?

Здесь содержимое параметра msubmenu считывается между символов & и =, после чего записывается в буфер размером 80 байт. Эксплуатируемость этой уязвимости не очень высокая: в GET-запрос нельзя запихнуть большинство символов, а urldecodeна данном этапе ещё не происходит. Поэтому перейдём к уязвимости номер 2.

Уязвимость номер 2

Эта штука посерьёзнее: ограничений на символы практически нет, за исключением 0x00 и ещё некоторых. Взглянем на неё:

Парсим HTTP-заголовки

Парсим HTTP-заголовки

Видим, что из хедера HTTP-авторизации читается содержимое переданного в функцию имени поля в аргументе name. Всё, что находится между символами двойных кавычек, будет скопировано по указателю dest. Посмотрим на место вызова этой функции:

Аргументов много, каждый уязвим

Аргументов много, каждый уязвим

Сначала очищается буфер tmp размером 0x800, а потом передаётся в функцию get_http_auth_key(). Сам же буфер лежит, конечно же, на стеке. Вот он:

Буфер для хранения ROP-цепочек

Буфер для хранения ROP-цепочек

Эксплуатируемость налицо (а точнее, на стек). Пиши ROP-цепочку и вперёд. Только вот есть одно НО: включённый ASLR.

Обходил я его довольно просто. Под отладкой я заметил, что диапазон адресов, по которому грузится libc, достаточно ограниченный, а значит, проще будет его забрутфорсить. Почему это сработает? Всё потому, что при обращении к CGI-скрипту lighttpd его поднимает, если тот ещё не запущен. Поэтому даже если наша цепочка пойдёт не туда, всё упадёт, а потом поднимется. Звучит крайне неплохо. Так я смог выполнять любые команды по сети.

Ищем нужные ROP-цепочки

Ищем нужные ROP-цепочки

Добиваем железку

Далее мне стало интересно, как и где хранится пароль от учётки admin. Посмотрев, какие файлы обновляются при изменении пароля, я выяснил, что мне нужен nvrConfig.xml, который располагается на внешнем HDD (видимо, на случай восстановления). Данные зашифрованы с помощью AES-CBC и пароля #5i#$@bmb$mf75ads89egs@#$bcx798! плюс Base64. Чтобы менять их удалённо, нужно было всего лишь повозиться с магией sed и заменой по регекспу, после чего я мог менять пароль динамически.

Общение с вендором

Конечно же, мы уведомили разработчика девайса об уязвимости. Меня даже попросили прислать PoC, что я и сделал.

Спустя время мне ответили приблизительно следующее:»Спасибо, что обнаружили уязвимость. Вообще наши внутренние тестировщики уже нашли её год назад, но, так как устройство уже находится в стадии End of Life, обновления мы не выпускаем».

В общем, единственный здравый совет здесь: ограничить доступ к HTTP-портам Wisenet HRX-1620 с недоверенных MAC- и IP-адресов. А лучше вообще выключить доступ по HTTP или перестать пользоваться устройством в пользу другого.

© Habrahabr.ru