# frozen_string_literal: true
#
# ronin-post_ex - a Ruby API for Post-Exploitation.
#
# Copyright (c) 2007-2023 Hal Brodigan (postmodern.mod3 at gmail.com)
#
# ronin-post_ex is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# ronin-post_ex is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with ronin-post_ex. If not, see .
#
require 'ronin/core/cli/command_shell'
require 'ronin/post_ex/cli/shell_shell'
require 'ronin/post_ex/remote_file'
module Ronin
module PostEx
module CLI
#
# A shell for {System}.
#
class SystemShell < Core::CLI::CommandShell
shell_name 'ronin-post_ex'
#
# Initializes the file-system shell.
#
# @param [System] system
# The file-system resource.
#
# @param [Hash{Symbol => Object}] kwargs
# Additional keyword arguments.
#
def initialize(system, **kwargs)
super(**kwargs)
@system = system
@files = {}
@next_file_id = 1
end
command 'fs.chdir', method_name: 'fs_chdir',
usage: 'DIR',
summary: 'Changes the current working directory'
#
# Changes the working directory.
#
# @param [String] path
# The new working directory.
#
# @see System::FS#chdir
#
def fs_chdir(path)
@system.fs.chdir(path)
puts "Current working directory is now: #{@system.fs.pwd}"
end
command 'fs.pwd', method_name: 'fs_pwd',
summary: 'Prints the current working directory'
#
# Prints the current working directory.
#
# @see System::FS#getcwd
#
def fs_pwd
puts "Current working directory: #{@system.fs.getcwd}"
end
command 'fs.readfile', method_name: 'fs_readfile',
usage: 'FILE',
summary: 'Reads the contents of a given FILE'
#
# Reads data from a file.
#
# @param [String] path
# The file to read from.
#
# @see System::FS#read
#
def fs_readfile(path)
write(@system.fs.readfile(path))
end
command 'fs.readlink', method_name: 'fs_readlink',
usage: 'SYMLINK',
summary: 'Reads the destination path of a symlink'
#
# Reads the destination of a link.
#
# @param [String] path
# The path to the link.
#
# @see System::FS#readlink
#
def fs_readlink(path)
puts @system.fs.readlink(path)
end
command 'fs.readdir', method_name: 'fs_readdir',
usage: 'DIR',
summary: 'Reads the contents of a given directory'
#
# Reads the entries of a directory.
#
# @param [String] path
# The path to the directory.
#
# @see System::FS#readdir
#
def fs_readdir(path)
@system.fs.readdir(path).each do |entry|
puts entry
end
end
command 'fs.hexdump', usage: 'FILE',
summary: 'Hexdumps a given file'
#
# Hexdumps a file.
#
# @param [String] path
# The file to hexdump.
#
# @see System::FS#hexdump
#
def hexdump(path)
@system.fs.hexdump(path,self)
end
command 'fs.copy', method_name: 'file_copy',
usage: 'SRC DEST',
summary: 'Copies the SRC file to the DEST path'
#
# Copies a file to a destination.
#
# @param [String] src
# The file to copy.
#
# @param [String] dest
# The destination to copy the file to.
#
# @see System::FS#copy
#
def fs_copy(src,dest)
@system.fs.copy(src,dest)
puts "Copied #{@system.fs.expand_path(src)} -> #{@fs.expand_path(dest)}"
end
command 'fs.unlink', method_name: 'file_unlink',
usage: 'FILE',
summary: 'Deletes a given file'
#
# Removes a file.
#
# @param [String] path
# The file to be removed.
#
# @see System::FS#unlink
#
def file_unlink(path)
@system.fs.unlink(path)
puts "Removed #{@system.fs.expand_path(path)}"
end
command 'fs.rmdir', method_name: 'fs_rmdir',
usage: 'DIR',
summary: 'Removes a given directory'
#
# Removes an empty directory.
#
# @param [String] path
# The file to be removed.
#
# @see System::FS#rmdir
#
def fs_rmdir(path)
@system.fs.rmdir(path)
puts "Removed directory #{@system.fs.expand_path(path)}"
end
command 'fs.mv', method_name: 'fs_mv',
usage: 'SRC DEST',
summary: 'Moves or renames a given file or directory'
#
# Moves a file or directory.
#
# @param [String] src
# The file or directory to move.
#
# @param [String] dest
# The destination to move the file or directory to.
#
# @see System::FS#move
#
def fs_mv(src,dest)
@system.fs.move(src,dest)
puts "Moved #{@system.fs.expand_path(src)} -> #{@fs.expand_path(dest)}"
end
command 'fs.link', method_name: 'fs_link',
usage: 'SRC DEST',
summary: 'Creates a link from the source to the destination'
#
# Creates a link to a file or directory.
#
# @param [String] src
# The file or directory to link to.
#
# @param [String] dest
# The path of the new link.
#
# @see System::FS#link
#
def fs_link(src,dest)
@system.fs.link(src,dest)
puts "Linked #{@system.fs.expand_path(src)} -> #{@fs.expand_path(dest)}"
end
command 'fs.chown', method_name: 'fs_chown',
usage: 'USER PATH',
summary: 'Changes the owner of a given file or directory'
#
# Changes ownership of a file or directory.
#
# @param [String] user
# The desired new user.
#
# @param [String] path
# The path of the file or directory.
#
# @see System::FS#chown
#
def fs_chown(user,path)
@system.fs.chown(user,path)
puts "Changed ownership of #{@system.fs.expand_path(path)} to #{user}"
end
command 'fs.chgrp', method_name: 'fs_chgrp',
usage: 'GROUP PATH',
summary: 'Changes the group of a given file or directory'
#
# Changes group ownership of a file or directory.
#
# @param [String] group
# The desired new group.
#
# @param [String] path
# The path of the file or directory.
#
# @see System::FS#chgrp
#
def fs_chgrp(group,path)
@system.fs.chgrp(group,path)
puts "Changed group ownership of #{@system.fs.expand_path(path)} to #{group}"
end
command 'fs.chmod', method_name: 'fs_chmod',
usage: 'MODE PATH',
summary: 'Changes the permission mode of a given file or directory'
#
# Changes the permissions of a file or directory.
#
# @param [String] mode
# The desired new octal permission mode.
#
# @param [String] path
# The path of the file or directory.
#
# @see System::FS#chmod
#
def fs_chmod(mode,path)
@system.fs.chmod(mode.to_i(8),path)
puts "Changed permissions on #{@system.fs.expand_path(path)} to #{mode}"
end
command 'fs.stat', method_name: 'fs_stat',
usage: 'PATH',
summary: 'Prints file system information about a given file or directory'
#
# Stats a file or directory.
#
# @param [String] path
# The file or directory to stat.
#
# @see System::FS#stat
#
def fs_stat(path)
stat = @system.fs.stat(path)
end
command 'file.open', method_name: 'file_open',
usage: 'PATH [MODE]',
summary: 'Opens a file for reading or writing'
#
# Opens a file.
#
# @param [String] path
# The path to the file.
#
# @param [String] mode
# Optional open mode.
#
# @see System::FS#open
#
def file_open(path,mode="r")
file = @system.fs.open(path,mode)
file_id = @next_file_id
@files[file_id] = file
@next_file_id += 1
puts "Opened file ##{file_id} for #{file.path}"
end
command 'files', summary: 'Lists opened files'
#
# Lists opened files.
#
def files
@files.each_with_index do |file,index|
if file
id = index + 1
puts " [#{id}] #{file.path}"
end
end
end
command 'file.seek', method_name: 'file_seek',
usage: 'FILE_ID POS [SEEK_SET | SEEK_CUR | SEEK_END | SEEK_DATA | SEEK_HOLE]',
summary: 'Seeks to a position within the file'
# Mapping of String whence values to Integer values.
WHENCE = {
'SEEK_SET' => RemoteFile::SEEK_SET,
'SEEK_CUR' => RemoteFile::SEEK_CUR,
'SEEK_END' => RemoteFile::SEEK_END,
'SEEK_DATA' => RemoteFile::SEEK_DATA,
'SEEK_HOLE' => RemoteFile::SEEK_HOLE
}
#
# Seeks to a position within an opened file.
#
# @param [String] file_id
# The file ID number.
#
# @param [String] pos
# The position to seek to.
#
# @param [String] whence
# Where to seek relative from. Acceptable values are:
# * `"SET"`
# * `"CUR"`
# * `"END"`
# * `"DATA"`
# * `"HOLE"`
#
# @see RemoteFile#seek
#
def file_seek(file_id,pos,whence='SEEK_SET')
unless WHENCE.has_key?(whence)
print_error "unknown file.seek whence value (#{whence}), must be #{WHENCE.keys.join(', ')}"
return false
end
file_id = file_id.to_i
pos = pos.to_i
whence = WHENCE[whence]
if (file = @files[file_id])
file.seek(pos,whence)
puts file.pos
else
print_error "unknown file id: #{file_id}"
end
end
command 'file.read', method_name: 'file_read',
usage: 'FILE_ID LENGTH',
summary: 'Reads LENGTH of data from an opened file'
#
# Reads data from an opened file.
#
# @param [String] file_id
# The file ID number.
#
# @param [String] length
# The length of data to read.
#
# @see RemoteFile#read
#
def file_read(file_id,length)
file_id = file_id.to_i
length = length.to_i
if (file = @files[file_id])
puts(file.read(length))
else
print_error "unknown file id: #{file_id}"
end
end
command 'file.write', method_name: 'file_write',
usage: 'FILE_ID DATA',
summary: 'Writes data to an opened file'
#
# Writes data from to an opened file.
#
# @param [String] file_id
# The file ID number.
#
# @param [String] data
# The data to write.
#
# @see RemoteFile#write
#
def file_write(file_id,data)
file_id = file_id.to_i
length = length.to_i
if (file = @files[file_id])
puts file.write(length)
else
print_error "unknown file id: #{file_id}"
end
end
command 'file.close', method_name: 'file_close',
usage: 'FILE_ID',
summary: 'Closes an open file'
#
# Closes an opened file.
#
# @param [String] file_id
# The file ID number.
#
# @see RemoteFile#close
#
def file_close(file_id)
file_id = file_id.to_i
length = length.to_i
if (file = @files[file_id])
file.close
@files.delete(file_id)
puts "Closed file ##{file_id} for #{file.path}"
else
print_error "unknown file id: #{file_id}"
end
end
command 'process.pid', method_name: 'process_pid',
summary: "Prints the process'es PID"
#
# Prints the process'es PID.
#
# @see System::Process#getpid
#
def process_pid
puts @system.process.getpid
end
command 'process.ppid', method_name: 'process_ppid',
summary: "Prints the process'es PPID"
#
# Prints the process'es PPID.
#
# @see System::Process#getppid
#
def process_ppid
puts @system.process.getppid
end
command 'process.uid', method_name: 'process_uid',
summary: "Prints the process'es UID"
#
# Prints the process'es UID.
#
# @see System::Process#getuid
#
def process_uid
puts @system.process.getuid
end
command 'process.setuid', method_name: 'process_setuid',
usage: 'UID',
summary: "Sets the process'es UID"
#
# Sets the process'es UID.
#
# @param [String] new_uid
#
# @see System::Process#setuid
#
def process_setuid(new_uid)
@system.process.setuid(new_uid.to_i)
end
command 'process.euid', method_name: 'process_euid',
usage: 'EUID',
summary: "Prints the process'es EUID"
#
# Prints the process'es EUID.
#
# @see System::Process#geteuid
#
def process_euid
puts @system.process.geteuid
end
command 'process.seteuid', method_name: 'process_seteuid',
usage: 'EUID',
summary: "Sets the process'es EUID"
#
# Sets the process'es EUID.
#
# @param [String] new_euid
#
# @see System::Process#seteuid
#
def process_seteuid(new_euid)
@system.process.seteuid(new_euid.to_i)
end
command 'process.gid', method_name: 'process_gid',
usage: 'COMMAND',
summary: "Prints the process'es GID"
#
# Prints the process'es GID.
#
# @see System::Process#getgid
#
def process_gid
puts @system.process.getgid
end
command 'process.setgid', method_name: 'process_setgid',
usage: 'GID',
summary: "Sets the process'es GID"
#
# Sets the process'es GID.
#
# @param [String] new_gid
#
# @see System::Process#setgid
#
def process_setgid(new_gid)
@system.process.setgid(new_gid.to_i)
end
command 'process.egid', method_name: 'process_egid',
summary: "Prints the process'es EGID"
#
# Prints the process'es EGID.
#
# @see System::Process#getegid
#
def process_egid
puts @system.process.getegid
end
command 'process.setegid', method_name: 'process_setegid',
usage: 'EGID',
summary: "Sets the process'es EGID"
#
# Sets the process'es EGID.
#
# @param [String] new_egid
#
# @see System::Process#setegid
#
def process_setegid(new_egid)
@system.process.setegid(new_egid.to_i)
end
command 'process.sid', method_name: 'process_sid',
summary: "Prints the process'es SID"
#
# Prints the process'es SID.
#
# @see System::Process#getsid
#
def process_sid
puts @system.process.getsid
end
command 'process.setsid', method_name: 'process_setsid',
usage: 'SID',
summary: "Prints the process'es SID"
#
# Sets the process'es SID.
#
# @param [String] new_sid
#
# @see System::Process#setsid
#
def process_setsid(new_sid)
@system.process.setsid(new_sid.to_i)
end
command 'process.env', method_name: 'process_env',
summary: "Prints the process'es environment variables"
#
# Prints the process'es environment variables.
#
# @see System::Process#environ
#
def process_env
@system.process.env.each do |name,value|
puts "#{name}=#{value}"
end
end
command 'process.getenv', method_name: 'process_getenv',
usage: 'NAME',
summary: 'Prints an environment variable from the process'
#
# Prints a specific environment variable from the process.
#
# @param [String] name
# The environment variable name.
#
# @see System::Process#getenv
#
def process_getenv(name)
puts @system.process.getenv(name)
end
command 'process.setenv', method_name: 'process_setenv',
usage: 'NAME=VALUE',
summary: 'Sets an environment variable for the process'
#
# Sets a specific environment variable from the process.
#
# @param [String] name_and_value
# The environment variable name.
#
# @see System::Process#getenv
#
def process_setenv(name_and_value)
name, value = name_and_value.split('=',2)
@system.process.setenv(name,value)
end
command 'process.unsetenv', method_name: 'process_getenv',
usage: 'NAME',
summary: 'Unsets an environment variable for the process'
#
# Unsets a process environment variable.
#
# @param [String] name
# The environment variable to unset.
#
# @see System::Process#unsetenv
#
def process_unsetenv(name)
@system.process.unsetenv(name)
end
command 'process.kill', method_name: 'process_kill',
usage: 'PID [SIGNAL]',
summary: 'Kills a process'
#
# Kills a process.
#
# @param [String] pid
# The process PID to kill.
#
# @param [String] signal
# The signal to send the process.
#
def process_kill(pid,signal='KILL')
@system.process.kill(pid.to_i,signal)
end
command 'process.spawn', method_name: 'process_spawn',
usage: 'PROGRAM [ARGS ...]',
summary: 'Spawns a new process'
#
# Spawns a new process.
#
# @param [String] program
# The program name.
#
# @param [Array] arguments
# Additional command arguments.
#
# @see System::Process#spawn
#
def process_spawn(program,*arguments)
pid = @system.process.spawn(program,*arguments)
puts "PID: #{pid}"
end
command 'shell.exec', method_name: 'shell_exec',
usage: 'COMMAND',
summary: 'Executes a command in the shell'
#
# Executes a shell command.
#
# @param [String] command
# The command to execute.
#
# @see System::Shell#run
#
def shell_exec(command)
puts @system.shell.run(command)
end
command 'shell', method_name: 'shell',
summary: 'Spawns an interactive command shell'
#
# Spawns an interactive command sub-shell.
#
# @see ShellShell
#
def shell
ShellShell.start(@system.shell)
end
command 'sys.time', method_name: 'sys_time',
summary: "Prints the system's current time"
#
# Prints the system's current time.
#
# @see System#time
#
def sys_time
puts @system.time
end
command 'sys.hostname', method_name: 'sys_hostname',
summary: "Prints the system's hostname"
#
# Prints the system's hostname.
#
# @see System#hostname
#
def sys_hostname
puts @system.hostname
end
end
end
end
end