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/msf/core/encoder.rb
Views: 1904
1
# -*- coding: binary -*-
2
3
module Msf
4
5
###
6
#
7
# This class is used to track the state of a single encoding operation
8
# from start to finish.
9
#
10
###
11
class EncoderState
12
13
#
14
# Initializes a new encoder state, optionally with a key.
15
#
16
def initialize(key = nil)
17
@orig_buf = nil
18
@buf = nil
19
reset(key)
20
end
21
22
#
23
# Reset the encoder state by initializing the encoded buffer to an empty
24
# string.
25
#
26
def reset(key = nil)
27
init_key(key)
28
29
self.encoded = ''
30
end
31
32
#
33
# Set the initial encoding key.
34
#
35
def init_key(key)
36
self.key = key
37
self.orig_key = key
38
end
39
40
#
41
# Set the raw buffer and the original buffer if one has not been set.
42
#
43
def buf=(buf)
44
@orig_buf = buf if (@orig_buf == nil or @buf == nil)
45
@buf = buf
46
end
47
48
attr_accessor :key # :nodoc:
49
attr_accessor :orig_key # :nodoc:
50
attr_reader :buf # :nodoc:
51
attr_reader :orig_buf # :nodoc:
52
attr_accessor :encoded # :nodoc:
53
attr_accessor :context # :nodoc:
54
attr_accessor :badchars # :nodoc:
55
56
# A boolean that indicates whether context encoding is enabled
57
attr_accessor :context_encoding
58
# The address that contains they key on the target machine
59
attr_accessor :context_address
60
61
# Decoder settings
62
attr_accessor :decoder_key_offset, :decoder_key_size, :decoder_key_pack # :nodoc:
63
attr_accessor :decoder_stub # :nodoc:
64
65
end
66
67
###
68
#
69
# This class is the base class that all encoders inherit from.
70
#
71
###
72
class Encoder < Module
73
74
#
75
# The type set that encoders can fall within. This classifies the type of
76
# output generated by the encoder in terms of the general character set
77
# that is used as well as other potential attributes.
78
#
79
module Type
80
#
81
# 'A' - 'Z', '0' - '9'
82
#
83
AlphanumUpper = "alpha_upper"
84
#
85
# 'a' - 'z', 'A' - 'Z', '0' - '9'
86
#
87
AlphanumMixed = "alpha_mixed"
88
#
89
# Unicode-safe 'A' - 'Z', '0' - '9'
90
#
91
AlphanumUnicodeUpper = "alpha_unicode_upper"
92
#
93
# Unicode-safe 'a' - 'z', 'A' - 'Z', '0' - '9'
94
#
95
AlphanumUnicodeMixed = "alpha_unicode_mixed"
96
#
97
# toupper/tolower safe ascii - not 'a' - 'z', 'A' - 'Z'
98
#
99
NonAlpha = "non_alpha"
100
#
101
# tolower safe ascii - not 'A' - 'Z' (more flexible than nonalpha)
102
#
103
NonUpper = "non_upper"
104
#
105
# tolower safe ascii UTF8-safe (<= 0x7f only)
106
#
107
NonUpperUtf8Safe = "non_upper_utf8_safe"
108
#
109
# tolower safe underscore safe for CVE-2012-2329 - PHP CGI apache_request_headers bof
110
#
111
NonUpperUnderscoreSafe = "non_upper_underscore"
112
#
113
# May result in the generation of any characters
114
#
115
Unspecified = "unspecified"
116
#
117
# The raw payload passed to the encoder will be the same as the encoded
118
# payload
119
#
120
Raw = "raw"
121
#
122
# Special Single Static Bit encoder
123
#
124
SingleStaticBit = "single_static_bit"
125
#
126
# Special printf(1) via PHP magic_quotes Command Encoder
127
#
128
PrintfPHPMagicQuotes = "printf_php_mq"
129
#
130
# perl encoding.
131
#
132
CmdPosixPerl = 'perl'
133
#
134
# Bourne shell echo encoding.
135
#
136
CmdPosixEcho = 'echo'
137
#
138
# Bourne shell ${IFS} encoding.
139
#
140
CmdPosixIFS = 'ifs'
141
#
142
# Bash brace expansion encoding.
143
#
144
CmdPosixBrace = 'brace'
145
#
146
# Base64 encoding.
147
#
148
CmdPosixBase64 = 'base64'
149
end
150
151
#
152
# Initializes an encoder module instance using the supplied information
153
# hash.
154
#
155
def initialize(info)
156
super({
157
'Platform' => '' # All platforms by default
158
}.update(info))
159
end
160
161
##
162
#
163
# Encoder information accessors that can be overridden
164
# by derived classes
165
#
166
##
167
168
#
169
# Returns MODULE_ENCODER to indicate that this is an encoder module.
170
#
171
def self.type
172
return Msf::MODULE_ENCODER
173
end
174
175
#
176
# Returns MODULE_ENCODER to indicate that this is an encoder module.
177
#
178
def type
179
return Msf::MODULE_ENCODER
180
end
181
182
#
183
# Returns the type or types of encoders that this specific module
184
# classifies as. If there is more than one type, the values should be
185
# separated by whitespace.
186
#
187
def encoder_type
188
module_info['EncoderType'] || Type::Unspecified
189
end
190
191
#
192
# Returns the decoder stub to use based on the supplied state.
193
#
194
def decoder_stub(state)
195
return decoder_hash['Stub'] || ''
196
end
197
198
#
199
# Returns the offset to the key associated with the decoder stub.
200
#
201
def decoder_key_offset
202
return decoder_hash['KeyOffset']
203
end
204
205
#
206
# Returns the size of the key, in bytes.
207
#
208
def decoder_key_size
209
return decoder_hash['KeySize']
210
end
211
212
#
213
# Returns the size of each logical encoding block, in bytes. This
214
# is typically the same as decoder_key_size.
215
#
216
def decoder_block_size
217
return decoder_hash['BlockSize']
218
end
219
220
#
221
# Returns the byte-packing character that should be used to encode
222
# the key.
223
#
224
def decoder_key_pack
225
return decoder_hash['KeyPack'] || 'V'
226
end
227
228
#
229
# Returns the module's decoder hash or an empty hash.
230
#
231
def decoder_hash
232
module_info['Decoder'] || {}
233
end
234
235
##
236
#
237
# Encoding
238
#
239
##
240
241
#
242
# This method generates an encoded version of the supplied buffer in buf
243
# using the bad characters as guides. On success, an encoded and
244
# functional version of the supplied buffer will be returned. Otherwise,
245
# an exception will be thrown if an error is encountered during the
246
# encoding process.
247
#
248
def encode(buf, badchars = nil, state = nil, platform = nil)
249
250
# Configure platform hints if necessary
251
init_platform(platform) if platform
252
253
# Initialize an empty set of bad characters
254
badchars = '' if (!badchars)
255
256
# Initialize the encoding state and key as necessary
257
if (state == nil)
258
state = EncoderState.new
259
end
260
261
# Prepend data to the buffer as necessary
262
buf = prepend_buf + buf
263
264
init_state(state)
265
266
# Save the buffer in the encoding state
267
state.badchars = badchars || ''
268
state.buf = buf
269
270
# If this encoder is key-based and we don't already have a key, find one
271
if ((decoder_key_size) and
272
(state.key == nil))
273
# Find a key that doesn't contain and won't generate any bad
274
# characters
275
state.init_key(obtain_key(buf, badchars, state))
276
277
if (state.key == nil)
278
raise NoKeyError, "A key could not be found for the #{self.name} encoder.", caller
279
end
280
end
281
282
# Reset the encoded buffer at this point since it may have been changed
283
# while finding a key.
284
state.encoded = ''
285
286
# Call encode_begin to do any encoder specific pre-processing
287
encode_begin(state)
288
289
# Perform the actual encoding operation with the determined state
290
do_encode(state)
291
292
# Call encoded_end to do any encoder specific post-processing
293
encode_end(state)
294
295
if arch?(ARCH_CMD)
296
dlog("#{self.name} result: #{state.encoded}")
297
end
298
299
# Return the encoded buffer to the caller
300
return state.encoded
301
end
302
303
#
304
# Performs the actual encoding operation after the encoder state has been
305
# initialized and is ready to go.
306
#
307
def do_encode(state)
308
309
# Copy the decoder stub since we may need to modify it
310
stub = decoder_stub(state).dup
311
312
if (state.key != nil and state.decoder_key_offset)
313
# Substitute the decoder key in the copy of the decoder stub with the
314
# one that we found
315
real_key = state.key
316
317
# If we're using context encoding, the actual value we use for
318
# substitution is the context address, not the key we use for
319
# encoding
320
real_key = state.context_address if (state.context_encoding)
321
322
stub[state.decoder_key_offset,state.decoder_key_size] = [ real_key.to_i ].pack(state.decoder_key_pack)
323
else
324
stub = encode_finalize_stub(state, stub)
325
end
326
327
# Walk the buffer encoding each block along the way
328
offset = 0
329
330
if (decoder_block_size)
331
while (offset < state.buf.length)
332
block = state.buf[offset, decoder_block_size]
333
334
# Append here (String#<<) instead of creating a new string with
335
# String#+ because the allocations kill performance with large
336
# buffers. This isn't usually noticeable on most shellcode, but
337
# when doing stage encoding on meterpreter (~750k bytes) the
338
# difference is 2 orders of magnitude.
339
state.encoded << encode_block(state,
340
block + ("\x00" * (decoder_block_size - block.length)))
341
342
offset += decoder_block_size
343
end
344
else
345
state.encoded = encode_block(state, state.buf)
346
end
347
348
# Prefix the decoder stub to the encoded buffer
349
state.encoded = stub + state.encoded
350
351
# Last but not least, do one last badchar pass to see if the stub +
352
# encoded payload leads to any bad char issues...
353
if ((badchar_idx = has_badchars?(state.encoded, state.badchars)) != nil)
354
raise BadcharError.new(state.encoded, badchar_idx, stub.length, state.encoded[badchar_idx]),
355
"The #{self.name} encoder failed to encode without bad characters.",
356
caller
357
end
358
359
return true
360
end
361
362
##
363
#
364
# Buffer management
365
#
366
##
367
368
#
369
# Returns a string that should be prepended to the encoded version of the
370
# buffer before returning it to callers.
371
#
372
def prepend_buf
373
return ''
374
end
375
376
##
377
#
378
# Pre-processing, post-processing, and block encoding stubs
379
#
380
##
381
382
#
383
# Called when encoding is about to start immediately after the encoding
384
# state has been initialized.
385
#
386
def encode_begin(state)
387
return nil
388
end
389
390
#
391
# This callback allows a derived class to finalize a stub after a key have
392
# been selected. The finalized stub should be returned.
393
#
394
def encode_finalize_stub(state, stub)
395
stub
396
end
397
398
#
399
# Called after encoding has completed.
400
#
401
def encode_end(state)
402
return nil
403
end
404
405
#
406
# Called once for each block being encoded based on the attributes of the
407
# decoder.
408
#
409
def encode_block(state, block)
410
return block
411
end
412
413
#
414
# Provides the encoder with an opportunity to return the native format (as
415
# in the format the code will be in when it executes on the target). In
416
# general, the same buffer is returned to the caller. However, for things
417
# like unicode, the buffer is unicod encoded and then returned.
418
#
419
def to_native(buf)
420
buf
421
end
422
423
#
424
# Determines whether the encoder can preserve registers at all
425
#
426
def can_preserve_registers?
427
false
428
end
429
430
#
431
# A list of registers always modified by the encoder
432
#
433
def modified_registers
434
[]
435
end
436
437
#
438
# Determines whether the encoder can preserve the stack frame
439
#
440
def preserves_stack?
441
false
442
end
443
444
#
445
# The amount of space available to the encoder, which may be nil,
446
# indicating that the smallest possible encoding should be used.
447
#
448
attr_accessor :available_space
449
450
protected
451
452
#
453
# Initializes the encoding state supplied as an argument to the attributes
454
# that have been defined for this decoder stub, such as key offset, size,
455
# and pack.
456
#
457
def init_state(state)
458
# Update the state with default decoder information
459
state.decoder_key_offset = decoder_key_offset
460
state.decoder_key_size = decoder_key_size
461
state.decoder_key_pack = decoder_key_pack
462
state.decoder_stub = nil
463
464
# Restore the original buffer in case it was modified.
465
state.buf = state.orig_buf
466
end
467
468
#
469
# This provides a hook method for platform specific
470
# processing prior to the rest of encode() running
471
#
472
def init_platform(platform)
473
474
end
475
#
476
# Obtains the key to use during encoding. If context encoding is enabled,
477
# special steps are taken. Otherwise, the derived class is given an
478
# opportunity to find the key.
479
#
480
def obtain_key(buf, badchars, state)
481
if datastore['EnableContextEncoding']
482
return find_context_key(buf, badchars, state)
483
else
484
return find_key(buf, badchars, state)
485
end
486
end
487
488
#
489
# This method finds a compatible key for the supplied buffer based also on
490
# the supplied bad characters list. This is meant to make encoders more
491
# reliable and less prone to bad character failure by doing a fairly
492
# complete key search before giving up on an encoder.
493
#
494
def find_key(buf, badchars, state)
495
# Otherwise, we use the traditional method
496
key_bytes = [ ]
497
cur_key = [ ]
498
bad_keys = find_bad_keys(buf, badchars)
499
found = false
500
allset = [*(0..255)]
501
502
# Keep chugging until we find something...right
503
while (!found)
504
# Scan each byte position
505
0.upto(decoder_key_size - 1) { |index|
506
507
# Subtract the bad and leave the good
508
good_keys = allset - bad_keys[index].keys
509
510
# Was there anything left for this index?
511
if (good_keys.length == 0)
512
# Not much we can do about this :(
513
return nil
514
end
515
516
# Set the appropriate key byte
517
key_bytes[index] = good_keys[ rand(good_keys.length) ]
518
}
519
520
# Assume that we're going to rock this...
521
found = true
522
523
# Scan each byte and see what we've got going on to make sure
524
# no funny business is happening
525
key_bytes.each { |byte|
526
if (badchars.index(byte.chr) != nil)
527
found = false
528
end
529
}
530
531
found = find_key_verify(buf, key_bytes, badchars) if found
532
end
533
534
# Do we have all the key bytes accounted for?
535
if (key_bytes.length != decoder_key_size)
536
return nil
537
end
538
539
return key_bytes_to_integer(key_bytes)
540
end
541
542
#
543
# Parses a context information file in an effort to find a compatible key
544
#
545
def find_context_key(buf, badchars, state)
546
# Make sure our context information file is sane
547
if !File.exist?(datastore['ContextInformationFile'])
548
raise NoKeyError, "A context information file must specified when using context encoding", caller
549
end
550
551
# Holds the address and key that we ultimately find
552
address = nil
553
key = nil
554
555
# Now, parse records from the information file searching for entries
556
# that are compatible with our bad character set
557
File.open(datastore['ContextInformationFile']) { |f|
558
begin
559
# Keep looping until we hit an EOF error or we find
560
# a compatible key
561
while key.nil?
562
# Read in the header
563
type, chunk_base_address, size = f.read(9).unpack('CNN')
564
offset = 0
565
566
# Read in the blob of data that will act as our key state
567
data = f.read(size)
568
569
# If the address doesn't contain bad characters, check to see
570
# the data itself will result in bad characters being generated
571
while data.length > decoder_key_size
572
# Extract the current set of key bytes
573
key_bytes = []
574
575
# My ruby is rusty
576
data[0, decoder_key_size].each_byte { |b|
577
key_bytes << b
578
}
579
580
# If the key verifies correctly, we need to check it's address
581
if find_key_verify(buf, key_bytes, badchars)
582
address = chunk_base_address + offset
583
584
# Pack it to byte form so that we can check each byte for
585
# bad characters
586
address_bytes = integer_to_key_bytes(address)
587
588
# Scan each byte and see what we've got going on to make sure
589
# no funny business is happening with the address
590
invalid_key = false
591
address_bytes.each { |byte|
592
if badchars.index(byte.chr)
593
invalid_key = true
594
end
595
}
596
597
if invalid_key == false
598
key = key_bytes_to_integer(key_bytes)
599
break
600
end
601
end
602
603
# If it didn't verify, then we need to proceed
604
data = data[1, data.length - 1]
605
offset += 1
606
end
607
end
608
rescue EOFError
609
end
610
}
611
612
# If the key is nil after all is said and done, then we failed to locate
613
# a compatible context-sensitive key
614
if key.nil?
615
raise NoKeyError, "No context key could be located in #{datastore['ContextInformationFile']}", caller
616
# Otherwise, we successfully determined the key, now we need to update
617
# the encoding state with our context address and set context encoding
618
# to true so that the encoders know to use it
619
else
620
ilog("#{refname}: Successfully found context address @ #{"%.8x" % address} using key #{"%.8x" % key}")
621
622
state.context_address = address
623
state.context_encoding = true
624
end
625
626
return key
627
end
628
629
#
630
# Returns the list of bad keys associated with this encoder.
631
#
632
def find_bad_keys(buf, badchars)
633
return Array.new(decoder_key_size) { Hash.new }
634
end
635
636
#
637
# Returns the index of any bad characters found in the supplied buffer.
638
#
639
def has_badchars?(buf, badchars)
640
badchars.each_byte { |badchar|
641
idx = buf.index(badchar.chr)
642
643
if (idx != nil)
644
return idx
645
end
646
}
647
648
return nil
649
end
650
651
#
652
# Convert individual key bytes into a single integer based on the
653
# decoder's key size and packing requirements
654
#
655
def key_bytes_to_integer(key_bytes)
656
return key_bytes_to_buffer(key_bytes).unpack(decoder_key_pack)[0]
657
end
658
659
#
660
# Convert individual key bytes into a byte buffer
661
#
662
def key_bytes_to_buffer(key_bytes)
663
return key_bytes.pack('C*')[0, decoder_key_size]
664
end
665
666
#
667
# Convert an integer into the individual key bytes based on the
668
# decoder's key size and packing requirements
669
#
670
def integer_to_key_bytes(integer)
671
return [ integer.to_i ].pack(decoder_key_pack).unpack('C*')[0, decoder_key_size]
672
end
673
674
#
675
# Determines if the key selected by find_key is usable
676
#
677
def find_key_verify(buf, key_bytes, badchars)
678
true
679
end
680
681
end
682
683
end
684
685
686