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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: aac104842b24e3ca148b53fec7496fdd91f05cbe
4
- data.tar.gz: fe6729af2bc28c2a0a3d2d27e41b55501cff5bb6
3
+ metadata.gz: df43d9c519841eb237a29d07f02423decce8ae9c
4
+ data.tar.gz: 3a9f144ffceefc2caf76a0b99aaacfd8d933cab5
5
5
  SHA512:
6
- metadata.gz: 7bdd018ad0bdae6925db322e986eced83c1a904f9ba09671b715496271b7d6642a671b9abdcc59626249751579dd94bc966cefac6490a803424f40e21684c822
7
- data.tar.gz: 321958012678ee3f900c9f2675bcbe721571d3def92906b136a1cdfea68ec96552a1d7953b2e1f0d7c7985f3f3f45a6cc36c72f7efc7ee2a21471ada2615f8bc
6
+ metadata.gz: 77a8d3d7de9523f6680346211b722b901eaac594ab51124c3f84053dfbf4dda8391524651d0bbbaeb1ab6b7592be3a4cd7b2a1aff227196b04c80932093e7f53
7
+ data.tar.gz: da9034ab7c33353c9eb890ff67885f025957f754be923264dbb0a5ad14545a818003c41131ea0a7bc77f81242ca9e0ae12ab279b68664a2a3cf1947c0cec9567
checksums.yaml.gz.sig CHANGED
Binary file
data.tar.gz.sig CHANGED
Binary file
@@ -33,5 +33,16 @@ loop do
33
33
  server.stop
34
34
  elsif command.chomp == 'park'
35
35
  client.release_session($stdin.gets.chomp)
36
+ elsif command.chomp == 'details'
37
+ client = Metasploit::Aggregator::ServerProxy.new(admin_host, admin_port)
38
+ client.sessions.each_pair do |payload, console|
39
+ details = client.session_details(payload)
40
+ $stdout.puts payload
41
+ details.each_pair do |key, attr|
42
+ $stdout.print "\t"
43
+ $stdout.print "#{key}:"
44
+ $stdout.puts "#{attr}"
45
+ end
46
+ end
36
47
  end
37
48
  end
@@ -42,6 +42,11 @@ module Metasploit
42
42
  # index for impl
43
43
  end
44
44
 
45
+ # return any extended details for the payload requested
46
+ def session_details(payload)
47
+
48
+ end
49
+
45
50
  # start a listening port maintained on the service
46
51
  # connections are forwarded to any registered default
47
52
  # TODO: may want to require a type here for future proof of api
@@ -116,6 +121,12 @@ module Metasploit
116
121
  Logger.log(e.to_s)
117
122
  end
118
123
 
124
+ def session_details(payload)
125
+ @client.call(:session_details, payload)
126
+ rescue MessagePack::RPC::TimeoutError => e
127
+ Logger.log(e.to_s)
128
+ end
129
+
119
130
  def add_cable(type, host, port, certificate = nil)
120
131
  @client.call(:add_cable, type, host, port, certificate)
121
132
  rescue MessagePack::RPC::TimeoutError => e
@@ -222,6 +233,10 @@ module Metasploit
222
233
  true # return always return success for now
223
234
  end
224
235
 
236
+ def session_details(payload)
237
+ @manager.connection_details(payload)
238
+ end
239
+
225
240
  def add_cable(type, host, port, certificate = nil)
226
241
  unless @manager.nil?
227
242
  case type
@@ -272,10 +287,6 @@ module Metasploit
272
287
  true
273
288
  end
274
289
 
275
- def release_session(host)
276
- @manager.park(host)
277
- end
278
-
279
290
  def request(uuid)
280
291
  # return requests here
281
292
  result = nil
@@ -15,6 +15,7 @@ module Metasploit
15
15
  @cables = []
16
16
  @manager_mutex = Mutex.new
17
17
  @router = Router.instance
18
+ @details_cache = SessionDetailService.instance
18
19
  end
19
20
 
20
21
  def self.ssl_generate_certificate
@@ -106,6 +107,23 @@ module Metasploit
106
107
  connections
107
108
  end
108
109
 
110
+ def connection_details(payload)
111
+ detail_map = {}
112
+ details = @details_cache.session_details(payload)
113
+ unless details.nil?
114
+ details.each_pair do |key, value|
115
+ detail_map[key] = value.to_s
116
+ end
117
+ end
118
+ @cables.each do |cable|
119
+ next unless cable.forwarder.connections.include?(payload)
120
+ # TODO: improve how time is exposed for live connections
121
+ time = cable.forwarder.connection_info(payload)['TIME']
122
+ detail_map['LAST_SEEN'] = Time.now - time unless time.nil?
123
+ end
124
+ detail_map
125
+ end
126
+
109
127
  def cables
110
128
  local_cables = []
111
129
  @cables.each do |cable|
@@ -33,16 +33,22 @@ module Metasploit
33
33
  connections
34
34
  end
35
35
 
