3
3
module Msf
4
4
module Exploit ::FileDropper
5
5
6
- include Msf ::Post ::Common
7
- include Msf ::Post ::File
8
-
9
6
def initialize ( info = { } )
10
7
super
11
8
12
9
register_advanced_options (
13
10
[
14
- OptInt . new ( 'FileDropperDelay' , [ false , 'Delay in seconds before attempting file cleanup' ] )
11
+ OptInt . new ( 'FileDropperDelay' , [ false , 'Delay in seconds before attempting file cleanup' ] )
15
12
] , self . class )
16
13
end
17
14
@@ -23,49 +20,22 @@ def initialize(info = {})
23
20
# @return [void]
24
21
#
25
22
def on_new_session ( session )
26
- super
27
-
28
- @session = session
23
+ super ( session )
29
24
30
- if session . type == " meterpreter"
31
- session . core . use ( " stdapi" ) unless session . ext . aliases . include? ( " stdapi" )
25
+ if session . type == ' meterpreter'
26
+ session . core . use ( ' stdapi' ) unless session . ext . aliases . include? ( ' stdapi' )
32
27
end
33
28
34
29
if not @dropped_files or @dropped_files . empty?
35
30
return true
36
31
end
37
32
38
33
@dropped_files . delete_if do |file |
39
- win_file = file . gsub ( "/" , "\\ \\ " )
40
- exists_before = check_file ( file , win_file )
41
-
42
- if session . type == "meterpreter"
43
- begin
44
- # Meterpreter should do this automatically as part of
45
- # fs.file.rm(). Until that has been implemented, remove the
46
- # read-only flag with a command.
47
- if session . platform =~ /win/
48
- session . shell_command_token ( %Q|attrib.exe -r #{ win_file } | )
49
- end
50
- session . fs . file . rm ( file )
51
- file_deleted? ( file , win_file , exists_before )
52
- rescue ::Rex ::Post ::Meterpreter ::RequestError
53
- return false
54
- end
34
+ exists_before = file_dropper_check_file ( file )
35
+ if file_dropper_delete ( file )
36
+ file_dropper_deleted? ( file , exists_before )
55
37
else
56
- win_cmds = [
57
- %Q|attrib.exe -r "#{ win_file } "| ,
58
- %Q|del.exe /f /q "#{ win_file } "|
59
- ]
60
- # We need to be platform-independent here. Since we can't be
61
- # certain that {#target} is accurate because exploits with
62
- # automatic targets frequently change it, we just go ahead and
63
- # run both a windows and a unix command in the same line. One
64
- # of them will definitely fail and the other will probably
65
- # succeed. Doing it this way saves us an extra round-trip.
66
- # Trick shared by @mihi42
67
- session . shell_command_token ( "rm -f \" #{ file } \" >/dev/null ; echo ' & #{ win_cmds . join ( " & " ) } & echo \" ' >/dev/null" )
68
- file_deleted? ( file , win_file , exists_before )
38
+ false
69
39
end
70
40
end
71
41
end
@@ -114,9 +84,8 @@ def cleanup
114
84
@dropped_files . delete_if do |file |
115
85
begin
116
86
file_rm ( file )
117
- print_good ( "Deleted #{ file } " )
118
- true
119
- #rescue ::Rex::SocketError, ::EOFError, ::IOError, ::Errno::EPIPE, ::Rex::Post::Meterpreter::RequestError => e
87
+ # We don't know for sure if file has been deleted, so always warn about it to the user
88
+ false
120
89
rescue ::Exception => e
121
90
vprint_error ( "Failed to delete #{ file } : #{ e } " )
122
91
elog ( "Failed to delete #{ file } : #{ e . class } : #{ e } " )
@@ -130,39 +99,69 @@ def cleanup
130
99
print_warning ( "This exploit may require manual cleanup of '#{ f } ' on the target" )
131
100
end
132
101
133
- private
102
+ end
134
103
135
- def session
136
- @session
137
- end
104
+ private
138
105
139
- alias :client :session
106
+ def file_dropper_win_file ( file )
107
+ file . gsub ( '/' , "\\ \\ " )
108
+ end
140
109
141
- def check_file ( file , win_file )
142
- if session . platform =~ /win/
143
- res = file_exist? ( win_file )
144
- else
145
- res = file_exist? ( file )
110
+ def file_dropper_delete ( file )
111
+ win_file = file_dropper_win_file ( file )
112
+
113
+ if session . type == 'meterpreter'
114
+ begin
115
+ # Meterpreter should do this automatically as part of
116
+ # fs.file.rm(). Until that has been implemented, remove the
117
+ # read-only flag with a command.
118
+ if session . platform =~ /win/
119
+ session . shell_command_token ( %Q|attrib.exe -r #{ win_file } | )
120
+ end
121
+ session . fs . file . rm ( file )
122
+ true
123
+ rescue ::Rex ::Post ::Meterpreter ::RequestError
124
+ false
146
125
end
126
+ else
127
+ win_cmds = [
128
+ %Q|attrib.exe -r "#{ win_file } "| ,
129
+ %Q|del.exe /f /q "#{ win_file } "|
130
+ ]
131
+ # We need to be platform-independent here. Since we can't be
132
+ # certain that {#target} is accurate because exploits with
133
+ # automatic targets frequently change it, we just go ahead and
134
+ # run both a windows and a unix command in the same line. One
135
+ # of them will definitely fail and the other will probably
136
+ # succeed. Doing it this way saves us an extra round-trip.
137
+ # Trick shared by @mihi42
138
+ session . shell_command_token ( "rm -f \" #{ file } \" >/dev/null ; echo ' & #{ win_cmds . join ( " & " ) } & echo \" ' >/dev/null" )
139
+ true
140
+ end
141
+ end
147
142
148
- res
143
+ def file_dropper_check_file ( file )
144
+ if session . platform =~ /win/
145
+ normalized = file_dropper_win_file ( file )
146
+ else
147
+ normalized = file
149
148
end
150
149
151
- def file_deleted? ( file , win_file , exists_before )
152
- if exists_before
153
- if check_file ( file , win_file )
154
- print_error ( "Unable to delete #{ file } " )
155
- false
156
- else
157
- print_good ( "Deleted #{ file } " )
158
- true
159
- end
160
- end
150
+ Msf ::Post ::File . file_exist? ( normalized )
151
+ end
161
152
153
+ def file_dropper_deleted? ( file , exists_before )
154
+ if exists_before && file_dropper_check_file ( file )
155
+ print_error ( "Unable to delete #{ file } " )
156
+ false
157
+ elsif exists_before
158
+ print_good ( "Deleted #{ file } " )
159
+ true
160
+ else
162
161
print_warning ( "Tried to delete #{ file } , unknown result" )
163
162
true
164
163
end
165
-
166
164
end
165
+
167
166
end
168
167
end
0 commit comments