Class: Ronin::CLI::Commands::Netcat Private

Inherits:
Ronin::CLI::Command show all
Includes:
CommandKit::Options::Verbose, Core::CLI::Logging
Defined in:
lib/ronin/cli/commands/netcat.rb

Overview

This class is part of a private API. You should avoid using this class if possible, as it may be removed or be changed in the future.

A netcat clone written in Ruby using the async-io gem.

Usage

[options] [--tcp | --udp | --ssl | --tls] {HOST PORT | -l [HOST] PORT | --unix PATH}

Options

-v, --verbose                    Enables verbose output
    --tcp                        Uses the TCP protocol
    --udp                        Uses the UDP protocol
-U, --unix PATH                  Uses the UNIX socket protocol
-l, --listen                     Listens for incoming connections
-s, --source HOST                Source address to bind to
-p, --source-port PORT           Source port to bind to
-b, --buffer-size INT            Buffer size to use (Default: 4096)
-x, --hexdump                    Hexdumps each message that is received
    --ssl                        Enables SSL mode
    --tls                        Enables TLS mode
    --ssl-version 1|1.1|1.2      Specifies the required SSL version
    --ssl-cert FILE              Specifies the SSL certificate file
    --ssl-key FILE               Specifies the SSL key file
    --ssl-verify none|peer|fail-if-no-peer-cert|client-once|true|false
                                 SSL verification mode
    --ssl-ca-bundle PATH         Path to the file or directory of CA certificates
-h, --help                       Print help information

Arguments

[HOST]                           The host to connect to or listen on
[POST]                           The port to connect to

Since:

  • 2.0.0

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(**kwargs) ⇒ Netcat

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Initializes the command.

Parameters:

  • kwargs (Hash{Symbol => Object})

    Additional keyword arguments.

Since:

  • 2.0.0



178
179
180
181
182
183
# File 'lib/ronin/cli/commands/netcat.rb', line 178

def initialize(**kwargs)
  super(**kwargs)

  @protocol = :tcp
  @mode     = :connect
end

Instance Attribute Details

#mode:connect, :listen (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Whether to connect or listen for connections.

Returns:

  • (:connect, :listen)

Since:

  • 2.0.0



170
171
172
# File 'lib/ronin/cli/commands/netcat.rb', line 170

def mode
  @mode
end

#protocol:tcp, ... (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

The protocol to use.

Returns:

  • (:tcp, :udp, :unix)

Since:

  • 2.0.0



165
166
167
# File 'lib/ronin/cli/commands/netcat.rb', line 165

def protocol
  @protocol
end

Instance Method Details

#async_endpointAsync::IO::Endpoint

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Creates the async endpoint object.

Returns:

  • (Async::IO::Endpoint)

Since:

  • 2.0.0



280
281
282
283
284
285
286
287
288
289
# File 'lib/ronin/cli/commands/netcat.rb', line 280

def async_endpoint
  case @protocol
  when :tcp  then Async::IO::Endpoint.tcp(@host,@port)
  when :udp  then Async::IO::Endpoint.udp(@host,@port)
  when :unix then Async::IO::Endpoint.unix(options[:unix])
  when :ssl
    Async::IO::Endpoint.ssl(@host,@port, hostname:    @host,
                                         ssl_context: ssl_context)
  end
end

#async_stdinAsync::IO::Stream

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Creates the async stdin stream.

Returns:

  • (Async::IO::Stream)

Since:

  • 2.0.0



296
297
298
# File 'lib/ronin/cli/commands/netcat.rb', line 296

def async_stdin
  Async::IO::Stream.new(Async::IO::Generic.new(self.stdin))
end

#client_loopObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

The client event loop.

Since:

  • 2.0.0



303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
# File 'lib/ronin/cli/commands/netcat.rb', line 303

