导语:我写这文章是为了分享我对 Edimax 生产的 IC-3116W IP 摄像头的分析经验。本文聚焦于如何开始分析 IP 摄像头,当然本文提到的工具同样适用于分析其他的设备。

我写这文章是为了分享我对 Edimax 生产的 IC-3116W IP 摄像头的分析经验。本文聚焦于如何开始分析 IP 摄像头,当然本文提到的工具同样适用于分析其他的设备。首先,我会介绍如何获取目标固件,并利用固件来收集信息;然后,会讲解如何进入系统;最后,会讲如何在设备上面安装 gdbserver。不过,本文不会去分析那些相对复杂的漏洞,而只专注于那些有助于我们分析设备漏洞的部分,包括后面会提及的一个管理界面远程代码执行漏洞(当然这个漏洞早已提交给了相关厂商)。

分析设备

这章开始,我们将会在一个已经搭建好的摄像头测试环境中介绍分析的步骤,当然这个测试环境与一般的 Web 应用渗透测试环境没什么太大的区别。在最初的阶段,我们需要通过一些外部资源(例如厂商网站或者谷歌)来收集摄像头的信息,然后利用适当的工具(Burp Suite,nmap等等)扫描摄像头可能暴露的服务(特别是管理界面)。随后就是利用阶段,我们需要拿到进入摄像头的权限,最后就是后利用阶段了,此时我们就可以适当的在摄像头上部署调试分析工具。

步骤1:收集信息

在分析设备前最关键的步骤就是尽可能多的收集相关信息,幸运的是,Edimax 官方网上提供了大量摄像头的信息,如数据表,操作手册,固件和构建工具(包括构建镜像的文件),但是一些涉及敏感信息的二进制文件源码没有公开。

固件可以提供对摄像头最初的认识,通过使用 binwalk 分析固件,可以提取出摄像头的文件系统。

$ binwalk -e IC3116W_v2.10.bin

DECIMAL         HEX             DESCRIPTION
-------------------------------------------------------------------------------------------------------
605             0x25D           LZMA compressed data, properties: 0x88, dictionary size: 1048576 bytes, uncompressed size: 65535 bytes
10392           0x2898          LZMA compressed data, properties: 0x5D, dictionary size: 8388608 bytes, uncompressed size: 3735204 bytes
1245312         0x130080        Squashfs filesystem, little endian, version 4.0, compression: lzma, size: 4072088 bytes,  907 inodes, blocksize: 131072 bytes, created: Mon Feb 22 11:50:40 2038

从上面信息可以得知,开发人员使用了 SquashFS 文件系统,为了浏览文件系统,我使用带有 LZMA 支持的 unsquashfs:

$ unsquashfs -d filesystem 130080.squashf

这样我们就获得解压过后的文件系统(存储在filesystem文件夹下面)

$ ls -a filesystem

.  ..  bin  dev  etc  home  init  lib  mnt  proc  sys  test  tmp  usr  var  web  www

在提取出文件系统后,我们就可以来浏览摄像头的相关文件了。这个文件系统里包含一些有趣的二进制文件,如:telnetd,wget,FTP等等,但是通过使用 Nmap 扫描得知,telnet 守护进程默认情况下没有运行。

$ nmap -sS -p0- --reason -v -T3 -Pn 192.168.2.3

[...]
Nmap scan report for 192.168.2.3
Host is up, received arp-response (0.00065s latency).
Not shown: 65534 closed ports
Reason: 65534 resets
PORT     STATE     SERVICE     REASON
80/tcp   open      http        syn-ack
554/tcp  open      rtsp        syn-ack
MAC Address: 74:DA:38:34:AA:75 (Unknown)
[...]

Web 服务的根目录位于 www 下面,在这里我发现了一些无需身份认证直接就能访问的 CGI 文件:

/www/camera-cgi/public/anonymous.cgi
/www/camera-cgi/public/getSysteminfo.cgi
/www/camera-cgi/public/supportiPhoneAppVersion.cgi

其中,anonymous.cgi 和 getSysteminfo.cgi 透露了很多 IP 摄像头的安装信息(包括内部IP地址,固件版本等等)。

