Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/lib/msf/core/encoder.rb
Views: 11779
# -*- coding: binary -*-12module Msf34###5#6# This class is used to track the state of a single encoding operation7# from start to finish.8#9###10class EncoderState1112#13# Initializes a new encoder state, optionally with a key.14#15def initialize(key = nil)16@orig_buf = nil17@buf = nil18reset(key)19end2021#22# Reset the encoder state by initializing the encoded buffer to an empty23# string.24#25def reset(key = nil)26init_key(key)2728self.encoded = ''29end3031#32# Set the initial encoding key.33#34def init_key(key)35self.key = key36self.orig_key = key37end3839#40# Set the raw buffer and the original buffer if one has not been set.41#42def buf=(buf)43@orig_buf = buf if (@orig_buf == nil or @buf == nil)44@buf = buf45end4647attr_accessor :key # :nodoc:48attr_accessor :orig_key # :nodoc:49attr_reader :buf # :nodoc:50attr_reader :orig_buf # :nodoc:51attr_accessor :encoded # :nodoc:52attr_accessor :context # :nodoc:53attr_accessor :badchars # :nodoc:5455# A boolean that indicates whether context encoding is enabled56attr_accessor :context_encoding57# The address that contains they key on the target machine58attr_accessor :context_address5960# Decoder settings61attr_accessor :decoder_key_offset, :decoder_key_size, :decoder_key_pack # :nodoc:62attr_accessor :decoder_stub # :nodoc:6364end6566###67#68# This class is the base class that all encoders inherit from.69#70###71class Encoder < Module7273#74# The type set that encoders can fall within. This classifies the type of75# output generated by the encoder in terms of the general character set76# that is used as well as other potential attributes.77#78module Type79#80# 'A' - 'Z', '0' - '9'81#82AlphanumUpper = "alpha_upper"83#84# 'a' - 'z', 'A' - 'Z', '0' - '9'85#86AlphanumMixed = "alpha_mixed"87#88# Unicode-safe 'A' - 'Z', '0' - '9'89#90AlphanumUnicodeUpper = "alpha_unicode_upper"91#92# Unicode-safe 'a' - 'z', 'A' - 'Z', '0' - '9'93#94AlphanumUnicodeMixed = "alpha_unicode_mixed"95#96# toupper/tolower safe ascii - not 'a' - 'z', 'A' - 'Z'97#98NonAlpha = "non_alpha"99#100# tolower safe ascii - not 'A' - 'Z' (more flexible than nonalpha)101#102NonUpper = "non_upper"103#104# tolower safe ascii UTF8-safe (<= 0x7f only)105#106NonUpperUtf8Safe = "non_upper_utf8_safe"107#108# tolower safe underscore safe for CVE-2012-2329 - PHP CGI apache_request_headers bof109#110NonUpperUnderscoreSafe = "non_upper_underscore"111#112# May result in the generation of any characters113#114Unspecified = "unspecified"115#116# The raw payload passed to the encoder will be the same as the encoded117# payload118#119Raw = "raw"120#121# Special Single Static Bit encoder122#123SingleStaticBit = "single_static_bit"124#125# Special printf(1) via PHP magic_quotes Command Encoder126#127PrintfPHPMagicQuotes = "printf_php_mq"128#129# perl encoding.130#131CmdPosixPerl = 'perl'132#133# Bourne shell echo encoding.134#135CmdPosixEcho = 'echo'136#137# Bourne shell ${IFS} encoding.138#139CmdPosixIFS = 'ifs'140#141# Bash brace expansion encoding.142#143CmdPosixBrace = 'brace'144#145# Base64 encoding.146#147CmdPosixBase64 = 'base64'148end149150#151# Initializes an encoder module instance using the supplied information152# hash.153#154def initialize(info)155super({156'Platform' => '' # All platforms by default157}.update(info))158end159160##161#162# Encoder information accessors that can be overridden163# by derived classes164#165##166167#168# Returns MODULE_ENCODER to indicate that this is an encoder module.169#170def self.type171return Msf::MODULE_ENCODER172end173174#175# Returns MODULE_ENCODER to indicate that this is an encoder module.176#177def type178return Msf::MODULE_ENCODER179end180181#182# Returns the type or types of encoders that this specific module183# classifies as. If there is more than one type, the values should be184# separated by whitespace.185#186def encoder_type187module_info['EncoderType'] || Type::Unspecified188end189190#191# Returns the decoder stub to use based on the supplied state.192#193def decoder_stub(state)194return decoder_hash['Stub'] || ''195end196197#198# Returns the offset to the key associated with the decoder stub.199#200def decoder_key_offset201return decoder_hash['KeyOffset']202end203204#205# Returns the size of the key, in bytes.206#207def decoder_key_size208return decoder_hash['KeySize']209end210211#212# Returns the size of each logical encoding block, in bytes. This213# is typically the same as decoder_key_size.214#215def decoder_block_size216return decoder_hash['BlockSize']217end218219#220# Returns the byte-packing character that should be used to encode221# the key.222#223def decoder_key_pack224return decoder_hash['KeyPack'] || 'V'225end226227#228# Returns the module's decoder hash or an empty hash.229#230def decoder_hash231module_info['Decoder'] || {}232end233234##235#236# Encoding237#238##239240#241# This method generates an encoded version of the supplied buffer in buf242# using the bad characters as guides. On success, an encoded and243# functional version of the supplied buffer will be returned. Otherwise,244# an exception will be thrown if an error is encountered during the245# encoding process.246#247def encode(buf, badchars = nil, state = nil, platform = nil)248249# Configure platform hints if necessary250init_platform(platform) if platform251252# Initialize an empty set of bad characters253badchars = '' if (!badchars)254255# Initialize the encoding state and key as necessary256if (state == nil)257state = EncoderState.new258end259260# Prepend data to the buffer as necessary261buf = prepend_buf + buf262263init_state(state)264265# Save the buffer in the encoding state266state.badchars = badchars || ''267state.buf = buf268269# If this encoder is key-based and we don't already have a key, find one270if ((decoder_key_size) and271(state.key == nil))272# Find a key that doesn't contain and won't generate any bad273# characters274state.init_key(obtain_key(buf, badchars, state))275276if (state.key == nil)277raise NoKeyError, "A key could not be found for the #{self.name} encoder.", caller278end279end280281# Reset the encoded buffer at this point since it may have been changed282# while finding a key.283state.encoded = ''284285# Call encode_begin to do any encoder specific pre-processing286encode_begin(state)287288# Perform the actual encoding operation with the determined state289do_encode(state)290291# Call encoded_end to do any encoder specific post-processing292encode_end(state)293294if arch?(ARCH_CMD)295dlog("#{self.name} result: #{state.encoded}")296end297298# Return the encoded buffer to the caller299return state.encoded300end301302#303# Performs the actual encoding operation after the encoder state has been304# initialized and is ready to go.305#306def do_encode(state)307308# Copy the decoder stub since we may need to modify it309stub = decoder_stub(state).dup310311if (state.key != nil and state.decoder_key_offset)312# Substitute the decoder key in the copy of the decoder stub with the313# one that we found314real_key = state.key315316# If we're using context encoding, the actual value we use for317# substitution is the context address, not the key we use for318# encoding319real_key = state.context_address if (state.context_encoding)320321stub[state.decoder_key_offset,state.decoder_key_size] = [ real_key.to_i ].pack(state.decoder_key_pack)322else323stub = encode_finalize_stub(state, stub)324end325326# Walk the buffer encoding each block along the way327offset = 0328329if (decoder_block_size)330while (offset < state.buf.length)331block = state.buf[offset, decoder_block_size]332333# Append here (String#<<) instead of creating a new string with334# String#+ because the allocations kill performance with large335# buffers. This isn't usually noticeable on most shellcode, but336# when doing stage encoding on meterpreter (~750k bytes) the337# difference is 2 orders of magnitude.338state.encoded << encode_block(state,339block + ("\x00" * (decoder_block_size - block.length)))340341offset += decoder_block_size342end343else344state.encoded = encode_block(state, state.buf)345end346347# Prefix the decoder stub to the encoded buffer348state.encoded = stub + state.encoded349350# Last but not least, do one last badchar pass to see if the stub +351# encoded payload leads to any bad char issues...352if ((badchar_idx = has_badchars?(state.encoded, state.badchars)) != nil)353raise BadcharError.new(state.encoded, badchar_idx, stub.length, state.encoded[badchar_idx]),354"The #{self.name} encoder failed to encode without bad characters.",355caller356end357358return true359end360361##362#363# Buffer management364#365##366367#368# Returns a string that should be prepended to the encoded version of the369# buffer before returning it to callers.370#371def prepend_buf372return ''373end374375##376#377# Pre-processing, post-processing, and block encoding stubs378#379##380381#382# Called when encoding is about to start immediately after the encoding383# state has been initialized.384#385def encode_begin(state)386return nil387end388389#390# This callback allows a derived class to finalize a stub after a key have391# been selected. The finalized stub should be returned.392#393def encode_finalize_stub(state, stub)394stub395end396397#398# Called after encoding has completed.399#400def encode_end(state)401return nil402end403404#405# Called once for each block being encoded based on the attributes of the406# decoder.407#408def encode_block(state, block)409return block410end411412#413# Provides the encoder with an opportunity to return the native format (as414# in the format the code will be in when it executes on the target). In415# general, the same buffer is returned to the caller. However, for things416# like unicode, the buffer is unicod encoded and then returned.417#418def to_native(buf)419buf420end421422#423# Determines whether the encoder can preserve registers at all424#425def can_preserve_registers?426false427end428429#430# A list of registers always modified by the encoder431#432def modified_registers433[]434end435436#437# Determines whether the encoder can preserve the stack frame438#439def preserves_stack?440false441end442443#444# The amount of space available to the encoder, which may be nil,445# indicating that the smallest possible encoding should be used.446#447attr_accessor :available_space448449protected450451#452# Initializes the encoding state supplied as an argument to the attributes453# that have been defined for this decoder stub, such as key offset, size,454# and pack.455#456def init_state(state)457# Update the state with default decoder information458state.decoder_key_offset = decoder_key_offset459state.decoder_key_size = decoder_key_size460state.decoder_key_pack = decoder_key_pack461state.decoder_stub = nil462463# Restore the original buffer in case it was modified.464state.buf = state.orig_buf465end466467#468# This provides a hook method for platform specific469# processing prior to the rest of encode() running470#471def init_platform(platform)472473end474#475# Obtains the key to use during encoding. If context encoding is enabled,476# special steps are taken. Otherwise, the derived class is given an477# opportunity to find the key.478#479def obtain_key(buf, badchars, state)480if datastore['EnableContextEncoding']481return find_context_key(buf, badchars, state)482else483return find_key(buf, badchars, state)484end485end486487#488# This method finds a compatible key for the supplied buffer based also on489# the supplied bad characters list. This is meant to make encoders more490# reliable and less prone to bad character failure by doing a fairly491# complete key search before giving up on an encoder.492#493def find_key(buf, badchars, state)494# Otherwise, we use the traditional method495key_bytes = [ ]496cur_key = [ ]497bad_keys = find_bad_keys(buf, badchars)498found = false499allset = [*(0..255)]500501# Keep chugging until we find something...right502while (!found)503# Scan each byte position5040.upto(decoder_key_size - 1) { |index|505506# Subtract the bad and leave the good507good_keys = allset - bad_keys[index].keys508509# Was there anything left for this index?510if (good_keys.length == 0)511# Not much we can do about this :(512return nil513end514515# Set the appropriate key byte516key_bytes[index] = good_keys[ rand(good_keys.length) ]517}518519# Assume that we're going to rock this...520found = true521522# Scan each byte and see what we've got going on to make sure523# no funny business is happening524key_bytes.each { |byte|525if (badchars.index(byte.chr) != nil)526found = false527end528}529530found = find_key_verify(buf, key_bytes, badchars) if found531end532533# Do we have all the key bytes accounted for?534if (key_bytes.length != decoder_key_size)535return nil536end537538return key_bytes_to_integer(key_bytes)539end540541#542# Parses a context information file in an effort to find a compatible key543#544def find_context_key(buf, badchars, state)545# Make sure our context information file is sane546if !File.exist?(datastore['ContextInformationFile'])547raise NoKeyError, "A context information file must specified when using context encoding", caller548end549550# Holds the address and key that we ultimately find551address = nil552key = nil553554# Now, parse records from the information file searching for entries555# that are compatible with our bad character set556File.open(datastore['ContextInformationFile']) { |f|557begin558# Keep looping until we hit an EOF error or we find559# a compatible key560while key.nil?561# Read in the header562type, chunk_base_address, size = f.read(9).unpack('CNN')563offset = 0564565# Read in the blob of data that will act as our key state566data = f.read(size)567568# If the address doesn't contain bad characters, check to see569# the data itself will result in bad characters being generated570while data.length > decoder_key_size571# Extract the current set of key bytes572key_bytes = []573574# My ruby is rusty575data[0, decoder_key_size].each_byte { |b|576key_bytes << b577}578579# If the key verifies correctly, we need to check it's address580if find_key_verify(buf, key_bytes, badchars)581address = chunk_base_address + offset582583# Pack it to byte form so that we can check each byte for584# bad characters585address_bytes = integer_to_key_bytes(address)586587# Scan each byte and see what we've got going on to make sure588# no funny business is happening with the address589invalid_key = false590address_bytes.each { |byte|591if badchars.index(byte.chr)592invalid_key = true593end594}595596if invalid_key == false597key = key_bytes_to_integer(key_bytes)598break599end600end601602# If it didn't verify, then we need to proceed603data = data[1, data.length - 1]604offset += 1605end606end607rescue EOFError608end609}610611# If the key is nil after all is said and done, then we failed to locate612# a compatible context-sensitive key613if key.nil?614raise NoKeyError, "No context key could be located in #{datastore['ContextInformationFile']}", caller615# Otherwise, we successfully determined the key, now we need to update616# the encoding state with our context address and set context encoding617# to true so that the encoders know to use it618else619ilog("#{refname}: Successfully found context address @ #{"%.8x" % address} using key #{"%.8x" % key}")620621state.context_address = address622state.context_encoding = true623end624625return key626end627628#629# Returns the list of bad keys associated with this encoder.630#631def find_bad_keys(buf, badchars)632return Array.new(decoder_key_size) { Hash.new }633end634635#636# Returns the index of any bad characters found in the supplied buffer.637#638def has_badchars?(buf, badchars)639badchars.each_byte { |badchar|640idx = buf.index(badchar.chr)641642if (idx != nil)643return idx644end645}646647return nil648end649650#651# Convert individual key bytes into a single integer based on the652# decoder's key size and packing requirements653#654def key_bytes_to_integer(key_bytes)655return key_bytes_to_buffer(key_bytes).unpack(decoder_key_pack)[0]656end657658#659# Convert individual key bytes into a byte buffer660#661def key_bytes_to_buffer(key_bytes)662return key_bytes.pack('C*')[0, decoder_key_size]663end664665#666# Convert an integer into the individual key bytes based on the667# decoder's key size and packing requirements668#669def integer_to_key_bytes(integer)670return [ integer.to_i ].pack(decoder_key_pack).unpack('C*')[0, decoder_key_size]671end672673#674# Determines if the key selected by find_key is usable675#676def find_key_verify(buf, key_bytes, badchars)677true678end679680end681682end683684685686