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

Inherits:
IO
  • Object
show all
Includes:
File
Defined in:
lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb

Overview

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

Class Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from File

atime, blockdev?, chardev?, chmod, chown, ctime, delete, directory?, dirname, executable?, executable_real?, extname, file?, fnmatch, fnmatch?, ftype, grpowned?, join, lchmod, lchown, link, lstat, mtime, owned?, #path, pipe?, readable?, readable_real?, setgid?, setuid?, size, socket?, sticky?, symlink?, writeable?, writeable_real?, zero?

Methods inherited from IO

#close, #sysread, #syswrite

Methods inherited from IO

#binmode, #close, #close_read, #close_write, #closed?, #each, #each_byte, #each_line, #eof?, #fcntl, #flush, #fsync, #getc, #gets, #ioctl, #isatty, #lineno, #print, #printf, #putc, #puts, #read, #readchar, #readline, #readlines, #rewind, #stat, #sync, #sysread, #syswrite, #tell, #tty?, #ungetc, #write

Constructor Details

#initialize(name, mode = "r", perms = 0) ⇒ File

Initializes and opens the specified file with the specified permissions.



274
275
276
277
# File 'lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb', line 274

def initialize(name, mode = "r", perms = 0)
  self.client = self.class.client
  self.filed  = _open(name, mode, perms)
end

Class Attribute Details

.clientObject

Returns the value of attribute client.



30
31
32
# File 'lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb', line 30

def client
  @client
end

Class Method Details

.basename(*a) ⇒ Object

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



96
97
98
99
100
101
102
103
104
105
# File 'lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb', line 96

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

.download(dest, *src_files, &stat) ⇒ Object

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



227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# File 'lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb', line 227

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)

    download_file(dest, src)

    stat.call('downloaded', src, dest) if (stat)
  }
end

.download_file(dest_file, src_file) ⇒ Object

Download a single file.



246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
# File 'lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb', line 246

def File.download_file(dest_file, src_file)
  src_fd = client.fs.file.new(src_file, "rb")
  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
end

.exists?(name) ⇒ Boolean

Determines if a file exists and returns true/false

Returns:

  • (Boolean)


160
161
162
163
# File 'lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb', line 160

def File.exists?(name)
  r = client.fs.filestat.new(name) rescue nil
  r ? true : false
end

.expand_path(path) ⇒ Object

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



111
112
113
114
115
116
117
118
119
# File 'lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb', line 111

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

.md5(path) ⇒ Object

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



125
126
127
128
129
130
131
132
133
134
# File 'lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb', line 125

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)

  # This is not really a file name, but a raw hash in bytes
  return response.get_tlv_value(TLV_TYPE_FILE_NAME)
end

.rm(name) ⇒ Object

Performs a delete on the specified file.



168
169
170
171
172
173
174
175
176
# File 'lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb', line 168

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

.search(root = nil, glob = "*.*", recurse = true, timeout = -1 )) ⇒ Object

Search for files.



64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb', line 64

def File.search( root=nil, glob="*.*", recurse=true, timeout=-1 )

  files = ::Array.new

  request = Packet.create_request( 'stdapi_fs_search' )

  root = client.unicode_filter_decode(root) if root
  root = root.chomp( '\\' ) if root

  request.add_tlv( TLV_TYPE_SEARCH_ROOT, root )
  request.add_tlv( TLV_TYPE_SEARCH_GLOB, glob )
  request.add_tlv( TLV_TYPE_SEARCH_RECURSE, recurse )

  # we set the response timeout to -1 to wait indefinatly as a
  # search could take an indeterminate ammount of time to complete.
  response = client.send_request( request, timeout )
  if( response.result == 0 )
    response.each( TLV_TYPE_SEARCH_RESULTS ) do | results |
      files << {
        'path' => client.unicode_filter_encode( results.get_tlv_value( TLV_TYPE_FILE_PATH ).chomp( '\\' ) ),
        'name' => client.unicode_filter_encode( results.get_tlv_value( TLV_TYPE_FILE_NAME ) ),
        'size' => results.get_tlv_value( TLV_TYPE_FILE_SIZE )
      }
    end
  end

  return files
end

.separatorObject Also known as: Separator, SEPARATOR

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



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb', line 36

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

.sha1(path) ⇒ Object

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



139
140
141
142
143
144
145
146
147
148
# File 'lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb', line 139

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)

  # This is not really a file name, but a raw hash in bytes
  return response.get_tlv_value(TLV_TYPE_FILE_NAME)
end

.stat(name) ⇒ Object

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



153
154
155
# File 'lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb', line 153

def File.stat(name)
  return client.fs.filestat.new( name )
end

Performs a delete on the specified file.



181
182
183
# File 'lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb', line 181

def File.unlink(name)
  return File.rm(name)
end

.upload(destination, *src_files, &stat) ⇒ Object

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



189
190
191
192
193
194
195
196
197
198
199
200
201
# File 'lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb', line 189

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) ⇒ Object

Upload a single file.



206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
# File 'lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb', line 206

def File.upload_file(dest_file, src_file)
  # Open the file on the remote side for writing and read
  # all of the contents of the local file
  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
end

Instance Method Details

#eofObject

Returns whether or not the file has reach EOF.



288
289
290
# File 'lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb', line 288

def eof
  return self.filed.eof
end

#posObject

Returns the current position of the file pointer.



295
296
297
# File 'lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb', line 295

def pos
  return self.filed.tell
end

#seek(offset, whence = ::IO::SEEK_SET) ⇒ Object

Synonym for sysseek.



302
303
304
# File 'lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb', line 302

def seek(offset, whence = ::IO::SEEK_SET)
  return self.sysseek(offset, whence)
end

#sysseek(offset, whence = ::IO::SEEK_SET) ⇒ Object

Seeks to the supplied offset based on the supplied relativity.



309
310
311
# File 'lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb', line 309

def sysseek(offset, whence = ::IO::SEEK_SET)
  return self.filed.seek(offset, whence)
end