Skip to content

Commit c51e903

Browse files
committed
Merge branch 'land_mipsbe_xor_encoder' into upstream-master
2 parents 75fb38f + 594ee42 commit c51e903

File tree

1 file changed

+146
-0
lines changed

1 file changed

+146
-0
lines changed

modules/encoders/mipsbe/byte_xori.rb

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
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

Comments
 (0)