Исследование безопасности IP-камеры Grandstream GXV3611_HD

Исследование безопасности IP-камеры Grandstream GXV3611_HD

Около года назад в моем распоряжении оказалась  IP-камера Grandstream  GXV3611_HD, у которой были проблемы с Power over Ethernet (PoE), технологией,  позволяющей передавать удаленному устройству, наряду с данными, электрическую  энергию.

Автор: boredhackerblog

Введение

Около года назад в моем распоряжении оказалась IP-камера Grandstream GXV3611_HD, у которой были проблемы с Power over Ethernet (PoE), технологией, позволяющей передавать удаленному устройству, наряду с данными, электрическую энергию. Я решил попробовать устранить этот недочет. Поскольку я не настолько хорошо разбираюсь в электронных схемах, мне пришлось посмотреть в блоге EEVblog множество видео по теме ремонта и устранения проблем у IP-камер. В конечно итоге, проблему решить не удалось, но зато получилось найти уязвимость, связанную с sql-инъекцией, и недокументированную команду, позволяющую запустить службу telnet и удаленно залогиниться с правами суперпользователя.

Аппаратная часть

Камера разобрана, а на рисунке ниже показано 10x2 пинов. Я предполагал, что эти контакты предназначались для отладки и были последовательными.

https://lh4.googleusercontent.com/rVh4UHVXeDOMPU6hTzGV7x71zV4qswt1J_VtUWp4_nn_G70LLzL3GERDoak3xd6TI1aXSCkuca6rqKa_tnG9Bo137WNT4BBEf2hUR8JINhNrZAOPhxtD3SyCr58a9K0B1kaN6zzP
Рисунок 1: Внутреннее устройство IP-камеры

Я подключил свой мультиметр ко всем пинам, что выяснить, присутствует ли где-то напряжение более 5 вольт, поскольку мой логический анализатор Saleae может оперировать с напряжениями не выше этого значения. На контактах не было напряжения более 5 вольт, и я решил подключить логический анализатор к случайным пинам.

https://lh3.googleusercontent.com/dPq8evcBhPCLqzJvedq_q1TLl6RRp0apqY3RYHGsUELBcV-72_8UJT71iPcL-5oZSBZVUy1qA2iWErzPDpZLbio4SWB8p6V7xNbAhxzK3MlAGL1MBPxzjIinuGZRgpK7gCgavyVd
Рисунок 2: Подключение логического анализатора

После включения камеры я заметил появление данных на одном из каналов и предположил, что этот разъем – последовательный.

https://lh5.googleusercontent.com/riggd38yvyq8j6d44B1CS81URiWpV4unwA_D1JbXPHSQA8fW2Ww9GeCihhLAmL2D8HN3x_Dv2uz8-iD1n-bmcryv_BbmeOxjGjG5vlwSsx3JIbenr6-kIztTb823aRhB9b02vHer
Рисунок 3: Информация на одном из каналов, отображаемая на экране логического анализатора

Коммуникация с камерой и получение шелла

Я подсоединил последовательный адаптер (FTDI) и подключился к камере при помощи терминала Putty. Скорость в бодах определялась на основе выходного сигнала на логическом анализаторе и была примерно 115200 бод, что является одним из стандартных значений.

https://lh6.googleusercontent.com/fwj5OMsWXQbYvhJ5Km0AyKoc6LA5FevTwLhzhbrN4e8BJnBw_kohOdnweRb_xytqWnQRjYfOkRksMa-zjfjL6C4XVDL_ntk-RMFJFkGIXwJ53l88Oy_aQ-MsTr2W3V_pnPnm5Bgc
Рисунок 4: Предварительная настройка терминала Putty

Я подключился к пину TX и смог получить данные с камеры в терминале.

https://lh3.googleusercontent.com/wgjSn2jSLN9reJEJ0W8nCH6kobvPA-Cbdgv1w7KRpzAg6KKntyeoQg_nB034Ozo1Jk-x9bDIORVK4MasUMc8J6RkoHMnyHpZYjooC41dajgFKVaHbue6y3lNsK8kBOcTwVNhg5mN
Рисунок 5: Процесс загрузки IP-камеры

