Protostar二进制靶场堆溢出题目原理及基础解析
字数 1503 2025-08-29 08:30:31

堆溢出漏洞原理与利用技术详解

一、堆基础概念

堆是动态内存分配的区域,程序在运行时用来分配内存。与栈不同,堆具有以下特点:

  • 使用如malloccallocrealloc等函数动态分配内存
  • 使用free函数释放不再需要的内存
  • 大小不固定,可以动态增长

堆内存分配示例:

char *buffer = (char *)malloc(64);  // 分配64字节堆内存
free(buffer);                      // 释放内存

二、堆溢出漏洞原理

1. 基本堆溢出

漏洞通常发生在不安全的字符串操作函数如strcpy处:

  • strcpy不会检查目标缓冲区大小
  • 当输入超过目标缓冲区大小时会导致缓冲区溢出
  • 可能覆盖关键数据结构如函数指针

利用步骤:

  1. 确定目标缓冲区大小
  2. 构造超出缓冲区大小的输入
  3. 覆盖关键数据(如函数指针)
  4. 控制程序执行流

2. Use-After-Free (UAF)漏洞

定义:程序释放了一块内存后再次错误地使用这块内存的情况。

发生条件

  1. 内存被释放(通过free函数)
  2. 释放后程序仍尝试访问该内存
  3. 内存可能被重新分配给其他用途

危害

  • 可能导致程序行为异常
  • 可能造成数据损坏或信息泄露
  • 可能允许执行任意代码

3. Fastbins机制

在glibc的ptmalloc分配器中:

  • 小于64字节的块使用Fastbins管理
  • Fastbins是单向链表,不同于常规双向链表
  • 忽略prev_sizebksize
  • 分配和释放速度更快但安全性较低

三、堆管理数据结构

malloc_chunk结构

在malloc.c中定义的内存块结构:

chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |             Size of previous chunk, if unallocated (P clear)  |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |             Size of chunk, in bytes                     |A|M|P|
  mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |             User data starts here...                          .
        .                                                               .
        .             (malloc_usable_size() bytes)                      .
        .                                                               |
nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |             (size of chunk, but used for application data)    |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |             Size of next chunk, in bytes                |A|M|P|
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

关键字段:

  • prev_size: 前一个块的大小(如果前一个块空闲)
  • size: 当前块大小,包含标志位
  • A: NON_MAIN_ARENA标志
  • M: IS_MMAPPED标志
  • P: PREV_INUSE标志

空闲块管理

空闲块使用双向链表管理,包含:

  • fd(forward pointer): 指向下一个空闲块
  • bk(backward pointer): 指向前一个空闲块

四、unlink操作原理

unlink是从双向链表中移除空闲块的操作:

#define unlink(P, BK, FD) {            
    FD = P->fd;                              
    BK = P->bk;                              
    FD->bk = BK;                             
    BK->fd = FD;                             
}

unlink攻击条件

  1. 能控制P->fdP->bk的值
  2. (P->fd)+12(P->bk)+8必须是可写内存

攻击效果

  • 可以覆盖任意内存
  • 通常用于覆盖GOT表条目

五、实战漏洞利用

1. 基础堆溢出利用

步骤

  1. 确定缓冲区大小和偏移
  2. 构造溢出payload覆盖函数指针
  3. 将函数指针指向目标地址(如winner函数)
  4. 触发函数调用

示例

echo -e "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x74\x97\x04\x08" > payload
./vulnerable_program $(cat payload)

2. UAF漏洞利用

步骤

  1. 分配并释放目标内存
  2. 重新分配相同大小内存并填充控制数据
  3. 利用残留指针访问被释放内存
  4. 修改关键数据(如认证标志)

示例

auth AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
reset
service BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
login

3. unlink攻击利用

步骤

  1. 构造伪造的堆块结构
  2. 设置fdbk指向目标地址
  3. 触发unlink操作
  4. 覆盖GOT表条目