1483007079891428.png

在查看摄像头文件系统中的文件后,下一步就是利用自动化工具结合手动测试来发现摄像头内部服务是如何运行的了。如之前 Nmap 的扫描结果,有一个运行在 80 端口的 Web 服务,通过查看相机背面的说明信息,得知其默认账号密码是 admin:1234。

1483007088941612.jpg

有了这个账号密码我们就可以进行下一步获取系统访问权限的内容了。

步骤2:获取系统访问

在通过自动化扫描和手工测试后,我在摄像头的 Web 界面中发现了 System Log 允许远程命令执行。通过输入 telnetd 的路径,摄像头的 telnet 服务就被开启了。

1483007097380313.png

这样,我们就可能通过 telnet 进入摄像头了:

$ telnet 192.168.2.3
Trying 192.168.2.3...
Connected to 192.168.2.3.
Escape character is '^]'.

IC-34AA75 login: admin
Password: 
RLX Linux version 2.0
         _           _  _
        | |         | ||_|                 
   _  _ | | _  _    | | _ ____  _   _  _  _ 
  | |/ || | / /   | || |  _ | | | | / /
  | |_/ | |/       | || | | | | |_| |/    
  |_|   |_|_/_/   |_||_|_| |_|____|_/_/

For further information check:
http://processor.realtek.com/


BusyBox v1.13.4 (2015-02-25 18:14:22 CST) built-in shell (ash)
Enter 'help' for a list of built-in commands.

# cat /etc/passwd
admin:$1$yAn92Ld/$u5nHFH9nLds0naDaLuK1d/:0:0:System Administrator,,,:/:/bin/sh

telnet 的用户凭证跟 Web 管理界面是一样的,从 /etc/passwd 文件发现只有一个账户 admin(uid 0,gid 0) 存在于系统之中,这就意味着我们直接就有了系统的 root 权限了。

当然,我们也还可以通过 UART 端口来获得系统 Shell,端口可以在下图中看到:

1483007106641557.jpg

可以通过使用类似 JTAGulator 的设备来访问 UART 端口。在进入系统后,我们就可以开始部署工具来帮助分析摄像头了。

步骤3:建立研究环境

在摄像头上有许多工具可以帮助我们分析运行的进程,但不幸的是,在摄像头上没有调试器或编译器,而我的目标是在摄像头上面运行调试器,具体点是,我想在摄像头上面运行 gdbserver,然后在本地的 x86 机器上面运行 gdb。

在摄像头上面运行 gdbserver 有这么几个优势。首先,gdbserver 的二进制文件大小比 gdb 的要小不少,鉴于嵌入摄像头的磁盘通常比较小,经常 gdbserver 会是我们调试唯一的选择;其次,gdbserver 的依赖项也比 gdb 少不少,而且更加容易编译。当然,gdbserver 也有它的缺点,例如,如果主机系统(运行 gdb 的系统)与目标系统(运行 gdbserver 的系统)位数不同就可能出现问题,这也就是为什么我让 gdb 运行在 x86 的机器上。

为了将安装文件上传到摄像头文件系统当中,我选择使用 wget,需要注意的是 squashfs 文件系统是只读的,但是我已经将闪存挂载到了 /var 目录下面,所以我们可以把文件写入这里。想要从摄像头传输文件出来,可以使用 lighttpd,这个是摄像头自带的 Web 服务器,只需要在启动服务器另一个实例并将根目录设置为 "/" 即可。

在建立了本机与摄像头文件传输的通道后,是时候在摄像头上编译 gdbserver 了。在此之前,我们需要先知道摄像头使用的处理器:

# cat /proc/cpuinfo
system type             : RTL819xD
processor               : 0
cpu model               : 56322
BogoMIPS                : 658.63
tlb_entries             : 32
mips16 implemented      : yes

从上面的输出我们得知使用的是 RTL819xD,这是一个基于 MIPS 的处理器。因此,我首先尝试使用标准的 MIPS 交叉编译。交叉编译的源码来自于 Aboriginal Linux 网站,他们不仅提供大量交叉编译器,还提供了用于构建环境使用的脚本。

