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/lib/rex/post/meterpreter/packet.rb
Views: 1904
1
# -*- coding: binary -*-
2
require 'openssl'
3
require 'rex/post/meterpreter/command_mapper'
4
5
module Rex
6
module Post
7
module Meterpreter
8
9
#
10
# Constants
11
#
12
PACKET_TYPE_REQUEST = 0
13
PACKET_TYPE_RESPONSE = 1
14
PACKET_TYPE_PLAIN_REQUEST = 10
15
PACKET_TYPE_PLAIN_RESPONSE = 11
16
17
#
18
# TLV Meta Types
19
#
20
TLV_META_TYPE_NONE = 0
21
TLV_META_TYPE_STRING = (1 << 16)
22
TLV_META_TYPE_UINT = (1 << 17)
23
TLV_META_TYPE_RAW = (1 << 18)
24
TLV_META_TYPE_BOOL = (1 << 19)
25
TLV_META_TYPE_QWORD = (1 << 20)
26
TLV_META_TYPE_COMPRESSED = (1 << 29)
27
TLV_META_TYPE_GROUP = (1 << 30)
28
TLV_META_TYPE_COMPLEX = (1 << 31)
29
30
# Exclude compressed from the mask since other meta types (e.g. RAW) can also
31
# be compressed
32
TLV_META_MASK = (
33
TLV_META_TYPE_STRING |
34
TLV_META_TYPE_UINT |
35
TLV_META_TYPE_RAW |
36
TLV_META_TYPE_BOOL |
37
TLV_META_TYPE_QWORD |
38
TLV_META_TYPE_GROUP |
39
TLV_META_TYPE_COMPLEX
40
)
41
42
#
43
# TLV base starting points
44
#
45
TLV_RESERVED = 0
46
TLV_EXTENSIONS = 20000
47
TLV_USER = 40000
48
TLV_TEMP = 60000
49
50
#
51
# TLV Specific Types
52
#
53
TLV_TYPE_ANY = TLV_META_TYPE_NONE | 0
54
TLV_TYPE_COMMAND_ID = TLV_META_TYPE_UINT | 1
55
TLV_TYPE_REQUEST_ID = TLV_META_TYPE_STRING | 2
56
TLV_TYPE_EXCEPTION = TLV_META_TYPE_GROUP | 3
57
TLV_TYPE_RESULT = TLV_META_TYPE_UINT | 4
58
59
60
TLV_TYPE_STRING = TLV_META_TYPE_STRING | 10
61
TLV_TYPE_UINT = TLV_META_TYPE_UINT | 11
62
TLV_TYPE_BOOL = TLV_META_TYPE_BOOL | 12
63
64
TLV_TYPE_LENGTH = TLV_META_TYPE_UINT | 25
65
TLV_TYPE_DATA = TLV_META_TYPE_RAW | 26
66
TLV_TYPE_FLAGS = TLV_META_TYPE_UINT | 27
67
68
TLV_TYPE_CHANNEL_ID = TLV_META_TYPE_UINT | 50
69
TLV_TYPE_CHANNEL_TYPE = TLV_META_TYPE_STRING | 51
70
TLV_TYPE_CHANNEL_DATA = TLV_META_TYPE_RAW | 52
71
TLV_TYPE_CHANNEL_DATA_GROUP = TLV_META_TYPE_GROUP | 53
72
TLV_TYPE_CHANNEL_CLASS = TLV_META_TYPE_UINT | 54
73
TLV_TYPE_CHANNEL_PARENTID = TLV_META_TYPE_UINT | 55
74
75
TLV_TYPE_SEEK_WHENCE = TLV_META_TYPE_UINT | 70
76
TLV_TYPE_SEEK_OFFSET = TLV_META_TYPE_UINT | 71
77
TLV_TYPE_SEEK_POS = TLV_META_TYPE_UINT | 72
78
79
TLV_TYPE_EXCEPTION_CODE = TLV_META_TYPE_UINT | 300
80
TLV_TYPE_EXCEPTION_STRING = TLV_META_TYPE_STRING | 301
81
82
TLV_TYPE_LIBRARY_PATH = TLV_META_TYPE_STRING | 400
83
TLV_TYPE_TARGET_PATH = TLV_META_TYPE_STRING | 401
84
TLV_TYPE_MIGRATE_PID = TLV_META_TYPE_UINT | 402
85
TLV_TYPE_MIGRATE_PAYLOAD = TLV_META_TYPE_RAW | 404
86
TLV_TYPE_MIGRATE_ARCH = TLV_META_TYPE_UINT | 405
87
TLV_TYPE_MIGRATE_BASE_ADDR = TLV_META_TYPE_UINT | 407
88
TLV_TYPE_MIGRATE_ENTRY_POINT = TLV_META_TYPE_UINT | 408
89
TLV_TYPE_MIGRATE_SOCKET_PATH = TLV_META_TYPE_STRING | 409
90
TLV_TYPE_MIGRATE_STUB = TLV_META_TYPE_RAW | 411
91
TLV_TYPE_LIB_LOADER_NAME = TLV_META_TYPE_STRING | 412
92
TLV_TYPE_LIB_LOADER_ORDINAL = TLV_META_TYPE_UINT | 413
93
94
TLV_TYPE_TRANS_TYPE = TLV_META_TYPE_UINT | 430
95
TLV_TYPE_TRANS_URL = TLV_META_TYPE_STRING | 431
96
TLV_TYPE_TRANS_UA = TLV_META_TYPE_STRING | 432
97
TLV_TYPE_TRANS_COMM_TIMEOUT = TLV_META_TYPE_UINT | 433
98
TLV_TYPE_TRANS_SESSION_EXP = TLV_META_TYPE_UINT | 434
99
TLV_TYPE_TRANS_CERT_HASH = TLV_META_TYPE_RAW | 435
100
TLV_TYPE_TRANS_PROXY_HOST = TLV_META_TYPE_STRING | 436
101
TLV_TYPE_TRANS_PROXY_USER = TLV_META_TYPE_STRING | 437
102
TLV_TYPE_TRANS_PROXY_PASS = TLV_META_TYPE_STRING | 438
103
TLV_TYPE_TRANS_RETRY_TOTAL = TLV_META_TYPE_UINT | 439
104
TLV_TYPE_TRANS_RETRY_WAIT = TLV_META_TYPE_UINT | 440
105
TLV_TYPE_TRANS_HEADERS = TLV_META_TYPE_STRING | 441
106
TLV_TYPE_TRANS_GROUP = TLV_META_TYPE_GROUP | 442
107
108
TLV_TYPE_MACHINE_ID = TLV_META_TYPE_STRING | 460
109
TLV_TYPE_UUID = TLV_META_TYPE_RAW | 461
110
TLV_TYPE_SESSION_GUID = TLV_META_TYPE_RAW | 462
111
112
TLV_TYPE_RSA_PUB_KEY = TLV_META_TYPE_RAW | 550
113
TLV_TYPE_SYM_KEY_TYPE = TLV_META_TYPE_UINT | 551
114
TLV_TYPE_SYM_KEY = TLV_META_TYPE_RAW | 552
115
TLV_TYPE_ENC_SYM_KEY = TLV_META_TYPE_RAW | 553
116
117
#
118
# Pivots
119
#
120
TLV_TYPE_PIVOT_ID = TLV_META_TYPE_RAW | 650
121
TLV_TYPE_PIVOT_STAGE_DATA = TLV_META_TYPE_RAW | 651
122
TLV_TYPE_PIVOT_NAMED_PIPE_NAME = TLV_META_TYPE_STRING | 653
123
124
125
#
126
# Core flags
127
#
128
LOAD_LIBRARY_FLAG_ON_DISK = (1 << 0)
129
LOAD_LIBRARY_FLAG_EXTENSION = (1 << 1)
130
LOAD_LIBRARY_FLAG_LOCAL = (1 << 2)
131
132
#
133
# Sane defaults
134
#
135
GUID_SIZE = 16
136
NULL_GUID = "\x00" * GUID_SIZE
137
138
def self.generate_command_id_map_c
139
id_map = CommandMapper.get_commands(*%w{
140
core
141
stdapi
142
priv
143
extapi
144
sniffer
145
winpmem
146
kiwi
147
unhook
148
espia
149
incognito
150
python
151
powershell
152
lanattacks
153
peinjector
154
})
155
156
command_ids = id_map.map {|k, v| "#define COMMAND_ID_#{k.upcase} #{v}"}
157
%Q^
158
/*!
159
* @file common_command_ids.h
160
* @brief Declarations of command ID values
161
* @description This file was generated #{::Time.now.utc}. Do not modify directly.
162
*/
163
#ifndef _METERPRETER_SOURCE_COMMON_COMMAND_IDS_H
164
#define _METERPRETER_SOURCE_COMMON_COMMAND_IDS_H
165
166
#{command_ids.join("\n")}
167
168
#endif
169
^
170
end
171
172
def self.generate_command_id_map_java
173
id_map = CommandMapper.get_commands(*%w{ core stdapi })
174
command_ids = id_map.map {|k, v| " public static final int #{k.upcase} = #{v};"}
175
%Q^
176
package com.metasploit.meterpreter.command;
177
178
/**
179
* All supported Command Identifiers
180
*
181
* @author Generated by a tool @ #{::Time.now.utc}
182
*/
183
public interface CommandId {
184
#{command_ids.join("\n")}
185
}
186
^
187
end
188
189
def self.generate_command_id_map_php_lib(lib, id_map)
190
command_ids = id_map.map {|k, v| "define('COMMAND_ID_#{k.upcase}', #{v});"}
191
%Q^
192
# ---------------------------------------------------------------
193
# --- THIS CONTENT WAS GENERATED BY A TOOL @ #{::Time.now.utc}
194
# IDs for #{lib}
195
#{command_ids.join("\n")}
196
# ---------------------------------------------------------------
197
^
198
end
199
200
def self.generate_command_id_map_php
201
%Q^
202
#{self.generate_command_id_map_php_lib('metsrv', CommandMapper.get_commands('core'))}
203
204
#{self.generate_command_id_map_php_lib('stdapi', CommandMapper.get_commands('stdapi'))}
205
^
206
end
207
208
def self.generate_command_id_map_python
209
id_map = CommandMapper.get_commands(*%w{ core stdapi })
210
command_ids = id_map.map {|k, v| " (#{v}, '#{k.downcase}'),"}
211
%Q^
212
# ---------------------------------------------------------------
213
# --- THIS CONTENT WAS GENERATED BY A TOOL @ #{::Time.now.utc}
214
COMMAND_IDS = (
215
#{command_ids.join("\n")}
216
)
217
# ---------------------------------------------------------------
218
^
219
end
220
221
def self.generate_command_id_map_python_extension
222
id_map = CommandMapper.get_commands(*%w{
223
core
224
stdapi
225
priv
226
extapi
227
sniffer
228
winpmem
229
kiwi
230
unhook
231
espia
232
incognito
233
python
234
powershell
235
lanattacks
236
peinjector
237
})
238
command_ids = id_map.map {|k, v| "COMMAND_ID_#{k.upcase} = #{v}"}
239
%Q^
240
# ---------------------------------------------------------------
241
# --- THIS CONTENT WAS GENERATED BY A TOOL @ #{::Time.now.utc}
242
243
#{command_ids.join("\n")}
244
245
# ---------------------------------------------------------------
246
^
247
end
248
249
def self.generate_command_id_map_csharp
250
id_map = CommandMapper.get_commands(*%w{
251
core
252
stdapi
253
priv
254
extapi
255
sniffer
256
winpmem
257
kiwi
258
unhook
259
espia
260
incognito
261
python
262
powershell
263
lanattacks
264
peinjector
265
})
266
command_ids = id_map.map {|k, v| "#{k.split('_').map(&:capitalize).join} = #{v},"}
267
%Q^
268
/// <summary>
269
// This content was generated by a tool @ #{::Time.now.utc}
270
/// </summary>
271
namespace MSF.Powershell.Meterpreter
272
{
273
public enum CommandId
274
{
275
#{command_ids.join("\n ")}
276
}
277
}
278
^
279
end
280
281
###
282
#
283
# Base TLV (Type-Length-Value) class
284
#
285
###
286
class Tlv
287
attr_accessor :type, :value, :compress
288
289
HEADER_SIZE = 8
290
291
##
292
#
293
# Constructor
294
#
295
##
296
297
#
298
# Returns an instance of a TLV.
299
#
300
def initialize(type, value = nil, compress=false)
301
@type = type
302
@compress = compress
303
304
if (value != nil)
305
if (type & TLV_META_TYPE_STRING == TLV_META_TYPE_STRING)
306
if (value.kind_of?(Integer))
307
@value = value.to_s
308
else
309
@value = value.dup
310
end
311
else
312
@value = value
313
end
314
end
315
end
316
317
def _tlv_type_string(value)
318
tlv_names = ::Rex::Post::Meterpreter::CommandMapper.get_tlv_names(value).map { |name| name.to_s.gsub('TLV_TYPE_', '').gsub('PACKET_TYPE_', '') }
319
320
case tlv_names.length
321
when 0
322
"unknown-#{value}"
323
when 1
324
tlv_names.first
325
else
326
# In the off-chance we have multiple TLV types which have the same value
327
# https://github.com/rapid7/metasploit-framework/issues/16267
328
# Sort it to ensure consistency across tests
329
"oneOf(#{tlv_names.sort_by(&:to_s).join(',')})"
330
end
331
end
332
333
def inspect
334
utype = type ^ TLV_META_TYPE_COMPRESSED
335
group = false
336
meta = case (utype & TLV_META_MASK)
337
when TLV_META_TYPE_STRING; "STRING"
338
when TLV_META_TYPE_UINT; "INT"
339
when TLV_META_TYPE_RAW; "RAW"
340
when TLV_META_TYPE_BOOL; "BOOL"
341
when TLV_META_TYPE_QWORD; "QWORD"
342
when TLV_META_TYPE_GROUP; group=true; "GROUP"
343
when TLV_META_TYPE_COMPLEX; "COMPLEX"
344
else; 'unknown-meta-type'
345
end
346
347
stype = case type
348
when PACKET_TYPE_REQUEST; 'Request'
349
when PACKET_TYPE_RESPONSE; 'Response'
350
else; _tlv_type_string(type)
351
end
352
353
group ||= (self.class.to_s =~ /Packet/)
354
if group
355
has_command_ids = type == PACKET_TYPE_RESPONSE && (self.method == COMMAND_ID_CORE_ENUMEXTCMD || self.method == COMMAND_ID_CORE_LOADLIB)
356
if has_command_ids
357
longest_command_id = self.get_tlvs(TLV_TYPE_UINT).map(&:value).max
358
longest_command_id_length = longest_command_id.to_s.length
359
end
360
361
tlvs_inspect = "tlvs=[\n"
362
@tlvs.each { |t|
363
if t.type == TLV_TYPE_UINT && has_command_ids && longest_command_id_length
364
command_name = ::Rex::Post::Meterpreter::CommandMapper.get_command_name(t.value)
365
command_output = "command=#{command_name}>\n"
366
this_value_length = t.value.to_s.length
367
adjusted_command_name = command_output.rjust(command_output.length + longest_command_id_length - this_value_length)
368
tlvs_inspect << " #{t.inspect.gsub(/>$/, '')} " << adjusted_command_name
369
else
370
tlvs_inspect << " #{t.inspect}\n"
371
end
372
}
373
tlvs_inspect << "]"
374
else
375
val = value.inspect
376
# Known list of datatypes that shouldn't be truncated, as their values are useful when debugging
377
is_val_truncation_allowed = ![
378
Rex::Post::Meterpreter::TLV_TYPE_UUID,
379
Rex::Post::Meterpreter::Extensions::Priv::TLV_TYPE_FS_FILE_PATH,
380
Rex::Post::Meterpreter::Extensions::Priv::TLV_TYPE_FS_SRC_FILE_PATH,
381
Rex::Post::Meterpreter::Extensions::Stdapi::TLV_TYPE_FILE_PATH,
382
Rex::Post::Meterpreter::Extensions::Stdapi::TLV_TYPE_DIRECTORY_PATH,
383
Rex::Post::Meterpreter::Extensions::Stdapi::TLV_TYPE_STAT_BUF,
384
Rex::Post::Meterpreter::Extensions::Stdapi::TLV_TYPE_PROCESS_PATH,
385
].include?(type)
386
if is_val_truncation_allowed && val.length > 50
387
val = val[0,50] + ' ..."'
388
end
389
tlvs_inspect = "meta=#{meta.ljust(10)} value=#{val}"
390
if type == TLV_TYPE_COMMAND_ID
391
begin
392
command_name = ::Rex::Post::Meterpreter::CommandMapper.get_command_name(value)
393
rescue
394
command_name = nil
395
end
396
tlvs_inspect <<= " command=#{command_name || 'unknown'}"
397
end
398
end
399
"#<#{self.class} type=#{stype.ljust(15)} #{tlvs_inspect}>"
400
end
401
402
##
403
#
404
# Conditionals
405
#
406
##
407
408
#
409
# Checks to see if a TLVs meta type is equivalent to the meta type passed.
410
#
411
def meta_type?(meta)
412
return (self.type & meta == meta)
413
end
414
415
#
416
# Checks to see if the TLVs type is equivalent to the type passed.
417
#
418
def type?(type)
419
return self.type == type
420
end
421
422
#
423
# Checks to see if the TLVs value is equivalent to the value passed.
424
#
425
def value?(value)
426
return self.value == value
427
end
428
429
##
430
#
431
# Serializers
432
#
433
##
434
435
#
436
# Converts the TLV to raw.
437
#
438
def to_r
439
# Forcibly convert to ASCII-8BIT encoding
440
raw = value.to_s.unpack("C*").pack("C*")
441
442
if (self.type & TLV_META_TYPE_STRING == TLV_META_TYPE_STRING)
443
raw += "\x00"
444
elsif (self.type & TLV_META_TYPE_UINT == TLV_META_TYPE_UINT)
445
raw = [value].pack("N")
446
elsif (self.type & TLV_META_TYPE_QWORD == TLV_META_TYPE_QWORD)
447
raw = [ self.htonq( value.to_i ) ].pack("Q<")
448
elsif (self.type & TLV_META_TYPE_BOOL == TLV_META_TYPE_BOOL)
449
if (value == true)
450
raw = [1].pack("c")
451
else
452
raw = [0].pack("c")
453
end
454
end
455
456
# check if the tlv is to be compressed...
457
if @compress
458
raw_uncompressed = raw
459
# compress the raw data
460
raw_compressed = Rex::Text.zlib_deflate( raw_uncompressed )
461
# check we have actually made the raw data smaller...
462
# (small blobs often compress slightly larger then the original)
463
# if the compressed data is not smaller, we dont use the compressed data
464
if( raw_compressed.length < raw_uncompressed.length )
465
# if so, set the TLV's type to indicate compression is used
466
self.type = self.type | TLV_META_TYPE_COMPRESSED
467
# update the raw data with the uncompressed data length + compressed data
468
# (we include the uncompressed data length as the C side will need to know this for decompression)
469
raw = [ raw_uncompressed.length ].pack("N") + raw_compressed
470
end
471
end
472
473
[raw.length + HEADER_SIZE, self.type].pack("NN") + raw
474
end
475
476
#
477
# Translates the raw format of the TLV into a sanitize version.
478
#
479
def from_r(raw)
480
self.value = nil
481
482
length, self.type = raw.unpack("NN");
483
484
# check if the tlv value has been compressed...
485
if( self.type & TLV_META_TYPE_COMPRESSED == TLV_META_TYPE_COMPRESSED )
486
# set this TLV as using compression
487
@compress = true
488
# remove the TLV_META_TYPE_COMPRESSED flag from the tlv type to restore the
489
# tlv type to its original, allowing for transparent data compression.
490
self.type = self.type ^ TLV_META_TYPE_COMPRESSED
491
# decompress the compressed data (skipping the length and type DWORD's)
492
raw_decompressed = Rex::Text.zlib_inflate( raw[HEADER_SIZE..length-1] )
493
# update the length to reflect the decompressed data length (+HEADER_SIZE for the length and type DWORD's)
494
length = raw_decompressed.length + HEADER_SIZE
495
# update the raw buffer with the new length, decompressed data and updated type.
496
raw = [length, self.type].pack("NN") + raw_decompressed
497
end
498
499
if (self.type & TLV_META_TYPE_STRING == TLV_META_TYPE_STRING)
500
if (raw.length > 0)
501
self.value = raw[HEADER_SIZE..length-2]
502
else
503
self.value = nil
504
end
505
elsif (self.type & TLV_META_TYPE_UINT == TLV_META_TYPE_UINT)
506
self.value = raw.unpack("NNN")[2]
507
elsif (self.type & TLV_META_TYPE_QWORD == TLV_META_TYPE_QWORD)
508
self.value = raw.unpack("NNQ<")[2]
509
self.value = self.ntohq( self.value )
510
elsif (self.type & TLV_META_TYPE_BOOL == TLV_META_TYPE_BOOL)
511
self.value = raw.unpack("NNc")[2]
512
513
if (self.value == 1)
514
self.value = true
515
else
516
self.value = false
517
end
518
else
519
self.value = raw[HEADER_SIZE..length-1]
520
end
521
522
length
523
end
524
525
protected
526
527
def htonq(value)
528
if [1].pack( 's' ) == [1].pack('n')
529
return value
530
else
531
[value].pack('Q<').reverse.unpack('Q<').first
532
end
533
end
534
535
def ntohq(value)
536
htonq(value)
537
end
538
539
end
540
541
###
542
#
543
# Group TLVs contain zero or more TLVs
544
#
545
###
546
class GroupTlv < Tlv
547
attr_accessor :tlvs
548
549
##
550
#
551
# Constructor
552
#
553
##
554
555
#
556
# Initializes the group TLV container to the supplied type
557
# and creates an empty TLV array.
558
#
559
def initialize(type)
560
super(type)
561
562
self.tlvs = []
563
end
564
565
##
566
#
567
# Group-based TLV accessors
568
#
569
##
570
571
#
572
# Enumerates TLVs of the supplied type.
573
#
574
def each(type = TLV_TYPE_ANY, &block)
575
get_tlvs(type).each(&block)
576
end
577
578
#
579
# Synonym for each.
580
#
581
def each_tlv(type = TLV_TYPE_ANY, &block)
582
each(type, &block)
583
end
584
585
#
586
# Enumerates TLVs of a supplied type with indexes.
587
#
588
def each_with_index(type = TLV_TYPE_ANY, &block)
589
get_tlvs(type).each_with_index(&block)
590
end
591
592
#
593
# Synonym for each_with_index.
594
#
595
def each_tlv_with_index(type = TLV_TYPE_ANY, &block)
596
each_with_index(type, block)
597
end
598
599
#
600
# Returns an array of TLVs for the given type.
601
#
602
def get_tlvs(type)
603
if type == TLV_TYPE_ANY
604
self.tlvs
605
else
606
type_tlvs = []
607
608
self.tlvs.each() { |tlv|
609
if (tlv.type?(type))
610
type_tlvs << tlv
611
end
612
}
613
614
type_tlvs
615
end
616
end
617
618
##
619
#
620
# TLV management
621
#
622
##
623
624
#
625
# Adds a TLV of a given type and value.
626
#
627
def add_tlv(type, value = nil, replace = false, compress=false)
628
629
# If we should replace any TLVs with the same type...remove them first
630
if replace
631
each(type) { |tlv|
632
if (tlv.type == type)
633
self.tlvs.delete(tlv)
634
end
635
}
636
end
637
638
if (type & TLV_META_TYPE_GROUP == TLV_META_TYPE_GROUP)
639
tlv = GroupTlv.new(type)
640
else
641
tlv = Tlv.new(type, value, compress)
642
end
643
644
self.tlvs << tlv
645
646
tlv
647
end
648
649
#
650
# Adds zero or more TLVs to the packet.
651
#
652
def add_tlvs(tlvs)
653
if tlvs
654
tlvs.each { |tlv|
655
add_tlv(tlv['type'], tlv['value'])
656
}
657
end
658
end
659
660
#
661
# Gets the first TLV of a given type.
662
#
663
def get_tlv(type, index = 0)
664
type_tlvs = get_tlvs(type)
665
666
if type_tlvs.length > index
667
type_tlvs[index]
668
else
669
nil
670
end
671
672
end
673
674
#
675
# Returns the value of a TLV if it exists, otherwise nil.
676
#
677
def get_tlv_value(type, index = 0)
678
tlv = get_tlv(type, index)
679
680
(tlv != nil) ? tlv.value : nil
681
end
682
683
#
684
# Returns an array of values for all tlvs of type type.
685
#
686
def get_tlv_values(type)
687
get_tlvs(type).collect { |a| a.value }
688
end
689
690
#
691
# Checks to see if the container has a TLV of a given type.
692
#
693
def has_tlv?(type)
694
get_tlv(type) != nil
695
end
696
697
#
698
# Zeros out the array of TLVs.
699
#
700
def reset
701
self.tlvs = []
702
end
703
704
##
705
#
706
# Serializers
707
#
708
##
709
710
#
711
# Converts all of the TLVs in the TLV array to raw and prefixes them
712
# with a container TLV of this instance's TLV type.
713
#
714
def to_r
715
raw = ''
716
717
self.each() { |tlv|
718
raw << tlv.to_r
719
}
720
721
[raw.length + HEADER_SIZE, self.type].pack("NN") + raw
722
end
723
724
#
725
# Converts the TLV group container from raw to all of the individual
726
# TLVs.
727
#
728
def from_r(raw)
729
offset = HEADER_SIZE
730
731
# Reset the TLVs array
732
self.tlvs = []
733
self.type = raw.unpack("NN")[1]
734
735
# Enumerate all of the TLVs
736
while offset < raw.length-1
737
738
tlv = nil
739
740
# Get the length and type
741
length, type = raw[offset..offset+HEADER_SIZE].unpack("NN")
742
743
if (type & TLV_META_TYPE_GROUP == TLV_META_TYPE_GROUP)
744
tlv = GroupTlv.new(type)
745
else
746
tlv = Tlv.new(type)
747
end
748
749
tlv.from_r(raw[offset..offset+length])
750
751
# Insert it into the list of TLVs
752
tlvs << tlv
753
754
# Move up
755
offset += length
756
end
757
end
758
759
end
760
761
###
762
#
763
# The logical meterpreter packet class
764
#
765
###
766
class Packet < GroupTlv
767
attr_accessor :created_at
768
attr_accessor :raw
769
attr_accessor :session_guid
770
attr_accessor :encrypt_flags
771
attr_accessor :length
772
773
##
774
#
775
# The Packet container itself has a custom header that is slightly different than the
776
# typical TLV packets. The header contains the following:
777
#
778
# XOR KEY - 4 bytes
779
# Session GUID - 16 bytes
780
# Encrypt flags - 4 bytes
781
# Packet length - 4 bytes
782
# Packet type - 4 bytes
783
# Packet data - X bytes
784
#
785
# If the encrypt flags are zero, then the Packet data is just straight TLV values as
786
# per the normal TLV packet structure.
787
#
788
# If the encrypt flags are non-zer, then the Packet data is encrypted based on the scheme.
789
#
790
# Flag == 1 (AES256)
791
# IV - 16 bytes
792
# Encrypted data - X bytes
793
#
794
# The key that is required to decrypt the data is stored alongside the session data,
795
# and hence when the packet is initially parsed, only the header is accessed. The
796
# packet itself will need to be decrypted on the fly at the point that it is required
797
# and at that point the decryption key needs to be provided.
798
#
799
###
800
801
XOR_KEY_SIZE = 4
802
ENCRYPTED_FLAGS_SIZE = 4
803
PACKET_LENGTH_SIZE = 4
804
PACKET_TYPE_SIZE = 4
805
PACKET_HEADER_SIZE = XOR_KEY_SIZE + GUID_SIZE + ENCRYPTED_FLAGS_SIZE + PACKET_LENGTH_SIZE + PACKET_TYPE_SIZE
806
807
AES_IV_SIZE = 16
808
809
ENC_FLAG_NONE = 0x0
810
ENC_FLAG_AES256 = 0x1
811
ENC_FLAG_AES128 = 0x2
812
813
##
814
#
815
# Factory
816
#
817
##
818
819
#
820
# Creates a request with the supplied method.
821
#
822
def Packet.create_request(method = nil)
823
Packet.new(PACKET_TYPE_REQUEST, method)
824
end
825
826
#
827
# Creates a response to a request if one is provided.
828
#
829
def Packet.create_response(request = nil)
830
response_type = PACKET_TYPE_RESPONSE
831
method = nil
832
id = nil
833
834
if (request)
835
if (request.type?(PACKET_TYPE_PLAIN_REQUEST))
836
response_type = PACKET_TYPE_PLAIN_RESPONSE
837
end
838
839
method = request.method
840
841
if request.has_tlv?(TLV_TYPE_REQUEST_ID)
842
id = request.get_tlv_value(TLV_TYPE_REQUEST_ID)
843
end
844
end
845
846
packet = Packet.new(response_type, method)
847
848
if id
849
packet.add_tlv(TLV_TYPE_REQUEST_ID, id)
850
end
851
852
packet
853
end
854
855
##
856
#
857
# Constructor
858
#
859
##
860
861
#
862
# Initializes the packet to the supplied packet type and method,
863
# if any. If the packet is a request, a request identifier is
864
# created.
865
#
866
def initialize(type = nil, method = nil)
867
super(type)
868
869
if method
870
self.method = method
871
end
872
873
self.created_at = ::Time.now
874
self.raw = ''
875
876
# If it's a request, generate a random request identifier
877
if ((type == PACKET_TYPE_REQUEST) ||
878
(type == PACKET_TYPE_PLAIN_REQUEST))
879
rid = ''
880
881
32.times { |val| rid << rand(10).to_s }
882
883
add_tlv(TLV_TYPE_REQUEST_ID, rid)
884
end
885
end
886
887
def add_raw(bytes)
888
self.raw << bytes
889
end
890
891
def raw_bytes_required
892
# if we have the xor bytes and length ...
893
if self.raw.length >= PACKET_HEADER_SIZE
894
# return a value based on the length of the data indicated by
895
# the header
896
xor_key = self.raw.unpack('a4')[0]
897
decoded_bytes = xor_bytes(xor_key, raw[0, PACKET_HEADER_SIZE])
898
_, _, _, length, _ = decoded_bytes.unpack('a4a16NNN')
899
length + PACKET_HEADER_SIZE - HEADER_SIZE - self.raw.length
900
else
901
# Otherwise ask for the remaining bytes for the metadata to get the packet length
902
# So we can do the rest of the calculation next time
903
PACKET_HEADER_SIZE - self.raw.length
904
end
905
end
906
907
def aes_encrypt(key, data)
908
size = key.length * 8
909
raise ArgumentError.new('AES key width must be 128 or 256 bits') unless (size == 128 || size == 256)
910
# Create the required cipher instance
911
aes = OpenSSL::Cipher.new("AES-#{size}-CBC")
912
# Generate a truly random IV
913
iv = aes.random_iv
914
915
# set up the encryption
916
aes.encrypt
917
aes.key = key
918
aes.iv = iv
919
920
# encrypt and return the IV along with the result
921
return iv, aes.update(data) + aes.final
922
end
923
924
def aes_decrypt(key, iv, data)
925
size = key.length * 8
926
raise ArgumentError.new('AES key width must be 128 or 256 bits') unless (size == 128 || size == 256)
927
# Create the required cipher instance
928
aes = OpenSSL::Cipher.new("AES-#{size}-CBC")
929
# Generate a truly random IV
930
931
# set up the encryption
932
aes.decrypt
933
aes.key = key
934
aes.iv = iv
935
936
# decrypt!
937
aes.update(data) + aes.final
938
end
939
940
#
941
# Override the function that creates the raw byte stream for
942
# sending so that it generates an XOR key, uses it to scramble
943
# the serialized TLV content, and then returns the key plus the
944
# scrambled data as the payload.
945
#
946
def to_r(session_guid = nil, key = nil)
947
xor_key = (rand(254) + 1).chr + (rand(254) + 1).chr + (rand(254) + 1).chr + (rand(254) + 1).chr
948
949
raw = (session_guid || NULL_GUID).dup
950
tlv_data = GroupTlv.instance_method(:to_r).bind(self).call
951
952
if key && key[:key] && (key[:type] == ENC_FLAG_AES128 || key[:type] == ENC_FLAG_AES256)
953
# encrypt the data, but not include the length and type
954
iv, ciphertext = aes_encrypt(key[:key], tlv_data[HEADER_SIZE..-1])
955
# now manually add the length/type/iv/ciphertext
956
raw << [key[:type], iv.length + ciphertext.length + HEADER_SIZE, self.type, iv, ciphertext].pack('NNNA*A*')
957
else
958
raw << [ENC_FLAG_NONE, tlv_data].pack('NA*')
959
end
960
961
# return the xor'd result with the key
962
xor_key + xor_bytes(xor_key, raw)
963
end
964
965
#
966
# Decrypt the packet based on the content of the encryption flags.
967
#
968
def decrypt_packet(key, encrypt_flags, data)
969
# TODO: throw an error if the expected encryption isn't the same as the given
970
# as this could be an indication of hijacking or side-channel packet addition
971
# as highlighted by Justin Steven on github.
972
if key && key[:key] && key[:type] && encrypt_flags == key[:type] && (encrypt_flags == ENC_FLAG_AES128 || encrypt_flags == ENC_FLAG_AES256)
973
iv = data[0, AES_IV_SIZE]
974
aes_decrypt(key[:key], iv, data[iv.length..-1])
975
else
976
data
977
end
978
end
979
980
def parse_header!
981
xor_key = self.raw.unpack('a4')[0]
982
data = xor_bytes(xor_key, self.raw[0..PACKET_HEADER_SIZE])
983
_, self.session_guid, self.encrypt_flags, self.length, self.type = data.unpack('a4a16NNN')
984
end
985
986
#
987
# Override the function that reads from a raw byte stream so
988
# that the XORing of data is included in the process prior to
989
# passing it on to the default functionality that can parse
990
# the TLV values.
991
#
992
def from_r(key=nil)
993
self.parse_header!
994
xor_key = self.raw.unpack('a4')[0]
995
data = xor_bytes(xor_key, self.raw[PACKET_HEADER_SIZE..-1])
996
raw = decrypt_packet(key, self.encrypt_flags, data)
997
super([self.length, self.type, raw].pack('NNA*'))
998
end
999
1000
#
1001
# Xor a set of bytes with a given XOR key.
1002
#
1003
def xor_bytes(xor_key, bytes)
1004
xor_key = xor_key.bytes
1005
result = ''
1006
i = 0
1007
bytes.each_byte do |b|
1008
result << (b ^ xor_key[i % xor_key.length]).chr
1009
i += 1
1010
end
1011
result
1012
end
1013
1014
##
1015
#
1016
# Conditionals
1017
#
1018
##
1019
1020
#
1021
# Checks to see if the packet is a response.
1022
#
1023
def response?
1024
(self.type == PACKET_TYPE_RESPONSE || self.type == PACKET_TYPE_PLAIN_RESPONSE)
1025
end
1026
1027
##
1028
#
1029
# Accessors
1030
#
1031
##
1032
1033
#
1034
# Checks to see if the packet's method is equal to the supplied method.
1035
#
1036
def method?(method)
1037
(get_tlv_value(TLV_TYPE_COMMAND_ID) == method)
1038
end
1039
1040
#
1041
# Sets the packet's method TLV to the method supplied.
1042
#
1043
def method=(method)
1044
raise ArgumentError.new("Packet.method must be an integer. Current value is #{method}") unless method.is_a?(Integer)
1045
add_tlv(TLV_TYPE_COMMAND_ID, method, true)
1046
end
1047
1048
#
1049
# Returns the value of the packet's method TLV.
1050
#
1051
def method
1052
get_tlv_value(TLV_TYPE_COMMAND_ID)
1053
end
1054
1055
#
1056
# Checks to see if the packet's result value is equal to the supplied
1057
# result.
1058
#
1059
def result?(result)
1060
(get_tlv_value(TLV_TYPE_RESULT) == result)
1061
end
1062
1063
#
1064
# Sets the packet's result TLV.
1065
#
1066
def result=(result)
1067
add_tlv(TLV_TYPE_RESULT, result, true)
1068
end
1069
1070
#
1071
# Gets the value of the packet's result TLV.
1072
#
1073
def result
1074
get_tlv_value(TLV_TYPE_RESULT)
1075
end
1076
1077
#
1078
# Gets the value of the packet's request identifier TLV.
1079
#
1080
def rid
1081
get_tlv_value(TLV_TYPE_REQUEST_ID)
1082
end
1083
end
1084
1085
1086
end; end; end
1087
1088