36
+ def connection_info(connection)
37
+ info = {}
38
+ info['TIME'] = @response_queues[connection].time unless @response_queues[connection].nil?
39
+ info
40
+ end
41
+
36
42
  def flush_stale_sessions
37
43
  @forwarder_mutex.synchronize do
38
44
  stale_sessions = []
39
- @response_queues.each_pair do |uri, queue|
45
+ @response_queues.each_pair do |payload, queue|
40
46
  unless (queue.time + CONNECTION_TIMEOUT) > Time.now
41
- stale_sessions << uri
47
+ stale_sessions << payload
42
48
  end
43
49
  end
44
- stale_sessions.each do |uri|
45
- stale_queue = @response_queues.delete(uri)
50
+ stale_sessions.each do |payload|
51
+ stale_queue = @response_queues.delete(payload)
46
52
  stale_queue.stop_processing unless stale_queue.nil?
47
53
  end
48
54
  end
@@ -1,3 +1,4 @@
1
+ require "metasploit/aggregator/session_detail_service"
1
2
  require "metasploit/aggregator/http/request"
2
3
 
3
4
  module Metasploit
@@ -19,6 +20,7 @@ module Metasploit
19
20
  @thread = Thread.new { process_requests }
20
21
  @time = Time.now
21
22
  @router = Router.instance
23
+ @session_service = SessionDetailService.instance
22
24
  @pending_requests = nil
23
25
  end
24
26
 
@@ -39,6 +41,7 @@ module Metasploit
39
41
  end
40
42
 
41
43
  # response from get_forward will be a queue to push messages onto and a response queue to retrieve result from
44
+ @session_service.add_request(request_task, @uri)
42
45
  send << request_task
43
46
  @pending_request = connection
44
47
 
@@ -47,6 +50,7 @@ module Metasploit
47
50
  # now get the response once available and send back using this connection
48
51
  begin
49
52
  request_obj = recv.pop
53
+ @session_service.add_request(request_task, @uri)
50
54
  @pending_request = nil
51
55
  request_obj.headers.each do |line|
52
56
  connection.write line
@@ -10,9 +10,6 @@ module Metasploit
10
10
  class HttpForwarder < Forwarder
11
11
  CONNECTION_TIMEOUT = 60 # one minute
12
12
 
13
- attr_accessor :log_messages
14
- attr_reader :response_queues
15
-
16
13
  def initialize
17
14
  super
18
15
  end
@@ -31,9 +31,9 @@ module Metasploit
31
31
  end
32
32
  end
33
33
 
34
- def get_forward(uri)
35
- unless @forward_routes[uri].nil?
36
- @forward_routes[uri]
34
+ def get_forward(payload)
35
+ unless @forward_routes[payload].nil?
36
+ @forward_routes[payload]
37
37
  else
38
38
  @forward_routes['default']
39
39
  end
@@ -0,0 +1,71 @@
1
+ require 'digest/md5'
2
+ require 'singleton'
3
+ require 'metasploit/aggregator/tlv/packet'
4
+ require 'metasploit/aggregator/tlv/packet_parser'
5
+ require 'metasploit/aggregator/tlv/uuid'
6
+
7
+ module Metasploit
8
+ module Aggregator
9
+ class SessionDetailService
10
+ include Singleton
11
+
12
+ def initialize
13
+ @mutex = Mutex.new
14
+ @tlv_queue = Queue.new
15
+ @thread = Thread.new { process_tlv }
16
+ # for now since all data is http no cipher is required on the parser
17
+ @parser = Metasploit::Aggregator::Tlv::PacketParser.new
18
+ @r, @w = IO.pipe
19
+ @payloads_count = 0;
20
+ @detail_cache = {}
21
+ end
22
+
23
+ def add_request(request, payload)
24
+ @tlv_queue << [ request, payload ]
25
+ if @detail_cache[payload] && @detail_cache[payload]['REMOTE_SOCKET'].nil?
26
+ @detail_cache[payload]['REMOTE_SOCKET'] = "#{request.socket.peeraddr[3]}:#{request.socket.peeraddr[1]}"
27
+ @detail_cache[payload]['LOCAL_SOCKET'] = "#{request.socket.addr[3]}:#{request.socket.addr[1]}"
28
+ end
29
+ end
30
+
31
+ def session_details(payload)
32
+ @detail_cache[payload]
33
+ end
34
+
35
+ def process_tlv
36
+ while true
37
+ begin
38
+ request, payload = @tlv_queue.pop
39
+ if request.body && request.body.length > 0
40
+ # process body as tlv
41
+ @w.write(request.body)
42
+ packet = @parser.recv(@r)
43
+ next unless packet
44
+ unless @detail_cache[payload]
45
+ @detail_cache[payload] = { 'ID' => (@payloads_count += 1) }
46
+ end
47
+ if packet.has_tlv?(Metasploit::Aggregator::Tlv::TLV_TYPE_UUID)
48
+ args = { :raw => packet.get_tlv_value(Metasploit::Aggregator::Tlv::TLV_TYPE_UUID) }
49
+ @detail_cache[payload]['UUID'] = Metasploit::Aggregator::Tlv::UUID.new(args)
50
+ end
51
+ if packet.has_tlv?(Metasploit::Aggregator::Tlv::TLV_TYPE_MACHINE_ID)
52
+ @detail_cache[payload]['MachineID'] = Digest::MD5.hexdigest(packet.get_tlv_value(Metasploit::Aggregator::Tlv::TLV_TYPE_MACHINE_ID).downcase.strip)
53
+ end
54
+ if packet.has_tlv?(Metasploit::Aggregator::Tlv::TLV_TYPE_USER_NAME)
55
+ @detail_cache[payload]['USER'] = packet.get_tlv_value(Metasploit::Aggregator::Tlv::TLV_TYPE_USER_NAME)
56
+ end
57
+ if packet.has_tlv?(Metasploit::Aggregator::Tlv::TLV_TYPE_COMPUTER_NAME)
58
+ @detail_cache[payload]['HOSTNAME'] = packet.get_tlv_value(Metasploit::Aggregator::Tlv::TLV_TYPE_COMPUTER_NAME)
59
+ end
60
+ if packet.has_tlv?(Metasploit::Aggregator::Tlv::TLV_TYPE_OS_NAME)
61
+ @detail_cache[payload]['OS'] = packet.get_tlv_value(Metasploit::Aggregator::Tlv::TLV_TYPE_OS_NAME)
62
+ end
63
+ end
64
+ rescue
65
+ Logger.log $!
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,740 @@
1
+ # -*- coding: binary -*-
2
+
3
+ module Metasploit
4
+ module Aggregator
5
+ module Tlv
6
+
7
+ #
8
+ # Constants
9
+ #
10
+ PACKET_TYPE_REQUEST = 0
11
+ PACKET_TYPE_RESPONSE = 1
12
+ PACKET_TYPE_PLAIN_REQUEST = 10
13
+ PACKET_TYPE_PLAIN_RESPONSE = 11
14
+
15
+ #
16
+ # TLV Meta Types
17
+ #
18
+ TLV_META_TYPE_NONE = 0
19
+ TLV_META_TYPE_STRING = (1 << 16)
20
+ TLV_META_TYPE_UINT = (1 << 17)
21
+ TLV_META_TYPE_RAW = (1 << 18)
22
+ TLV_META_TYPE_BOOL = (1 << 19)
23
+ TLV_META_TYPE_QWORD = (1 << 20)
24
+ TLV_META_TYPE_COMPRESSED = (1 << 29)
25
+ TLV_META_TYPE_GROUP = (1 << 30)
26
+ TLV_META_TYPE_COMPLEX = (1 << 31)
27
+
28
+ # Exclude compressed from the mask since other meta types (e.g. RAW) can also
29
+ # be compressed
30
+ TLV_META_MASK = (
31
+ TLV_META_TYPE_STRING |
32
+ TLV_META_TYPE_UINT |
33
+ TLV_META_TYPE_RAW |
34
+ TLV_META_TYPE_BOOL |
35
+ TLV_META_TYPE_QWORD |
36
+ TLV_META_TYPE_GROUP |
37
+ TLV_META_TYPE_COMPLEX
38
+ )
39
+
40
+ #
41
+ # TLV base starting points
42
+ #
43
+ TLV_RESERVED = 0
44
+ TLV_EXTENSIONS = 20000
45
+ TLV_USER = 40000
46
+ TLV_TEMP = 60000
47
+
48
+ #
49
+ # TLV Specific Types
50
+ #
51
+ TLV_TYPE_ANY = TLV_META_TYPE_NONE | 0
52
+ TLV_TYPE_METHOD = TLV_META_TYPE_STRING | 1
53
+ TLV_TYPE_REQUEST_ID = TLV_META_TYPE_STRING | 2
54
+ TLV_TYPE_EXCEPTION = TLV_META_TYPE_GROUP | 3
55
+ TLV_TYPE_RESULT = TLV_META_TYPE_UINT | 4
56
+
57
+
58
+ TLV_TYPE_STRING = TLV_META_TYPE_STRING | 10
59
+ TLV_TYPE_UINT = TLV_META_TYPE_UINT | 11
60
+ TLV_TYPE_BOOL = TLV_META_TYPE_BOOL | 12
61
+
62
+ TLV_TYPE_LENGTH = TLV_META_TYPE_UINT | 25
63
+ TLV_TYPE_DATA = TLV_META_TYPE_RAW | 26
64
+ TLV_TYPE_FLAGS = TLV_META_TYPE_UINT | 27
65
+
66
+ TLV_TYPE_CHANNEL_ID = TLV_META_TYPE_UINT | 50
67
+ TLV_TYPE_CHANNEL_TYPE = TLV_META_TYPE_STRING | 51
68
+ TLV_TYPE_CHANNEL_DATA = TLV_META_TYPE_RAW | 52
69
+ TLV_TYPE_CHANNEL_DATA_GROUP = TLV_META_TYPE_GROUP | 53
70
+ TLV_TYPE_CHANNEL_CLASS = TLV_META_TYPE_UINT | 54
71
+ TLV_TYPE_CHANNEL_PARENTID = TLV_META_TYPE_UINT | 55
72
+
73
+ TLV_TYPE_SEEK_WHENCE = TLV_META_TYPE_UINT | 70
74
+ TLV_TYPE_SEEK_OFFSET = TLV_META_TYPE_UINT | 71
75
+ TLV_TYPE_SEEK_POS = TLV_META_TYPE_UINT | 72
76
+
77
+ TLV_TYPE_EXCEPTION_CODE = TLV_META_TYPE_UINT | 300
78
+ TLV_TYPE_EXCEPTION_STRING = TLV_META_TYPE_STRING | 301
79
+
80
+ TLV_TYPE_LIBRARY_PATH = TLV_META_TYPE_STRING | 400
81
+ TLV_TYPE_TARGET_PATH = TLV_META_TYPE_STRING | 401
82
+ TLV_TYPE_MIGRATE_PID = TLV_META_TYPE_UINT | 402
83
+ TLV_TYPE_MIGRATE_LEN = TLV_META_TYPE_UINT | 403
84
+ TLV_TYPE_MIGRATE_PAYLOAD = TLV_META_TYPE_STRING | 404
85
+ TLV_TYPE_MIGRATE_ARCH = TLV_META_TYPE_UINT | 405
86
+ TLV_TYPE_MIGRATE_BASE_ADDR = TLV_META_TYPE_UINT | 407
87
+ TLV_TYPE_MIGRATE_ENTRY_POINT = TLV_META_TYPE_UINT | 408
88
+ TLV_TYPE_MIGRATE_SOCKET_PATH = TLV_META_TYPE_STRING | 409
89
+ TLV_TYPE_MIGRATE_STUB_LEN = TLV_META_TYPE_UINT | 410
90
+ TLV_TYPE_MIGRATE_STUB = TLV_META_TYPE_STRING | 411
91
+
92
+
93
+ TLV_TYPE_TRANS_TYPE = TLV_META_TYPE_UINT | 430
94
+ TLV_TYPE_TRANS_URL = TLV_META_TYPE_STRING | 431
95
+ TLV_TYPE_TRANS_UA = TLV_META_TYPE_STRING | 432
96
+ TLV_TYPE_TRANS_COMM_TIMEOUT = TLV_META_TYPE_UINT | 433
97
+ TLV_TYPE_TRANS_SESSION_EXP = TLV_META_TYPE_UINT | 434
98
+ TLV_TYPE_TRANS_CERT_HASH = TLV_META_TYPE_RAW | 435
99
+ TLV_TYPE_TRANS_PROXY_HOST = TLV_META_TYPE_STRING | 436
100
+ TLV_TYPE_TRANS_PROXY_USER = TLV_META_TYPE_STRING | 437
101
+ TLV_TYPE_TRANS_PROXY_PASS = TLV_META_TYPE_STRING | 438
102
+ TLV_TYPE_TRANS_RETRY_TOTAL = TLV_META_TYPE_UINT | 439
103
+ TLV_TYPE_TRANS_RETRY_WAIT = TLV_META_TYPE_UINT | 440
104
+ TLV_TYPE_TRANS_GROUP = TLV_META_TYPE_GROUP | 441
105
+
106
+ TLV_TYPE_MACHINE_ID = TLV_META_TYPE_STRING | 460
107
+ TLV_TYPE_UUID = TLV_META_TYPE_RAW | 461
108
+
109
+ TLV_TYPE_CIPHER_NAME = TLV_META_TYPE_STRING | 500
110
+ TLV_TYPE_CIPHER_PARAMETERS = TLV_META_TYPE_GROUP | 501
111
+
112
+ #
113
+ # Core flags
114
+ #
115
+ LOAD_LIBRARY_FLAG_ON_DISK = (1 << 0)
116
+ LOAD_LIBRARY_FLAG_EXTENSION = (1 << 1)
117
+ LOAD_LIBRARY_FLAG_LOCAL = (1 << 2)
118
+
119
+ #
120
+ # Stdapi TLVs - Config
121
+ #
122
+ TLV_TYPE_COMPUTER_NAME = TLV_META_TYPE_STRING | 1040
123
+ TLV_TYPE_OS_NAME = TLV_META_TYPE_STRING | 1041
124
+ TLV_TYPE_USER_NAME = TLV_META_TYPE_STRING | 1042
125
+ TLV_TYPE_ARCHITECTURE = TLV_META_TYPE_STRING | 1043
126
+ TLV_TYPE_LANG_SYSTEM = TLV_META_TYPE_STRING | 1044
127
+ TLV_TYPE_SID = TLV_META_TYPE_STRING | 1045
128
+ TLV_TYPE_DOMAIN = TLV_META_TYPE_STRING | 1046
129
+ TLV_TYPE_LOGGED_ON_USER_COUNT = TLV_META_TYPE_UINT | 1047
130
+ TLV_TYPE_LOCAL_DATETIME = TLV_META_TYPE_STRING | 1048
131
+
132
+ ###
133
+ #
134
+ # Base TLV (Type-Length-Value) class
135
+ #
136
+ ###
137
+ class Tlv
138
+ attr_accessor :type, :value, :compress
139
+
140
+ ##
141
+ #
142
+ # Constructor
143
+ #
144
+ ##
145
+
146
+ #
147
+ # Returns an instance of a TLV.
148
+ #
149
+ def initialize(type, value = nil, compress=false)
150
+ @type = type
151
+ @compress = compress
152
+
153
+ if (value != nil)
154
+ if (type & TLV_META_TYPE_STRING == TLV_META_TYPE_STRING)
155
+ if (value.kind_of?(Integer))
156
+ @value = value.to_s
157
+ else
158
+ @value = value.dup
159
+ end
160
+ else
161
+ @value = value
162
+ end
163
+ end
164
+ end
165
+
166
+ def inspect
167
+ utype = type ^ TLV_META_TYPE_COMPRESSED
168
+ group = false
169
+ meta = case (utype & TLV_META_MASK)
170
+ when TLV_META_TYPE_STRING; "STRING"
171
+ when TLV_META_TYPE_UINT; "INT"
172
+ when TLV_META_TYPE_RAW; "RAW"
173
+ when TLV_META_TYPE_BOOL; "BOOL"
174
+ when TLV_META_TYPE_QWORD; "QWORD"
175
+ when TLV_META_TYPE_GROUP; group=true; "GROUP"
176
+ when TLV_META_TYPE_COMPLEX; "COMPLEX"
177
+ else; 'unknown-meta-type'
178
+ end
179
+ stype = "unknown-#{type}"
180
+ Metasploit::Aggregator::Tlv.constants.each do |value|
181
+ next unless Metasploit::Aggregator::Tlv.const_get(value) == type
182
+ stype = value.to_s
183
+ break
184
+ end
185
+ val = value.inspect
186
+ if val.length > 50
187
+ val = val[0,50] + ' ..."'
188
+ end
189
+ group ||= (self.class.to_s =~ /Packet/)
190
+ if group
191
+ tlvs_inspect = "tlvs=[\n"
192
+ @tlvs.each { |t|
193
+ tlvs_inspect << " #{t.inspect}\n"
194
+ }
195
+ tlvs_inspect << "]"
196
+ else
197
+ tlvs_inspect = "meta=#{meta.ljust 10} value=#{val}"
198
+ end
199
+ "#<#{self.class} type=#{stype.ljust 15} #{tlvs_inspect}>"
200
+ end
201
+
202
+ ##
203
+ #
204
+ # Conditionals
205
+ #
206
+ ##
207
+
208
+ #
209
+ # Checks to see if a TLVs meta type is equivalent to the meta type passed.
210
+ #
211
+ def meta_type?(meta)
212
+ return (self.type & meta == meta)
213
+ end
214
+
215
+ #
216
+ # Checks to see if the TLVs type is equivalent to the type passed.
217
+ #
218
+ def type?(type)
219
+ return self.type == type
220
+ end
221
+
222
+ #
223
+ # Checks to see if the TLVs value is equivalent to the value passed.
224
+ #
225
+ def value?(value)
226
+ return self.value == value
227
+ end
228
+
229
+ ##
230
+ #
231
+ # Serializers
232
+ #
233
+ ##
234
+
235
+ #
236
+ # Converts the TLV to raw.
237
+ #
238
+ def to_r
239
+ # Forcibly convert to ASCII-8BIT encoding
240
+ raw = value.to_s.unpack("C*").pack("C*")
241
+
242
+ if (self.type & TLV_META_TYPE_STRING == TLV_META_TYPE_STRING)
243
+ raw += "\x00"
244
+ elsif (self.type & TLV_META_TYPE_UINT == TLV_META_TYPE_UINT)
245
+ raw = [value].pack("N")
246
+ elsif (self.type & TLV_META_TYPE_QWORD == TLV_META_TYPE_QWORD)
247
+ raw = [ self.htonq( value.to_i ) ].pack("Q<")
248
+ elsif (self.type & TLV_META_TYPE_BOOL == TLV_META_TYPE_BOOL)
249
+ if (value == true)
250
+ raw = [1].pack("c")
251
+ else
252
+ raw = [0].pack("c")
253
+ end
254
+ end
255
+
256
+ # check if the tlv is to be compressed...
257
+ if( @compress )
258
+ raw_uncompressed = raw
259
+ # compress the raw data
260
+ raw_compressed = Rex::Text.zlib_deflate( raw_uncompressed )
261
+ # check we have actually made the raw data smaller...
262
+ # (small blobs often compress slightly larger then the origional)
263
+ # if the compressed data is not smaller, we dont use the compressed data
264
+ if( raw_compressed.length < raw_uncompressed.length )
265
+ # if so, set the TLV's type to indicate compression is used
266
+ self.type = self.type | TLV_META_TYPE_COMPRESSED
267
+ # update the raw data with the uncompressed data length + compressed data
268
+ # (we include the uncompressed data length as the C side will need to know this for decompression)
269
+ raw = [ raw_uncompressed.length ].pack("N") + raw_compressed
270
+ end
271
+ end
272
+
273
+ return [raw.length + 8, self.type].pack("NN") + raw
274
+ end
275
+
276
+ #
277
+ # Translates the raw format of the TLV into a sanitize version.
278
+ #
279
+ def from_r(raw)
280
+ self.value = nil
281
+
282
+ length, self.type = raw.unpack("NN");
283
+
284
+ # check if the tlv value has been compressed...
285
+ if( self.type & TLV_META_TYPE_COMPRESSED == TLV_META_TYPE_COMPRESSED )
286
+ # set this TLV as using compression
287
+ @compress = true
288
+ # remove the TLV_META_TYPE_COMPRESSED flag from the tlv type to restore the
289
+ # tlv type to its origional, allowing for transparent data compression.
290
+ self.type = self.type ^ TLV_META_TYPE_COMPRESSED
291
+ # decompress the compressed data (skipping the length and type DWORD's)
292
+ raw_decompressed = Rex::Text.zlib_inflate( raw[8..length-1] )
293
+ # update the length to reflect the decompressed data length (+8 for the length and type DWORD's)
294
+ length = raw_decompressed.length + 8
295
+ # update the raw buffer with the new length, decompressed data and updated type.
296
+ raw = [length, self.type].pack("NN") + raw_decompressed
297
+ end
298
+
299
+ if (self.type & TLV_META_TYPE_STRING == TLV_META_TYPE_STRING)
300
+ if (raw.length > 0)
301
+ self.value = raw[8..length-2]
302
+ else
303
+ self.value = nil
304
+ end
305
+ elsif (self.type & TLV_META_TYPE_UINT == TLV_META_TYPE_UINT)
306
+ self.value = raw.unpack("NNN")[2]
307
+ elsif (self.type & TLV_META_TYPE_QWORD == TLV_META_TYPE_QWORD)
308
+ self.value = raw.unpack("NNQ<")[2]
309
+ self.value = self.ntohq( self.value )
310
+ elsif (self.type & TLV_META_TYPE_BOOL == TLV_META_TYPE_BOOL)
311
+ self.value = raw.unpack("NNc")[2]
312
+
313
+ if (self.value == 1)
314
+ self.value = true
315
+ else
316
+ self.value = false
317
+ end
318
+ else
319
+ self.value = raw[8..length-1]
320
+ end
321
+
322
+ return length;
323
+ end
324
+
325
+ protected
326
+
327
+ def htonq( value )
328
+ if( [1].pack( 's' ) == [1].pack( 'n' ) )
329
+ return value
330
+ end
331
+ return [ value ].pack( 'Q<' ).reverse.unpack( 'Q<' ).first
332
+ end
333
+
334
+ def ntohq( value )
335
+ return htonq( value )
336
+ end
337
+
338
+ end
339
+
340
+ ###
341
+ #
342
+ # Group TLVs contain zero or more TLVs
343
+ #
344
+ ###
345
+ class GroupTlv < Tlv
346
+ attr_accessor :tlvs
347
+
348
+ ##
349
+ #
350
+ # Constructor
351
+ #
352
+ ##
353
+
354
+ #
355
+ # Initializes the group TLV container to the supplied type
356
+ # and creates an empty TLV array.
357
+ #
358
+ def initialize(type)
359
+ super(type)
360
+
361
+ self.tlvs = [ ]
362
+ end
363
+
364
+ ##
365
+ #
366
+ # Group-based TLV accessors
367
+ #
368
+ ##
369
+
370
+ #
371
+ # Enumerates TLVs of the supplied type.
372
+ #
373
+ def each(type = TLV_TYPE_ANY, &block)
374
+ get_tlvs(type).each(&block)
375
+ end
376
+
377
+ #
378
+ # Synonym for each.
379
+ #
380
+ def each_tlv(type = TLV_TYPE_ANY, &block)
381
+ each(type, &block)
382
+ end
383
+
384
+ #
385
+ # Enumerates TLVs of a supplied type with indexes.
386
+ #
387
+ def each_with_index(type = TLV_TYPE_ANY, &block)
388
+ get_tlvs(type).each_with_index(&block)
389
+ end
390
+
391
+ #
392
+ # Synonym for each_with_index.
393
+ #
394
+ def each_tlv_with_index(type = TLV_TYPE_ANY, &block)
395
+ each_with_index(type, block)
396
+ end
397
+
398
+ #
399
+ # Returns an array of TLVs for the given type.
400
+ #
401
+ def get_tlvs(type)
402
+ if (type == TLV_TYPE_ANY)
403
+ return self.tlvs
404
+ else
405
+ type_tlvs = []
406
+
407
+ self.tlvs.each() { |tlv|
408
+ if (tlv.type?(type))
409
+ type_tlvs << tlv
410
+ end
411
+ }
412
+
413
+ return type_tlvs
414
+ end
415
+ end
416
+
417
+ ##
418
+ #
419
+ # TLV management
420
+ #
421
+ ##
422
+
423
+ #
424
+ # Adds a TLV of a given type and value.
425
+ #
426
+ def add_tlv(type, value = nil, replace = false, compress=false)
427
+
428
+ # If we should replace any TLVs with the same type...remove them first
429
+ if (replace)
430
+ each(type) { |tlv|
431
+ if (tlv.type == type)
432
+ self.tlvs.delete(tlv)
433
+ end
434
+ }
435
+ end
436
+
437
+ if (type & TLV_META_TYPE_GROUP == TLV_META_TYPE_GROUP)
438
+ tlv = GroupTlv.new(type)
439
+ else
440
+ tlv = Tlv.new(type, value, compress)
441
+ end
442
+
443
+ self.tlvs << tlv
444
+
445
+ return tlv
446
+ end
447
+
448
+ #
449
+ # Adds zero or more TLVs to the packet.
450
+ #
451
+ def add_tlvs(tlvs)
452
+ if (tlvs != nil)
453
+ tlvs.each { |tlv|
454
+ add_tlv(tlv['type'], tlv['value'])
455
+ }
456
+ end
457
+ end
458
+
459
+ #
460
+ # Gets the first TLV of a given type.
461
+ #
462
+ def get_tlv(type, index = 0)
463
+ type_tlvs = get_tlvs(type)
464
+
465
+ if (type_tlvs.length > index)
466
+ return type_tlvs[index]
467
+ end
468
+
469
+ return nil
470
+ end
471
+
472
+ #
473
+ # Returns the value of a TLV if it exists, otherwise nil.
474
+ #
475
+ def get_tlv_value(type, index = 0)
476
+ tlv = get_tlv(type, index)
477
+
478
+ return (tlv != nil) ? tlv.value : nil
479
+ end
480
+
481
+ #
482
+ # Returns an array of values for all tlvs of type type.
483
+ #
484
+ def get_tlv_values(type)
485
+ get_tlvs(type).collect { |a| a.value }
486
+ end
487
+
488
+ #
489
+ # Checks to see if the container has a TLV of a given type.
490
+ #
491
+ def has_tlv?(type)
492
+ return get_tlv(type) != nil
493
+ end
494
+
495
+ #
496
+ # Zeros out the array of TLVs.
497
+ #
498
+ def reset
499
+ self.tlvs = []
500
+ end
501
+
502
+ ##
503
+ #
504
+ # Serializers
505
+ #
506
+ ##
507
+
508
+ #
509
+ # Converts all of the TLVs in the TLV array to raw and prefixes them
510
+ # with a container TLV of this instance's TLV type.
511
+ #
512
+ def to_r
513
+ raw = ''
514
+
515
+ self.each() { |tlv|
516
+ raw << tlv.to_r
517
+ }
518
+
519
+ return [raw.length + 8, self.type].pack("NN") + raw
520
+ end
521
+
522
+ #
523
+ # Converts the TLV group container from raw to all of the individual
524
+ # TLVs.
525
+ #
526
+ def from_r(raw)
527
+ offset = 8
528
+
529
+ # Reset the TLVs array
530
+ self.tlvs = []
531
+ self.type = raw.unpack("NN")[1]
532
+
533
+ # Enumerate all of the TLVs
534
+ while (offset < raw.length-1)
535
+
536
+ tlv = nil
537
+
538
+ # Get the length and type
539
+ length, type = raw[offset..offset+8].unpack("NN")
540
+
541
+ if (type & TLV_META_TYPE_GROUP == TLV_META_TYPE_GROUP)
542
+ tlv = GroupTlv.new(type)
543
+ else
544
+ tlv = Tlv.new(type)
545
+ end
546
+
547
+ tlv.from_r(raw[offset..offset+length])
548
+
549
+ # Insert it into the list of TLVs
550
+ tlvs << tlv
551
+
552
+ # Move up
553
+ offset += length
554
+ end
555
+ end
556
+
557
+ end
558
+
559
+ ###
560
+ #
561
+ # The logical meterpreter packet class
562
+ #
563
+ ###
564
+ class Packet < GroupTlv
565
+ attr_accessor :created_at
566
+
567
+ ##
568
+ #
569
+ # Factory
570
+ #
571
+ ##
572
+
573
+ #
574
+ # Creates a request with the supplied method.
575
+ #
576
+ def Packet.create_request(method = nil)
577
+ return Packet.new(PACKET_TYPE_REQUEST, method)
578
+ end
579
+
580
+ #
581
+ # Creates a response to a request if one is provided.
582
+ #
583
+ def Packet.create_response(request = nil)
584
+ response_type = PACKET_TYPE_RESPONSE
585
+ method = nil
586
+
587
+ if (request)
588
+ if (request.type?(PACKET_TYPE_PLAIN_REQUEST))
589
+ response_type = PACKET_TYPE_PLAIN_RESPONSE
590
+ end
591
+
592
+ method = request.method
593
+ end
594
+
595
+ return Packet.new(response_type, method)
596
+ end
597
+
598
+ ##
599
+ #
600
+ # Constructor
601
+ #
602
+ ##
603
+
604
+ #
605
+ # Initializes the packet to the supplied packet type and method,
606
+ # if any. If the packet is a request, a request identifier is
607
+ # created.
608
+ #
609
+ def initialize(type = nil, method = nil)
610
+ super(type)
611
+
612
+ if (method)
613
+ self.method = method
614
+ end
615
+
616
+ self.created_at = ::Time.now
617
+
618
+ # If it's a request, generate a random request identifier
619
+ if ((type == PACKET_TYPE_REQUEST) ||
620
+ (type == PACKET_TYPE_PLAIN_REQUEST))
621
+ rid = ''
622
+
623
+ 32.times { |val| rid << rand(10).to_s }
624
+
625
+ add_tlv(TLV_TYPE_REQUEST_ID, rid)
626
+ end
627
+ end
628
+
629
+ #
630
+ # Override the function that creates the raw byte stream for
631
+ # sending so that it generates an XOR key, uses it to scramble
632
+ # the serialized TLV content, and then returns the key plus the
633
+ # scrambled data as the payload.
634
+ #
635
+ def to_r
636
+ raw = super
637
+ xor_key = rand(254) + 1
638
+ xor_key |= (rand(254) + 1) << 8
639
+ xor_key |= (rand(254) + 1) << 16
640
+ xor_key |= (rand(254) + 1) << 24
641
+ result = [xor_key].pack('N') + xor_bytes(xor_key, raw)
642
+ result
643
+ end
644
+
645
+ #
646
+ # Override the function that reads from a raw byte stream so
647
+ # that the XORing of data is included in the process prior to
648
+ # passing it on to the default functionality that can parse
649
+ # the TLV values.
650
+ #
651
+ def from_r(bytes)
652
+ xor_key = bytes[0,4].unpack('N')[0]
653
+ super(xor_bytes(xor_key, bytes[4, bytes.length]))
654
+ end
655
+
656
+ #
657
+ # Xor a set of bytes with a given DWORD xor key.
658
+ #
659
+ def xor_bytes(xor_key, bytes)
660
+ result = ''
661
+ bytes.bytes.zip([xor_key].pack('V').bytes.cycle).each do |b|
662
+ result << (b[0].ord ^ b[1].ord).chr
663
+ end
664
+ result
665
+ end
666
+
667
+ ##
668
+ #
669
+ # Conditionals
670
+ #
671
+ ##
672
+
673
+ #
674
+ # Checks to see if the packet is a response.
675
+ #
676
+ def response?
677
+ return ((self.type == PACKET_TYPE_RESPONSE) ||
678
+ (self.type == PACKET_TYPE_PLAIN_RESPONSE))
679
+ end
680
+
681
+ ##
682
+ #
683
+ # Accessors
684
+ #
685
+ ##
686
+
687
+ #
688
+ # Checks to see if the packet's method is equal to the supplied method.
689
+ #
690
+ def method?(method)
691
+ return (get_tlv_value(TLV_TYPE_METHOD) == method)
692
+ end
693
+
694
+ #
695
+ # Sets the packet's method TLV to the method supplied.
696
+ #
697
+ def method=(method)
698
+ add_tlv(TLV_TYPE_METHOD, method, true)
699
+ end
700
+
701
+ #
702
+ # Returns the value of the packet's method TLV.
703
+ #
704
+ def method
705
+ return get_tlv_value(TLV_TYPE_METHOD)
706
+ end
707
+
708
+ #
709
+ # Checks to see if the packet's result value is equal to the supplied
710
+ # result.
711
+ #
712
+ def result?(result)
713
+ return (get_tlv_value(TLV_TYPE_RESULT) == result)
714
+ end
715
+
716
+ #
717
+ # Sets the packet's result TLV.
718
+ #
719
+ def result=(result)
720
+ add_tlv(TLV_TYPE_RESULT, result, true)
721
+ end
722
+
723
+ #
724
+ # Gets the value of the packet's result TLV.
725
+ #
726
+ def result
727
+ return get_tlv_value(TLV_TYPE_RESULT)
728
+ end
729
+
730
+ #
731
+ # Gets the value of the packet's request identifier TLV.
732
+ #
733
+ def rid
734
+ return get_tlv_value(TLV_TYPE_REQUEST_ID)
735
+ end
736
+ end
737
+
738
+
739
+ end; end; end
740
+