Class: Ronin::PostEx::Sessions::ShellSession

Inherits:
Session
  • Object
show all
Defined in:
lib/ronin/post_ex/sessions/shell_session.rb

Overview

Base class for all interactive shell based post-exploitation sessions.

Features

  • Supports Bash, Zsh, and all POSIX shells.
  • Emulates most of the post-exploitation API via shell commands.

Direct Known Subclasses

RemoteShellSession

Shell Methods collapse

DELIMINATOR =

Deliminator line to indicate the beginning and end of output

'---'

Instance Attribute Summary collapse

Shell Methods collapse

System Methods collapse

File-System methods collapse

Process methods collapse

Instance Method Summary collapse

Methods inherited from Session

#name, #system, #to_s

Constructor Details

#initialize(io) ⇒ ShellSession

Initializes the shell session.

Parameters:

  • io (Socet, IO)

    The IO object used to communicate with the shell.



52
53
54
# File 'lib/ronin/post_ex/sessions/shell_session.rb', line 52

def initialize(io)
  @io = io
end

Instance Attribute Details

#ioSocket, IO (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

The IO object used to communicate with the shell.

Returns:

  • (Socket, IO)


44
45
46
# File 'lib/ronin/post_ex/sessions/shell_session.rb', line 44

def io
  @io
end

Instance Method Details

#closeObject

Closes the remote shell.



611
612
613
# File 'lib/ronin/post_ex/sessions/shell_session.rb', line 611

def close
  @io.close
end

#command_exec(command, *arguments) ⇒ String?

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Invokes a specific command with arguments.

Parameters:

  • command (String)

    The command name to execute.

  • arguments (Array<String>)

    Additional arguments for the command.

Returns:

  • (String, nil)

    The command's output or nil if there was no output.



150
151
152
153
154
155
156
# File 'lib/ronin/post_ex/sessions/shell_session.rb', line 150

def command_exec(command,*arguments)
  output = shell_exec(command_join(command,*arguments))

  if output.empty? then nil
  else                  output
  end
end

#command_join(command, *arguments) ⇒ String

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Joins a command with arguments into a single command String.

Parameters:

  • command (String)

    The command name to execute.

  • arguments (Array<String>)

    Additional arguments for the command.

Returns:

  • (String)

    The command string.



132
133
134
# File 'lib/ronin/post_ex/sessions/shell_session.rb', line 132

def command_join(command,*arguments)
  Shellwords.join([command,*arguments])
end

#fs_chdir(path) ⇒ Object

Note:

executes the cd <path> command.

Changes the current working directory.

Parameters:

  • path (String)

    The new remote current working directory.



209
210
211
# File 'lib/ronin/post_ex/sessions/shell_session.rb', line 209

def fs_chdir(path)
  shell_puts("cd #{Shellwords.escape(path)} 2>/dev/null")
end

#fs_chgrp(group, path) ⇒ Object

Note:

executes the chgrp <group> <path> command.

Changes the group ownership of a remote file or directory.

Parameters:

  • group (String)

    The new group name for the remote file or directory.

  • path (String)

    The path of the remote file or directory.



385
386
387
# File 'lib/ronin/post_ex/sessions/shell_session.rb', line 385

def fs_chgrp(group,path)
  command_exec('chgrp',group,path)
end

#fs_chmod(mode, path) ⇒ Object

Note:

executes the chmod <umask> <path> command.

Changes the permissions on a remote file or directory.

Parameters:

  • mode (Integer)

    The permissions mode for the remote file or directory.

  • path (String)

    The path of the remote file or directory.



415
416
417
418
419
# File 'lib/ronin/post_ex/sessions/shell_session.rb', line 415

def fs_chmod(mode,path)
  umask = "%.4o" % mode

  command_exec('chmod',umask,path)
end

#fs_chown(user, path) ⇒ Object

Note:

executes the chown <user> <path> command.

Changes the user ownership of remote a file or directory.

Parameters:

  • user (String)

    The new user for the remote file or directory.

  • path (String)

    The path of the remote file or directory.



