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/modules/encoders/x86/avoid_utf8_tolower.rb
Views: 11779
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45#6# NOTE: Read this if you plan on using this encoder:7#8# This encoder has some limitations that must be considered. First, this9# encoder cannot be used with all of the payloads included in the framework.10# Most notably, this includes windows/shell_reverse_tcp. The reason for this11# is that some payloads are of a size that leads to a bad character (uppercase12# character) being generated in the decoder stub header.13#14# A second thing to consider is that some IP addresses used in payloads are15# incompatible with this encoder depending on their alignment within the16# payload. For example, the use of 127.0.0.1 may not work due to the fact17# that it's impossible to reach the bytes 127, 0, and 1 in a single add or sub18# due to the algorithm that this encoder uses.19#20# Here's a description of how it works:21#22# This encoder is pretty lame. It has a huge size overhead. Alas, it23# does produce tolower safe and UTF8 safe payloads. The decoder itself is24# split into three distinct chunks. The first chunk is the header, the second25# chunk is the inline-decoding, and the third chunk is where the decoded data26# is persisted. Unlike most encoders, this encoder does not use any branch27# instructions and instead runs into the decoded data after it completes due28# to the fact that it is decoding inline.29#30# The basic approach taken to implement the encoder is this. First, the31# decoder header assumes that a register (ecx) points to the first byte32# in the decoder stub. It then proceeds to calculate the offset to the33# third chunk of the decoder (the persisted data) and updates the context34# register (ecx) to point to the first byte of the third chunk of the decoder35# stub. Following that, the second chunk of the decoder begins executing36# which uses a series of add or subtract operations on the third chunk of the37# decoder to produce the actual opcodes of the encoded payload. For each four38# bytes of encoded data, a sub or add instruction is used in combination with39# complementary information stored in the third chunk of the decoder.40#41# For example, in order to produce 0x01fdfeff one could do the following:42#43# 0x5e096f7c44# - 0x5c0b707d45# ------------46# 0x01fdfeff47#48# After all of the inline decoding operations complete, the payload should49# simply fall through into the now-decoded payload that was stored in the50# third chunk of the decoder.51#52# The following is an example encoding of:53#54# "\xcc\x41\xcc\x41\xcc\x41\xcc\x41\xff\xfe\xfd\x01\xff\x02\x82\x4c"55#56# 00000000 6A04 push byte +0x457# 00000002 6B3C240B imul edi,[esp],byte +0xb58# 00000006 60 pusha59# 00000007 030C24 add ecx,[esp]60# 0000000A 6A11 push byte +0x1161# 0000000C 030C24 add ecx,[esp]62# 0000000F 6A04 push byte +0x463# 00000011 68640F5F31 push dword 0x315f0f6464# 00000016 5F pop edi65# 00000017 0139 add [ecx],edi66# 00000019 030C24 add ecx,[esp]67# 0000001C 6870326B32 push dword 0x326b327068# 00000021 5F pop edi69# 00000022 0139 add [ecx],edi70# 00000024 030C24 add ecx,[esp]71# 00000027 687D700B5C push dword 0x5c0b707d72# 0000002C 5F pop edi73# 0000002D 2939 sub [ecx],edi74# 0000002F 030C24 add ecx,[esp]75# 00000032 6804317F32 push dword 0x327f310476# 00000037 5F pop edi77# 00000038 2939 sub [ecx],edi78# 0000003A 030C24 add ecx,[esp]79# 0000003D 68326D105C push dword 0x5c106d3280# 00000042 0F610F punpcklwd mm1,[edi]81# 00000045 7C6F jl 0xb682# 00000047 095E03 or [esi+0x3],ebx83# 0000004A 3401 xor al,0x184# 0000004C 7F db 0x7F85#86class MetasploitModule < Msf::Encoder8788# This encoder has a manual ranking because it should only be used in cases89# where information has been explicitly supplied, like the BufferOffset.90Rank = ManualRanking9192def initialize93super(94'Name' => 'Avoid UTF8/tolower',95'Description' => 'UTF8 Safe, tolower Safe Encoder',96'Author' => 'skape',97'Arch' => ARCH_X86,98'License' => MSF_LICENSE,99'EncoderType' => Msf::Encoder::Type::NonUpperUtf8Safe,100'Decoder' =>101{102'KeySize' => 4,103'BlockSize' => 4,104})105end106107#108# Returns the decoder stub that is adjusted for the size of109# the buffer being encoded110#111def decoder_stub(state)112len = ((state.buf.length + 3) & (~0x3)) / 4113114# Grab the number of additional bytes that we need to adjust by in order115# to get the context register to point immediately after the stub header116off = (datastore['BufferOffset'] || 0).to_i117118# Check to make sure that the length is a valid size119if is_badchar(state, len)120raise EncodingError.new("The payload being encoded is of an incompatible size (#{len} bytes)")121end122123decoder =124"\x6a" + [len].pack('C') + # push len125"\x6b\x3c\x24\x0b" + # imul 0xb126"\x60" + # pusha127"\x03\x0c\x24" + # add ecx, [esp]128"\x6a" + [0x11+off].pack('C') + # push byte 0x11 + off129"\x03\x0c\x24" + # add ecx, [esp]130"\x6a\x04" # push byte 0x4131132# encoded sled133state.context = ''134135return decoder136end137138def encode_block(state, block)139buf = try_add(state, block)140141if (buf.nil?)142buf = try_sub(state, block)143end144145if (buf.nil?)146raise BadcharError.new(state.encoded, 0, 0, 0)147end148149buf150end151152#153# Appends the encoded context portion.154#155def encode_end(state)156state.encoded += state.context157end158159#160# Generate the instructions that will be used to produce a valid161# block after decoding using the sub instruction in conjunction with162# two UTF8/tolower safe values.163#164def try_sub(state, block)165buf = "\x68";166vbuf = ''167ctx = ''168carry = 0169170block.each_byte { |b|171# It's impossible to reach 0x7f, 0x80, 0x81 with two subs172# of a value that is < 0x80 without NULLs.173return nil if (b == 0x80 or b == 0x81 or b == 0x7f)174175x = 0176y = 0177attempts = 0178prev_carry = carry179180begin181carry = prev_carry182183if (b > 0x80)184diff = 0x100 - b185y = rand(0x80 - diff - 1).to_i + 1186x = (0x100 - (b - y + carry))187carry = 1188else189diff = 0x7f - b190x = rand(diff - 1) + 1191y = (b + x + carry) & 0xff192carry = 0193end194195attempts += 1196197# Lame.198return nil if (attempts > 512)199200end while (is_badchar(state, x) or is_badchar(state, y))201202vbuf += [x].pack('C')203ctx += [y].pack('C')204}205206buf += vbuf + "\x5f\x29\x39\x03\x0c\x24"207208state.context += ctx209210return buf211212end213214#215# Generate instructions that will be used to produce a valid block after216# decoding using the add instruction in conjunction with two UTF8/tolower217# safe values.218#219def try_add(state, block)220buf = "\x68"221vbuf = ''222ctx = ''223224block.each_byte { |b|225# It's impossible to produce 0xff and 0x01 using two non-NULL,226# tolower safe, and UTF8 safe values.227return nil if (b == 0xff or b == 0x01 or b == 0x00)228229attempts = 0230231begin232xv = rand(b - 1) + 1233234attempts += 1235236# Lame.237return nil if (attempts > 512)238239end while (is_badchar(state, xv) or is_badchar(state, b - xv))240241vbuf += [xv].pack('C')242ctx += [b - xv].pack('C')243}244245buf += vbuf + "\x5f\x01\x39\x03\x0c\x24"246247state.context += ctx248249return buf250end251252def is_badchar(state, val)253((val >= 0x41 and val <= 0x5a) or val >= 0x80) or Rex::Text.badchar_index([val].pack('C'), state.badchars)254end255end256257258