def client_loop
  finished    = Async::Notification.new
  endpoint    = async_endpoint
  stdin       = async_stdin
  buffer_size = options[:buffer_size]

  Async do |task|
    socket = begin
               endpoint.connect
             rescue StandardError => error
               print_error(error.message)
               exit(1)
             end

    stream = Async::IO::Stream.new(socket)

    begin
      client = task.async do
        while (data = stream.read_partial(buffer_size))
          print_data(data)
        end
      rescue EOFError
        # ignore EOFError
      ensure
        finished.signal
      end

      user = task.async do
        while (data = stdin.read_partial(buffer_size))
          socket.write(data)
        end
      rescue EOFError
        # ignore EOFError
      ensure
        finished.signal
      end

      finished.wait
    ensure
      client.stop
      user.stop
      socket.close
    end
  end
end

#load_asyncObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Loads the async-io library.

Since:

  • 2.0.0



254
255
256
257
258
# File 'lib/ronin/cli/commands/netcat.rb', line 254

def load_async
  require 'async/notification'
  require 'async/io'
  require 'async/io/stream'
end

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Prints or hexdumps data to stdout.

Parameters:

  • data (String)

    The data to print or hexdump.

Since:

  • 2.0.0



408
409
410
411
412
413
414
# File 'lib/ronin/cli/commands/netcat.rb', line 408

def print_data(data)
  if @hexdump
    @hexdump.hexdump(data)
  else
    print(data)
  end
end

#run(*args) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Runs the ronin netcat command.

Parameters:

  • args (Array<String>)

    Additional command-line arguments.

Since:

  • 2.0.0



191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
# File 'lib/ronin/cli/commands/netcat.rb', line 191

def run(*args)
  if options[:hexdump]
    require 'hexdump'
    @hexdump = Hexdump::Hexdump.new
  end

  case @mode
  when :connect
    @host, @port = *args

    unless @host
      print_error "host argument required"
      exit(-1)
    end

    unless @port
      print_error "port argument required"
      exit(-1)
    end

    if options[:verbose]
      if @protocol == :unix
        log_info "Connecting to #{options[:unix]} ..."
      else
        log_info "Connecting to #{@host}:#{@port} ..."
      end
    end

    load_async
    client_loop
  when :listen
    case args.length
    when 0
      @port = options.fetch(:port,0)
      @host = nil
    when 1
      @port = args[0].to_i
      @host = nil
    when 2
      @host = args[0]
      @port = args[1].to_i
    end

    if options[:verbose]
      if @protocol == :unix
        log_info "Listening on #{options[:unix]} ..."
      else
        if @host
          log_info "Listening #{@host}:#{@port} ..."
        else
          log_info "Listening port #{@port} ..."
        end
      end
    end

    load_async
    server_loop
  end
end

#server_loopObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

The server event loop.

Since:

  • 2.0.0



352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
# File 'lib/ronin/cli/commands/netcat.rb', line 352

def server_loop
  finished    = Async::Notification.new
  endpoint    = async_endpoint
  stdin       = async_stdin
  clients     = []
  buffer_size = options[:buffer_size]

  Async do |task|
    endpoint.accept do |socket|
      if options[:verbose]
        log_info "Client #{socket} connected"
      end

      clients << socket
      stream = Async::IO::Stream.new(socket)

      begin
        while (data = stream.read_partial(buffer_size))
          print_data(data)
        end
      rescue EOFError
        # ignore EOFError
      end

      clients.delete(socket)

      if options[:verbose]
        log_warn "Client #{socket} disconnected"
      end
    end

    task.async do
      while (data = stdin.read_partial(buffer_size))
        clients.each { |client| client.write(data) }
      end
    rescue EOFError
      # ignore EOFError
    ensure
      finished.signal
    end

    finished.wait
  rescue StandardError => error
    print_error(error.message)
    exit(1)
  ensure
    clients.each(&:close)
  end
end

#ssl_contextRonin::Support::Network::SSL

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Creates an SSL context.

Returns:

  • (Ronin::Support::Network::SSL)

Since:

  • 2.0.0



265
266
267
268
269
270
271
272
273
# File 'lib/ronin/cli/commands/netcat.rb', line 265

def ssl_context
  Support::Network::SSL.context(
    version:   options[:ssl_version],
    verify:    options[:ssl_verify],
    key_file:  options[:ssl_key],
    cert_file: options[:ssl_cert],
    ca_bundle: options[:ssl_ca_bundle]
  )
end