但是底层的 Realtek CPU 使用的却是改进的指令集,而纯 MIPS 二进制文件通常无法直接在摄像头上运行。但是正如之前提到的,Edimax 已经为我们准备好了一套用于构建的工具。通过使用 CentOS 7.3 和提供的工具,我建立了一个摄像头的环境,关于构建环境的步骤都在官方提供工具的一个 pdf 说明文档中,基本上就是如下步骤:

1. cd TARGET_DIR
2. bzip2 -cd rsdk-{VERSION}-{LIBRARY}-{PLATFORM}.tar.bz2 | tar xvf –
3. ln -s rsdk-{VERSION}/{PLATFORM}/{LIBRARY} rsdk
4. export PATH=TARGET_DIR/rsdk/bin:$PATH

现在我可以通过 CentOS 系统来交叉编译用于摄像头的二进制文件了。例如交叉编译 gdbserver 只需要如下命令:

$ cd gdbserver_src
$ ./configure  --host=mips-linux CC=rsdk-linux-gcc
$ ./make CC=rsdk-linux-gcc AS=rsdk-linux-as LD=rsdk-linux-ld

最后,我们获得了可以运行在摄像头上面的 gdbserver 二进制文件。相应的,我们可以通过相同的方法获得 gdb 的二进制文件,不过幸运的是,官方提供了一个预编译好的二进制文件。当然,如果你想要自己编译也是可以的,只需要在编译的时候使用不同参数:

$ cd gdb_src
$ ./configure  --target=mips-linux
$ ./make

在构建过程中,我们必须要制定目标系统,即 gdbserver 将要运行在哪个系统之上。另外,我测试了多个不同版本的 gdb/gdbserver 后,发现 gdb-6.8 可以运行在摄像头上。

最后,我想要说明 gdb/gdbserver 是如何分析运行在摄像头上二进制文件的。但请先将 gdbserver 二进制文件拷贝到 /var 目录下面,并通过 chmod 给予执行权限。然后我们就可以通过如下命令进行调试了:

# /var/gdbserver ip:port --attach pid

这里的 IP 是运行 gdb 主机的地址,而指定的端口 port 则会在目标系统上开放,随后的 PID 是我们想要连接的进程 ID。当然,我们还可以在摄像头中启动一个新的进程,通过指定可执行文件的路径来代替 –attach 参数。

一个在摄像头上抓取 /bin/ipcam 二进制文件运行的实例如下:

# /var/gdbserver 192.168.2.10:1234 --attach 9266 
Attached; pid = 9266
Listening on port 1234

在执行了该命令后,gdbserver 就会在 1234 端口上等待连接,而在 x86 主机上,我们需要启动 gdb 并使用如下命令连接到目标系统:

$ rsdk-mips-gdb -q
(gdb) target remote 192.168.2.3:1234 

Remote debugging using 192.168.2.3:1234
[New Thread 9266]
0x2ab6b89c in ?? ()

(gdb)

然而,我们看到 gdb 没有上下文,即它不知道当前的状态。这是因为 gdb 加载的二进制文件符号表是在目标服务器上进行调试的,因此,需要在本地使用 gdn 的文件命令在加载一次符号表。此外,在本地调试摄像头文件系统中库的副本时,需要保持和 gdb 同处于根目录之下。

$ cd cam_root_dir
$ rsdk-mips-gdb -q
(gdb) file cam_root_dir/bin/ipcam
Reading symbols from cam_root_dir/bin/ipcam...(no debugging symbols found)...done.
(gdb) target remote 192.168.2.3:1234 
Remote debugging using 192.168.2.3:1234
[New Thread 9266]
0x2aaa8a40 in _start() from cam_root_dir/lib/ld-uClibc.so.0
(gdb)

至此,我们就可以像在摄像头上原生使用 gdb 一样进行调试了,例如设置断点,分析寄存器等等。当我们拥有了这样一个分析环境后,就可以进一步去分析摄像头的其他服务了。

源链接

Hacking more

...