从零开始复现CNVD-2018-01084
环境配置
笔者复现的环境是Ubuntu 22.04(wsl2),ida9.0
配置mips架构的运行环境:
1 | sudo apt-get install gcc-mips-linux-gnu |
安装qemu、binwalk、sasquatch、gdb-multiarch等工具
参考:安装sasquatch在22.04等高版本Ubuntu、kali中的安装错误解决方案
漏洞固件 Firmware:DIR-645_A1_FW: v1.02b08 (for WW) (tw官网选择 DIR-645 第一个文件)版本号为 v1.02(v1.03完成修复)
漏洞复现
定位漏洞文件
根据官方公告,找到存在漏洞的二进制文件
官方公告

提取固件:
1 | binwalk -eM DIR645A1_FW102B08.bin |
在解压提取固件时可能在提取出来的文件夹中没有内容,是因为sasquatch这个没安装
根据“漏洞描述”中的关键词service.cgi进行查找:

在图中就可以看出漏洞文件位于./htdocs/cgibin,将其拖进IDA中先进行静态分析。
对二进制文件进行静态分析
main()函数
先看一下开头的代码

v3 = *argv;argv是一个指向程序启动参数字符串数组的指针。*argv(等同于argv[0]) 永远是程序自身的完整路径和名称。- 所以,
v3现在的值是程序的完整路径,例如"/htdocs/cgibin"。
v6 = strrchr(*argv, 47);strrchr是一个C语言函数,用于在字符串中查找最后一个出现的指定字符。47是字符/的ASCII码值。- 这行代码的作用是:在程序路径
"/htdocs/cgibin"中,从后往前找,找到最后一个/。 - 执行后,
v6会指向这个/字符。
if ( v6 ) v3 = v6 + 1;if (v6)判断是否找到了/。如果找到了,v6就不是空指针(NULL)。v3 = v6 + 1;如果找到了/,那么v6 + 1就指向了/后面的第一个字符。- 这 cleverly 的一步操作,就是从完整路径中提取出程序的文件名。
- 例如,如果
v3原本是"/htdocs/cgibin",执行后v3就变成了"cgibin"。
if ( !strcmp(v3, "scandir.sgi") )strcmp是字符串比较函数。如果两个字符串完全相同,它返回0。!是逻辑非操作符,!0的结果是true。- 所以,这行代码的意思是:判断程序的文件名是不是等于
"scandir.sgi"。
在main函数中Ctrl+F直接搜即可找到对应关键字"service.cgi"

当传入的第一个参数是service.cgi,比对成功后,会进入servicecgi_main函数。
return (phpcgi_main_1)(argc_1, argv, envp);
- 执行跳转:程序立即调用刚刚赋值的函数指针,也就是直接跳转去执行 servicecgi_main 函数,并将所有的命令行参数和环境变量都传递给它。
servicecgi_main()函数
跟进servicecgi_main()函数
打开它的汇编代码,我们先对servicecgi_main这个函数整体的调用路线进行一个宏观的分析:

我们猜测漏洞点存在于这里的system函数处,它是由lxmldbc_system函数调用的:

在lxmldbc_system函数中,会先进行一个格式化字符串的拼接,再将拼接好的字符串作为system的参数调用,因此,这里的确可能存在一个可被利用的点:
回到servicecgi_main()函数中

strcasecmp(s1, s2)的返回值
比较 strcasecmp(s1, s2) |
返回值 |
|---|---|
| s1 等于 s2 | 0 |
| s1 小于 s2 | < 0 |
| s1 大于 s2 | > 0 |
首先获取了环境变量REQUEST_METHOD进行判断:
- 当为POST请求时,将n1024设置为1024
- 当处理不为GET请求时,他会跳转到LABEL_10,而这个LABEL_10位于
lxmldbc_system()下方

所以,为了利用到lxmldbc_system中的漏洞,我们的请求方式只能为POST。
cgibin_parse_request()函数
在servicecgi_main()中如下位置跟进
