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

#command_terminationObject


42
43
44
# File 'lib/msf/core/session/provider/single_command_shell.rb', line 42

def command_termination
  "\n"
end

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


113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/msf/core/session/provider/single_command_shell.rb', line 113

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}#{command_termination}")
  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


87
88
89
90
91
92
93
94
# File 'lib/msf/core/session/provider/single_command_shell.rb', line 87

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


100
101
102
103
104
105
106
107
108
109
# File 'lib/msf/core/session/provider/single_command_shell.rb', line 100

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


131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/msf/core/session/provider/single_command_shell.rb', line 131

def shell_command_token_win32(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.
  # NOTE: if the session echoes input we don't need to echo the token twice.
  shell_write(cmd + "&echo #{token}#{command_termination}")
  res = shell_read_until_token(token, @shell_token_index, timeout)
  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


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
81
82
83
84
85
# File 'lib/msf/core/session/provider/single_command_shell.rb', line 49

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
          unless buf.nil?
            # normalize the line endings following the token and parse them
            buf.gsub!("#{token}\n", "#{token}\r\n")
            parts = buf.split("#{token}\r\n", -1)
            if parts.length == parts_needed
              # cause another prompt to appear (just in case)
              shell_write(command_termination)
              return parts[wanted_idx]
            end
          end
        end
      end
    end
  rescue Timeout::Error
    # This is expected in many cases
  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