400
401
402
# File 'lib/ronin/post_ex/sessions/shell_session.rb', line 400

def fs_chown(user,path)
  command_exec('chown',user,path)
end

#fs_copy(path, new_path) ⇒ Object

Note:

executes the cp -r <path> <new_path> command.

Copies a source file to the destination path.

Parameters:

  • path (String)

    The source file.

  • new_path (String)

    The destination path.



315
316
317
# File 'lib/ronin/post_ex/sessions/shell_session.rb', line 315

def fs_copy(path,new_path)
  command_exec('cp','-r',path,new_path)
end

#fs_getcwdString

Note:

executes the pwd command.

Gets the current working directory and returns the directory path.

Returns:

  • (String)

    The remote current working directory.



197
198
199
# File 'lib/ronin/post_ex/sessions/shell_session.rb', line 197

def fs_getcwd
  shell_exec('pwd').chomp
end

#fs_glob(pattern, &block) ⇒ Array<String>

Note:

executes the ls <pattern> command.

Evaluates a directory glob pattern and returns all matching paths.

Parameters:

  • pattern (String)

    The glob pattern to search for remotely.

Returns:

  • (Array<String>)

    The matching paths.



273
274
275
# File 'lib/ronin/post_ex/sessions/shell_session.rb', line 273

def fs_glob(pattern,&block)
  shell_exec("ls #{pattern}").lines(chomp: true)
end
Note:

executes the ln -s <src> <dest> command.

Creates a remote symbolic link at the destination path pointing to the source path.

Parameters:

  • src (String)

    The source file path for the new symbolic link.

  • dest (String)

    The remote path of the new symbolic link.



370
371
372
# File 'lib/ronin/post_ex/sessions/shell_session.rb', line 370

def fs_link(src,dest)
  command_exec('ln','-s',src,dest)
end

#fs_mkdir(new_path) ⇒ Object

Note:

executes the mkdir <path> command.

Creates a new remote directory at the given path.

Parameters:

  • new_path (String)

    The new remote directory to create.



300
301
302
# File 'lib/ronin/post_ex/sessions/shell_session.rb', line 300

def fs_mkdir(new_path)
  command_exec('mkdir',new_path)
end

#fs_mktemp(basename) ⇒ String

Note:

executes the mktemp <basename> command.

Creates a remote temporary file with the given file basename.

Parameters:

  • basename (String)

    The basename for the new temporary file.

Returns:

  • (String)

    The path of the newly created temporary file.



288
289
290
# File 'lib/ronin/post_ex/sessions/shell_session.rb', line 288

def fs_mktemp(basename)
  command_exec('mktemp',basename).chomp
end

#fs_move(path, new_path) ⇒ Object

Note:

executes the mv <path> <new_path> command.

Moves or renames a remote source file to a new destination path.

Parameters:

  • path (String)

    The source file path.

  • new_path (String)

    The destination file path.



354
355
356
# File 'lib/ronin/post_ex/sessions/shell_session.rb', line 354

def fs_move(path,new_path)
  command_exec('mv',path,new_path)
end

#fs_readdir(path) ⇒ Array<String>

Note:

executes the ls <path> command.

Reads the contents of a remote directory and returns an Array of directory entry names.

Parameters:

  • path (String)

    The path of the remote directory to read.

Returns:

  • (Array<String>)

    The entities within the remote directory.



258
259
260
# File 'lib/ronin/post_ex/sessions/shell_session.rb', line 258

def fs_readdir(path)
  command_exec('ls',path).lines(chomp: true)
end

#fs_readfile(path) ⇒ String?

Note:

executes the cat <path> command.

Reads the entire file at the given path and returns the full file's contents.

Parameters:

  • path (String)

    The remote path to read.

Returns:

  • (String, nil)

    The contents of the remote file or nil if the file could not be read.



226
227
228
# File 'lib/ronin/post_ex/sessions/shell_session.rb', line 226

def fs_readfile(path)
  command_exec('cat',path)
end
Note:

executes the readlink -f <path> command.

