class Ronin::CLI::Commands::Netcat
A ‘netcat` clone written in Ruby using the [async-io] gem.
[async-io]: github.com/socketry/async-io#readme
## 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
Attributes
mode[R]
Whether to connect or listen for connections.
@return [:connect, :listen]
protocol[R]
The protocol to use.
@return [:tcp, :udp, :unix]
Public Class Methods
new(**kwargs)
click to toggle source
Initializes the command.
@param [Hash{Symbol => Object}] kwargs
Additional keyword arguments.
Calls superclass method
# File lib/ronin/cli/commands/netcat.rb, line 178 def initialize(**kwargs) super(**kwargs) @protocol = :tcp @mode = :connect end
Public Instance Methods
async_endpoint()
click to toggle source
Creates the async endpoint object.
@return [Async::IO::Endpoint]
# 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_stdin()
click to toggle source
Creates the async stdin stream.
@return [Async::IO::Stream]
# File lib/ronin/cli/commands/netcat.rb, line 296 def async_stdin Async::IO::Stream.new(Async::IO::Generic.new(self.stdin)) end
client_loop()
click to toggle source
The client event loop.
# 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_async()
click to toggle source
Loads the async-io library.
# File lib/ronin/cli/commands/netcat.rb, line 254 def load_async require 'async/notification' require 'async/io' require 'async/io/stream' end
print_data(data)
click to toggle source
Prints or hexdumps data to stdout.
@param [String] data
The data to print or hexdump.
# 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)
click to toggle source
Runs the ‘ronin netcat` command.
@param [Array<String>] args
Additional command-line arguments.
# 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_loop()
click to toggle source
The server event loop.
# 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_context()
click to toggle source
Creates an SSL context.
@return [Ronin::Support::Network::SSL]
# 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