趁着午休的间隙看了一下题,感觉还挺有趣的,没有想象中那么粗制滥造,有一些思路可以记录一下。
pwn1
这道题有一些东拼西凑的感觉,有趣的点在于栈上溢出的数量非常有限,只能改写到返回地址,同时 gadget 也很少,没有控制 rsi、rdx 的能力。
最初考虑:程序开始的时候读了一些东西到 .bss 段上,那就栈迁移过去让 ROP 链接上,但是发现栈迁移过去后 puts 函数无法正常调用 - 因为栈太浅了,这条路也就断了。
在公司里没有 ida,愣是花了半天才发现存在一个 magic_gadget
,主要是两个功能:
- 造成栈错位的现象,最终 rbp 位于栈顶 rsp 上面
- 最后返回到一开始设置好的 rbp 地址
上述能力提供了获取输入时修改下个被调用函数(这里是 read)返回地址的能力,因此就可以构造更长的 ROP 链。
最后还要在堆上找到 flag 内容,这里考虑 libc 中 mp_
的 sbrk_base
域,会指向堆地址的开头:
pwn2
这道题第一眼看到以为是普通的 strfmt,没想到题目还把标准输出关了。不过好在提供了泄露栈地址的能力。因此即使没有 elf 和 libc 基地址,也能借助改栈上残留地址的末位,进而实现一定程度的任意地址写。
思路如下:
- 泄露栈地址
- 前期准备工作,包括构造溢出、布置指向 stdout 的指针
- 篡改 stdout 指针到 stderr,重新获取输出
- 有输出的情况下就常规打法了,记得 getshell 后要
1>&2
因为 elf 地址和 libc 地址都是未知的,因此需要爆破两次 161,还是可以接受的: