metasploit-aggregator 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,103 @@
1
+ # -*- coding: binary -*-
2
+ require 'metasploit/aggregator/tlv/packet'
3
+
4
+ module Metasploit
5
+ module Aggregator
6
+ module Tlv
7
+ ###
8
+ #
9
+ # This class is responsible for reading in and decrypting meterpreter
10
+ # packets that arrive on a socket
11
+ #
12
+ ###
13
+ class PacketParser
14
+
15
+ # 4 byte xor
16
+ # 4 byte length
17
+ # 4 byte type
18
+ HEADER_SIZE = 12
19
+
20
+ #
21
+ # Initializes the packet parser context with an optional cipher.
22
+ #
23
+ def initialize(cipher = nil)
24
+ self.cipher = cipher
25
+
26
+ reset
27
+ end
28
+
29
+ #
30
+ # Resets the parser state so that a new packet can begin being parsed.
31
+ #
32
+ def reset
33
+ self.raw = ''
34
+ self.hdr_length_left = HEADER_SIZE
35
+ self.payload_length_left = 0
36
+ end
37
+
38
+ #
39
+ # Reads data from the wire and parse as much of the packet as possible.
40
+ #
41
+ def recv(sock)
42
+ # Create a typeless packet
43
+ packet = Packet.new(0)
44
+
45
+ if (self.hdr_length_left > 0)
46
+ buf = sock.read(self.hdr_length_left)
47
+
48
+ if (buf)
49
+ self.raw << buf
50
+
51
+ self.hdr_length_left -= buf.length
52
+ else
53
+ raise EOFError
54
+ end
55
+
56
+ # If we've finished reading the header, set the
57
+ # payload length left to the number of bytes
58
+ # specified in the length
59
+ if (self.hdr_length_left == 0)
60
+ xor_key = raw[0, 4].unpack('N')[0]
61
+ length_bytes = packet.xor_bytes(xor_key, raw[4, 4])
62
+ # header size doesn't include the xor key, which is always tacked on the front
63
+ self.payload_length_left = length_bytes.unpack("N")[0] - (HEADER_SIZE - 4)
64
+ end
65
+ end
66
+ if (self.payload_length_left > 0)
67
+ buf = sock.read(self.payload_length_left)
68
+
69
+ if (buf)
70
+ self.raw << buf
71
+
72
+ self.payload_length_left -= buf.length
73
+ else
74
+ raise EOFError
75
+ end
76
+ end
77
+
78
+ # If we've finished reading the entire packet
79
+ if ((self.hdr_length_left == 0) &&
80
+ (self.payload_length_left == 0))
81
+
82
+ # TODO: cipher decryption
83
+ if (cipher)
84
+ end
85
+
86
+ # Deserialize the packet from the raw buffer
87
+ packet.from_r(self.raw)
88
+
89
+ # Reset our state
90
+ reset
91
+
92
+ return packet
93
+ end
94
+ end
95
+
96
+ protected
97
+ attr_accessor :cipher, :raw, :hdr_length_left, :payload_length_left # :nodoc:
98
+
99
+ end
100
+ end
101
+ end
102
+ end
103
+
@@ -0,0 +1,275 @@
1
+ # -*- coding => binary -*-
2
+ require 'rex/arch'
3
+ #
4
+ # This class provides methods for calculating, extracting, and parsing
5
+ # unique ID values used by payloads.
6
+ #
7
+ module Metasploit
8
+ module Aggregator
9
+ module Tlv
10
+ class UUID
11
+
12
+ include Rex::Arch
13
+ #
14
+ # Constants
15
+ #
16
+
17
+ Architectures = {
18
+ 0 => nil,
19
+ 1 => ARCH_X86,
20
+ 2 => ARCH_X64, # removed ARCH_X86_64, now consistent across the board
21
+ 3 => ARCH_X64,
22
+ 4 => ARCH_MIPS,
23
+ 5 => ARCH_MIPSLE,
24
+ 6 => ARCH_MIPSBE,
25
+ 7 => ARCH_PPC,
26
+ 8 => ARCH_PPC64,
27
+ 9 => ARCH_CBEA,
28
+ 10 => ARCH_CBEA64,
29
+ 11 => ARCH_SPARC,
30
+ 12 => ARCH_ARMLE,
31
+ 13 => ARCH_ARMBE,
32
+ 14 => ARCH_CMD,
33
+ 15 => ARCH_PHP,
34
+ 16 => ARCH_TTY,
35
+ 17 => ARCH_JAVA,
36
+ 18 => ARCH_RUBY,
37
+ 19 => ARCH_DALVIK,
38
+ 20 => ARCH_PYTHON,
39
+ 21 => ARCH_NODEJS,
40
+ 22 => ARCH_FIREFOX,
41
+ 23 => ARCH_ZARCH,
42
+ 24 => ARCH_AARCH64,
43
+ 25 => ARCH_MIPS64,
44
+ 26 => ARCH_PPC64LE
45
+ }
46
+
47
+ Platforms = {
48
+ 0 => nil,
49
+ 1 => 'windows',
50
+ 2 => 'netware',
51
+ 3 => 'android',
52
+ 4 => 'java',
53
+ 5 => 'ruby',
54
+ 6 => 'linux',
55
+ 7 => 'cisco',
56
+ 8 => 'solaris',
57
+ 9 => 'osx',
58
+ 10 => 'bsd',
59
+ 11 => 'openbsd',
60
+ 12 => 'bsdi',
61
+ 13 => 'netbsd',
62
+ 14 => 'freebsd',
63
+ 15 => 'aix',
64
+ 16 => 'hpux',
65
+ 17 => 'irix',
66
+ 18 => 'unix',
67
+ 19 => 'php',
68
+ 20 => 'js',
69
+ 21 => 'python',
70
+ 22 => 'nodejs',
71
+ 23 => 'firefox'
72
+ }
73
+
74
+ # The raw length of the UUID structure
75
+ RawLength = 16
76
+
77
+ # The base64url-encoded length of the UUID structure
78
+ UriLength = 22
79
+
80
+ # Validity constraints for UUID timestamps in UTC
81
+ TimestampMaxFuture = Time.now.utc.to_i + (30*24*3600) # Up to 30 days in the future
82
+ TimestampMaxPast = 1420070400 # Since 2015-01-01 00:00:00 UTC
83
+
84
+ #
85
+ # Class Methods
86
+ #
87
+
88
+ #
89
+ # Parse a raw 16-byte payload UUID and return the payload ID, platform, architecture, and timestamp
90
+ #
91
+ # @param raw [String] The raw 16-byte payload UUID to parse
92
+ # @return [Hash] A hash containing the Payload ID, platform, architecture, and timestamp
93
+ #
94
+ def self.parse_raw(raw)
95
+ if raw.to_s.length < 16
96
+ raise ArgumentError, "Raw UUID must be at least 16 bytes"
97
+ end
98
+
99
+ puid, plat_xor, arch_xor, plat_id, arch_id, tstamp = raw.unpack('a8C4N')
100
+ plat = find_platform_name(plat_xor ^ plat_id)
101
+ arch = find_architecture_name(arch_xor ^ arch_id)
102
+ time_xor = [plat_xor, arch_xor, plat_xor, arch_xor].pack('C4').unpack('N').first
103
+ time = time_xor ^ tstamp
104
+ { puid: puid, platform: plat, arch: arch, timestamp: time, xor1: plat_xor, xor2: arch_xor }
105
+ end
106
+
107
+ #
108
+ # Filter out UUIDs with obviously invalid fields and return either
109
+ # a validated UUID or a UUID with the arch, platform, and timestamp
110
+ # fields strippped out.
111
+ #
112
+ # @param uuid [Hash] The UUID in hash format
113
+ # @return [Hash] The filtered UUID in hash format
114
+ #
115
+ def self.filter_invalid(uuid)
116
+ # Verify the UUID fields and return just the Payload ID unless the
117
+ # timestamp is within our constraints and the UUID has either a
118
+ # valid architecture or platform
119
+ if uuid[:timestamp] > TimestampMaxFuture ||
120
+ uuid[:timestamp] < TimestampMaxPast ||
121
+ (uuid[:arch].nil? && uuid[:platform].nil?)
122
+ return { puid: uuid[:puid] }
123
+ end
124
+ uuid
125
+ end
126
+
127
+ #
128
+ # Look up the numeric platform ID given a string or PlatformList as input
129
+ #
130
+ # @param platform [String] The name of the platform to lookup
131
+ # @return [Fixnum] The integer value of this platform
132
+ #
133
+ def self.find_platform_id(platform)
134
+ name = name.first if name.kind_of? ::Array
135
+ ( Platforms.keys.select{ |k|
136
+ Platforms[k] == name
137
+ }.first || Platforms[0] ).to_i
138
+ end
139
+
140
+ #
141
+ # Look up the numeric architecture ID given a string as input
142
+ #
143
+ # @param name [String] The name of the architecture to lookup
144
+ # @return [Fixnum] The integer value of this architecture
145
+ #
146
+ def self.find_architecture_id(name)
147
+ name = name.first if name.kind_of? ::Array
148
+ ( Architectures.keys.select{ |k|
149
+ Architectures[k] == name
150
+ }.first || Architectures[0] ).to_i
151
+ end
152
+
153
+ def self.find_platform_name(num)
154
+ Platforms[num]
155
+ end
156
+
157
+ def self.find_architecture_name(num)
158
+ Architectures[num]
159
+ end
160
+
161
+ #
162
+ # Instance methods
163
+ #
164
+
165
+ def initialize(opts=nil)
166
+ opts = load_new if opts.nil?
167
+ opts = load_raw(opts[:raw]) if opts[:raw]
168
+
169
+ self.puid = opts[:puid]
170
+ self.timestamp = opts[:timestamp]
171
+ self.arch = opts[:arch]
172
+ self.platform = opts[:platform]
173
+ self.xor1 = opts[:xor1]
174
+ self.xor2 = opts[:xor2]
175
+
176
+ # Generate some sensible defaults
177
+ self.puid ||= SecureRandom.random_bytes(8)
178
+ self.xor1 ||= rand(256)
179
+ self.xor2 ||= rand(256)
180
+ self.timestamp ||= Time.now.utc.to_i
181
+ end
182
+
183
+ #
184
+ # Initializes a UUID object given a raw 16+ byte blob
185
+ #
186
+ # @param raw [String] The string containing at least 16 bytes of encoded data
187
+ # @return [Hash] The attributes encoded into this UUID
188
+ #
189
+ def load_raw(raw)
190
+ self.class.filter_invalid(self.class.parse_raw(raw))
191
+ end
192
+
193
+ def load_new
194
+ self.class.parse_raw(self.class.generate_raw())
195
+ end
196
+
197
+ #
198
+ # Provides a string representation of a UUID
199
+ #
200
+ # @return [String] The human-readable version of the UUID data
201
+ #
202
+ def to_s
203
+ arch_id = self.class.find_architecture_id(self.arch).to_s
204
+ plat_id = self.class.find_platform_id(self.platform).to_s
205
+ [
206
+ self.puid_hex,
207
+ [ self.arch || "noarch", arch_id ].join("="),
208
+ [ self.platform || "noplatform", plat_id ].join("="),
209
+ Time.at(self.timestamp.to_i).utc.strftime("%Y-%m-%dT%H:%M:%SZ")
210
+ ].join("/")
211
+ end
212
+
213
+ #
214
+ # Return a string that represents the Meterpreter arch/platform
215
+ #
216
+ def session_type
217
+ # mini-patch for x86 so that it renders x64 instead. This is
218
+ # mostly to keep various external modules happy.
219
+ arch = self.arch
220
+ if arch == ARCH_X86_64
221
+ arch = ARCH_X64
222
+ end
223
+ "#{arch}/#{self.platform}"
224
+ end
225
+
226
+ #
227
+ # Provides a hash representation of a UUID
228
+ #
229
+ # @return [Hash] The hash representation of the UUID suitable for creating a new one
230
+ #
231
+ def to_h
232
+ {
233
+ puid: self.puid,
234
+ arch: self.arch, platform: self.platform,
235
+ timestamp: self.timestamp,
236
+ xor1: self.xor1, xor2: self.xor2
237
+ }
238
+ end
239
+
240
+ #
241
+ # Provides a raw byte representation of a UUID
242
+ #
243
+ # @return [String] The 16-byte raw encoded version of the UUID
244
+ #
245
+ def to_raw
246
+ self.class.generate_raw(self.to_h)
247
+ end
248
+
249
+ #
250
+ # Provides a hex representation of the Payload UID of the UUID
251
+ #
252
+ # @return [String] The 16-byte hex string representing the Payload UID
253
+ #
254
+ def puid_hex
255
+ self.puid.unpack('H*').first
256
+ end
257
+
258
+ #
259
+ # Clears the two random XOR keys used for obfuscation
260
+ #
261
+ def xor_reset
262
+ self.xor1 = self.xor2 = nil
263
+ self
264
+ end
265
+
266
+ attr_accessor :arch
267
+ attr_accessor :platform
268
+ attr_accessor :timestamp
269
+ attr_accessor :puid
270
+ attr_accessor :xor1
271
+ attr_accessor :xor2
272
+ end
273
+ end
274
+ end
275
+ end
@@ -1,5 +1,5 @@
1
1
  module Metasploit
