metasploit-aggregator 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
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
+