Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/lib/rex/post/meterpreter/extensions/stdapi/fs/dir.rb
Views: 11794
# -*- coding: binary -*-12require 'rex/post/dir'3require 'rex/post/meterpreter/extensions/stdapi/stdapi'45module Rex6module Post7module Meterpreter8module Extensions9module Stdapi10module Fs1112###13#14# This class implements directory operations against the remote endpoint. It15# implements the Rex::Post::Dir interface.16#17###18class Dir < Rex::Post::Dir1920class << self21attr_accessor :client22end2324##25#26# Constructor27#28##2930#31# Initializes the directory instance.32#33def initialize(path)34self.path = path35self.client = self.class.client36end3738##39#40# Enumeration41#42##4344#45# Enumerates all of the contents of the directory.46#47def each(&block)48client.fs.dir.foreach(self.path, &block)49end5051#52# Enumerates all of the files/folders in a given directory.53#54def Dir.entries(name = getwd, glob = nil)55request = Packet.create_request(COMMAND_ID_STDAPI_FS_LS)56files = []57name = name + ::File::SEPARATOR + glob if glob5859request.add_tlv(TLV_TYPE_DIRECTORY_PATH, client.unicode_filter_decode(name))6061response = client.send_request(request)6263response.each(TLV_TYPE_FILE_NAME) { |file_name|64files << client.unicode_filter_encode(file_name.value)65}6667return files68end6970#71# Enumerates files with a bit more information than the default entries.72#73def Dir.entries_with_info(name = getwd)74request = Packet.create_request(COMMAND_ID_STDAPI_FS_LS)75files = []76sbuf = nil77new_stat_buf = true7879request.add_tlv(TLV_TYPE_DIRECTORY_PATH, client.unicode_filter_decode(name))8081response = client.send_request(request)8283fname = response.get_tlvs(TLV_TYPE_FILE_NAME)84fsname = response.get_tlvs(TLV_TYPE_FILE_SHORT_NAME)85fpath = response.get_tlvs(TLV_TYPE_FILE_PATH)8687if response.has_tlv?(TLV_TYPE_STAT_BUF)88sbuf = response.get_tlvs(TLV_TYPE_STAT_BUF)89else90sbuf = response.get_tlvs(TLV_TYPE_STAT_BUF32)91new_stat_buf = false92end9394if (!fname or !sbuf)95return []96end9798fname.each_with_index { |file_name, idx|99st = nil100101if sbuf[idx] && sbuf[idx].value.length > 0102st = ::Rex::Post::FileStat.new103if new_stat_buf104st.update(sbuf[idx].value)105else106st.update32(sbuf[idx].value)107end108end109110files <<111{112'FileName' => client.unicode_filter_encode(file_name.value),113'FilePath' => client.unicode_filter_encode(fpath[idx].value),114'FileShortName' => fsname[idx] ? fsname[idx].value : nil,115'StatBuf' => st,116}117}118119return files120end121122#123# Enumerates all of the files and folders matched with name.124# When option match_dir is true, return matched folders.125#126def Dir.match(name, match_dir = false)127path = name + '*'128files = []129sbuf = nil130new_stat_buf = true131132request = Packet.create_request(COMMAND_ID_STDAPI_FS_LS)133request.add_tlv(TLV_TYPE_DIRECTORY_PATH, client.unicode_filter_decode(path))134response = client.send_request(request)135136fpath = response.get_tlvs(TLV_TYPE_FILE_PATH)137138if response.has_tlv?(TLV_TYPE_STAT_BUF)139sbuf = response.get_tlvs(TLV_TYPE_STAT_BUF)140else141sbuf = response.get_tlvs(TLV_TYPE_STAT_BUF32)142new_stat_buf = false143end144145unless fpath && sbuf146return []147end148149fpath.each_with_index do |file_name, idx|150is_dir = false151if sbuf[idx]152st = ::Rex::Post::FileStat.new153if new_stat_buf154st.update(sbuf[idx].value)155else156st.update32(sbuf[idx].value)157end158is_dir = st.ftype == 'directory'159next if (match_dir && !is_dir) # if file_name isn't directory160end161162if !file_name.value.end_with?('.', '\\', '/') # Exclude current and parent directory163name = client.unicode_filter_encode(file_name.value)164if is_dir165name += client.fs.file.separator166end167files << name168end169end170171files172end173174##175#176# General directory operations177#178##179180#181# Changes the working directory of the remote process.182#183def Dir.chdir(path)184request = Packet.create_request(COMMAND_ID_STDAPI_FS_CHDIR)185186request.add_tlv(TLV_TYPE_DIRECTORY_PATH, client.unicode_filter_decode( path ))187188client.send_request(request)189190getwd(refresh: true)191return 0192end193194#195# Creates a directory.196#197def Dir.mkdir(path)198request = Packet.create_request(COMMAND_ID_STDAPI_FS_MKDIR)199200request.add_tlv(TLV_TYPE_DIRECTORY_PATH, client.unicode_filter_decode( path ))201202client.send_request(request)203204return 0205end206207#208# Returns the current working directory of the remote process.209#210def Dir.pwd(refresh: true)211if @working_directory.nil? || refresh212request = Packet.create_request(COMMAND_ID_STDAPI_FS_GETWD)213214response = client.send_request(request)215216@working_directory = client.unicode_filter_encode(response.get_tlv(TLV_TYPE_DIRECTORY_PATH).value)217end218@working_directory219end220221#222# Synonym for pwd.223#224def Dir.getwd(refresh: true)225pwd(refresh: refresh)226end227228#229# Removes the supplied directory if it's empty.230#231def Dir.delete(path)232request = Packet.create_request(COMMAND_ID_STDAPI_FS_DELETE_DIR)233234request.add_tlv(TLV_TYPE_DIRECTORY_PATH, client.unicode_filter_decode( path ))235236client.send_request(request)237238return 0239end240241#242# Synonyms for delete.243#244def Dir.rmdir(path)245delete(path)246end247248#249# Synonyms for delete.250#251def Dir.unlink(path)252delete(path)253end254255##256#257# Directory mirroring258#259##260261#262# Downloads the contents of a remote directory a263# local directory, optionally in a recursive fashion.264#265def Dir.download(dst, src, opts = {}, force = true, glob = nil, &stat)266src.force_encoding('UTF-8')267dst.force_encoding('UTF-8')268tries_cnt = 0269270continue = opts["continue"]271recursive = opts["recursive"]272timestamp = opts["timestamp"]273tries_no = opts["tries_no"] || 0274tries = opts["tries"]275276begin277dir_files = self.entries(src, glob)278rescue Rex::TimeoutError279if (tries && (tries_no == 0 || tries_cnt < tries_no))280tries_cnt += 1281stat.call('error listing - retry #', tries_cnt, src) if (stat)282retry283else284stat.call('error listing directory - giving up', src, dst) if (stat)285raise286end287end288289dir_files.each { |src_sub|290src_sub.force_encoding('UTF-8')291dst_sub = src_sub.dup292dst_sub.gsub!(::File::SEPARATOR, '_') # '/' on all systems293dst_sub.gsub!(::File::ALT_SEPARATOR, '_') if ::File::ALT_SEPARATOR # nil on Linux, '\' on Windows294295dst_item = ::File.join(dst, client.unicode_filter_encode(dst_sub))296src_item = src + client.fs.file.separator + client.unicode_filter_encode(src_sub)297298if (src_sub == '.' or src_sub == '..')299next300end301302tries_cnt = 0303begin304src_stat = client.fs.filestat.new(src_item)305rescue Rex::TimeoutError306if (tries && (tries_no == 0 || tries_cnt < tries_no))307tries_cnt += 1308stat.call('error opening file - retry #', tries_cnt, src_item) if (stat)309retry310else311stat.call('error opening file - giving up', tries_cnt, src_item) if (stat)312raise313end314end315316if (src_stat.file?)317if timestamp318dst_item << timestamp319end320321stat.call('downloading', src_item, dst_item) if (stat)322323begin324if (continue || tries) # allow to file.download to log messages325result = client.fs.file.download_file(dst_item, src_item, opts, &stat)326else327result = client.fs.file.download_file(dst_item, src_item, opts)328end329stat.call(result, src_item, dst_item) if (stat)330rescue ::Rex::Post::Meterpreter::RequestError => e331if force332stat.call('failed', src_item, dst_item) if (stat)333else334raise e335end336end337338elsif (src_stat.directory?)339if (recursive == false)340next341end342343begin344::Dir.mkdir(dst_item)345rescue346end347348stat.call('mirroring', src_item, dst_item) if (stat)349download(dst_item, src_item, opts, force, glob, &stat)350stat.call('mirrored', src_item, dst_item) if (stat)351end352} # entries353end354355#356# Uploads the contents of a local directory to a remote357# directory, optionally in a recursive fashion.358#359def Dir.upload(dst, src, recursive = false, &stat)360::Dir.entries(src).each { |src_sub|361dst_item = dst + client.fs.file.separator + client.unicode_filter_encode(src_sub)362src_item = src + ::File::SEPARATOR + client.unicode_filter_encode(src_sub)363364if (src_sub == '.' or src_sub == '..')365next366end367368src_stat = ::File.stat(src_item)369370if (src_stat.file?)371stat.call('uploading', src_item, dst_item) if (stat)372client.fs.file.upload(dst_item, src_item)373stat.call('uploaded', src_item, dst_item) if (stat)374elsif (src_stat.directory?)375if (recursive == false)376next377end378379begin380self.mkdir(dst_item)381rescue382end383384stat.call('mirroring', src_item, dst_item) if (stat)385upload(dst_item, src_item, recursive, &stat)386stat.call('mirrored', src_item, dst_item) if (stat)387end388}389end390391#392# The path of the directory that was opened.393#394attr_reader :path395protected396attr_accessor :client # :nodoc:397attr_writer :path # :nodoc:398399end400401end; end; end; end; end; end402403404405