Lucene search
K

Single Static Bit

🗓️ 28 Dec 2009 20:39:43Reported by jduck <[email protected]>Type 
metasploit
 metasploit
🔗 www.rapid7.com👁 21 Views

Module for single static bit with specific bit valu

Code
##
# 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

07 Jan 2024 19:06Current
7.4High risk
Vulners AI Score7.4
21