首页 > 其他分享 >pwn堆的结构及堆溢出理解

pwn堆的结构及堆溢出理解

时间:2024-05-30 09:55:46浏览次数:29  
标签:bin chunk free 内存 pwn 及堆 溢出 size

堆其实就是程序虚拟地址空间的一块连续的线性区域,它由低地址向高地址方向增长(栈由高地址向低地址增长)。我们一般称管理堆的那部分程序为堆管理器堆是分配给程序的内存空间 与栈不同,堆内存可以动态分配。这意味着程序可以在需要的时候从堆段中请求释放内存。此外,此内存是全局的,即可以从程序中的任何地方访问和修改它,并且不会局限于分配它的函数。这是通过使用指针来引用动态分配的内存来完成的,与使用局部变量(在栈上)相比,这反过来会导致性能的小幅下降。

请求与释放内存主要是通malooc与free函数实现

堆在程序中的位如图所示

image-20240301171015458

堆和栈的对比如下表所示

申请 程序在运行过程中动态分配,由程序控制申请 程序运行前分配
释放 不能自动释放,由程序控制释放 自动释放
特点 地址由低 => 高 地址由高=>低
内存分配 非线性,无序 线性,有序-----------

如果频繁的呼叫syscall则程序会频繁的在kernal与user之间切换,会造成效率的降低

因此library会提前申请一大块区域并进行各种操作

image-20240304141702939

本篇文章主要是写关于glibc ptmalloc

pwndbg里面的parseheap会出现heap构造

image-20240304142131266

经过free

image-20240304142214582

ptmalloc 请求0x20但是因为存在pre size与size会占用0x10的空间

所以是0x30

同时如果free掉这段chunk则bin(堆管理器)会连接free chunk

image-20240304143244539

在ptmalloc管理下

image-20240304143536878

chunk分为

allocated chunk已经分配的chunk freechunk 已经释放的chunk topchunk剩余的chunk

chunk的结构如图所示

image-20240302152702864

pre size 用来储存前一个chunk的大小信息,同时不会存在两个相邻的空闲chunk

size 记录了当前chunk的大小,chunk的大小都是8字节对齐,所以size的低3位都是0,不用来表示地址。为了充分利用内存空间,这三位被当作了标志位A M P

A 记录当前chunk是否属于主线程 1不属于 0属于

M 记录是否当前chunk由mmap分配 1是 0否

P 记录前一个chunk是否被分配 1是 0否

chunk合并

当size后三位P显示前一个chunk是 0未被分配,鉴于节省空间考虑将会合并两个chunk

这也就是为什么没有两个相邻的空闲chunk

bin 堆管理器

在主线程中arana中存在fastbiny与bins

image-20240307140019182

fast bin

image-20240302163635738

image-20240304152631938

小于0x80的free bin 都会存在于fast bin

fast bin共有七个0x20-0x80

free这类chunk时不会清除下一块chunk的P的值 即下一块chunk依旧会P=1

同时在fast bin中会使用到fd即指向下一个free chunk而bk是不会被用到的

image-20240304153354465

如上图 连接起来所有的free chunk fd指向chunk header

image-20240304160503314

image-20240304160528447

small bin

存在fd与bk

image-20240302164024528

  • Small Bins用于存储较小尺寸的空闲chunk,这些chunk按照特定的大小分类存放在多个链表中。每个链表中的chunk大小相近,这样可以快速地找到与请求分配内存大小匹配或稍大的chunk。

small bin与fast bin相比较fast bin中的chunk通常更小以便更快速的完成任务

malloc首先检查Fast Bins来满足小内存分配请求,若Fast Bins中无合适chunk,则转而去Small Bins或其他bins中查找或分配新的内存空间。

large bin

image-20240302164048283

large bin是相对于small bin来说的

Large Bins用于存储那些超出Small Bins管理范围的较大尺寸的空闲chunk。

储存较大的chunk即大于504byte的free chunk

当程序分配内存时会首先向large bin检查

如果Large Bins也无法满足请求,malloc可能会尝试从Top Chunk(堆顶chunk)分割内存,或者直接向操作系统申请更多的内存空间。

unsorted bin

存在fd与bk

