Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add nonnull encoder aarch64 #19708

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 92 additions & 0 deletions modules/encoders/aarch64/nonnull.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
#
# This module was developed during a semester projecter under the supervision of the CYD campus.
##

class MetasploitModule < Msf::Encoder
Rank = NormalRanking

def initialize
super(
'Name' => 'AArch64 null-byte encoder',
'Description' => %q{
This encoder produces an output that is guaranteed to be NULL-byte free.
Max payload size is 4136 Bytes.
},
'Author' => 'A5t4t1ne',
'Arch' => ARCH_AARCH64,
'License' => MSF_LICENSE
)
end

# Encodes payload
def encode_block(state, buf)
enc_pl = '_' * buf.length * 2 # encoding nibbles to chars -> length will be doubled

for i in 0...buf.length do
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's more "ruby like" to use something like each_with_index do |i, c| instead of using a classic for loop

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I fixed that.

q = buf[i].ord
enc_pl[2 * i] = mkchr((q >> 4) & 0xF) # c will always be between 0x41 ('A') and 0x50 ('P')
enc_pl[2 * i + 1] = mkchr(q & 0xF)
end

return decode_stub(state, enc_pl)
end

def mkchr(ch)
return (0x41 + ch).chr
end

# Generate the decode stub
def decode_stub(_state, enc_buf)
forward_jump, nops, backward_jump, while_condition = min_jmp_back(enc_buf)

return 'jiL0' + # adr x10, 0x98D2D - calc addr of encoded shellcode
"JaB\xf1" + # subs x10, x10, #0x98, lsl #12
"\x4a\x95\x34\xf1" + # subs x10, x10, #0xd25
"\x4b\x01\x1f\xca" + # eor x11, x10, xzr - start of encoded shellcode becomes start of decoded instructions
'sBSj' + # ands w19, w19, w19, lsr #16 - clear w19
'sBSj' + # ands w19, w19, w19, lsr #16
'b2Sj' + # ands w2, w19, w19, lsr #12 - clear w2
while_condition + # loop: tbnz w2, #<bit>, #0x40 - branch to code after n-iterations
'RQA9' + # ldrb w18, [x10, #84] - load first byte
'YUA9' + # ldrb w25, [x10, #85] - load second byte
"Jm0\xb1" + # adds x10, x10, #0xc1b - encoded_buf_index += 2
"Je0\xf1" + # subs x10, x10, #0xc19
"\x52\x02\x04\x11" + # add w18, w18, #0x100 - sub 0x41 (upper nibble)
"\x52\x06\x05\x51" + # sub w18, w18, #0x141
"\x39\x03\x04\x11" + # add w25, w25, #0x100 - sub 0x41 (lower nibble)
"\x39\x07\x05\x51" + # sub w25, w25, #0x141
"\x39\x13\x12\x2a" + # orr w25, w25, w18, lsl #4 - assemble the nibbles to the original byte
"\x79\x51\x01\x39" + # strb w25, [x11, #84] - store original byte
"ki0\xb1" + # adds x11, x11, #0xc1a - x11++ decoded payload index
"ke0\xf1" + # subs x11, x11, #0xc19
'Bh01' + # adds w2, w2, #0xc1a - w2++ (loop counter)
'Bd0q' + # subs w2, w2, #0xc19
forward_jump + # tbz w19, #9, <offset> - jump into nops
enc_buf +
nops +
backward_jump # tbz w19, #9, <to lbl 'loop'> - end of decoding while-loop
end

def min_jmp_back(enc_buf)
jump_back_offsets = [
[540, 600, "\xf3\x10\x48\x36", "\x53\xed\x4f\x36", "\x02\x02\x48\x37"], # +540, -600, 512 iterations
[1040, 1100, "\x93\x20\x48\x36", "\xb3\xdd\x4f\x36", "\x02\x02\x50\x37"], # +1040, -1100, 1024 iterations
[2060, 2140, "\x73\x40\x48\x36", "\x33\xbd\x4f\x36", "\x02\x02\x58\x37"], # +2060, -2140, 2048 iterations
[4140, 4276, "\x73\x81\x48\x36", 'szO6', "\x02\x02\x60\x37"], # +4140, -4276, 4096 iterations
]

jump_back_offsets.each do |val|
next if enc_buf.length >= val[0]

bytes_to_fill = val[1] - enc_buf.length
nops = (bytes_to_fill / 4) - 16 # loop lbl is 16 instructions above buffer

return [val[2], "\x1f\x20\x03\xd5" * nops, val[3], val[4]]
end

raise ArgumentError, 'Encoding failed, payload too big.'
end
end
Loading