Я выбрал пин, находящийся над TX, чтобы убедиться, сможет ли этот контакт принимать информацию. Так и оказалось. Единственный пригодный способ для нахождения пина RX, который я знаю, - отслеживание дорожек на плате.

https://lh6.googleusercontent.com/FYQlRrUiRso44UtojJ_RrUZLsY62z5XFfHXad676rNce0Q_xmWhzoLQtkIz3R8IhVtODWPqh43DF6lZNFFRvrhRHr0a_cxqetopGOnt_BKYrRTh-PHg12JNZgnBmOA808nuM_DJP
Рисунок 6: Подключение к пину RX

Я перезагрузил камеру и остановил автозагрузку.

https://lh3.googleusercontent.com/J0A3F1VKmvXzLIKwRmCHYUDOxT7El1r3gDKMgXH9PBeIjvQTDD5-B3tjGQT-gJx3yI53yQQnS0vSGtZqOkeoA5cqU7P0PRNd5ISZDS1FM9QvUC_ImQr6NX-BTk8xJpVrxR5GaYxX
Рисунок 7: Остановленный процесс автозагрузки

В камере был загрузчик U-Boot, используемый во многих подобных устройствах.

Я посмотрел видео под названием «Hacking 20 devices in 45 minutes» с конференции Defcon, где рассказывалось о получения шелла при помощи изменения опции init в U-Boot, и поступил схожим образом.

Команда printenv выводит все текущие настройки загрузки.

https://lh3.googleusercontent.com/8OAqmRvwVbTvwMqv5FmoOrxxvZ_AdzGlga1eGj679cw9opwvDcg8qO6wr37dkrsP3BhoVw17_Jrx2Nc53MRwz_SjAdrJQiTsGoJJRwFmE4mVfSodcQ4EVJIq2HtHJn0yXj2G2wXd
Рисунок 8: Текущие настройки загрузки

Команда setenv позволяет изменять значение опций загрузки. Я установил init=/bin/sh, чтобы получить доступ к шеллу.

https://lh6.googleusercontent.com/xFMFWDnTtHEVhxqSO1gqx0nfOAJ611haxUB5BSn9oGGVvhxiMtqxITiHleyJ6TDkw0hpoCqoUFuoodtSgySfG6MPctfrXl5Tyg0r4Useuiy90cOjMpfPHE7s8XqumtFKJh6kbRmV
Рисунок 9: Изменение настроек загрузки

Команда bootm используется для загрузки из памяти. Адрес берется из выходных данных команды printenv.

https://lh3.googleusercontent.com/D825vNKT8KwBob1iZV6JYpEcKzbC-ygV8PZ3x7ZZf7y7-1c2PRAozvmdwVvEZJOMLeU7JbWwG1qHiGhV6O3rQJ_sHhxYAPNFpeImBQPSBd9LvE1LzmQ_f0Nye37gQclo4aB127rT
Рисунок 10: Возобновление загрузки после изменения настроек

Камера загрузилась, и я получил доступ к шеллу busybox:

Повторное получение шелла

Я начал просматривать файловую систему и заметил пустые папки. Подобное случилось потому, что я модифицировать процесс загрузки.

https://lh3.googleusercontent.com/ATrbSknT1zFC7zvcjSJHn_FqEYpajGizDgTemj9u1HX-_SiMdAp1FNWOzOdpMX0lUgGZDKXNOnUKS-U-HQvj_0VdPD3K5vu8zC0lupkClfYe2U9qL4TDxtX3t031XffUtJOz3Njy
Рисунок 11: Просмотр содержимого некоторых папок

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

https://lh4.googleusercontent.com/q_YX5o_5Ub5IvRQ4o4ULX_-bW2d3U6hW6p3lYqPlHg5kwjkmf3Z6c34sY0d8EUbxz1n7O3adwJNMOgztQFh1Ptj5jY4skHld3V1j9z7BojrLHRpHjOiEIdZIdBThLrgOaMoJ2682
Рисунок 12: Перезагрузка камеры в обычном режиме