image-20240302163854724

又被成为垃圾桶回收还未来的及进入分类的chunk

  • Unsorted Bin不按照chunk大小进行排序,因此被称为“未排序”。
  • 刚释放的chunk会直接插入到unsorted bin的链表头部。
  • 在新的内存分配请求发生时,malloc首先检查unsorted bin是否有合适的chunk可用,因为这里可能存放了最近刚刚释放的大块内存。
  • 一段时间后(例如,在下一次malloc或realloc操作),unsorted bin中的chunk会被正确地转移到相应的small bin、large bin或其他适当的区域,以确保内存管理的有序性和效率。

使用unsorted bin可以快速响应和利用最近释放的大块内存,同时避免了立即进行复杂的数据结构调整。

tcache

单项链表同fast

为了更高效率产生的

image-20240304161012907

tcache在libc 2.6出现

在libc2.23时free chunk存入fast bin

image-20240304162303857

fd指向上一个chunk的fd bk存入key用作安全检查

而在fast bin中fd指向上一个chunk的chunk头 bk内容是不变的

image-20240304163200613

cnt表示存在几个entry

image-20240304163826353

heap info

image-20240304144028272

image-20240304144103875

每种chunk的结构大同小异chunk结构分为header与data主要的差异存在于header

结构如下

image-20240304144544311

pre size 用来储存前一个chunk的大小信息,同时不会存在两个相邻的空闲chunk

size 记录了当前chunk的大小,chunk的大小都是8字节对齐,所以size的低3位都是0,不用来表示地址。为了充分利用内存空间,这三位被当作了标志位A M P

A 记录当前chunk是否属于主线程 1不属于 0属于

M 记录是否当前chunk由mmap分配 1是 0否

P 记录前一个chunk是否被分配 1是 0否

1表示上图chunk正在被分配

p表示上一个chunk

image-20240304145351487

image-20240304145517720

fd指向下一块 free chunk

bk指向上一块free chunk

image-20240304151833653

TOP CHUNK

存在于heap的头部 代表剩余空间

在他的下方并没有任何东西

image-20240304152319559

堆溢出攻击

堆溢出与栈溢出类似(堆溢出是一种特殊的缓冲区溢出。同时栈溢出与bss溢出也属于)

在向堆块chunk写入数据时超过了堆块自身的限度,并覆盖到物理相邻的高地址的下一个堆块。

因此发生堆溢出的主要前提是

  • 向程序内写入数据
  • 写入的数据大小未 能得到控制导致溢出

但是在进行堆溢出是并没有像栈溢出那样的返回地址可以控制,因此我们怎么来进行堆溢出攻击获取flag呢

通过堆溢出我们可以覆盖chunk的内容

chunk

  • pre size
  • size
  • data

因此利用某些堆机制我们可以实现任意地址的写入以及修改堆快内容控制程序执行流

如下程序

#include <stdio.h>

int main(void) 
{
  char *chunk;
  chunk=malloc(24);
  puts("Get input:");
  gets(chunk);
  return 0;
}

可以看到申请了24大小的chunk

0x602000: 0x0000000000000000  0x0000000000000021 <===chunk
0x602010: 0x0000000000000000  0x0000000000000000
0x602020: 0x0000000000000000  0x0000000000020fe1 <===top chunk
0x602030: 0x0000000000000000  0x0000000000000000 
0x602040: 0x0000000000000000  0x0000000000000000


那我们究竟可以溢出多少字节才能达到目的呢

首先

pre size与size 这个长度一般是字长的 2 倍,比如 32 位系统是 8 个字节,64 位系统是 16 个字节。

因此

chunk_head.size = 用户区域大小 + 2 * 字长

对于写入是从data块开始的

下面是向chunk中写入0x100字节的A所呈现的heap结构

0x602000:   0x0000000000000000  0x0000000000000021 <===chunk
0x602010:   0x4141414141414141  0x4141414141414141
0x602020:   0x4141414141414141  0x4141414141414141 <===top chunk(已被溢出)
0x602030:   0x4141414141414141  0x4141414141414141
0x602040:   0x4141414141414141  0x4141414141414141

因此我们可以通过上述方式进行攻击

