Skip to content

Commit ed0b9b0

Browse files
committed
Land rapid7#6072, @hmoore-r7's lands Fix rapid7#6050 and moves RMI/JMX mixin namespace
2 parents 209fd78 + b9b488c commit ed0b9b0

File tree

41 files changed

+1340
-1212
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+1340
-1212
lines changed

lib/msf/core.rb

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,6 @@ module Msf
7575
# Kerberos Support
7676
require 'msf/kerberos/client'
7777

78-
# Java RMI Support
79-
require 'msf/java/rmi/util'
80-
require 'msf/java/rmi/client'
81-
8278
# Drivers
8379
require 'msf/core/exploit_driver'
8480

lib/msf/core/exploit/java.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
###
1515

1616
require 'msf/core'
17+
require 'msf/core/exploit/java/rmi/util'
18+
require 'msf/core/exploit/java/rmi/client'
1719

1820
module Msf
1921
module Exploit::Java
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
# -*- coding: binary -*-
2+
3+
require 'rex/java/serialization'
4+
5+
module Msf
6+
class Exploit
7+
class Remote
8+
module Java
9+
module Rmi
10+
module Builder
11+
# Builds a RMI header stream
12+
#
13+
# @param opts [Hash{Symbol => <String, Fixnum>}]
14+
# @option opts [String] :signature
15+
# @option opts [Fixnum] :version
16+
# @option opts [Fixnum] :protocol
17+
# @return [Rex::Proto::Rmi::Model::OutputHeader]
18+
def build_header(opts = {})
19+
signature = opts[:signature] || Rex::Proto::Rmi::Model::SIGNATURE
20+
version = opts[:version] || 2
21+
protocol = opts[:protocol] || Rex::Proto::Rmi::Model::STREAM_PROTOCOL
22+
23+
header = Rex::Proto::Rmi::Model::OutputHeader.new(
24+
signature: signature,
25+
version: version,
26+
protocol: protocol)
27+
28+
header
29+
end
30+
31+
# Builds a RMI call stream
32+
#
33+
# @param opts [Hash{Symbol => <Fixnum, Array>}]
34+
# @option opts [Fixnum] :message_id
35+
# @option opts [Fixnum] :object_number Random to identify the object.
36+
# @option opts [Fixnum] :uid_number Identifies the VM where the object was generated.
37+
# @option opts [Fixnum] :uid_time Time where the object was generated.
38+
# @option opts [Fixnum] :uid_count Identifies different instance of the same object generated from the same VM
39+
# at the same time.
40+
# @option opts [Fixnum] :operation On JDK 1.1 stub protocol the operation index in the interface. On JDK 1.2
41+
# it is -1.
42+
# @option opts [Fixnum] :hash On JDK 1.1 stub protocol the stub's interface hash. On JDK1.2 is a hash
43+
# representing the method to call.
44+
# @option opts [Array] :arguments
45+
# @return [Rex::Proto::Rmi::Model::Call]
46+
def build_call(opts = {})
47+
message_id = opts[:message_id] || Rex::Proto::Rmi::Model::CALL_MESSAGE
48+
object_number = opts[:object_number] || 0
49+
uid_number = opts[:uid_number] || 0
50+
uid_time = opts[:uid_time] || 0
51+
uid_count = opts[:uid_count] || 0
52+
operation = opts[:operation] || -1
53+
hash = opts[:hash] || 0
54+
arguments = opts[:arguments] || []
55+
56+
uid = Rex::Proto::Rmi::Model::UniqueIdentifier.new(
57+
number: uid_number,
58+
time: uid_time,
59+
count: uid_count
60+
)
61+
62+
call_data = Rex::Proto::Rmi::Model::CallData.new(
63+
object_number: object_number,
64+
uid: uid,
65+
operation: operation,
66+
hash: hash,
67+
arguments: arguments
68+
)
69+
70+
call = Rex::Proto::Rmi::Model::Call.new(
71+
message_id: message_id,
72+
call_data: call_data
73+
)
74+
75+
call
76+
end
77+
78+
# Builds a RMI dgc ack stream
79+
#
80+
# @param opts [Hash{Symbol => <Fixnum, String>}]
81+
# @option opts [Fixnum] :stream_id
82+
# @option opts [String] :unique_identifier
83+
# @return [Rex::Proto::Rmi::Model::DgcAck]
84+
def build_dgc_ack(opts = {})
85+
stream_id = opts[:stream_id] || Rex::Proto::Rmi::Model::DGC_ACK_MESSAGE
86+
unique_identifier = opts[:unique_identifier] || "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
87+
88+
dgc_ack = Rex::Proto::Rmi::Model::DgcAck.new(
89+
stream_id: stream_id,
90+
unique_identifier: unique_identifier
91+
)
92+
93+
dgc_ack
94+
end
95+
96+
end
97+
end
98+
end
99+
end
100+
end
101+
end
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
# -*- coding: binary -*-
2+
require 'rex/proto/rmi'
3+
require 'rex/java/serialization'
4+
require 'stringio'
5+
require 'msf/core/exploit/java/rmi/util'
6+
require 'msf/core/exploit/java/rmi/builder'
7+
require 'msf/core/exploit/java/rmi/client/registry'
8+
require 'msf/core/exploit/java/rmi/client/jmx'
9+
10+
module Msf
11+
class Exploit
12+
class Remote
13+
module Java
14+
module Rmi
15+
module Client
16+
17+
include Msf::Exploit::Remote::Java::Rmi::Util
18+
include Msf::Exploit::Remote::Java::Rmi::Builder
19+
include Msf::Exploit::Remote::Java::Rmi::Client::Registry
20+
include Msf::Exploit::Remote::Java::Rmi::Client::Jmx
21+
include Msf::Exploit::Remote::Tcp
22+
23+
def initialize(info = {})
24+
super
25+
26+
register_advanced_options(
27+
[
28+
OptInt.new('RmiReadLoopTimeout', [ true, 'Maximum number of seconds to wait for data between read iterations', 1])
29+
], Msf::Exploit::Remote::Java::Rmi::Client
30+
)
31+
end
32+
33+
# Returns the timeout to wait for data between read iterations
34+
#
35+
# @return [Fixnum]
36+
def read_loop_timeout
37+
datastore['RmiReadLoopTimeout'] || 1
38+
end
39+
40+
# Returns the target host
41+
#
42+
# @return [String]
43+
def rhost
44+
datastore['RHOST']
45+
end
46+
47+
# Returns the target port
48+
#
49+
# @return [Fixnum]
50+
def rport
51+
datastore['RPORT']
52+
end
53+
54+
# Returns the RMI server peer
55+
#
56+
# @return [String]
57+
def peer
58+
"#{rhost}:#{rport}"
59+
end
60+
61+
# Sends a RMI header stream
62+
#
63+
# @param opts [Hash]
64+
# @option opts [Rex::Socket::Tcp] :sock
65+
# @return [Fixnum] the number of bytes sent
66+
# @see Msf::Rmi::Client::Streams#build_header
67+
def send_header(opts = {})
68+
nsock = opts[:sock] || sock
69+
stream = build_header(opts)
70+
nsock.put(stream.encode + "\x00\x00\x00\x00\x00\x00")
71+
end
72+
73+
# Sends a RMI CALL stream
74+
#
75+
# @param opts [Hash]
76+
# @option opts [Rex::Socket::Tcp] :sock
77+
# @option opts [Rex::Proto::Rmi::Model::Call] :call
78+
# @return [Fixnum] the number of bytes sent
79+
# @see Msf::Rmi::Client::Streams#build_call
80+
def send_call(opts = {})
81+
nsock = opts[:sock] || sock
82+
call = opts[:call] || build_call(opts)
83+
nsock.put(call.encode)
84+
end
85+
86+
# Sends a RMI DGCACK stream
87+
#
88+
# @param opts [Hash]
89+
# @option opts [Rex::Socket::Tcp] :sock
90+
# @return [Fixnum] the number of bytes sent
91+
# @see Msf::Rmi::Client::Streams#build_dgc_ack
92+
def send_dgc_ack(opts = {})
93+
nsock = opts[:sock] || sock
94+
stream = build_dgc_ack(opts)
95+
nsock.put(stream.encode)
96+
end
97+
98+
# Reads the Protocol Ack
99+
#
100+
# @param opts [Hash]
101+
# @option opts [Rex::Socket::Tcp] :sock
102+
# @return [Rex::Proto::Rmi::Model::ProtocolAck] if success
103+
# @return [NilClass] otherwise
104+
# @see Rex::Proto::Rmi::Model::ProtocolAck.decode
105+
def recv_protocol_ack(opts = {})
106+
nsock = opts[:sock] || sock
107+
data = safe_get_once(nsock)
108+
begin
109+
ack = Rex::Proto::Rmi::Model::ProtocolAck.decode(StringIO.new(data))
110+
rescue Rex::Proto::Rmi::DecodeError
111+
return nil
112+
end
113+
114+
ack
115+
end
116+
117+
# Reads a ReturnData message and returns the java serialized stream
118+
# with the return data value.
119+
#
120+
# @param opts [Hash]
121+
# @option opts [Rex::Socket::Tcp] :sock
122+
# @return [Rex::Proto::Rmi::Model::ReturnValue] if success
123+
# @return [NilClass] otherwise
124+
# @see Rex::Proto::Rmi::Model::ReturnData.decode
125+
def recv_return(opts = {})
126+
nsock = opts[:sock] || sock
127+
data = safe_get_once(nsock)
128+
129+
begin
130+
return_data = Rex::Proto::Rmi::Model::ReturnData.decode(StringIO.new(data))
131+
rescue Rex::Proto::Rmi::DecodeError
132+
return nil
133+
end
134+
135+
return_data.return_value
136+
end
137+
138+
# Helper method to read fragmented data from a ```Rex::Socket::Tcp```
139+
#
140+
# @param nsock [Rex::Socket::Tcp]
141+
# @return [String]
142+
def safe_get_once(nsock = sock, loop_timeout = read_loop_timeout)
143+
data = ''
144+
begin
145+
res = nsock.get_once
146+
rescue ::EOFError
147+
res = nil
148+
end
149+
150+
while res && nsock.has_read_data?(loop_timeout)
151+
data << res
152+
begin
153+
res = nsock.get_once
154+
rescue ::EOFError
155+
res = nil
156+
end
157+
end
158+
159+
data << res if res
160+
data
161+
end
162+
end
163+
164+
end
165+
end
166+
end
167+
end
168+
end
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# -*- coding: binary -*-
2+
require 'msf/core/exploit/java/rmi/client/jmx/server'
3+
require 'msf/core/exploit/java/rmi/client/jmx/connection'
4+
5+
module Msf
6+
class Exploit
7+
class Remote
8+
module Java
9+
module Rmi
10+
module Client
11+
module Jmx
12+
13+
include Msf::Exploit::Remote::Java::Rmi::Client::Jmx::Server
14+
include Msf::Exploit::Remote::Java::Rmi::Client::Jmx::Connection
15+
16+
OBJECT_NAME_UID = 1081892073854801359
17+
BYTE_ARRAY_UID = -5984413125824719648
18+
MARSHALLED_OBJECT_UID = 8988374069173025854
19+
STRING_ARRAY_UID = -5921575005990323385
20+
OBJECT_ARRAY_UID = -8012369246846506644
21+
end
22+
end
23+
end
24+
end
25+
end
26+
end
27+
end

0 commit comments

Comments
 (0)