CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/post/windows/gather/enum_services.rb
Views: 11655
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
class MetasploitModule < Msf::Post
7
include Msf::Post::Windows::Services
8
9
def initialize(info = {})
10
super(
11
update_info(
12
info,
13
'Name' => 'Windows Gather Service Info Enumeration',
14
'Description' => %q{
15
This module will query the system for services and display name and
16
configuration info for each returned service. It allows you to
17
optionally search the credentials, path, or start type for a string
18
and only return the results that match. These query operations are
19
cumulative and if no query strings are specified, it just returns all
20
services. NOTE: If the script hangs, windows firewall is most likely
21
on and you did not migrate to a safe process (explorer.exe for
22
example).
23
},
24
'License' => MSF_LICENSE,
25
'Author' => ['Keith Faber', 'Kx499'],
26
'Platform' => ['win'],
27
'SessionTypes' => %w[meterpreter powershell shell],
28
'Notes' => {
29
'Stability' => [CRASH_SAFE],
30
'Reliability' => [],
31
'SideEffects' => []
32
}
33
)
34
)
35
register_options([
36
OptString.new('CRED', [ false, 'String to search credentials for' ]),
37
OptString.new('PATH', [ false, 'String to search path for' ]),
38
OptEnum.new('TYPE', [true, 'Service startup option', 'All', ['All', 'Auto', 'Manual', 'Disabled' ]])
39
])
40
end
41
42
def run
43
credential_count = {}
44
qcred = datastore['CRED'] || nil
45
qpath = datastore['PATH'] || nil
46
47
if datastore['TYPE'] == 'All'
48
qtype = nil
49
else
50
qtype = datastore['TYPE'].downcase
51
print_status("Start Type Filter: #{qtype}")
52
end
53
54
if qcred
55
qcred = qcred.downcase
56
print_status("Credential Filter: #{qcred}")
57
end
58
59
if qpath
60
qpath = qpath.downcase
61
print_status("Executable Path Filter: #{qpath}")
62
end
63
64
results_table = Rex::Text::Table.new(
65
'Header' => 'Services',
66
'Indent' => 1,
67
'SortIndex' => 0,
68
'Columns' => ['Name', 'Credentials', 'Command', 'Startup']
69
)
70
71
print_status('Listing Service Info for matching services, please wait...')
72
73
services = service_list
74
75
vprint_status("Found #{services.length} Windows services")
76
77
services.each do |srv|
78
srv_conf = {}
79
80
# make sure we got a service name
81
if srv[:name].blank?
82
print_error("Problem retrieving service information - no name found for service: #{srv}")
83
next
84
end
85
86
begin
87
srv_conf = service_info(srv[:name])
88
89
next unless srv_conf && srv_conf[:startname] && srv_conf[:path]
90
91
# filter service based on provided filters
92
next if qcred && !srv_conf[:startname].downcase.include?(qcred)
93
next if qpath && !srv_conf[:path].downcase.include?(qpath)
94
95
# There may not be a 'Startup', need to check nil
96
start_type = srv_conf[:starttype]
97
start_type = start_type.blank? ? '' : START_TYPE[start_type].to_s
98
99
next if qtype && !start_type.downcase.include?(qtype)
100
101
# count the occurance of specific credentials services are running as
102
service_cred = srv_conf[:startname].upcase
103
unless service_cred.empty?
104
if credential_count.key?(service_cred)
105
credential_count[service_cred] += 1
106
else
107
credential_count[service_cred] = 1
108
# let the user know a new service account has been detected for possible lateral
109
# movement opportunities
110
print_good("New service credential detected: #{srv[:name]} is running as '#{srv_conf[:startname]}'")
111
end
112
end
113
114
results_table << [
115
srv[:name],
116
srv_conf[:startname],
117
start_type,
118
srv_conf[:path]
119
]
120
rescue RuntimeError => e
121
print_error("An error occurred enumerating service: #{srv[:name]}: #{e}")
122
end
123
end
124
125
print_status("Found #{results_table.rows.size} Windows services matching filters")
126
127
return if results_table.rows.empty?
128
129
print_line("\n#{results_table}")
130
131
p = store_loot('windows.services', 'text/plain', session, results_table.to_s, 'windows_services.txt', 'Windows Services')
132
print_good("Loot file stored in: #{p}")
133
end
134
end
135
136