但有以下几点需要注意

一般情况下我们是通过malloc分配堆内存的,但在某些情况下是通过relloc实现的

#include <stdio.h>

int main(void) 
{
  char *chunk,*chunk1;
  chunk=malloc(16);
  chunk1=realloc(chunk,32);
  return 0;
}

realloc

当新分配的chunk小于pre chunk时

如果新size与原来的size之间不足以插入另一个最小chunk则保持不变

如果差距过大则分割这个chunk 并对另一部分chunk进行free

当新分配的chunk大于pre chunk时

如果 chunk 与 top chunk 相邻,直接扩展这个 chunk 到新 size 大小

如果 chunk 与 top chunk 不相邻,相当于free这一个小chunk并且malloc一个大的chunk

危险函数

  • 输入
    • gets,直接读取一行,忽略 '\x00'
    • scanf
    • vscanf
  • 输出
    • sprintf
  • 字符串
    • strcpy,字符串复制,遇到 '\x00' 停止
    • strcat,字符串拼接,遇到 '\x00' 停止
    • bcopy

标签:bin,chunk,free,内存,pwn,及堆,溢出,size
From: https://www.cnblogs.com/j1nxi/p/18061969

相关文章

  • pwn长征路
    只是私人学习记录的备份,不建议参考学习模板frompwnimport*context(os='linux',arch='amd64',log_level='debug')#context.update(arch='i386',os='linux',log_level='debug')#context(os='linux',arch='......
  • pwn常用工具快捷键学习
    vim普通模式G(普通模式)来的文本最下方g+g(普通模式下)回到文本的开头f+目标单词的首字母(find普通模式)移动到目标单词d(delete)删除当前行u(undo)撤销文本模式I从当前行开头进行输入A当前行文末输入idaF7单步执行,遇到call......
  • pwn题libc换源
    资料:pwn题更换libc版本(z1r0.top)​pwn技术分享——使用patchelf和glibc-all-in-one替换程序依赖的libc文件_哔哩哔哩_bilibili下载libc./download2.23-0ubuntu11.2_amd64#glibc为你想要下载glibc的名字./download_oldlibc#list没有,可以使用./downl......
  • 栈溢出漏洞利用,详解基本ROP,构造rop链条实现攻击(pwn入门)
    写在前面:随着NX(Non-eXecutable)保护的开启,传统的直接向栈或者堆上直接注入代码的方式难以继续发挥效果,由此攻击者们也提出来相应的方法来绕过保护。目前被广泛使用的攻击手法是 返回导向编程 (ReturnOrientedProgramming),其主要思想是在 栈缓冲区溢出的基础上,利用......
  • BUUCTF pwn actf_2019_babystack
    先checksec看保护: ida看主程序:主要部分图片已经说了,由于最多只能往s中写入224字节,padding占据208字节,fakeebp是8字节,ret是8字节,便填满了,由于此处没有backdoor,于是想到栈迁移,在s上部署system("/bin/sh"),在leave_ret到s栈的地址,实行system("/bin/sh")思路分析: 1.先......
  • ctf-pwn 学习前知(1)
    学习pwn这个抽象到一定程度的东西,前期的坐牢是一定的,一个题目延申出的新知识也是超多的。所以写一个这个板块记录一下自己学习的东西,或许会有(2),(3)....checksec拿buuctf的test_your_nc为例子可以看到checksec后出现了很多东西Arch:amd64-64-little(程序架构信息,这是一个64位......
  • pwn练习
    [GFCTF2021]where_is_shellfrompwnimport*>>>elf=ELF("./shell")[*]'/home/za/ctf/pwn/nssctf/whereisshell/shell'Arch:amd64-64-littleRELRO:PartialRELROStack:NocanaryfoundNX:NXen......
  • pwn杂项之linux命令执行
    通常pwn题目,时常会考到对Linux命令的一些使用,比如当cat被禁用的时候,可以使用tac,或者别的命令代替......
  • Pwned
    Pwned⏲️ReleaseDate//2020-09-25✔️MD5//4fff941050062efd06bc63ac8e740132☠Root//414......
  • 【介绍下Pwn,什么是Pwn?】
    ......