From d1f5fa06cf4802b7ddff259cbd3cfa2f23f0ed5d Mon Sep 17 00:00:00 2001 From: Spencer McIntyre Date: Thu, 15 Dec 2022 09:08:39 -0500 Subject: [PATCH] Don't use File in cmd_upload / cmd_download It does not look like shell sessions define their own File class, meaning that the local-platform specific one is always used. Instead we'll define the separator ourselves since it's all we need to perform the basic operations necessary to analyze the path string. --- lib/msf/base/sessions/command_shell.rb | 18 +++++++++++------- .../meterpreter/extensions/stdapi/fs/file.rb | 6 ++++-- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/lib/msf/base/sessions/command_shell.rb b/lib/msf/base/sessions/command_shell.rb index 892972e449..ab8df3a759 100644 --- a/lib/msf/base/sessions/command_shell.rb +++ b/lib/msf/base/sessions/command_shell.rb @@ -425,12 +425,15 @@ Shell Banner: return end - if (::File.basename(dst) != File.basename(src)) - # The destination when downloading is a local file so use this system's separator - dst += ::File::SEPARATOR + File.basename(src) + fs_sep = platform == 'windows' ? '\\' : '/' + if dst.blank? + dst = src.split(fs_sep).last + elsif ::File.directory?(dst) + dst += ::File::SEPARATOR unless dst.end_with?(::File::SEPARATOR) + dst += src.split(fs_sep).last end - dir = ::File.dirname(dst) - ::FileUtils.mkdir_p(dir) if dir and not ::File.directory?(dir) + dst_dir = ::File.dirname(dst) + ::FileUtils.mkdir_p(dst_dir) if dst_dir and not ::File.directory?(dst_dir) # Get file content # match the output style of the Meterpreter equivalent @@ -438,7 +441,7 @@ Shell Banner: content = _file_transfer.read_file(src) # Write file to local machine - File.binwrite(dst, content) + ::File.binwrite(dst, content) print_status("Completed : #{src} -> #{dst}") end @@ -477,7 +480,8 @@ Shell Banner: print_status("Uploading : #{src} -> #{dst}") begin - content = File.binread(src) + # Read file from local machine + content = ::File.binread(src) _file_transfer.write_file(dst, content) print_status("Completed : #{src} -> #{dst}") rescue => e diff --git a/lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb b/lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb index b44ae7671e..ed5feee004 100644 --- a/lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb +++ b/lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb @@ -293,7 +293,8 @@ class File < Rex::Post::Meterpreter::Extensions::Stdapi::Fs::IO def File.upload(dest, *src_files, &stat) src_files.each { |src| if (self.basename(dest) != ::File.basename(src)) - dest += self.separator + ::File.basename(src) unless dest.end_with?(self.separator) + dest += self.separator unless dest.end_with?(self.separator) + dest += ::File.basename(src) end stat.call('Uploading', src, dest) if (stat) @@ -350,7 +351,8 @@ class File < Rex::Post::Meterpreter::Extensions::Stdapi::Fs::IO if (::File.basename(dest) != File.basename(src)) # The destination when downloading is a local file so use this # system's separator - dest += ::File::SEPARATOR + File.basename(src) unless dest.end_with?(::File::SEPARATOR) + dest += ::File::SEPARATOR unless dest.end_with?(::File::SEPARATOR) + dest += File.basename(src) end # XXX: dest can be the same object as src, so we use += instead of <<