Module: Msf::Session::Provider::SingleCommandShell

Overview

This interface is to be implemented by a session that is only capable of providing an interface to a single command shell.

Instance Method Summary collapse

Instance Method Details

#set_shell_token_index(timeout) ⇒ Object

NOTE: if the session echoes input we don't need to echo the token twice. This setting will persist for the duration of the session.


108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/msf/core/session/provider/single_command_shell.rb', line 108

def set_shell_token_index(timeout)
  return @shell_token_index if @shell_token_index
  token = ::Rex::Text.rand_text_alpha(32)
  numeric_token = rand(0xffffffff) + 1
  cmd = "echo #{numeric_token}"
  shell_write(cmd + ";echo #{token}\n")
  res = shell_read_until_token(token, 0, timeout)
  if res.to_i == numeric_token
    @shell_token_index = 0
  else
    @shell_token_index = 1
  end
end

#shell_closeObject

Closes the command shell.

Raises:

  • (NotImplementedError)

38
39
40
# File 'lib/msf/core/session/provider/single_command_shell.rb', line 38

def shell_close()
  raise NotImplementedError
end

#shell_command_token(cmd, timeout = 10) ⇒ Object


82
83
84
85
86
87
88
89
# File 'lib/msf/core/session/provider/single_command_shell.rb', line 82

def shell_command_token(cmd, timeout=10)
  if platform == 'windows'
    output = shell_command_token_win32(cmd, timeout)
  else
    output = shell_command_token_unix(cmd, timeout)
  end
  output
end

#shell_command_token_unix(cmd, timeout = 10) ⇒ Object

Explicitly run a single command and return the output. This version uses a marker to denote the end of data (instead of a timeout).


95
96
97
98
99
100
101
102
103
104
# File 'lib/msf/core/session/provider/single_command_shell.rb', line 95

def shell_command_token_unix(cmd, timeout=10)
  # read any pending data
  buf = shell_read(-1, 0.01)
  set_shell_token_index(timeout)
  token = ::Rex::Text.rand_text_alpha(32)

  # Send the command to the session's stdin.
  shell_write(cmd + ";echo #{token}\n")
  shell_read_until_token(token, @shell_token_index, timeout)
end

#shell_command_token_win32(cmd, timeout = 10) ⇒ Object

Explicitly run a single command and return the output. This version uses a marker to denote the end of data (instead of a timeout).


126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/msf/core/session/provider/single_command_shell.rb', line 126

def shell_command_token_win32(cmd, timeout=10)
  # read any pending data
  buf = shell_read(-1, 0.01)
  token = ::Rex::Text.rand_text_alpha(32)

  # Send the command to the session's stdin.
  # NOTE: if the session echoes input we don't need to echo the token twice.
  shell_write(cmd + "&echo #{token}\n")
  res = shell_read_until_token(token, 1, timeout)
  # I would like a better way to do this, but I don't know of one
  res.reverse!.chomp!.reverse! # the presence of a leading newline is not consistent
  res
end

#shell_initObject

Initializes the command shell.

Raises:

  • (NotImplementedError)

17
18
19
# File 'lib/msf/core/session/provider/single_command_shell.rb', line 17

def shell_init()
  raise NotImplementedError
end

#shell_read(length = nil) ⇒ Object

Reads data from the command shell.

Raises:

  • (NotImplementedError)

24
25
26
# File 'lib/msf/core/session/provider/single_command_shell.rb', line 24

def shell_read(length = nil)
  raise NotImplementedError
end

#shell_read_until_token(token, wanted_idx = 0, timeout = 10) ⇒ Object

Read data until we find the token


45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/msf/core/session/provider/single_command_shell.rb', line 45

def shell_read_until_token(token, wanted_idx=0, timeout=10)
  return if timeout.to_i == 0

  if wanted_idx == 0
    parts_needed = 2
  else
    parts_needed = 1 + (wanted_idx * 2)
  end

  # Read until we get the data between two tokens or absolute timeout.
  begin
    ::Timeout.timeout(timeout) do
      buf = ''
      idx = nil
      loop do
        if (tmp = shell_read(-1))
          buf << tmp

          # see if we have the wanted idx
          parts = buf.split(token, -1)

          if parts.length == parts_needed
            # cause another prompt to appear (just in case)
            shell_write("\n")
            return parts[wanted_idx]
          end
        end
      end
    end
  rescue
    # nothing, just continue
  end

  # failed to get any data or find the token!
  nil
end

#shell_write(buf) ⇒ Object

Writes data to the command shell.

Raises:

  • (NotImplementedError)

31
32
33
# File 'lib/msf/core/session/provider/single_command_shell.rb', line 31

def shell_write(buf)
  raise NotImplementedError
end