class Rex::Post::Meterpreter::Extensions::Stdapi::Fs::File

This class implements the Rex::Post::File interface and wraps interaction with files on the remote machine.

Attributes

client[RW]

Public Class Methods

SEPARATOR()
Alias for: separator
Separator()
Alias for: separator
basename(*a) click to toggle source

Returns the base name of the supplied file path to the caller.

# File lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb, line 106
def File.basename(*a)
  path = a[0]

  # Allow both kinds of dir serparators since lots and lots of code
  # assumes one or the other so this ends up getting called with strings
  # like: "C:\\foo/bar"
  path =~ %r#.*[/\\](.*)$#

  Rex::FileUtils.clean_path($1 || path)
end
delete(name)
Alias for: rm
download(dest, *src_files, &stat) click to toggle source

Download one or more files from the remote computer to the local directory supplied in destination.

If a block is given, it will be called before each file is downloaded and again when each download is complete.

# File lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb, line 282
def File.download(dest, *src_files, &stat)
  src_files.each { |src|
    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)
    end

    stat.call('downloading', src, dest) if (stat)
    result = download_file(dest, src)
    stat.call(result, src, dest) if (stat)
  }
end
download_file(dest_file, src_file) click to toggle source

Download a single file.

# File lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb, line 299
def File.download_file(dest_file, src_file)
  src_fd = client.fs.file.new(src_file, "rb")

  # Check for changes
  src_stat = client.fs.filestat.new(src_file)
  if ::File.exists?(dest_file)
    dst_stat = ::File.stat(dest_file)
    if src_stat.size == dst_stat.size && src_stat.mtime == dst_stat.mtime
      return 'skipped'
    end
  end

  # Make the destination path if necessary
  dir = ::File.dirname(dest_file)
  ::FileUtils.mkdir_p(dir) if dir and not ::File.directory?(dir)

  dst_fd = ::File.new(dest_file, "wb")

  # Keep transferring until EOF is reached...
  begin
    while ((data = src_fd.read) != nil)
      dst_fd.write(data)
    end
  rescue EOFError
  ensure
    src_fd.close
    dst_fd.close
  end

  # Clone the times from the remote file
  ::File.utime(src_stat.atime, src_stat.mtime, dest_file)
  return 'download'
end
exists?(name) click to toggle source

Returns true if the remote file name exists, false otherwise

# File lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb, line 186
def File.exists?(name)
  r = client.fs.filestat.new(name) rescue nil
  r ? true : false
end
expand_path(path) click to toggle source

Expands a file path, substituting all environment variables, such as %TEMP%.

Examples:

client.fs.file.expand_path("%appdata%")
# => "C:\\Documents and Settings\\user\\Application Data"
client.fs.file.expand_path("asdf")
# => "asdf"

NOTE: This method is fairly specific to Windows. It has next to no relation to the ::File.expand_path method! In particular, it does not do ~ expansion or environment variable expansion on non-Windows systems. For these reasons, this method may be deprecated in the future. Use it with caution.

# File lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb, line 133
def File.expand_path(path)
  request = Packet.create_request('stdapi_fs_file_expand_path')

  request.add_tlv(TLV_TYPE_FILE_PATH, client.unicode_filter_decode( path ))

  response = client.send_request(request)

  return client.unicode_filter_encode(response.get_tlv_value(TLV_TYPE_FILE_PATH))
