lib/msf/ui/console/local_file_system.rb
# -*- coding: binary -*-
module Msf
module Ui
module Console
###
#
# This module provides commands for the local file system
#
###
module LocalFileSystem
#
# Options for the lls command
#
@@lls_opts = Rex::Parser::Arguments.new(
'-h' => [ false, 'Help banner' ],
'-S' => [ true, 'Search string on filename (as regular expression)' ],
'-t' => [ false, 'Sort by time' ],
'-s' => [ false, 'Sort by size' ],
'-r' => [ false, 'Reverse sort order' ]
)
#
# List of supported local commands.
#
# @return [Hash] Hash of local commands
def local_fs_commands
{
'getlwd' => 'Print local working directory (alias for lpwd)',
'lcat' => 'Read the contents of a local file to the screen',
'lcd' => 'Change local working directory',
'lmkdir' => 'Create new directory on local machine',
'lpwd' => 'Print local working directory',
'lls' => 'List local files',
'ldir' => 'List local files (alias for lls)'
}
end
#
# List local files
#
# @param [Array] args
# @return [Rex::Text::Table] The results lls command
def cmd_lls(*args)
# Set Defaults
path = ::Dir.pwd
sort = 'Name'
order = :forward
search_term = nil
# Parse the args
@@lls_opts.parse(args) do |opt, _idx, val|
case opt
# Sort options
when '-s'
sort = 'Size'
when '-t'
sort = 'Last modified'
# Output options
when '-r'
order = :reverse
# Search
when '-S'
search_term = val
if search_term.nil?
print_error('Enter a search term')
return true
else
search_term = /#{search_term}/nmi
end
# Help and path
when '-h'
cmd_lls_help
return 0
when nil
path = val
end
end
list_local_path(path, sort, order, search_term)
end
#
# Help output for lss command
#
# @return [Rex::Parser::Arguments]
def cmd_lls_help
print_line 'Usage: lls [options]'
print_line
print_line 'Lists contents of a local directory or file info'
print_line @@lls_opts.usage
end
#
# Alias the lls command to dir, for those of us who have windows muscle-memory
#
alias cmd_ldir cmd_lls
#
# Change the local working directory.
#
# @param [Array] args
# @return [TrueClass]
def cmd_lcd(*args)
if args.empty?
print_line('Usage: lcd directory')
return true
end
::Dir.chdir(args[0])
true
end
#
# Tab completion for the lcd command
#
# @param [String] str
# @param [Array] words
def cmd_lcd_tabs(str, words)
tab_complete_directory(str, words)
end
alias cmd_lls_tabs cmd_lcd_tabs
#
# Get list local path information for lls command
#
# @param [String] path
# @param [String] sort
# @param [Symbol] order
# @param [nil] search_term
# @return [Rex::Text::Table, String] The results lcd command
def list_local_path(path, sort, order, search_term = nil)
# Single file as path
unless ::File.directory?(path)
perms = pretty_perms(path)
stat = ::File.stat(path)
print_line("#{perms} #{stat.size} #{stat.ftype[0, 3]} #{stat.mtime} #{path}")
return
end
# Enumerate each item...
# No need to sort as Table will do it for us
columns = [ 'Mode', 'Size', 'Type', 'Last modified', 'Name' ]
tbl = Rex::Text::Table.new(
'Header' => "Listing Local: #{path}",
'SortIndex' => columns.index(sort),
'SortOrder' => order,
'Columns' => columns
)
items = 0
files = ::Dir.entries(path)
files.each do |file|
file_path = ::File.join(path, file)
perms = pretty_perms(file_path)
stat = ::File.stat(file_path)
row = [
perms || '',
stat.size ? stat.size.to_s : '',
stat.ftype ? stat.ftype[0, 3] : '',
stat.mtime || '',
file
]
if file != '.' && file != '..' && (row.join(' ') =~ /#{search_term}/)
tbl << row
items += 1
end
end
if items > 0
print_line(tbl.to_s)
else
print_line("No entries exist in #{path}")
end
end
#
# Reads the contents of a local file and prints them to the screen.
#
# @param [Array] args
# @return [TrueClass]
def cmd_lcat(*args)
if args.empty? || args.include?('-h') || args.include?('--help')
print_line('Usage: lcat file')
return true
end
path = args[0]
path = ::File.expand_path(path) if path =~ path_expand_regex
if ::File.stat(path).directory?
print_error("#{path} is a directory")
else
fd = ::File.new(path, 'rb')
begin
print(fd.read) until fd.eof?
# EOFError is raised if file is empty, do nothing, just catch
rescue EOFError
end
fd.close
end
true
end
#
# Tab completion for the lcat command
#
# @param [Object] str
# @param [Object] words
# @return [Array] List of matches
def cmd_lcat_tabs(str, words)
tab_complete_filenames(str, words)
end
#
# Create new directory on local machine
#
# @param [Array] args
# @return [Array]
def cmd_lmkdir(*args)
if args.empty?
print_line('Usage: lmkdir </path/to/directory>')
return
end
args.each do |path|
::FileUtils.mkdir_p(path)
print_line("Directory '#{path}' created successfully.")
rescue ::StandardError => e
print_error("Error creating #{path} directory: #{e}")
end
end
#
# Display the local working directory.
#
# @param [Array] args
# @return [TrueClass]
def cmd_lpwd(*args)
print_line(::Dir.pwd)
true
end
alias cmd_getlwd cmd_lpwd
#
# Code from prettymode in lib/rex/post/file_stat.rb
# adapted for local file usage
#
# @param [Object] path
# @return [String]
def pretty_perms(path)
m = ::File.stat(path).mode
om = '%04o' % m
perms = ''
3.times do
perms = ((m & 0o1) == 0o1 ? 'x' : '-') + perms
perms = ((m & 0o2) == 0o2 ? 'w' : '-') + perms
perms = ((m & 0o4) == 0o4 ? 'r' : '-') + perms
m >>= 3
end
"#{om}/#{perms}"
end
private
# @return [Regexp]
def path_expand_regex
if shell.session.platform == 'windows'
/%(\w*)%/
else
/\$(([A-Za-z0-9_]+)|\{([A-Za-z0-9_]+)\})|^~/
end
end
end
end
end
end