После прочтения комментария от awoland во вчерашней статье Как SmartTV забыли о главном, я сразу полез пробовать получить root-права и telnet/ssh на своем телевизоре. Оказывается, все уже готово для этого, и это проще простого!
Достаточно установить Виджет SamyGo, и он все сделает за вас!
Что дает нам SamyGO?
- Root-доступ на ТВ через Telnet
- Виртуальную флешку, монтирование NFS, Samba, FTP на нее
- Samba, FTP-сервера
- Apache2 с PHP
- Уйму веселья!
# -*- DISCLAIMER -*-
Все, что вы делаете со своим ТВ, вы делаете на свой страх и риск. Автор этой статьи не несет никакой ответственности за ваш анал.
Для моего ТВ (E-серия), мне необходимо было:
- Установить Skype на ТВ и запустить его 1 раз
- Скачать инсталлятор виджета SamyGo на флешку
- Запустить его с флешки
- ???
- PROFIT!
Как они это сделали, демоны?
Вот как выглядит скрипт инсталлятора:
var Main = { }
var widgetAPI = new Common.API.Widget();
var tvKey = new Common.API.TVKeyValue();
var runf1=1;
var runf2=1;
var LabelString="Log:
";
var usbPlugin;
var FilePlugin;
var nUSBCount;
var commonFilePath;
Main.onLoad = function()
{
alert("Main.onLoad()");
this.enableKeys();
widgetAPI.sendReadyEvent();
Func();
};
Main.onUnload = function()
{
};
Main.enableKeys = function()
{
document.getElementById("anchor").focus();
};
Main.keyDown = function()
{
var keyCode = event.keyCode;
switch(keyCode)
{
case tvKey.KEY_RETURN:
case tvKey.KEY_PANEL_RETURN:
widgetAPI.sendReturnEvent();
break;
case tvKey.KEY_RED:
if(runf2==1)
{
runf2=0;
Log ("
Please Wait 20-30 sec....");
setTimeout("Func1(commonFilePath);",3000);
}
else Log('Activated yet!');
break;
case tvKey.KEY_ENTER:
case tvKey.KEY_PANEL_ENTER:
if(runf1==1)
{
runf1=0;
Log ("
Please Wait 20-30 sec....");
setTimeout("Func1(commonFilePath);",3000);
}
else Log('Activated yet!');
break;
default:
alert("Unhandled key");
break;
}
};
function Log(Str)
{
var Label = document.getElementById("LogLabel");
LabelString = LabelString+Str+"
";
widgetAPI.putInnerHTML(Label,LabelString);
};
function sleep(ms)
{
ms += new Date().getTime();
while (new Date() < ms){}
};
function Func()
{
usbPlugin = document.getElementById("pluginStorage");
FilePlugin = document.getElementById("pluginObjectFile");
nUSBCount = eval("usbPlugin.GetUSBListSize()");
var Param;
var r1=0;
var r2=0;
var r3=0;
Log("Found <b style='font-size:30px; color:green'>" + nUSBCount + "</b> USB devices");
for (var i = 0; i < nUSBCount; i++)
{
var nid1 = eval("usbPlugin.GetUSBDeviceID("+i+")");
var nid = parseInt(nid1);
var VN = "
Vendor Name = <b style='color:green'>" + eval("usbPlugin.GetUSBVendorName("+nid+")") + "</b>";
var MN = "
Model Name = <b style='color:green'>" + eval("usbPlugin.GetUSBModelName("+nid+")") + "</b>";
nPartition = eval("usbPlugin.GetUSBPartitionNum("+nid+")");
for (var j = 0; j < nPartition; j++)
{
var mntPath = eval("usbPlugin.GetUSBMountPath("+nid+", "+j+")");
commonFilePath = '/dtv/usb/' + mntPath;
Param = "FilePlugin.IsExistedPath(commonFilePath + '/InstallSamygo/data/SamyGO.zip')";
r1 = eval(Param);
Param = "FilePlugin.IsExistedPath(commonFilePath + '/InstallSamygo/data/AutoStart')";
r2 = eval(Param);
Param = "FilePlugin.IsExistedPath(commonFilePath + '/InstallSamygo/data/libSkype.so')";
r3 = eval(Param);
if (r1 == 1 && r2 == 1 && r3 == 1)
{
Log("The installation files found on USB: " + commonFilePath + VN + MN);
return;
}
else
{
Log("Some installation files not found on USB: " + commonFilePath + VN + MN);
return;
}
}
Log("The installation files not found on USB: error");
}
};
function Func1(Path)
{
var r=0;
var Param;
var str ='';
Param="FilePlugin.Copy ('"+ Path +"/InstallSamygo/data/AutoStart','/mtd_rwcommon/moip/engines/Skype/AutoStart')";
r = eval(Param);
if (r==1) str = 'OK'; else str = 'No';
Log("Step1: " + str)
Param="FilePlugin.Copy ('"+ Path +"/InstallSamygo/data/libSkype.so','/mtd_rwcommon/moip/engines/Skype/libSkype.so')";
r = eval(Param);
if (r==1) str = 'OK'; else str = 'No';
Log("Step2: " + str);
if(runf2==1)
{
Param="FilePlugin.Unzip('"+ Path +"/InstallSamygo/data/SamyGO.zip','/mtd_rwcommon/widgets/user/SamyGO/')";
r = eval(Param);
if (r==1) str = 'OK'; else str = 'No';
Log("Step3: " + str);
}
Log("Now press exit and restart tv");
};
Уязвимость в функции FilePlugin.Copy, вызываемой через eval, которая позволяет копировать что угодно куда угодно. Скрипт берет и копирует подмененный libSkype.so, который умеет только запускать другой скрипт, и устанавливает сам виджет SamyGo.
Что же в виджите SamyGo?
var Main = {
}
var widgetAPI = new Common.API.Widget();
var tvKey = new Common.API.TVKeyValue();
Main.onLoad = function() {
alert("Main.onLoad()");
widgetAPI.sendReadyEvent();
document.getElementById("anchor").focus();
var FilePlugin = document.getElementById("pluginObjectFile");
var Param1="FilePlugin.Copy ("/proc/self/cmdline", "$(sh /mtd_rwcommon/widgets/user/SamyGO/data/run.sh)/tmp/cmdline")";
eval(Param1);
}
Main.keyDown = function() {
var keyCode = event.keyCode;
alert("Main Key code : " + keyCode);
switch (keyCode) {
case tvKey.KEY_RETURN:
break;
}
}
Ну это вообще пушка! Мы можем выполнять shell-команды из все той же функции, используя $()-синтаксис.
run.sh выполняет инсталляцию busybox и прочей мишуры, монтирует data.xfs, запускает telnetd и nc, который запускает sh при коннекте (если будут какие-то проблемы с /dev/pts и к telnet нельзя будет подключиться), запускает подобия init-скриптов.
Что внутри?
Внутри у нас 2-ядерный процессор с архитектурой ARMv7, с поддержкой NEON, я полагаю, семейства Cortex-A8, видео MALI 400, 512МБ оперативной памяти, ядро 2.6.35.13. В общем, довольно типичный «планшет» 2012 года.
VDLinux#> cat /proc/cpuinfo
Processor : ARMv7 Processor rev 0 (v7l)
processor : 0
BogoMIPS : 1794.04
processor : 1
BogoMIPS : 1794.04
Features : swp half thumb fastmult vfp edsp neon vfpv3
CPU implementer : 0x41
CPU architecture: 7
CPU variant : 0x3
CPU part : 0xc09
CPU revision : 0
Hardware : amber3
Revision : 0000
Serial : 0000000000000000
Ядро поддерживает SquashFS, FAT32, XFS, RFS (Самсунговская ФС, FAT32 + журналирование), NTFS (Драйвер tntfs от Tuxera). Есть поддержка модулей, в SamyGo поставляются несколько модулей ФС, FUSE загружается, а, например, ext2/3/4 — нет, т.к. в ядре нет символов для них.
На ТВ запущен самый обычный X-сервер с xf86-video-mali, за весь SmartTV отвечает 125-мегабайтный файл exeDSP (загружался в IDA PRO 17 минут до начала анализа), а вот со звуком интересней: alsa нет, и, похоже, exeDSP общается с /dev/system напрямую.
Что можно делать-то?
Да что угодно. Я лентяй, и стараюсь лишний раз не кросс-компилировать что-либо, поэтому просто взял Ubuntu Core, создал на флешке XFS-раздел, распаковал туда Ubuntu и вставил в ТВ. С armhf-версией были проблемы (всякие unknown instruction, там компилируют с thumb2?), поэтому нашел 12.04 armel.
Остается только вставить флешку в ТВ, подключиться по telnet и сделать:
chroot /dtv/usb/sda1 /bin/bash
И мы получим полноценную убунту 12.04.
mount --bind не работает, поэтому, если вам нужен proc и sys в chroot (а он вам будет нужен), используйте:
mount -t sysfs sysfs ./sys
mount -t proc proc ./proc
Первым делом, я, конечно же, поставил mplayer. И знаете, работает! Медленно, конечно, и из выводов только x11 работает, но показывает! Я посмотрел вчерашний опенинг с субтитрами и без звука ;)
Скриншотов, вот, scrot'ом поснимал:
Прошу обратить внимание, разрешение скриншотов я не менял, и, на самом деле, разрешение у ТВ (по крайней мере у X-сервера) 1280×720!
Ну а дальше я решил поставить Ace Stream Engine и AceProxy для просмотра ТВ-стримов и Torrent прямо на ТВ. Для этого нам необходим Python, т.к. именно на нем написаны эти два продукта. Т.к. Ace Stream официально не выпускается для ARM, да и вообще, его разработчики несколько дикие, то мы возьмем распакованную версию для Raspberry PI, ну а AceProxy из моего репозитория
Собственно, нужные пакеты для Ace Stream написаны в ссылке, а для AceProxy нужен только python-gevent. Запускаем все это дело, можно даже открыть страницу статистики AceProxy во встроенном браузере ТВ:
На удивление, Ace Stream не особо грузит процессор (где-то на 15% судя по top), так что его вполне можно использовать на ТВ.
Теперь остается только взять какой-нибудь плеер (nStreamLmod, например) и сделать плейлист для AceProxy.
Что-то еще?
Это все proof-of-concept. Я все это делал чисто из кратковременного интереса и, скорее всего, не буду продолжать дальше. Однако, если кто-нибудь подопнет меня, как происходит работа со звуком, то можно будет смотреть видео с FLAC и Vorbis в MKV, просто запуская их вместе.
Будьте осторожны с SamyGo. По умолчанию, он запускает много сервисов, и доступ по telnet осуществляется без пароля.
Успехов!
Автор: ValdikSS