end
is_glob?(name) click to toggle source
# File lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb, line 271
def File.is_glob?(name)
  /\*|\[|\?/ === name
end
md5(path) click to toggle source

Calculates the MD5 (16-bytes raw) of a remote file

# File lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb, line 147
def File.md5(path)
  request = Packet.create_request('stdapi_fs_md5')

  request.add_tlv(TLV_TYPE_FILE_PATH, client.unicode_filter_decode( path ))

  response = client.send_request(request)

  # older meterpreter binaries will send FILE_NAME containing the hash
  hash = response.get_tlv_value(TLV_TYPE_FILE_HASH) ||
    response.get_tlv_value(TLV_TYPE_FILE_NAME)
  return hash
end
move(oldname, newname)
Alias for: mv
mv(oldname, newname) click to toggle source

Performs a rename from oldname to newname

# File lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb, line 212
def File.mv(oldname, newname)
  request = Packet.create_request('stdapi_fs_file_move')

  request.add_tlv(TLV_TYPE_FILE_NAME, client.unicode_filter_decode( oldname ))
  request.add_tlv(TLV_TYPE_FILE_PATH, client.unicode_filter_decode( newname ))

  response = client.send_request(request)

  return response
end
Also aliased as: move, rename
new(name, mode = "r", perms = 0) click to toggle source

Initializes and opens the specified file with the specified permissions.

# File lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb, line 361
def initialize(name, mode = "r", perms = 0)
  self.client = self.class.client
  self.filed  = _open(name, mode, perms)
end
open(name, mode="r", perms=0) { |f| ... } click to toggle source

With no associated block, File.open is a synonym for ::new. If the optional code block is given, it will be passed the opened file as an argument, and the File object will automatically be closed when the block terminates. In this instance, File.open returns the value of the block.

(doc stolen from www.ruby-doc.org/core-1.9.3/File.html#method-c-open)

# File lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb, line 341
def File.open(name, mode="r", perms=0)
  f = new(name, mode, perms)
  if block_given?
    ret = yield f
    f.close
    return ret
  else
    return f
  end
end
rename(oldname, newname)
Alias for: mv
rm(name) click to toggle source

Performs a delete on the remote file name

# File lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb, line 194
def File.rm(name)
  request = Packet.create_request('stdapi_fs_delete_file')

  request.add_tlv(TLV_TYPE_FILE_PATH, client.unicode_filter_decode( name ))

  response = client.send_request(request)

  return response
end
Also aliased as: unlink, delete
separator() click to toggle source

Return the directory separator, i.e.: “/” on unix, “\” on windows

# File lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb, line 34
def File.separator()
  # The separator won't change, so cache it to prevent sending
  # unnecessary requests.
  return @separator if @separator

  request = Packet.create_request('stdapi_fs_separator')

  # Fall back to the old behavior of always assuming windows.  This
  # allows meterpreter executables built before the addition of this
  # command to continue functioning.
  begin
    response = client.send_request(request)
    @separator = response.get_tlv_value(TLV_TYPE_STRING)
  rescue RequestError
    @separator = "\\"
  end

  return @separator
end
Also aliased as: Separator, SEPARATOR
sha1(path) click to toggle source

Calculates the SHA1 (20-bytes raw) of a remote file

# File lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb, line 163
def File.sha1(path)
  request = Packet.create_request('stdapi_fs_sha1')

  request.add_tlv(TLV_TYPE_FILE_PATH, client.unicode_filter_decode( path ))

  response = client.send_request(request)

  # older meterpreter binaries will send FILE_NAME containing the hash
  hash = response.get_tlv_value(TLV_TYPE_FILE_HASH) ||
    response.get_tlv_value(TLV_TYPE_FILE_NAME)
  return hash
end
stat(name) click to toggle source

Performs a stat on a file and returns a FileStat instance.

# File lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb, line 179
def File.stat(name)
  return client.fs.filestat.new( name )
end
upload(destination, *src_files, &stat) click to toggle source

Upload one or more files to the remote remote directory supplied in destination.

If a block is given, it will be called before each file is uploaded and again when each upload is complete.

# File lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb, line 235
def File.upload(destination, *src_files, &stat)
  src_files.each { |src|
    dest = destination

    stat.call('uploading', src, dest) if (stat)
    if (self.basename(destination) != ::File.basename(src))
      dest += self.separator + ::File.basename(src)
    end

    upload_file(dest, src)
    stat.call('uploaded', src, dest) if (stat)
  }
end
upload_file(dest_file, src_file, &stat) click to toggle source

Upload a single file.

# File lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb, line 252
def File.upload_file(dest_file, src_file, &stat)
  # Open the file on the remote side for writing and read
  # all of the contents of the local file
  stat.call('uploading', src_file, dest_file) if (stat)
  dest_fd = client.fs.file.new(dest_file, "wb")
  src_buf = ''

  ::File.open(src_file, 'rb') { |f|
    src_buf = f.read(f.stat.size)
  }

  begin
    dest_fd.write(src_buf)
  ensure
    dest_fd.close
  end
  stat.call('uploaded', src_file, dest_file) if (stat)
end

Public Instance Methods

eof() click to toggle source

Returns whether or not the file has reach EOF.

# File lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb, line 375
def eof
  return self.filed.eof
end
pos() click to toggle source

Returns the current position of the file pointer.

# File lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb, line 382
def pos
  return self.filed.tell
end
seek(offset, whence = ::IO::SEEK_SET) click to toggle source

Synonym for sysseek.

# File lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb, line 389
def seek(offset, whence = ::IO::SEEK_SET)
  return self.sysseek(offset, whence)
end
sysseek(offset, whence = ::IO::SEEK_SET) click to toggle source

Seeks to the supplied offset based on the supplied relativity.

# File lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb, line 396
def sysseek(offset, whence = ::IO::SEEK_SET)
  return self.filed.seek(offset, whence)
end

Protected Instance Methods

_open(name, mode = "r", perms = 0) click to toggle source

Creates a File channel using the supplied information.

# File lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb, line 411
def _open(name, mode = "r", perms = 0)
  return Rex::Post::Meterpreter::Channels::Pools::File.open(
      self.client, name, mode, perms)
end