Class: Rex::Proto::Ssh::Server

Inherits:
Object
  • Object
show all
Includes:
Rex::Proto
Defined in:
lib/rex/proto/ssh/server.rb

Overview

Acts as an SSH server, accepting clients and extending them with Connections

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(port = 22, listen_host = '0.0.0.0', context = {}, comm = nil, ssh_opts = default_options, cc_cb = nil, cd_cb = nil) ⇒ Server

Initializes an SSH server as listening on the provided port and hostname.

[View source] [View on GitHub]

52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/rex/proto/ssh/server.rb', line 52

def initialize(port = 22, listen_host = '0.0.0.0', context = {}, comm = nil,
  ssh_opts = default_options, cc_cb = nil, cd_cb = nil)

  self.listen_host            = listen_host
  self.listen_port            = port
  self.context                = context
  self.comm                   = comm
  self.listener               = nil
  self.server_options         = ssh_opts
  self.on_client_connect_proc = cc_cb
  self.on_client_data_proc    = cd_cb
end

Instance Attribute Details

#clientsObject

Returns the value of attribute clients.

[View on GitHub]

138
139
140
# File 'lib/rex/proto/ssh/server.rb', line 138

def clients
  @clients
end

#commObject

Returns the value of attribute comm.

[View on GitHub]

138
139
140
# File 'lib/rex/proto/ssh/server.rb', line 138

def comm
  @comm
end

#contextObject

Returns the value of attribute context.

[View on GitHub]

138
139
140
# File 'lib/rex/proto/ssh/server.rb', line 138

def context
  @context
end

#listen_hostObject

Returns the value of attribute listen_host.

[View on GitHub]

138
139
140
# File 'lib/rex/proto/ssh/server.rb', line 138

def listen_host
  @listen_host
end

#listen_portObject

Returns the value of attribute listen_port.

[View on GitHub]

138
139
140
# File 'lib/rex/proto/ssh/server.rb', line 138

def listen_port
  @listen_port
end

#listenerObject

Returns the value of attribute listener.

[View on GitHub]

139
140
141
# File 'lib/rex/proto/ssh/server.rb', line 139

def listener
  @listener
end

#monitor_threadObject

Returns the value of attribute monitor_thread.

[View on GitHub]

138
139
140
# File 'lib/rex/proto/ssh/server.rb', line 138

def monitor_thread
  @monitor_thread
end

#on_client_connect_procObject

Returns the value of attribute on_client_connect_proc.

[View on GitHub]

139
140
141
# File 'lib/rex/proto/ssh/server.rb', line 139

def on_client_connect_proc
  @on_client_connect_proc
end

#on_client_data_procObject

Returns the value of attribute on_client_data_proc.

[View on GitHub]

139
140
141
# File 'lib/rex/proto/ssh/server.rb', line 139

def on_client_data_proc
  @on_client_data_proc
end

#server_optionsObject

Returns the value of attribute server_options.

[View on GitHub]

139
140
141
# File 'lib/rex/proto/ssh/server.rb', line 139

def server_options
  @server_options
end

Class Method Details

.hardcore_alias(*args) ⇒ Object

Returns the hardcore alias for the SSH service

[View source] [View on GitHub]

74
75
76
# File 'lib/rex/proto/ssh/server.rb', line 74

def self.hardcore_alias(*args)
  "#{(args[0])}-#{(args[1])}-#{args[4] || ''}"
end

Instance Method Details

#aliasObject

SSH server.

[View source] [View on GitHub]

81
82
83
# File 'lib/rex/proto/ssh/server.rb', line 81

def alias
  super || "SSH Server"
end

#close_client(cli) ⇒ Object

Closes the supplied client, if valid.

[View source] [View on GitHub]

132
133
134
135
# File 'lib/rex/proto/ssh/server.rb', line 132

def close_client(cli)
  clients.delete(cli)
  listener.close_client(cli.parent)
end

#enqueue_client(cli) ⇒ Object (protected)

Waits for SSH client to “grow a pair” of FDs and adds a ChannelFD object derived from the client’s Connection Channel’s FDs to the Ssh::Server’s clients array

Parameters:

[View source] [View on GitHub]

187
188
189
190
191
192
193
194
195
196
197
198
199
200
# File 'lib/rex/proto/ssh/server.rb', line 187

def enqueue_client(cli)
  Rex::ThreadFactory.spawn("ChannelFDWaiter", false) do
    begin
      Timeout::timeout(15) do
        while cli.connection.open_channel_keys.empty? do
          sleep 0.02
        end
        self.clients.push(Ssh::ChannelFD.new(cli))
      end
    rescue Timeout::Error
      elog("Unable to find channel FDs for client #{cli}")
    end
  end
end

#inspectString

More readable inspect that only shows the url and resources

Returns:

  • (String)
[View source] [View on GitHub]

67
68
69
# File 'lib/rex/proto/ssh/server.rb', line 67

def inspect
  "#<#{self.class} ssh://#{listen_host}:#{listen_port}>"
end

#monitor_clientsObject (protected)

Watches FD channel abstractions, removes closed instances, checks for read data on clients if client data callback is defined, invokes the callback if possible, sleeps otherwise.

[View source] [View on GitHub]

162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
# File 'lib/rex/proto/ssh/server.rb', line 162

def monitor_clients
  loop do
    self.clients.delete_if {|c| c.closed? }
    if self.on_client_data_proc
      if clients.any? { |cli|
        cli.has_read_data? and self.on_client_data_proc.call(cli)}
        next
      else
        sleep 0.05
      end
    else
      sleep 0.5
    end
  end
rescue => e
  wlog(e)
end

#on_client_connect(cli) ⇒ Object (protected)

Extends new clients with the ServerClient module and initializes them.

[View source] [View on GitHub]

146
147
148
149
150
151
152
153
154
155
# File 'lib/rex/proto/ssh/server.rb', line 146

def on_client_connect(cli)
  cli.extend(ServerClient)

  cli.init_cli(self)
  if self.on_client_connect_proc
    self.on_client_connect_proc.call(cli)
  else
    enqueue_client(cli)
  end
end

#start(srvsock = nil) ⇒ Object

Listens on the defined port and host and starts monitoring for clients.

[View source] [View on GitHub]

89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/rex/proto/ssh/server.rb', line 89

def start(srvsock = nil)

  self.listener = srvsock.is_a?(Rex::Socket::TcpServer) ? srvsock : Rex::Socket::TcpServer.create(
    'LocalHost' => self.listen_host,
    'LocalPort' => self.listen_port,
    'Context'   => self.context,
    'Comm'      => self.comm
  )

  # Register callbacks
  self.listener.on_client_connect_proc = Proc.new { |cli|
    on_client_connect(cli)
  }
  # self.listener.on_client_data_proc = Proc.new { |cli|
  #   on_client_data(cli)
  # }
  self.clients         = []
  self.monitor_thread  = Rex::ThreadFactory.spawn("SshServerClientMonitor", false) {
    monitor_clients
  }
  self.listener.start
end

#stopObject

Terminates the monitor thread and turns off the listener.

[View source] [View on GitHub]

115
116
117
118
119
# File 'lib/rex/proto/ssh/server.rb', line 115

def stop
  self.listener.stop
  self.listener.close
  self.clients = []
end

#waitObject

Waits for the SSH service to terminate

[View source] [View on GitHub]

125
126
127
# File 'lib/rex/proto/ssh/server.rb', line 125

def wait
  self.listener.wait if self.listener
end