Поскольку логина я не знал, то перезагрузил камеру и снова изменил init на /bin/sh, а затем выгрузил хеши.

https://lh5.googleusercontent.com/MLaZXqx_VKtMrAh-8qi2jagIQquO4ehAmVzQnFctY-EAN78cpKgOTMrtGsn8gt1QFdnE9bhG0tngz-6ouKMZ_CM9bjaj_1qhZs3mEzjmTFopLD_aBWO8H8b1nHLCJBUezOWt9BN_
Рисунок 13: Содержимое файла passwd

Пароль оказался пустым.

https://lh3.googleusercontent.com/K_5F9VFLEhS7D2U3NdV6P3PbbSbpd95gwqyB6Jj9ti9M98QWYbrODcDR5Ihtanh1a6h_TwUpFye2Gi0Ou6xkMa2h6OI34HlLauHqUFgMET_GGbO9JFEp0UYzEIu98OmXo227K9SK
Рисунок 14: Поиск паролей к найденным хешам

Я загрузил камеру в обычном режиме и залогинился. Теперь я мог просматривать содержимое папок, которые ранее были пустыми.

https://lh3.googleusercontent.com/2sEjDyiDeCq6efsqyz2fwBZ7G4--NP_j6rYmDxoiMlV2XXPt6KU6KfUYCL437kYeYrbAbG3_Tun4DQmkU4py8GUhPHXUurqROSPl3dab6Guq8biOS0WlQ1OO8SmXAZ-G1zbOjXNZ
Рисунок 15: Содержимое некоторых папок после ввода корректного логина/пароля

Поиск уязвимостей

После получения последовательного шелла и доступа к файловой системе я начал поиск уязвимостей, связанных с удаленным доступом, посредством исследования процессов, запущенных на устройстве.

https://lh6.googleusercontent.com/Z1HNjgLRHQCSGAvzmWwzB8YPySdfXRDnW6V9CUA41ICXYMbzQHvF1jKWHkfPsXL0_UrGydhpVNZqnSlnEOkKtfRkVOKwXQj62LExpA_fn2eNSJE7p20ai1vzKzwbOkhi_OgkO1H1
Рисунок 16: Перечень процессов, запущенных на устройстве

В перечне на рисунке выше отмечены запущенные процессы webs и cli. Webs – веб-сервер, cli – сервер, связанный с настройкой telnet (telnet configuration server).

Было решено проанализировать оба этих процесса в IDA.

Я начал с cli поскольку этот процесс по объему оказался сильно меньше, чем webs. После подключения к серверу telnet и авторизации, нам становится доступен перечень команд.

https://lh6.googleusercontent.com/3dFnNbY3at6oRBS-SUHu4s8pLzaDhjE-o2-Pyw7uRcOocyWd3Iz8u_8aKj0hFlVUyLB3J-7lCCdHJ3VXIxCcX6H5cYDsk4qUX33u25-tyUHqVVelN8MMnGB7ic7Eha3E4l3WuS0n
Рисунок 17: Перечень команд, доступных в telnet

Я загрузил бинарник в IDA и стал искать строку «Username:»

https://lh6.googleusercontent.com/TEwH7NdcAkiimqH4Y1qzJVWM0AFgoIek15YLOr286i4ufZyhhd7jYFwNwF6VZ8PcGdq-9DPlfzR-tOvqMxzoznW9OXZwGkGT6jhw7uAsWGtybocg_5WR1BHn5UUVDT-1_8qk4icS
https://lh4.googleusercontent.com/T9jMoUy8iWfpT072V2-N0gXNPwkpUDYRvvf3c_rkEVWgRn071NPaYKBH8q25HxDaJIXZoDrGdGp0xMfFZnpZmKmf1MyHF0p41DRwpeRK7VXuLOWFdTBCyfcphwZmh7oHmxAruPf5
Рисунок 18: Результаты поиска по строке «Username:»

