CTF-PWN-堆

house of force

当申请堆时,若所以已经被free的块都无法满足要求(所有bin都无法满足)同时检验top chunk size减去要分配的chunk大小(szie大小)仍然满足chunk的最小大小,则会从topchunk中分割出相应大小作为申请的的堆块空间。

通过控制top chunk size值(改为-1因为对应无符号形式),然后malloc从而使得top chunk跳转到任意位置随后再malloc(该位置形式满足chunk)则可以控制该位置的内容

向前控制内存:
1.通过已经分配的chunk得到的chunk指针加上一定的数值使其对应的地址为top chunk size的地址
2.通过取修改后的指针内容进行修改
3.malloc合适的值(经过检验和转换),使得修改后的top chunk size的值既满足条件。同时top chunk地址加上malloc中的参数后的地址为需要的地址。

当传入负数时,我们知道无论是无符号数还是有符号数,其实都是将其对应的二进制形式编码相加,只是最终结果识别方式不同。二者的有符号数形式相加结果为正数,则无符号形式相加结果也一模一样。

向后控制内存:
上同只不过参数为正

公式:newchunk地址-0x10-topchunk地址=malloc的参数

(64位)
参数为负数的时候此时计算出来的数仍然是0x10的整数倍,再 加上SIZE_SZ + MALLOC_ALIGN_MASK然后值进行& ! MALLOC_ALIGN_MASK得到的结果相当于原数加0x10仍然不变(32位差不多)


强转为函数指针并调用之,将v3[1]变量变为函数指针变量,存储函数地址,并调用该函数

思路:

1.寻找会执行的可以覆盖的函数指针
2.分配一个chunk,利用重写时无限制溢出覆盖top_chunk 的size值为-1
3.最后分配malloc一个合适的值使得top chunk移动到目标覆盖位置-0x10的位置
4.最后malloc合适的值,然后覆盖函数地址为目标函数地址
5.调用甲函数执行乙函数

劫持_malloc_hook和_free_hook

mallo和free时会 根据_malloc_hook变量和_free_hook变量储存的函数地址进行跳转,从而执行对应函数。此时参数malloc对应分配的大小,free对应某个地址(chunk use data处覆盖/bin/sh的字符串)

bin 垃圾桶

struct malloc_state
{ 
  ...
  /*other member*/
  ...
 
  /* Fastbins */
  mfastbinptr fastbinsY[NFASTBINS];
 
  /* Normal bins packed as described above */
  mchunkptr bins[NBINS * 2 - 2];
 
  ...
  /*other member*/
  ...
}; 

每个bins链表在bins数组中存储的是一个fd和bk成员

用户free掉的内存并不是都会马上归还给系统,ptmalloc会统一管理heap和mmap中的free掉的chunk。当用户进行下一次分配请求时,ptmalloc会首先试图在free掉的chunk中挑选一块给用户。128个bin,并使用一个数组来存储这些bin,bin 1为unsorted bin,bin 2-63为small bin,bin 64-126为large bin,同时还有一个fastbin数组(大小根据size字段)

fastbin

后进先出
只使用fd成员,是个单链表结构
不对P位操作,不会主动合并,某些特定情况会合并
fastbinY位管理fastbin的数组,每个成员分别管理不同大小的链表,且均指向当前链表的尾节点
malloc时先到fastbin中寻找是否有合适的free的chunk

fastbin_attack

fastbin中被free的堆是用单链表来连接的,只有fd,并且如果free后会进入fastbin的chunk就算被free后它的下一个物理相邻的chunk也不会把pre_inuse位变为0(0为前一个chunk被free了,1则仍在使用)

free到fastbin的检测:

1.chunk的lsmmap位不能为1
2.chunk的地址对齐
3.size大小满足fastbin的回收需求
4.链表头不能是该fakechunk
5.fake的(物理相邻上)对应形式上的next chunk的size不能小于2*SIZE_SZ,同时不能大于av->system

C语言的free ()函数不会自动将指针赋值为NULL

fastbin double free

1.被释放后物理相邻的下一个chunk的pre_inuse位不会被清空,所以free时候认为它仍然在使用中
2.对应fastbin 的chunk free时候仅仅验证了链表数组中直接指向的块,对后面的没有验证,所以连续free两次不行,但是free两次中间还有一个free其他的就可以成功