2
2
  module Aggregator
3
- VERSION = '0.1.1'
3
+ VERSION = '0.1.2'
4
4
  end
5
5
  end
@@ -17,7 +17,7 @@ Gem::Specification.new do |spec|
17
17
  f.match(%r{^(test|spec|features)/})
18
18
  end
19
19
  spec.bindir = "bin"
20
- spec.executables << 'msfaggregator'
20
+ spec.executables << 'metasploit-aggregator'
21
21
  spec.require_paths = ["lib"]
22
22
 
23
23
  spec.add_development_dependency "bundler", "~> 1.13"
@@ -25,4 +25,5 @@ Gem::Specification.new do |spec|
25
25
  spec.add_development_dependency "rspec", "~> 3.0"
26
26
  spec.add_runtime_dependency 'msgpack'
27
27
  spec.add_runtime_dependency 'msgpack-rpc'
28
+ spec.add_runtime_dependency 'rex-arch'
28
29
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: metasploit-aggregator
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Metasploit Hackers
@@ -88,7 +88,7 @@ cert_chain:
88
88
  G+Hmcg1v810agasPdoydE0RTVZgEOOMoQ07qu7JFXVWZ9ZQpHT7qJATWL/b2csFG
89
89
  8mVuTXnyJOKRJA==
90
90
  -----END CERTIFICATE-----