Reads the destination path of a remote symbolic link.

Parameters:

  • path (String)

    The remote path to read.

Returns:

  • (String, nil)

    The destination of the remote symbolic link or nil if the symbolic link could not be read.



242
243
244
# File 'lib/ronin/post_ex/sessions/shell_session.rb', line 242

def fs_readlink(path)
  command_exec('readlink','-f',path).chomp
end

#fs_rmdir(path) ⇒ Object

Note:

executes the rmdir <path> command.

Removes an empty directory at the given path.

Parameters:

  • path (String)

    The remote directory path to remove.



339
340
341
# File 'lib/ronin/post_ex/sessions/shell_session.rb', line 339

def fs_rmdir(path)
  command_exec('rmdir',path)
end

#fs_stat(path) ⇒ Hash{Symbol => Object}?

Note:

executes the stat -t <path> command.

Queries file information for the given remote path and returns a Hash of file metadata.

Parameters:

  • path (String)

    The path to the remote file or directory.

Returns:

  • (Hash{Symbol => Object}, nil)

    The metadata for the remote file.



433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
# File 'lib/ronin/post_ex/sessions/shell_session.rb', line 433

def fs_stat(path)
  fields = command_exec('stat','-t',path).strip.split(' ')

  return {
    path:      path,
    size:      fields[1].to_i,
    blocks:    fields[2].to_i,
    uid:       fields[4].to_i,
    gid:       fields[5].to_i,
    inode:     fields[7].to_i,
    links:     fields[8].to_i,
    atime:     Time.at(fields[11].to_i),
    mtime:     Time.at(fields[12].to_i),
    ctime:     Time.at(fields[13].to_i),
    blocksize: fields[14].to_i
  }
end
Note:

executes the rm <path> command.

Removes a file at the given path.

Parameters:

  • path (String)

    The remote path to remove.



327
328
329
# File 'lib/ronin/post_ex/sessions/shell_session.rb', line 327

def fs_unlink(path)
  command_exec('rm',path)
end

#process_environHash{String => String}

Note:

executes the env command.

Queries all environment variables of the current process. Returns a Hash of the env variable names and values.

Returns:

  • (Hash{String => String})

    The Hash of environment variables.



512
513
514
515
516
# File 'lib/ronin/post_ex/sessions/shell_session.rb', line 512

def process_environ
  Hash[command_exec('env').each_line(chomp: true).map { |line|
    line.split('=',2)
  }]
end

#process_exitObject

Note:

executes the exit command.

Exits the current process.



604
605
606
# File 'lib/ronin/post_ex/sessions/shell_session.rb', line 604

def process_exit
  shell_puts('exit')
end

#process_getenv(name) ⇒ String

Note:

executes the echo $<name> command.

Gets an individual environment variable. If the environment variable has not been set, nil will be returned.

Parameters:

  • name (String)

    The environment variable name to get.

Returns:

  • (String)

    The environment variable value.



530
531
532
# File 'lib/ronin/post_ex/sessions/shell_session.rb', line 530

def process_getenv(name)
  shell_exec("echo $#{name}").chomp
end

#process_getgidInteger

Note:

executes the id -g command.

Gets the current process's group ID (GID).

Returns:

  • (Integer)

    The group ID (GID) for the current process.



499
500
501
# File 'lib/ronin/post_ex/sessions/shell_session.rb', line 499

def process_getgid
  command_exec('id','-g').to_i
end

#process_getpidInteger

Note:

executes the echo $$ command.

Gets the current process's Process ID (PID).

Returns:

  • (Integer)

    The current process's PID.



463
464
465
# File 'lib/ronin/post_ex/sessions/shell_session.rb', line 463

def process_getpid
  shell_exec('echo $$').to_i
end

#process_getppidInteger

Note:

executes the echo $PPID command.

Gets the current process's parent Process ID (PPID).

Returns:

  • (Integer)

    The current process's PPID.



475
476
477
# File 'lib/ronin/post_ex/sessions/shell_session.rb', line 475

def process_getppid
  shell_exec('echo $PPID').to_i