关键点

  • 使用负数size(如0xfffffffc
  • 精确计算偏移量
  • 选择合适的目标地址(通常是GOT表)

六、防护措施

  1. 使用安全函数替代不安全函数:

    • strncpy替代strcpy
    • snprintf替代sprintf
  2. 启用堆保护机制:

    • GLIBC_SECURE_MALLOC
    • 堆cookie/canary
  3. 及时清空指针:

    • 释放内存后将指针置为NULL
  4. 使用现代内存分配器:

    • jemalloc
    • tcmalloc
  5. 启用ASLR和DEP保护

七、调试技巧

  1. GDB常用命令:

    break *0x080485a1       # 设置断点
    x/32wx 0x0804a000       # 查看堆内存
    info proc mappings       # 查看内存映射
    
  2. 自动化调试:

    define hook-stop
    x/32wx 0x0804a000
    end
    
  3. 查看堆块信息:

    p *(struct malloc_chunk*)0x0804a008
    
  4. 跟踪函数调用:

    catch syscall exit
    

通过深入理解堆管理机制和常见漏洞模式,可以更有效地发现和利用堆相关漏洞,同时也能更好地防护此类安全问题。

堆溢出漏洞原理与利用技术详解 一、堆基础概念 堆是动态内存分配的区域,程序在运行时用来分配内存。与栈不同,堆具有以下特点: 使用如 malloc 、 calloc 、 realloc 等函数动态分配内存 使用 free 函数释放不再需要的内存 大小不固定,可以动态增长 堆内存分配示例: 二、堆溢出漏洞原理 1. 基本堆溢出 漏洞通常发生在不安全的字符串操作函数如 strcpy 处: strcpy 不会检查目标缓冲区大小 当输入超过目标缓冲区大小时会导致缓冲区溢出 可能覆盖关键数据结构如函数指针 利用步骤: 确定目标缓冲区大小 构造超出缓冲区大小的输入 覆盖关键数据(如函数指针) 控制程序执行流 2. Use-After-Free (UAF)漏洞 定义 :程序释放了一块内存后再次错误地使用这块内存的情况。 发生条件 : 内存被释放(通过 free 函数) 释放后程序仍尝试访问该内存 内存可能被重新分配给其他用途 危害 : 可能导致程序行为异常 可能造成数据损坏或信息泄露 可能允许执行任意代码 3. Fastbins机制 在glibc的ptmalloc分配器中: 小于64字节的块使用Fastbins管理 Fastbins是单向链表,不同于常规双向链表 忽略 prev_size 、 bk 和 size 位 分配和释放速度更快但安全性较低 三、堆管理数据结构 malloc_ chunk结构 在malloc.c中定义的内存块结构: 关键字段: prev_size : 前一个块的大小(如果前一个块空闲) size : 当前块大小,包含标志位 A : NON_ MAIN_ ARENA标志 M : IS_ MMAPPED标志 P : PREV_ INUSE标志 空闲块管理 空闲块使用双向链表管理,包含: fd (forward pointer): 指向下一个空闲块 bk (backward pointer): 指向前一个空闲块 四、unlink操作原理 unlink是从双向链表中移除空闲块的操作: unlink攻击条件 : 能控制 P->fd 和 P->bk 的值 (P->fd)+12 和 (P->bk)+8 必须是可写内存 攻击效果 : 可以覆盖任意内存 通常用于覆盖GOT表条目 五、实战漏洞利用 1. 基础堆溢出利用 步骤 : 确定缓冲区大小和偏移 构造溢出payload覆盖函数指针 将函数指针指向目标地址(如 winner 函数) 触发函数调用 示例 : 2. UAF漏洞利用 步骤 : 分配并释放目标内存 重新分配相同大小内存并填充控制数据 利用残留指针访问被释放内存 修改关键数据(如认证标志) 示例 : 3. unlink攻击利用 步骤 : 构造伪造的堆块结构 设置 fd 和 bk 指向目标地址 触发unlink操作 覆盖GOT表条目 关键点 : 使用负数size(如 0xfffffffc ) 精确计算偏移量 选择合适的目标地址(通常是GOT表) 六、防护措施 使用安全函数替代不安全函数: strncpy 替代 strcpy snprintf 替代 sprintf 启用堆保护机制: GLIBC_SECURE_MALLOC 堆cookie/canary 及时清空指针: 释放内存后将指针置为NULL 使用现代内存分配器: jemalloc tcmalloc 启用ASLR和DEP保护 七、调试技巧 GDB常用命令: 自动化调试: 查看堆块信息: 跟踪函数调用: 通过深入理解堆管理机制和常见漏洞模式,可以更有效地发现和利用堆相关漏洞,同时也能更好地防护此类安全问题。