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/gather/enum_services.rb
Views: 11655
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Post6include Msf::Post::Windows::Services78def initialize(info = {})9super(10update_info(11info,12'Name' => 'Windows Gather Service Info Enumeration',13'Description' => %q{14This module will query the system for services and display name and15configuration info for each returned service. It allows you to16optionally search the credentials, path, or start type for a string17and only return the results that match. These query operations are18cumulative and if no query strings are specified, it just returns all19services. NOTE: If the script hangs, windows firewall is most likely20on and you did not migrate to a safe process (explorer.exe for21example).22},23'License' => MSF_LICENSE,24'Author' => ['Keith Faber', 'Kx499'],25'Platform' => ['win'],26'SessionTypes' => %w[meterpreter powershell shell],27'Notes' => {28'Stability' => [CRASH_SAFE],29'Reliability' => [],30'SideEffects' => []31}32)33)34register_options([35OptString.new('CRED', [ false, 'String to search credentials for' ]),36OptString.new('PATH', [ false, 'String to search path for' ]),37OptEnum.new('TYPE', [true, 'Service startup option', 'All', ['All', 'Auto', 'Manual', 'Disabled' ]])38])39end4041def run42credential_count = {}43qcred = datastore['CRED'] || nil44qpath = datastore['PATH'] || nil4546if datastore['TYPE'] == 'All'47qtype = nil48else49qtype = datastore['TYPE'].downcase50print_status("Start Type Filter: #{qtype}")51end5253if qcred54qcred = qcred.downcase55print_status("Credential Filter: #{qcred}")56end5758if qpath59qpath = qpath.downcase60print_status("Executable Path Filter: #{qpath}")61end6263results_table = Rex::Text::Table.new(64'Header' => 'Services',65'Indent' => 1,66'SortIndex' => 0,67'Columns' => ['Name', 'Credentials', 'Command', 'Startup']68)6970print_status('Listing Service Info for matching services, please wait...')7172services = service_list7374vprint_status("Found #{services.length} Windows services")7576services.each do |srv|77srv_conf = {}7879# make sure we got a service name80if srv[:name].blank?81print_error("Problem retrieving service information - no name found for service: #{srv}")82next83end8485begin86srv_conf = service_info(srv[:name])8788next unless srv_conf && srv_conf[:startname] && srv_conf[:path]8990# filter service based on provided filters91next if qcred && !srv_conf[:startname].downcase.include?(qcred)92next if qpath && !srv_conf[:path].downcase.include?(qpath)9394# There may not be a 'Startup', need to check nil95start_type = srv_conf[:starttype]96start_type = start_type.blank? ? '' : START_TYPE[start_type].to_s9798next if qtype && !start_type.downcase.include?(qtype)99100# count the occurance of specific credentials services are running as101service_cred = srv_conf[:startname].upcase102unless service_cred.empty?103if credential_count.key?(service_cred)104credential_count[service_cred] += 1105else106credential_count[service_cred] = 1107# let the user know a new service account has been detected for possible lateral108# movement opportunities109print_good("New service credential detected: #{srv[:name]} is running as '#{srv_conf[:startname]}'")110end111end112113results_table << [114srv[:name],115srv_conf[:startname],116start_type,117srv_conf[:path]118]119rescue RuntimeError => e120print_error("An error occurred enumerating service: #{srv[:name]}: #{e}")121end122end123124print_status("Found #{results_table.rows.size} Windows services matching filters")125126return if results_table.rows.empty?127128print_line("\n#{results_table}")129130p = store_loot('windows.services', 'text/plain', session, results_table.to_s, 'windows_services.txt', 'Windows Services')131print_good("Loot file stored in: #{p}")132end133end134135136