Во время просмотра дизассемблированной версии я нашел sql-выражения. Я посмотрел в окно со строками и функциями и обнаружил, что программа использует sqlite.

https://lh4.googleusercontent.com/Rur8kOTqYNmeEr4ahKQcDpcf4Sh0FgXoDGLuxf6j2x_je724nujXPDy4zG4tjY1qpjX2b4aWM-sNMYCs-FczOZ5CKXBWJyKrm0L1t1OTQtUG2jkiklDZYZe-9qxwyntwk4oS_-si
https://lh4.googleusercontent.com/JO5hjN2O-feo0wMlhXOEu81p_knmez57u_xe7NSTeKQMpZhmQlAWLOzXbcrxjdt4hkwysz8AOzJqDFnlNtoVguzFvD3UeODiYTf_updR-N4VdtxjxAeugvKvuS7IT0-SJl_i8bfV
Рисунок 19: Окна со строками и функциями

Я скопировал файлы cli, webs и system.db на свой компьютер. System.db представляет собой базу данных в sqlite, в которой есть таблица user с именами пользователей, паролей, привилегий и статусами учетных записей.

https://lh3.googleusercontent.com/dfc9YejeQ6eHjce5MGDO5QkNb3mDfq7_KVQueMJCRcby7O4MopMA77s5kHko1s4-smXQGOgCiWZ0pV-oleHctJzbxqpJ-bcVfgPsDcRTVOmTNsWC2fJb_GLKcNr6x1opYvoTJu1H
Рисунок 20: Содержимое таблицы user

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

https://lh4.googleusercontent.com/VGsGbvAUx8Sokgslfmes6b3EP31F5LFh3W4XB2Km-oE86mFJqM-nPOeA84NMbqsX5MQwnUag8d6069v-7jmt79Bd3-OLqfjJJDhZL-NTNJScLOswpDraW-orYxIw53PeLXxxYvdP
Рисунок 21: Часть кода, взаимодействующего с таблицей user

Часть кода, связанная с аутентификацией и подверженная sql-инъекции.

https://lh4.googleusercontent.com/5K1sj3N7a9rIbg5SHmTiqSpVJVMvcolh30QBkywqZvFrHP-QVjOe5F5-rR2LO3-McwXRec3OLS0QtH3HMmAlDZ3btkB8CIxUv0Ubpajy_fTYqO2ysEEYZ5rSeEbhERvsgUwhjKKu
Рисунок 22: Уязвимость, связанная с sql-инъекцией

В обычном режиме запрос выполняется так:

На входе = Имя пользователя

Итоговый запрос = select * from users where name = ' Имя пользователя ';

Мы можем сделать так:

На входе = ';на собственный sql запрос;--

Итоговый запрос = select * from users where name = ''; на собственный sql запрос;--';

Я открыл базу данных system.db в SQLite Database Browser и опробовал некоторые выражения перед выполнением запросов непосредственно внутри камеры.

Первой моей мыслью было изменить пароль административного аккаунта.

https://lh5.googleusercontent.com/yV9fS2FSmiiyWmz_FzXRpLg8MdA9cfzdwo-DA_A1-veO8OcxTijagN8wRNXo6znvT2m77yJnIDPkxxghY9j4HGTkBQEezMG3tXS4iOMeqFgAPPJ3qO-8uiaIs11zfxLG29SsU1vo
Рисунок 23: Выполнение запроса на изменение пароля у пользователя admin

Трюк сработал.

Однако внутри камеры при выполнении запроса возникла ошибка.

https://lh5.googleusercontent.com/3qClPDSFptGS_40IA59P1uTgzrvhOZTE71v0ZribXX9HenVwphXrYoq8W-DkEDC4rNJhlKxW0G5x0dd03sHj-1xZVajcWTltCwgoRZ-knP3r12kRvDbTDyTU2ipRCGwD-d8NBPmc
Рисунок 24: Обрыв соединения после выполнение запроса

Соединение обрывалось, если в поле Username передавалось слишком много данных.

