3
3
module Msf ::Post ::File
4
4
5
5
#
6
- # Change directory in the remote session to +path+
6
+ # Change directory in the remote session to +path+, which may be relative or
7
+ # absolute.
7
8
#
9
+ # @return [void]
8
10
def cd ( path )
11
+ e_path = expand_path ( path ) rescue path
9
12
if session . type == "meterpreter"
10
- e_path = session . fs . file . expand_path ( path ) rescue path
11
13
session . fs . dir . chdir ( e_path )
12
14
else
13
- session . shell_command_token ( "cd ' #{ path } ' " )
15
+ session . shell_command_token ( "cd \" #{ e_path } \" " )
14
16
end
15
17
end
16
18
17
19
#
18
20
# Returns the current working directory in the remote session
19
21
#
22
+ # @note This may be inaccurate on shell sessions running on Windows before
23
+ # XP/2k3
24
+ #
25
+ # @return [String]
20
26
def pwd
21
27
if session . type == "meterpreter"
22
28
return session . fs . dir . getwd
@@ -51,6 +57,7 @@ def dir(directory)
51
57
#
52
58
# See if +path+ exists on the remote system and is a directory
53
59
#
60
+ # @param path [String] Remote filename to check
54
61
def directory? ( path )
55
62
if session . type == "meterpreter"
56
63
stat = session . fs . file . stat ( path ) rescue nil
@@ -60,7 +67,7 @@ def directory?(path)
60
67
if session . platform =~ /win/
61
68
f = cmd_exec ( "cmd.exe /C IF exist \" #{ path } \\ *\" ( echo true )" )
62
69
else
63
- f = session . shell_command_token ( "test -d ' #{ path } ' && echo true" )
70
+ f = session . shell_command_token ( "test -d \" #{ path } \" && echo true" )
64
71
end
65
72
66
73
return false if f . nil? or f . empty?
@@ -72,6 +79,7 @@ def directory?(path)
72
79
#
73
80
# Expand any environment variables to return the full path specified by +path+.
74
81
#
82
+ # @return [String]
75
83
def expand_path ( path )
76
84
if session . type == "meterpreter"
77
85
return session . fs . file . expand_path ( path )
@@ -83,6 +91,7 @@ def expand_path(path)
83
91
#
84
92
# See if +path+ exists on the remote system and is a regular file
85
93
#
94
+ # @param path [String] Remote filename to check
86
95
def file? ( path )
87
96
if session . type == "meterpreter"
88
97
stat = session . fs . file . stat ( path ) rescue nil
@@ -95,7 +104,7 @@ def file?(path)
95
104
f = cmd_exec ( "cmd.exe /C IF exist \" #{ path } \\ \\ \" ( echo false ) ELSE ( echo true )" )
96
105
end
97
106
else
98
- f = session . shell_command_token ( "test -f ' #{ path } ' && echo true" )
107
+ f = session . shell_command_token ( "test -f \" #{ path } \" && echo true" )
99
108
end
100
109
101
110
return false if f . nil? or f . empty?
@@ -109,15 +118,16 @@ def file?(path)
109
118
#
110
119
# Check for existence of +path+ on the remote file system
111
120
#
121
+ # @param path [String] Remote filename to check
112
122
def exist? ( path )
113
123
if session . type == "meterpreter"
114
124
stat = session . fs . file . stat ( path ) rescue nil
115
125
return !!( stat )
116
126
else
117
127
if session . platform =~ /win/
118
- f = cmd_exec ( "cmd.exe /C IF exist \" #{ path } \" ( echo true )" )
128
+ f = cmd_exec ( "cmd.exe /C IF exist \" #{ path } \" ( echo true )" )
119
129
else
120
- f = session . shell_command_token ( "test -e ' #{ path } ' && echo true" )
130
+ f = cmd_exec ( "test -e \" #{ path } \" && echo true" )
121
131
end
122
132
123
133
return false if f . nil? or f . empty?
@@ -126,31 +136,19 @@ def exist?(path)
126
136
end
127
137
end
128
138
129
- #
130
- # Remove a remote file
131
- #
132
- def file_rm ( file )
133
- if session . type == "meterpreter"
134
- session . fs . file . rm ( file )
135
- else
136
- if session . platform =~ /win/
137
- session . shell_command_token ( "del \" #{ file } \" " )
138
- else
139
- session . shell_command_token ( "rm -f '#{ file } '" )
140
- end
141
- end
142
- end
143
-
144
139
#
145
140
# Writes a given string to a given local file
146
141
#
147
- def file_local_write ( file2wrt , data2wrt )
148
- if not ::File . exists? ( file2wrt )
149
- ::FileUtils . touch ( file2wrt )
142
+ # @param local_file_name [String]
143
+ # @param data [String]
144
+ # @return [void]
145
+ def file_local_write ( local_file_name , data )
146
+ unless ::File . exists? ( local_file_name )
147
+ ::FileUtils . touch ( local_file_name )
150
148
end
151
149
152
- output = ::File . open ( file2wrt , "a" )
153
- data2wrt . each_line do |d |
150
+ output = ::File . open ( local_file_name , "a" )
151
+ data . each_line do |d |
154
152
output . puts ( d )
155
153
end
156
154
output . close
@@ -159,22 +157,27 @@ def file_local_write(file2wrt, data2wrt)
159
157
#
160
158
# Returns a MD5 checksum of a given local file
161
159
#
162
- def file_local_digestmd5 ( file2md5 )
163
- if not :: File . exists? ( file2md5 )
164
- raise "File #{ file2md5 } does not exists!"
165
- else
160
+ # @param local_file_name [String] Local file name
161
+ # @return [String] Hex digest of file contents
162
+ def file_local_digestmd5 ( local_file_name )
163
+ if :: File . exists? ( local_file_name )
166
164
require 'digest/md5'
167
165
chksum = nil
168
- chksum = Digest ::MD5 . hexdigest ( ::File . open ( file2md5 , "rb" ) { |f | f . read } )
166
+ chksum = Digest ::MD5 . hexdigest ( ::File . open ( local_file_name , "rb" ) { |f | f . read } )
169
167
return chksum
168
+ else
169
+ raise "File #{ local_file_name } does not exists!"
170
170
end
171
171
end
172
172
173
173
#
174
174
# Returns a MD5 checksum of a given remote file
175
175
#
176
- def file_remote_digestmd5 ( file2md5 )
177
- data = read_file ( file2md5 )
176
+ # @note THIS DOWNLOADS THE FILE
177
+ # @param file_name [String] Remote file name
178
+ # @return [String] Hex digest of file contents
179
+ def file_remote_digestmd5 ( file_name )
180
+ data = read_file ( file_name )
178
181
chksum = nil
179
182
if data
180
183
chksum = Digest ::MD5 . hexdigest ( data )
@@ -185,22 +188,27 @@ def file_remote_digestmd5(file2md5)
185
188
#
186
189
# Returns a SHA1 checksum of a given local file
187
190
#
188
- def file_local_digestsha1 ( file2sha1 )
189
- if not :: File . exists? ( file2sha1 )
190
- raise "File #{ file2sha1 } does not exists!"
191
- else
191
+ # @param local_file_name [String] Local file name
192
+ # @return [String] Hex digest of file contents
193
+ def file_local_digestsha1 ( local_file_name )
194
+ if :: File . exists? ( local_file_name )
192
195
require 'digest/sha1'
193
196
chksum = nil
194
- chksum = Digest ::SHA1 . hexdigest ( ::File . open ( file2sha1 , "rb" ) { |f | f . read } )
197
+ chksum = Digest ::SHA1 . hexdigest ( ::File . open ( local_file_name , "rb" ) { |f | f . read } )
195
198
return chksum
199
+ else
200
+ raise "File #{ local_file_name } does not exists!"
196
201
end
197
202
end
198
203
199
204
#
200
205
# Returns a SHA1 checksum of a given remote file
201
206
#
202
- def file_remote_digestsha1 ( file2sha1 )
203
- data = read_file ( file2sha1 )
207
+ # @note THIS DOWNLOADS THE FILE
208
+ # @param file_name [String] Remote file name
209
+ # @return [String] Hex digest of file contents
210
+ def file_remote_digestsha1 ( file_name )
211
+ data = read_file ( file_name )
204
212
chksum = nil
205
213
if data
206
214
chksum = Digest ::SHA1 . hexdigest ( data )
@@ -211,22 +219,27 @@ def file_remote_digestsha1(file2sha1)
211
219
#
212
220
# Returns a SHA256 checksum of a given local file
213
221
#
214
- def file_local_digestsha2 ( file2sha2 )
215
- if not :: File . exists? ( file2sha2 )
216
- raise "File #{ file2sha2 } does not exists!"
217
- else
222
+ # @param local_file_name [String] Local file name
223
+ # @return [String] Hex digest of file contents
224
+ def file_local_digestsha2 ( local_file_name )
225
+ if :: File . exists? ( local_file_name )
218
226
require 'digest/sha2'
219
227
chksum = nil
220
- chksum = Digest ::SHA256 . hexdigest ( ::File . open ( file2sha2 , "rb" ) { |f | f . read } )
228
+ chksum = Digest ::SHA256 . hexdigest ( ::File . open ( local_file_name , "rb" ) { |f | f . read } )
221
229
return chksum
230
+ else
231
+ raise "File #{ local_file_name } does not exists!"
222
232
end
223
233
end
224
234
225
235
#
226
236
# Returns a SHA2 checksum of a given remote file
227
237
#
228
- def file_remote_digestsha2 ( file2sha2 )
229
- data = read_file ( file2sha2 )
238
+ # @note THIS DOWNLOADS THE FILE
239
+ # @param file_name [String] Remote file name
240
+ # @return [String] Hex digest of file contents
241
+ def file_remote_digestsha2 ( file_name )
242
+ data = read_file ( file_name )
230
243
chksum = nil
231
244
if data
232
245
chksum = Digest ::SHA256 . hexdigest ( data )
@@ -238,6 +251,8 @@ def file_remote_digestsha2(file2sha2)
238
251
# Platform-agnostic file read. Returns contents of remote file +file_name+
239
252
# as a String.
240
253
#
254
+ # @param file_name [String] Remote file name to read
255
+ # @return [String] Contents of the file
241
256
def read_file ( file_name )
242
257
data = nil
243
258
if session . type == "meterpreter"
@@ -246,19 +261,20 @@ def read_file(file_name)
246
261
if session . platform =~ /win/
247
262
data = session . shell_command_token ( "type \" #{ file_name } \" " )
248
263
else
249
- data = session . shell_command_token ( "cat \' #{ file_name } \' " )
264
+ data = session . shell_command_token ( "cat \" #{ file_name } \" " )
250
265
end
251
266
252
267
end
253
268
data
254
269
end
255
270
256
- #
257
271
# Platform-agnostic file write. Writes given object content to a remote file.
258
- # Returns Boolean true if successful
259
272
#
260
273
# NOTE: *This is not binary-safe on Windows shell sessions!*
261
274
#
275
+ # @param file_name [String] Remote file name to write
276
+ # @param data [String] Contents to put in the file
277
+ # @return [void]
262
278
def write_file ( file_name , data )
263
279
if session . type == "meterpreter"
264
280
fd = session . fs . file . new ( file_name , "wb" )
@@ -281,6 +297,9 @@ def write_file(file_name, data)
281
297
#
282
298
# NOTE: *This is not binary-safe on Windows shell sessions!*
283
299
#
300
+ # @param file_name [String] Remote file name to write
301
+ # @param data [String] Contents to put in the file
302
+ # @return [void]
284
303
def append_file ( file_name , data )
285
304
if session . type == "meterpreter"
286
305
fd = session . fs . file . new ( file_name , "ab" )
@@ -300,57 +319,77 @@ def append_file(file_name, data)
300
319
# Read a local file +local+ and write it as +remote+ on the remote file
301
320
# system
302
321
#
322
+ # @param remote [String] Destination file name on the remote filesystem
323
+ # @param local [String] Local file whose contents will be uploaded
324
+ # @return (see #write_file)
303
325
def upload_file ( remote , local )
304
326
write_file ( remote , ::File . read ( local ) )
305
327
end
306
328
307
329
#
308
330
# Delete remote files
309
331
#
332
+ # @param remote_files [Array<String>] List of remote filenames to
333
+ # delete
334
+ # @return [void]
310
335
def rm_f ( *remote_files )
311
336
remote_files . each do |remote |
312
337
if session . type == "meterpreter"
313
338
session . fs . file . delete ( remote ) if exist? ( remote )
314
339
else
315
340
if session . platform =~ /win/
316
- cmd_exec ( "del /q /f #{ remote } " )
341
+ cmd_exec ( "del /q /f \" #{ remote } \" " )
317
342
else
318
- cmd_exec ( "rm -f #{ remote } " )
343
+ cmd_exec ( "rm -f \" #{ remote } \" " )
319
344
end
320
345
end
321
346
end
322
347
end
323
348
349
+ alias :file_rm :rm_f
350
+
324
351
#
325
352
# Rename a remote file.
326
353
#
354
+ # @param old_file [String] Remote file name to move
355
+ # @param new_file [String] The new name for the remote file
327
356
def rename_file ( old_file , new_file )
328
- if session . respond_to? :commands and session . commands . include? ( "stdapi_fs_file_move" )
329
- session . fs . file . mv ( old_file , new_file )
357
+ if session . respond_to? :commands && session . commands . include? ( "stdapi_fs_file_move" )
358
+ return ( session . fs . file . mv ( old_file , new_file ) . result == 0 )
330
359
else
331
- if session . platform =~ /win/
332
- cmd_exec ( %Q|move /y "#{ old_file } " "#{ new_file } "| )
360
+ if session . platform =~ /win/
361
+ if cmd_exec ( %Q|move /y "#{ old_file } " "#{ new_file } "| ) =~ /moved/
362
+ return true
333
363
else
334
- cmd_exec ( %Q|mv -f " #{ old_file } " " #{ new_file } "| )
364
+ return false
335
365
end
366
+ else
367
+ if cmd_exec ( %Q|mv -f "#{ old_file } " "#{ new_file } "| ) . empty?
368
+ return true
369
+ else
370
+ return false
371
+ end
372
+ end
336
373
end
337
374
end
338
375
alias :move_file :rename_file
339
376
alias :mv_file :rename_file
340
377
341
378
protected
379
+
342
380
#
343
381
# Meterpreter-specific file read. Returns contents of remote file
344
382
# +file_name+ as a String or nil if there was an error
345
383
#
346
384
# You should never call this method directly. Instead, call {#read_file}
347
385
# which will call this if it is appropriate for the given session.
348
386
#
387
+ # @return [String]
349
388
def _read_file_meterpreter ( file_name )
350
389
begin
351
390
fd = session . fs . file . new ( file_name , "rb" )
352
391
rescue ::Rex ::Post ::Meterpreter ::RequestError => e
353
- print_error ( "Failed to open file: #{ file_name } " )
392
+ print_error ( "Failed to open file: #{ file_name } : #{ e } " )
354
393
return nil
355
394
end
356
395
@@ -370,10 +409,11 @@ def _read_file_meterpreter(file_name)
370
409
#
371
410
# Truncates if +append+ is false, appends otherwise.
372
411
#
373
- # You should never call this method directly. Instead, call #write_file or
374
- # #append_file which will call this if it is appropriate for the given
412
+ # You should never call this method directly. Instead, call { #write_file}
413
+ # or { #append_file} which will call this if it is appropriate for the given
375
414
# session.
376
415
#
416
+ # @return [void]
377
417
def _write_file_unix_shell ( file_name , data , append = false )
378
418
redirect = ( append ? ">>" : ">" )
379
419
@@ -482,7 +522,7 @@ def _write_file_unix_shell(file_name, data, append=false)
482
522
# The first command needs to use the provided redirection for either
483
523
# appending or truncating.
484
524
cmd = command . sub ( "CONTENTS" ) { chunks . shift }
485
- session . shell_command_token ( "#{ cmd } #{ redirect } ' #{ file_name } ' " )
525
+ session . shell_command_token ( "#{ cmd } #{ redirect } \" #{ file_name } \" " )
486
526
487
527
# After creating/truncating or appending with the first command, we
488
528
# need to append from here on out.
@@ -499,6 +539,7 @@ def _write_file_unix_shell(file_name, data, append=false)
499
539
#
500
540
# Calculate the maximum line length for a unix shell.
501
541
#
542
+ # @return [Fixnum]
502
543
def _unix_max_line_length
503
544
# Based on autoconf's arg_max calculator, see
504
545
# http://www.in-ulm.de/~mascheck/various/argmax/autoconf_check.html
0 commit comments