Pure Ruby Netcat

Simple Ncat.rb

I found this simple ncat so I did some enhancements on it and add some comments in it as well.

  1. #!/usr/bin/ruby
  2. require 'optparse'
  3. require 'ostruct'
  4. require 'socket'
  5. class String
  6. def red; colorize(self, "\e[1m\e[31m"); end
  7. def green; colorize(self, "\e[1m\e[32m"); end
  8. def cyan; colorize(self, "\e[1;36m"); end
  9. def bold; colorize(self, "\e[1m"); end
  10. def colorize(text, color_code) "#{color_code}#{text}\e[0m" end
  11. end
  12. class NetCat
  13. #
  14. # Parsing options
  15. #
  16. def parse_opts(args)
  17. @options = OpenStruct.new
  18. opts = OptionParser.new do |opts|
  19. opts.banner = "Usage: #{__FILE__}.rb [options]"
  20. opts.on('-c', '--connect',
  21. "Connect to a remote host") do
  22. @options.connection_type = :connect
  23. end
  24. opts.on('-l', '--listen',
  25. "Listen for a remote host to connect to this host") do
  26. @options.connection_type = :listen
  27. end
  28. opts.on('-r', '--remote-host HOSTNAME', String,
  29. "Specify the host to connect to") do |hostname|
  30. @options.hostname = hostname || '127.0.0.1'
  31. end
  32. opts.on('-p', '--port PORT', Integer,
  33. "Specify the TCP port") do |port|
  34. @options.port = port
  35. end
  36. opts.on('-v', '--verbose') do
  37. @options.verbose = :verbose
  38. end
  39. opts.on_tail('-h', '--help', "Show this message") do
  40. puts opts
  41. exit
  42. end
  43. end
  44. begin
  45. opts.parse!(args)
  46. rescue OptionParser::ParseError => err
  47. puts err.message
  48. puts opts
  49. exit
  50. end
  51. if @options.connection_type == nil
  52. puts "[!] ".red + "No Connection Type specified"
  53. puts opts
  54. exit
  55. end
  56. if @options.port == nil
  57. puts "[!] ".red + "No Port specified to #{@options.connection_type.to_s.capitalize}"
  58. puts opts
  59. exit
  60. end
  61. if @options.connection_type == :connect && @options.hostname == nil
  62. puts "[!] ".red + "Connection type connect requires a hostname"
  63. puts opts
  64. exit
  65. end
  66. end
  67. #
  68. # Socket Management
  69. #
  70. def connect_socket
  71. begin
  72. if @options.connection_type == :connect
  73. # Client
  74. puts "[+] ".green + "Connecting to " + "#{@options.hostname}".bold + " on port " + "#{@options.port}".bold if @options.verbose == :verbose
  75. @socket = TCPSocket.open(@options.hostname, @options.port)
  76. else
  77. # Server
  78. puts "[+] ".green + "Listing on port " + "#{@options.port}".bold if @options.verbose == :verbose
  79. server = TCPServer.new(@options.port)
  80. server.listen(1)
  81. @socket = server.accept
  82. print "-> ".cyan
  83. end
  84. rescue Exception => e
  85. puts "[!] ".red + "Error [1]: " + "#{e}"
  86. exit
  87. end
  88. end
  89. #
  90. # Data Transfer Management
  91. #
  92. def forward_data
  93. while true
  94. if IO.select([],[],[@socket, STDIN],0)
  95. socket.close
  96. end
  97. # Send command if done from receiving upto 2-billions bytes
  98. begin
  99. while (data = @socket.recv_nonblock(2000000000)) != ""
  100. STDOUT.write(data)
  101. print "-> ".cyan
  102. end
  103. exit
  104. rescue Errno::EAGAIN
  105. # http://stackoverflow.com/questions/20604130/how-to-use-rubys-write-nonblock-read-nonblock-with-servers-clients
  106. end
  107. begin
  108. while (data = STDIN.read_nonblock(2000000000)) != ""
  109. @socket.write(data)
  110. end
  111. exit
  112. rescue Errno::EAGAIN
  113. # http://stackoverflow.com/questions/20604130/how-to-use-rubys-write-nonblock-read-nonblock-with-servers-clients
  114. rescue EOFError
  115. exit
  116. end
  117. # Get all remote system socket(STDIN, STDOUT, STDERR) To my STDIN
  118. IO.select([@socket, STDIN], [@socket, STDIN], [@socket, STDIN])
  119. end
  120. end
  121. #
  122. # Run Ncat
  123. #
  124. def run(args)
  125. parse_opts(args)
  126. connect_socket
  127. forward_data
  128. end
  129. end
  130. ncat = NetCat.new
  131. ncat.run(ARGV)
  • To listen

    1. ruby ncat.rb -lvp 443
  • To connect

    1. ruby ncat.rb -cv -r RHOST -p 443

Another Implementation of Ncat.rb

Again from Hood3dRob1n a standalone RubyCat which supports password protection for bind shell.