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 = Ssh::Connection.default_options, cc_cb = nil, cd_cb = nil) ⇒ Server

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


47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/rex/proto/ssh/server.rb', line 47

def initialize(port = 22, listen_host = '0.0.0.0', context = {}, comm = nil,
  ssh_opts = Ssh::Connection.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


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

def clients
  @clients
end

#commObject

Returns the value of attribute comm


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

def comm
  @comm
end

#contextObject

Returns the value of attribute context


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

def context
  @context
end

#listen_hostObject

Returns the value of attribute listen_host


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

def listen_host
  @listen_host
end

#listen_portObject

Returns the value of attribute listen_port


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

def listen_port
  @listen_port
end

#listenerObject

Returns the value of attribute listener


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

def listener
  @listener
end

#monitor_threadObject

Returns the value of attribute monitor_thread


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

def monitor_thread
  @monitor_thread
end

#on_client_connect_procObject

Returns the value of attribute on_client_connect_proc


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

def on_client_connect_proc
  @on_client_connect_proc
end

#on_client_data_procObject

Returns the value of attribute on_client_data_proc


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

def on_client_data_proc
  @on_client_data_proc
end

#server_optionsObject

Returns the value of attribute server_options


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

def server_options
  @server_options
end

Class Method Details

.hardcore_alias(*args) ⇒ Object

Returns the hardcore alias for the SSH service


69
70
71
# File 'lib/rex/proto/ssh/server.rb', line 69

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

Instance Method Details

#aliasObject

SSH server.


76
77
78
# File 'lib/rex/proto/ssh/server.rb', line 76

def alias
  super || "SSH Server"
end

#close_client(cli) ⇒ Object

Closes the supplied client, if valid.


127
128
129
130
# File 'lib/rex/proto/ssh/server.rb', line 127

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:


182
183
184
185
186
187
188
189
190
191
192
193
194
195
# File 'lib/rex/proto/ssh/server.rb', line 182

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)

62
63
64
# File 'lib/rex/proto/ssh/server.rb', line 62

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.


157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/rex/proto/ssh/server.rb', line 157

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.


141
142
143
144
145
146
147
148
149
150
# File 'lib/rex/proto/ssh/server.rb', line 141

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.


84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/rex/proto/ssh/server.rb', line 84

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.


110
111
112
113
114
# File 'lib/rex/proto/ssh/server.rb', line 110

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

#waitObject

Waits for the SSH service to terminate


120
121
122
# File 'lib/rex/proto/ssh/server.rb', line 120

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