CVE-2025-5623 DIR-816 路由器用户模拟与栈溢出漏洞复现

新发布用户模拟栈溢出ROP构造
2025-06-13 12:54
17592

DIR-816的用户模拟与栈溢出漏洞复现

CVE-2025-5623

在 D-Link 的 DIR-816 1.10CNB05 设备中发现了一个漏洞,该漏洞已被评定为严重级别。此漏洞影响了文件 /goform/qosClassifier 中的 qosClassifier 功能。对参数 dip_address/sip_address 的操作会导致栈溢出漏洞。有可能通过远程发起攻击。该漏洞的利用方法已向公众公布,并且可能被利用。此漏洞仅影响那些已不再由维护方支持的产品。

启动程序

提取固件

拿到固件,查看是否加密

binwalk -E DIR-816A2_FWv1.10CNB05_R1B011D88210.img

没有加密直接用binwalk提取。

binwalk -Me DIR-816A2_FWv1.10CNB05_R1B011D88210.img

1749126784687-41bb1972-f354-4a15-9d20-a729d6058cc6.png

启动项分析

启动项分析是找到系统启动时自动运行的程序、找到能够启动我们程序的Web服务器,通常查看/etc/rcS脚本。若/etc找不到,可查看/etc_ro。常见的Web服务器有httpdgoaheadmini_httpd等。
1749179248258-e75f0585-2ea4-4f2a-8f96-459c88eed23f.png
在启动脚本rcS发现有goahead二进制文件,并且在后台运行程序。
1749179213003-cdc92548-0b39-4921-ba1f-359976d5bad3.png
我们现在通过下面的命令找到web服务器。找到bin/goahead。像这种web服务器一般都是二进制文件,在bin目录或者sbin目录下。

grep -ir "goahead"

1749180337576-b1decfe1-673c-4d8b-9639-3ef533e861c0.png
也可以用firmwalker工具搜集信息
Snipaste_2025-06-06_15-31-48.png
用readelf指令查看一下,goahead是mips架构小端序。
readelf.png

模拟程序

这里有两种模拟方案,手动进行qemu系统模拟或者qemu用户模拟。我们选择qemu用户模拟单个程序,这种方法不需要配置整个系统需要的文件、网卡等,仅需要绕过一些判断环境的程序(因为我们没有完整系统),但是模拟起来的程序缺少一些支撑,后续工作会更困难。

复制qemu-mipsel-static到当前squashfs-root文件系统下

cp $(which qemu-mipsel-static) ./

启动goahead程序

sudo chroot . ./qemu-mipsel-static  ./bin/goahead

程序运行报错,没有/dev/nvram文件,选择创建文件解决。

下面还有个goahead.c: cannot open pid file这个错误,我们打开ida分析解决
1749181151821-8f2ee4c7-6ccb-4c30-b38f-71e08b9de6fa.png
根据IDA分析,v4等于0,会跳转到报错程序。分析函数,fopen需要打开文件,打不开1就返回0,系统报错是打不开文件,因为我们var/run目录下没有goahead.pid文件,因此我们在他指定的目录下创建一个文件。
1749181663751-38175f62-1862-4883-929d-1d87f1f5b25b.png
1749184408658-9d0201ac-4ca3-448f-ab7b-e294c6fe0d5d.png
继续运行,发现程序一直在等待运行,根据输出信息定位到程序停留的地方
1749184914517-e6f82e91-bf3e-4863-b3c0-aedaa76dc2a7.png
分析一下,函数是while(1),要找到break跳出循环,需要v1等于1。我们同样创建这个指定目录下的文件。
1749186040153-91be293f-a214-4216-a635-4eef23bfbf2f.png
重新启动程序,发现还是有报错,我们继续复制报错内容,在ida里面搜索
1749186682632-ee185c06-f837-4bdb-b313-aef648936181.png
1749186819845-0121e682-7f80-45bc-8b09-993733ed166d.png
动态调试,这里选择修改汇编代码里$v0的值改变跳转方向
1749187447061-497405cc-1b22-44ef-b42b-734477b56753.png
1749187781738-8ed771eb-832b-4f71-b9fc-da6c5a61307c.png
修改完,登录服务就启动了。输入我们本机的ip地址加路径/dir_login.asp就可以进入登录页面
1749462322351-b910a56d-dc0b-483f-a0ad-401e9afd698c.png
现在我们同样需要绕过账号密码的验证,我们在ida里面找到对应的登录函数。
1749530575403-90fd6fbe-4756-4e88-b9a9-b4da9189c872.png
研究登录逻辑发现只需要账号、密码为空就可以实现登录。
1749530634247-628f4304-77eb-48c6-884a-678753c4f1e4.png
这里有两种处理方式
一种使用burp抓包,修改账户和密码为空,把show_username的值删除
1749540084545-4e1ca0a1-193d-43e8-8fb7-8a00932e557b.png
一种还是在ida里面判断账号的地方,下断点修改值,令$v0=0
1749535589572-1caf7960-5579-42f1-88cb-ad8bfc1f0def.png
1749537270936-6090c3dc-6b21-4531-a70d-da0068a3d9ff.png
这里将修改断点的启动程序整理成一个python脚本,方便多次pwndbg调试。其中登录账号需要在dir_login.asp手动输入任意值并点击登录。
Snipaste_2025-06-10_22-23-22.png

import pexpect
import time
import sys

child = pexpect.spawn('pwndbg ./bin/goahead', encoding='utf-8')
PROMPT = 'pwndbg>'

def send_expect(cmd, expect_prompts=None, delay=0.5, description=None):
    if description:
        print(f"[*] 执行:{description}")
    if expect_prompts is None:
        expect_prompts = ['pwndbg>', r'Breakpoint \d+,', r'Continuing\.']
    child.sendline(cmd)
    try:
        index = child.expect(expect_prompts, timeout=30)
        time.sleep(delay)
        return index
    except pexpect.exceptions.TIMEOUT:
        print(f"[!] 超时:执行命令 `{cmd}` 后未匹配期望提示符。")
        print(f"[!] GDB输出如下(最后200字符):\n{child.before[-200:]}")
        sys.exit(1)

def confirm_register_value(reg_name, expected_value):
    """检查寄存器值是否设置成功"""
    child.sendline(f'print ${reg_name}')
    child.expect(PROMP

试读结束,发布七天后转为公开

公开时间:2025年6月20日 12:54:22

提前解锁全文,需花费 50 积分

登录解锁全文
分享到

参与评论

0 / 200

全部评论 1

Aiyflowers的头像
很难不赞
2025-06-16 10:33
投稿
签到
联系我们
关于我们