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.


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.


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

def clients
  @clients
end

#commObject

Returns the value of attribute comm.


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

def comm
  @comm
end

#contextObject

Returns the value of attribute context.


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.


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.


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.


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.


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.


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.


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.


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


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.


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.


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:


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)

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.


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.


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.


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.


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


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

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