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.



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

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.



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

def client
  @client
end

Class Method Details

.basename(*a) ⇒ Object

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



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

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.



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

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.



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

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)


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

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%.



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

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



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

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.



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

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.



63
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
# File 'lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb', line 63

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



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

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



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

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.



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

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

Performs a delete on the specified file.



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

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.



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

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.



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

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.



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

def eof
	return self.filed.eof
end

#posObject

Returns the current position of the file pointer.



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

def pos
	return self.filed.tell
end

#seek(offset, whence = SEEK_SET) ⇒ Object

Synonym for sysseek.



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

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

#sysseek(offset, whence = SEEK_SET) ⇒ Object

Seeks to the supplied offset based on the supplied relativity.



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

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