Netcat Cheatsheet

Banner Grabbing

Use this Netcat reference while you build software engineering projects, review code, or refresh the syntax you reach for most.

Services that announce themselves

Some protocols send a greeting the moment you connect, so connecting is the whole probe. No input needed.

nc -v -w 3 10.0.0.5 22          # SSH version string
nc -v -w 3 mail.example.com 25  # SMTP 220 greeting
nc -v -w 3 10.0.0.5 21          # FTP 220
nc -v -w 3 10.0.0.5 110         # POP3 +OK
nc -v -w 3 10.0.0.5 143         # IMAP * OK
SSH-2.0-OpenSSH_9.6p1 Ubuntu-3ubuntu13.5
PortServiceGreeting starts with
21FTP220
22SSHSSH-2.0-
23TelnetNegotiation bytes, use -t
25 / 587SMTP220
110POP3+OK
143IMAP* OK
3306MySQLBinary, version string is readable inside
5432PostgresSilent, needs a startup packet
6379RedisSilent, send PING
11211MemcachedSilent, send stats

-w is essential here. Without it, a service that greets you and then waits keeps netcat open indefinitely, and your script hangs.

Services that need a prompt

The rest say nothing until you speak first.

# HTTP
printf 'HEAD / HTTP/1.0\r\n\r\n' | nc -w 3 example.com 80

# HTTP/1.1 with a Host header, needed for virtual hosts
printf 'HEAD / HTTP/1.1\r\nHost: example.com\r\nConnection: close\r\n\r\n' \
  | nc -w 3 example.com 80

# Redis
printf 'PING\r\n' | nc -w 2 10.0.0.5 6379

# Redis version and config, if unauthenticated
printf 'INFO server\r\n' | nc -w 2 10.0.0.5 6379

# Memcached
printf 'stats\r\n' | nc -w 2 10.0.0.5 11211

# Whois
echo "example.com" | nc -w 5 whois.verisign-grs.com 43

HEAD rather than GET keeps the response to headers only, which is all a banner grab needs.

Reading an HTTP server banner

printf 'HEAD / HTTP/1.0\r\n\r\n' | nc -w 3 example.com 80 | \
  grep -i '^server:'
HTTP/1.1 200 OK
Server: nginx/1.24.0
X-Powered-By: PHP/8.2.10
HeaderTells you
Server:Web server and often the exact version
X-Powered-By:Application runtime
X-AspNet-Version:.NET version
Set-Cookie:Framework, from names like JSESSIONID, PHPSESSID
Via: / X-Cache:A proxy or CDN sits in front
Location:A redirect, often plain HTTP to HTTPS

Many servers suppress or fake these. An absent Server: header means the operator turned it off, not that the service is unusual.

TLS ports need TLS

Plain netcat against 443 fails, because your cleartext is not a ClientHello. The server either closes the connection or returns a handshake error.

# This does NOT work
printf 'HEAD / HTTP/1.0\r\n\r\n' | nc example.com 443

# Ncat wraps the connection in TLS
printf 'HEAD / HTTP/1.0\r\n\r\n' | ncat --ssl -w 3 example.com 443

# openssl s_client, available almost everywhere
printf 'HEAD / HTTP/1.0\r\n\r\n' | \
  openssl s_client -quiet -connect example.com:443 -servername example.com

# Certificate details only
openssl s_client -connect example.com:443 -servername example.com \
  </dev/null 2>/dev/null | openssl x509 -noout -subject -issuer -dates

# STARTTLS on SMTP, which begins in cleartext
openssl s_client -starttls smtp -connect mail.example.com:587

-servername sends SNI, which almost every modern host requires. Without it you get the default virtual host's certificate, or a handshake failure.

PortWrapper
443ncat --ssl or openssl s_client
465openssl s_client -connect host:465
587openssl s_client -starttls smtp
993openssl s_client -connect host:993
995openssl s_client -connect host:995
636openssl s_client -connect host:636
5432openssl s_client -starttls postgres

Telnet negotiation

A real telnet server opens with IAC negotiation bytes (0xff …), which print as garbage and can confuse your terminal.

# Answer the negotiation so the session is usable
nc -t 10.0.0.5 23

# See the raw bytes instead
nc -w 2 10.0.0.5 23 | xxd | head

GNU netcat spells this -T, not -t. netcat-traditional uses -t.

Scripting a sweep

# Grab whatever the port volunteers, across a list
for p in 21 22 25 110 143 3306 6379; do
  echo "=== $p ==="
  nc -w 2 -v 10.0.0.5 "$p" </dev/null 2>&1 | head -3
done

# HTTP server headers across a subnet
for h in 10.0.0.{1..254}; do
  b=$(printf 'HEAD / HTTP/1.0\r\n\r\n' | nc -w 1 "$h" 80 2>/dev/null | \
      grep -i '^server:')
  [ -n "$b" ] && echo "$h $b"
done

# Parallel version
printf '10.0.0.%s\n' {1..254} | xargs -P 40 -I{} sh -c \
  'printf "HEAD / HTTP/1.0\r\n\r\n" | nc -w 1 {} 80 2>/dev/null | \
   grep -i "^server:" | sed "s|^|{} |"'

</dev/null on the client matters. Without it netcat inherits the loop's stdin and swallows the rest of your input, which makes the loop behave bizarrely.

Better tools for the same job

netcat grabs a banner. Dedicated tools identify the service.

NeedCommand
Banner from one portnc -w 3 -v host port
Service and version, many portsnmap -sV -p 22,80,443 host
Full HTTP inspectioncurl -sSv -o /dev/null https://host
Headers onlycurl -sSI https://host
TLS configuration auditnmap --script ssl-enum-ciphers -p 443 host
Certificate chainopenssl s_client -showcerts -connect host:443
HTTP over TLS by handncat --ssl host 443
# curl beats netcat for anything HTTP, and follows redirects
curl -sSI -L https://example.com | grep -iE '^(HTTP|server|location):'

Banner grabbing is a connection to a service you do not control. Do it only against hosts you own or are authorized to test.