从零开始复现CNVD-2018-01084

环境配置

笔者复现的环境是Ubuntu 22.04(wsl2),ida9.0

配置mips架构的运行环境:

1
2
3
4
sudo apt-get install gcc-mips-linux-gnu
sudo apt-get install gcc-mipsel-linux-gnu
sudo apt-get install gcc-mips64-linux-gnuabi64
sudo apt-get install gcc-mips64el-linux-gnuabi64

安装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完成修复)

漏洞复现

定位漏洞文件

根据官方公告,找到存在漏洞的二进制文件

官方公告

image-20250906164255939

提取固件:

1
binwalk -eM DIR645A1_FW102B08.bin

在解压提取固件时可能在提取出来的文件夹中没有内容,是因为sasquatch这个没安装

根据“漏洞描述”中的关键词service.cgi进行查找:

image-20250906163314353

在图中就可以看出漏洞文件位于./htdocs/cgibin,将其拖进IDA中先进行静态分析。

对二进制文件进行静态分析

main()函数

先看一下开头的代码

image-20250906165244464

  1. v3 = *argv;

    • argv 是一个指向程序启动参数字符串数组的指针。
    • *argv (等同于 argv[0]) 永远是程序自身的完整路径和名称
    • 所以,v3 现在的值是程序的完整路径,例如 "/htdocs/cgibin"
  2. v6 = strrchr(*argv, 47);

    • strrchr 是一个C语言函数,用于在字符串中查找最后一个出现的指定字符。
    • 47 是字符 / 的ASCII码值。
    • 这行代码的作用是:在程序路径 "/htdocs/cgibin" 中,从后往前找,找到最后一个 /
    • 执行后,v6 会指向这个 / 字符。
  3. if ( v6 ) v3 = v6 + 1;

    • if (v6) 判断是否找到了 /。如果找到了,v6 就不是空指针(NULL)。
    • v3 = v6 + 1; 如果找到了 /,那么 v6 + 1 就指向了 / 后面的第一个字符。
    • 这 cleverly 的一步操作,就是从完整路径中提取出程序的文件名
    • 例如,如果 v3 原本是 "/htdocs/cgibin",执行后 v3 就变成了 "cgibin"
  4. if ( !strcmp(v3, "scandir.sgi") )

    • strcmp 是字符串比较函数。如果两个字符串完全相同,它返回 0
    • ! 是逻辑非操作符,!0 的结果是 true
    • 所以,这行代码的意思是:判断程序的文件名是不是等于 "scandir.sgi"

在main函数中Ctrl+F直接搜即可找到对应关键字"service.cgi"

image-20250906164553853

当传入的第一个参数是service.cgi,比对成功后,会进入servicecgi_main函数。

return (phpcgi_main_1)(argc_1, argv, envp);

  • 执行跳转:程序立即调用刚刚赋值的函数指针,也就是直接跳转去执行 servicecgi_main 函数,并将所有的命令行参数和环境变量都传递给它。

servicecgi_main()函数

跟进servicecgi_main()函数

打开它的汇编代码,我们先对servicecgi_main这个函数整体的调用路线进行一个宏观的分析:

image-20250906172558242

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

image-20250906173010200

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

回到servicecgi_main()函数中

image-20250906173514879

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()下方

image-20250906173841821

所以,为了利用到lxmldbc_system中的漏洞,我们的请求方式只能为POST

cgibin_parse_request()函数

在servicecgi_main()中如下位置跟进

image-20250906174147327