end

#process_getuidInteger

Note:

executes the id -u command.

Gets the current process's user ID (UID).

Returns:

  • (Integer)

    The current process's UID.



487
488
489
# File 'lib/ronin/post_ex/sessions/shell_session.rb', line 487

def process_getuid
  command_exec('id','-u').to_i
end

#process_kill(pid, signal) ⇒ Object

Note:

executes the kill -s <signal> <pid> command.

Kills another process using the given Process ID (POD) and the signal number.

Parameters:

  • pid (Integer)

    The process ID (PID) to kill.

  • signal (Integer)

    The signal to send the process ID (PID).



573
574
575
# File 'lib/ronin/post_ex/sessions/shell_session.rb', line 573

def process_kill(pid,signal)
  command_exec('kill','-s',signal,pid)
end

#process_setenv(name, value) ⇒ Object

Note:

executes the export <name>=<value> command.

Sets an environment variable to the given value.

Parameters:

  • name (String)

    The environment variable name to set.

  • value (String)

    The new value for the environment variable.



545
546
547
# File 'lib/ronin/post_ex/sessions/shell_session.rb', line 545

def process_setenv(name,value)
  shell_puts("export #{name}=#{value}")
end

#process_spawn(command, *arguments) ⇒ Integer

Note:

executes the command with additional arguments as a background process.

Spawns a new process using the given program and additional arguments.

Parameters:

  • command (String)

    The command name to spawn.

  • arguments (Array<String>)

    Additional arguments for the program.

Returns:

  • (Integer)

    The process ID (PID) of the spawned process.



593
594
595
596
597
# File 'lib/ronin/post_ex/sessions/shell_session.rb', line 593

def process_spawn(command,*arguments)
  command = command_join(command,*arguments)

  shell_exec("#{command} 2>&1 >/dev/null &; echo $!").to_i
end

#process_unsetenv(name) ⇒ Object

Note:

executes the unset <name> command.

Un-sets an environment variable.

Parameters:

  • name (String)

    The environment variable to unset.



557
558
559
# File 'lib/ronin/post_ex/sessions/shell_session.rb', line 557

def process_unsetenv(name)
  shell_puts("unset #{name}")
end

#shell_exec(command) ⇒ String

Executes a shell command and returns it's output.

Parameters:

  • command (String)

    The shell command to execute.

Returns:

  • (String)

    The output of the shell command.



95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/ronin/post_ex/sessions/shell_session.rb', line 95

def shell_exec(command)
  shell_puts("echo #{DELIMINATOR}; #{command} 2>/dev/null | base64; echo #{DELIMINATOR}")

  # consume any leading output before the command output
  while (line = shell_gets)
    if line.chomp == DELIMINATOR
      break
    end
  end

  output = String.new

  while (line = shell_gets)
    if line.chomp == DELIMINATOR
      break
    end

    output << line
  end

  return Base64.decode64(output)
end

#shell_getsString?

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Reads a line from the shell.

Returns:

  • (String, nil)


79
80
81
# File 'lib/ronin/post_ex/sessions/shell_session.rb', line 79

def shell_gets
  @io.gets
end

#shell_puts(line) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Writes a line to the shell.

Parameters:

  • line (String)

    The line to write.



68
69
70
# File 'lib/ronin/post_ex/sessions/shell_session.rb', line 68

def shell_puts(line)
  @io.write("#{line}\n")
end

#sys_hostnameString

Note:

executes the echo $HOSTNAME command.

Gets the system's hostname.

Returns:

  • (String)


181
182
183
# File 'lib/ronin/post_ex/sessions/shell_session.rb', line 181

def sys_hostname
  shell_exec("echo $HOSTNAME").chomp
end

#sys_timeInteger

Note:

executes the date +%s command.

Gets the current time and returns the UNIX timestamp.

Returns:

  • (Integer)

    The current time as a UNIX timestamp.



170
171
172
# File 'lib/ronin/post_ex/sessions/shell_session.rb', line 170

def sys_time
  shell_exec('date +%s').to_i
end