fastbin:当程序malloc时且该malloc大小是要去fastbin中挑选时,会选择新加入的拿来分配 即先进先出

思路:

1.free(chunk1) free(chunk2) free(chunk1) 第二次free时fd指向chunk2
2.malloc得到chunk1的userdata指针,此时chunk1与第二次free时一样
3.修改malloc出的chunk即修改了chunk1的userdata,但此时对应在链表中的chunk1修改fd等字段
4.寻找或构造fd字段指向的位置所对应的堆块,size段为合适大小使得最后malloc成功。(fd可为got区域区域 里面存储着函数开始的位置)
5.最后malloc两次,使得链表数组中存着fd的值。
6最后malloc(合适大小)使得分配成功(malloc中的_int_mallc会对分配位置对应的size来验证是否与当前fast链表数组位置所对应的size大小相同)
7.对最后分配成功的chunk进行修改(为got区域则可修改got对应的函数地址)
8.使对应函数运行达到运行函数甲实则运行乙的效果

CPU执行"call 标号"时,相当于进行:
push 下一个地址(返回地址)
jmp 函数地址

house of spirit

依旧是覆盖fd指针,当释放时得到的堆块为目标地址部分的fakechunk、

思路

1.找到各可控变量在栈中的位置(通过IDA看源代码或者gdb动态调试)
2.首先通过IDA查看栈或者通过长度尝试,然后利用printf自带的/x00 截断的特性来输出某个函数返回地址的值(字符串填满后不留/x00导致可能printf往后继续输出直到遇到/x00)
3.分配一个chunk,同时根据函数功能输入shellcode二进制编码同时修改原chunk的指针值(伪造chunk只是一部分该payload前部分还有shellcode的二进制编码
4.将chunk的地址值覆盖后使其指为伪造的chunk的userdata的地址
5.然后free被覆盖的chunk的地址值,再次分配能修改分配的chunk的userdata内容,由于此次chunk在栈上,内容可取覆盖返回地址,该覆盖内容为shellcode地址

alloc to stack

通过某些手段修改 fastbin链表中的chunk的fd的值为我们想要在栈上控制的区域的地址,并先提前在该区域构造好合适的fakechunk(其实就是这个fakechunk的size段的值为malloc分配大小对应),从而控制栈中的一些数据

Arbitrary Alloc

与alloc to stack相似,但微微的区别是它对应的fd的值不再局限于栈内,可以是任意的内存地址(如函数)

核心思想:利用unsortedbin泄露libc基地址,覆盖_malloc_hook got表中地址

思路

1.分配五个chunk最后一个为0x80作为free到unsortbin中使用。2.首先free第二个和第三个chunk时,free第二个和第三chunk。利用重写第一个chunk时溢出覆盖到第三个chunk的fd的值(修改为第五个chunk的地址)同时利用重写第四个chunk溢出覆盖到第五个chunk的size值为合适的值
3.随后重新申请两次chunk,则此时第二个chunk指针为原第三个chunk的地址,第三个chunk的指针为第五个chunk的地址
4.再次利用重写第四个chunk溢出覆盖到第五个chunk的size值为0x91使得满足free时到unsortbin中,然后再申请一个chunk(使得该第五个chunk满足不与topchunk相邻同时不属于fastbin中从而free时到unsortbin)然后free第五个chunk,进入到unsortbin中。
5.因为此时第三个chunk指针也是第五个chunk的地址,利用打印函数将此时第五个chunk的fd处unsortbin的地址打印出来
6,计算libc基址,同时再申请合适的可以回收到fastbin大小的chunk。此时unsortbin中chunk分裂一部分可使用,一部分仍然在unsortbin中只是size大小变了
7.再次free该第五个chunk指针对应的chunk,利用重写第三个chunk时实则重写第五个chunk的特性继续溢出覆盖第五个chunk的fd值为需要控制的可满足的fakechunk的内存区域。
8.两次申请,第二次申请得到某内存区域的地址
9.重写第二次申请得到的第七个chunk使得重写内存区域(_malloc_hook)的值为system的地址(system地址根据基址和libc.symbol来算)
9.调用malloc函数即可getshell

smallbin

1.当malloc的请求fastbin中不满足,会去small bin中寻找
2.双向链表
3.先进先出
4.当满足small bin的chunk被free后,优先放到unsortedbin,只有在一定情况才会放到smallbin中
5.某chunk free时发现物理相邻的chunk为free时,会合并再放入中

unsortbin

1.当大小不属于fast bin的堆块被释放时,并且不与topchunk相邻首先会被放入unsorted bin中
2.unsorted bin为一个双向循环链表,对chunk的大小没有限制
3.当fastbin,smallbin中的chunk都不能满足用户请求chunk大小时,堆管理器就会使用unsorted bin。它会对堆中碎片进行合并
4.遍历顺序FLFO(后入后出),插入时候插到unsortedbin头部,取出从链尾取出,使用bk指针遍历
5.free一个不属于fsat bin的chunk,并且该chunk不和topchunk紧靠,该chunk就会首先放到unsorted bin中

unsortedbin attack

控制unsortedbin chunk队头的bk指针,当malloc时,实现队头bk对应的fakechunk的fd段被修改为bin元素的地址。

在这里插入图片描述

思路

1.题目某个函数要求某个变量大于某个值时,即可getshell。根据此变量作为fakechunk的fd字段弄出对应的fakechunk的地址。
2.创建三个chunk,第一个chunk用于溢出覆盖第二个chunk,第二个chunk用于free到unsortedbin中,第三个chunk用于隔绝第二个chunk和topchunk使得free时得以进入unsortedbin
3.利用重写第一个chunk时溢出覆盖第二个chunk的fd和bk值(fd随便,bk为之前fakechunk的地址),然后free第二个chunk
4.根据输入调用某个函数

unsortbin的unlink
free

可以这样简单理解,调用free函数会使用到unlink()

free函数
{
_int_free()
{
unlink()
}
}

unlink原理

free某个堆的时候,会检查这个堆的前一个堆块是否处于free状态(此时是物理相邻的,就是挨着的)。如果是,这个堆块会将相邻的那个堆块根据fd 和 bk 中从对于的链表卸下,此时按照fd bk的先后顺序从前往后开始修改所在chunk的fd和bk(仅仅需要fd和bk就可以完成unlink流程),并且与待free堆块合并再插入相应的链表 ,(前一个或后一个堆块只要是满足能识别为已经freechunk的都会)

chunk状态检查
缓冲区

缓冲区是内存空间的一部分。也就是说,在内存空间中预留了一定的存储空间,这些存储空间用来缓冲输入或输出的数据,这部分预留的空间就叫做缓冲区。缓冲区根据其对应的是输入设备还是输出设备,分为输入缓冲区和输出缓冲区。

没有进行setbuf操作,所以初次输入输出操作会申请缓冲区(初次输入操作在分配第一个堆前,初次输出操作在第一个堆后)

思路

1.创建真实chunk,在要free的chunk的前一个chunk的usedata处伪造fakechunk且伪造成释放状态
3.确定合适的fakechunk的fd和bk值使得可以对某些位置进行修改(如某指针数组,使得fd和bk为指针数组两个相邻的元素的地址最终会使得bk+8的位置中的元素变为fd)
在这里插入图片描述
2.伪造时通过栈溢出方式修改相邻堆块的pre_size和size(为了绕过检查,pre_size得修改为fakechunk的size大小同时size的p位设置为0且要大于0x80
3.free 该chunk,使得发生向前合并,并使得指针数组元素内容改变
4.根据输入使得对指针指向内容(指针位置在指针数组之前或刚开始可以修改指针数组的内容)进行修改覆盖指针数组内容为系列file.got[函数]。
5.再次根据输入使得对其他指针指向内容(此时已经是刚刚被覆盖内容过后的指针)进行修改为其他函数地址从而达到用函数甲却实际用函数乙(为puts_plt)的效果
6.然后调用某函数实际却实行乙函数(输出之前覆盖内容(file.got[函数]所指向的函数地址))
7.最后求libc基地址然后得到system函数地址再次根据输入使得对其他指针(该指针为file.got[atoi])指向内容修改为system函数地址
8.最后输入/bin/sh,程序运行进入到atoi即可getshell了

tcache(libc-2.26)

1.tcache每个元素对应链表最多可以有7个chunk,共64个链表。对应大小为0x10-0x208(8字节递增32位) 0x20-0x410(16字节递增)
2.当tcache满后free的chunk会放入fastbin与unsortedbin
3.malloc属于fastbin大小的chunk时,若tcahe仍有chunk,首先将tcache末尾的chunk取出
4.后进先出
5.

house of spirit

依旧是覆盖fd指针,当释放时得到的堆块为目标地址部分的fakechunk、

思路

1.找到各可控变量在栈中的位置(通过IDA看源代码或者gdb动态调试)
2.首先通过IDA查看栈或者通过长度尝试,然后利用printf自带的/x00 截断的特性来输出某个函数返回地址的值(字符串填满后不留/x00导致可能printf往后继续输出直到遇到/x00)
3.分配一个chunk,同时根据函数功能输入shellcode二进制编码同时修改原chunk的指针值(伪造chunk只是一部分该payload前部分还有shellcode的二进制编码
4.将chunk的地址值覆盖后使其指为伪造的chunk的userdata的地址
5.然后free被覆盖的chunk的地址值,再次分配能修改分配的chunk的userdata内容,由于此次chunk在栈上,内容可取覆盖返回地址,该覆盖内容为shellcode地址

tcache attack poisoning

chunk free到tcache后覆盖修改free后的chunk的fd值,再次malloc合适的值使其该freechunk恢复

tcache attack dup

没有检查chunk是否free,可以对同一个chunk多次free

思路

总结:free溢出到unsortedbin中从而获得libc基地址,覆盖fd为_free_hook的地址,malloc即可修改_free_hook的值为shellcode函数

malloc时候,先改变tcache后改变得到的chunk

1.free两次同一个chunk指针再打印内容可计算出该chunk的usedata地址,然后再malloc两次复原tcache
2.申请多个chunk,内容均为p64(0)+0x91,free最后一个chunk两次,然后malloc第一次内容为某个fakechunk满足size部位0x91的地址。随后再次malloc内容随意,再次malloc,内容为某个size为0x51的chunk地址,此时得到了size部位为0x91的fakechunk且该fakechunk的fd是刚刚malloc时的内容(tcache不会对fd对应的chunksize作检查,也就是说修改fd对应的chunk的size即使与当前该链表的szie不同也不会影响)
3.free 该size 为0x91的fake chunk八次,使得进入unsortedbin,此时该fake chunk的fd和bk被修改为unsortbin的地址,打印该fake chunk的内容,然后计算出libc基地址,随后计算出_free_hook的地址和getshell函数的地址
4.然后再次malloc此时出来的的是之前fakechunk的fd位置的chunk,内容为随意,然后free该chunk两次,再次malloc此时内容为_free_hook的地址,然后再次malloc,内容随意,再次malloc此时内容为getshell的函数地址且得到的是以_free_hook地址为userdata地址的chunk。即修改了_free_hook的值为getshell的函数地址
5.最后根据输入调用free函数

tcache attack house of spirit (free)

1.fake chunk size在tcache的范围中,且ISMMAP位不为1
2.fake chunk的地址对齐
3.无需构造next chunk的size
4.不用考虑连续free多次这个问题,因为free到链表中时不会检查

free到一个构造的fake chunk地址,然后再malloc即可控制该地址

伪造tcache机制的tcache_perthread_struct结构体

原因:泄露libc基地址时,我们有时候需要将tcache 填满才能把free的chunk放入unsortedbin中,才能进行地址泄露。但有时会对malloc和free操作次数限制导致无法填满,这时可以通过修该tcache_perthread_struct结构体中的count数组使得造成tcache已满的假像,从而free时会进入unsortedbin进而泄露libc基地址

tcache_perthread_struct结构体也是堆分配的
在这里插入图片描述
然后查看该地址内容,前十六个字节为chunk的pre_size段和size段 (可见size为291,所以第一个malloc的chunk与该结构体chunk头地址相差290)

随后时64个char类型的数组所占四行
随后对应fd链表指针共64个,对应free的chunk大小从0x20到0x410(以0x10递增)
在这里插入图片描述

思路

1.malloc一个chunk,然后free两次最后打印(存在use after free),可得该chunk地址
2.然后malloc一个chunk,fd对应的内容部分为之前得到的地址-tcache_perthread_struct结构体堆的size的大小(即tcache_perthread_struct地址)此时链表中为该chunkusedata地址->tcache_perthread_struct结构体usedata地址
3.然后malloc两次,第二次可得tcache_perthread_struct结构体usedata的地址,usedata此时对应count数组,此时写入usedata段count数组部分覆盖为大于所规定的链表最大个数值。
4.此时free 掉tcache_perthread_struct结构体的chunk,该chunk会被放入unsortedbin中,随后打印该chunk所得地址减去unsortedbin偏移可得libc基地址
5.构造one_gadget,再次malloc 此时因为只有usortedbin存在free的chunk(内容构造为修改某链表地址对应部分为_malloc_hook地址),于是此时将unsortbin对应的chunk分割(类似top_chunk的分割)剩余的部分依然为unsortedbin所管理.如图所示,
在这里插入图片描述
6.再次malloc,对应的size符合之前覆盖的链表所对应的chunk大小,此时可得到malloc_hook地址为usedata地址的chunk,修改内容为one_gadget的地址
7.再次malloc就会getshell

mmap

当用户请求堆大于128KB 并且没有任何arena有足够空间,系统会执行mmap函数分配 ,该堆释放后同样不会给系统

多线程支持

所有线程共享堆

house of spirit

依旧是覆盖fd指针,当释放时得到的堆块为目标地址部分的fakechunk、

思路

1.找到各可控变量在栈中的位置(通过IDA看源代码或者gdb动态调试)
2.首先通过IDA查看栈或者通过长度尝试,然后利用printf自带的/x00 截断的特性来输出某个函数返回地址的值(字符串填满后不留/x00导致可能printf往后继续输出直到遇到/x00)
3.分配一个chunk,同时根据函数功能输入shellcode二进制编码同时修改原chunk的指针值(伪造chunk只是一部分该payload前部分还有shellcode的二进制编码
4.将chunk的地址值覆盖后使其指为伪造的chunk的userdata的地址
5.然后free被覆盖的chunk的地址值,再次分配能修改分配的chunk的userdata内容,由于此次chunk在栈上,内容可取覆盖返回地址,该覆盖内容为shellcode地址

ctfd-pwn是一个非常受欢迎的CTF(Capture The Flag)比赛中的一个赛题类型,它主要涉及二进制漏洞的利用和系统安全的挑战。 在ctfd-pwn赛题的收集过程中,通常需要考虑以下几个方面: 1. 题目类型:ctfd-pwn赛题可以包含多种类型的漏洞,例如缓冲区溢出、格式化字符串漏洞、整数溢出等。在收集赛题时需要确保涵盖各种漏洞类型,增加题目的多样性和挑战性。 2. 难度级别:赛题的难度级别应该根据参赛者的水平来确定。可以设置多个难度级别的赛题,包括初级、中级和高级,以便参赛者可以逐步提高自己的技能。 3. 原创性:收集ctfd-pwn赛题时应尽量保持赛题的原创性,避免过多的抄袭或重复的赛题。这有助于增加参赛者的学习价值,同时也能提高比赛的公平性。 4. 实用性:收集的赛题应该具有实际应用的意义,能够模拟真实的漏洞和攻击场景。这样可以帮助参赛者更好地理解和掌握系统安全的基本原理。 5. 文档和解答:为每个收集的赛题准备详细的文档和解答是很有必要的。这些文档包括赛题的描述、利用漏洞的步骤和参考资源等,可以帮助参赛者更好地理解赛题和解题思路。 6. 持续更新:CTF比赛的赛题应该定期进行更新和维护,以适应不断变化的网络安全环境。同时也要根据参赛者的反馈和需求,不断收集新的赛题,提供更好的比赛体验。 综上所述,ctfd-pwn赛题的收集需要考虑赛题类型、难度级别、原创性、实用性、文档和解答的准备,以及持续更新的需求。这样才能提供一个富有挑战性和教育性的CTF比赛平台。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

看星猩的柴狗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值