Я вернулся в SQLite Database Browser, и после некоторых экспериментов появился следующий запрос: '; update user set password='a';--

https://lh3.googleusercontent.com/YaMd2N0RRKdu8Q-qgith92k_vFCVNdlZZBpAo5dAtCeDFRCiwXdwJUSuVpNhurdbdzERblW2-pOOncZP6iqtsoaFFEOpYaMuJS-83uzBcIWM2jhoSyVlei4SBrin9gBLgtdnH97c
Рисунок 25: Результат выполнения обновленного запроса

Запрос, показанный выше, позволяет выставить пароль «a» всем пользователям таблицы user.

Сейчас я понимаю, что мог бы изменять поля privilege и disable, чтобы лучше замаскироваться. В таком случае я мог бы залогиниться при помощи анонимной учетной записи.

Получение удаленного шелла

Я продолжил исследование файла cli и заметил команду !#/, которая не присутствовала в справке, когда я вводил команду 'help'.

https://lh5.googleusercontent.com/Iz6KW2u9_903ys3TNhso4G7RzALGB8URHXW9SqONvwHdgRFFUDXM3UTtRD5MUx4rukvZj_Z6slXksUlQX1ywSyO5RXHFmWAQ8knVWB_jGJFtNhEovUbtlOYsZW-7cy02YlquMxSN
https://lh5.googleusercontent.com/8ty2L3pOlUR-4fU-7_i-RYl27dfcwOqubXcypqfeDNMyLagGeMs8RBzBTLPukf524NyCuQ4cs7d0-dCICGXUB7tDvh-uX8B5STVItRtIP6cdPRASlrlnoA3cRLd5tZoFTracfljj
https://lh3.googleusercontent.com/YX2FIWBlvjqm6Y78z71-a5CLAj52Q0NB3E5AqUv6Oou05S1zfP7qPmrfhZdhTY-onhOPUYoOhCrJ4cbohdmDIK0ij8IoZwuvSYZcMq5-I_hZ17QS2qadDMOZIzhmzH-RJQ_00eTL
Рисунок 26: Недокументированная команда !#/

На рисунке ниже показано место, куда происходит переход:

https://lh3.googleusercontent.com/4xmKACsz4ryfT36Yl1XGCMQwlx0bzpOGeLdIiSG9hzNC3TAos8X8tNiDhZciL0Mrza6CA9ngU2r2aGTHy3N3D-yGFNBXSD-XyT6jsLRpSEpBU6_715JmbGQrRESMbiaOres9OAL1
Рисунок 27: Участок кода, выполняемый после команды !#/

Попросту говоря, происходит выполнение telnetd на порту 20000. После sql-инъекции и получения доступа к конфигурационному меню командной строки я могу выполнить команду !#/ и запустить telnetd. Далее я могу авторизироваться удаленно при помощи логина root и пустого пароля.

https://lh5.googleusercontent.com/MsdsCWfwQYSi0YpT1HAeIxm9pA_PCCqYxXj1811FDHsVGDuD2QXoGqq30ehP4-mNAlRjovE775U4txru5xx1HxBhSmzhe7jfCK5usK9efGuU6xIZr-wgWZA7c1TkSOUa5vyNgZ8N
Рисунок 28: Удаленное подключение к камере

Ссылки

http://www.grandstream.com/products/ip-video-surveillance/hd-ip-cameras/product/gxv3611hd

https://www.youtube.com/user/EEVblog

Vulnerability Note: https://www.kb.cert.org/vuls/id/253708

CVE: https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2015-2866

https://www.saleae.com/

https://www.adafruit.com/products/284

https://www.youtube.com/watch?v=h5PRvBpLuJs

https://en.wikipedia.org/wiki/Das_U-Boot

http://www.denx.de/wiki/U-Boot/WebHome

http://www.denx.de/wiki/view/DULG/UBootCmdGroupEnvironment

http://sqlitebrowser.org/

Не ждите, пока хакеры вас взломают - подпишитесь на наш канал и станьте неприступной крепостью!

Подписаться