91
- date: 2017-01-31 00:00:00.000000000 Z
91
+ date: 2017-02-02 00:00:00.000000000 Z
92
92
  dependencies:
93
93
  - !ruby/object:Gem::Dependency
94
94
  name: bundler
@@ -160,11 +160,25 @@ dependencies:
160
160
  - - ">="
161
161
  - !ruby/object:Gem::Version
162
162
  version: '0'
163
+ - !ruby/object:Gem::Dependency
164
+ name: rex-arch
165
+ requirement: !ruby/object:Gem::Requirement
166
+ requirements:
167
+ - - ">="
168
+ - !ruby/object:Gem::Version
169
+ version: '0'
170
+ type: :runtime
171
+ prerelease: false
172
+ version_requirements: !ruby/object:Gem::Requirement
173
+ requirements:
174
+ - - ">="
175
+ - !ruby/object:Gem::Version
176
+ version: '0'
163
177
  description: metasploit-aggregator
164
178
  email:
165
179
  - metasploit-hackers@lists.sourceforge.net
166
180
  executables:
167
- - msfaggregator
181
+ - metasploit-aggregator
168
182
  extensions: []
169
183
  extra_rdoc_files: []
170
184
  files:
@@ -177,7 +191,7 @@ files:
177
191
  - LICENSE
178
192
  - README.md
179
193
  - Rakefile
180
- - bin/msfaggregator
194
+ - bin/metasploit-aggregator
181
195
  - lib/metasploit/aggregator.rb
182
196
  - lib/metasploit/aggregator/cable.rb
183
197
  - lib/metasploit/aggregator/connection_manager.rb
@@ -192,6 +206,10 @@ files:
192
206
  - lib/metasploit/aggregator/https_forwarder.rb
193
207
  - lib/metasploit/aggregator/logger.rb
194
208
  - lib/metasploit/aggregator/router.rb
209
+ - lib/metasploit/aggregator/session_detail_service.rb
210
+ - lib/metasploit/aggregator/tlv/packet.rb
211
+ - lib/metasploit/aggregator/tlv/packet_parser.rb
212
+ - lib/metasploit/aggregator/tlv/uuid.rb
195
213
  - lib/metasploit/aggregator/version.rb
196
214
  - metasploit-aggregator.gemspec
197
215
  homepage: https://www.msf.com