Skip to content
shellmap

Send raw TCP data to a port

Push arbitrary bytes (an HTTP request, a SMTP greeting, a custom protocol probe) to a remote TCP port and inspect the reply — for debugging service compatibility, capturing banners, reproducing protocol-level bugs, or scripting integrations with text-based protocols.

How to send raw tcp data to a port in each shell

Bashunix
printf "GET / HTTP/1.0\r\nHost: example.com\r\n\r\n" | nc example.com 80

`printf "BYTES" | nc HOST PORT` pipes the bytes, `nc` opens TCP and writes them. **CRLF is critical for HTTP** — `\r\n` line ending, NOT just `\n`. Two CRLFs end the request (`\r\n\r\n`). For binary data: `printf "\x00\x01\x02" | nc HOST PORT`. To keep the connection open after sending (read server response then close): `nc` auto-closes when stdin ends; for an interactive session use `nc HOST PORT` without pipe.

Zshunix
printf "GET / HTTP/1.0\r\nHost: example.com\r\n\r\n" | nc example.com 80
Fishunix
printf "GET / HTTP/1.0\r\nHost: example.com\r\n\r\n" | nc example.com 80
PowerShellwindows
$c = New-Object Net.Sockets.TcpClient "example.com", 80; $s = $c.GetStream(); $w = New-Object IO.StreamWriter $s; $w.NewLine = "`r`n"; $w.WriteLine("GET / HTTP/1.0"); $w.WriteLine("Host: example.com"); $w.WriteLine(""); $w.Flush(); $r = New-Object IO.StreamReader $s; $r.ReadToEnd(); $c.Close()

pwsh has no built-in netcat — `[Net.Sockets.TcpClient]` is the .NET socket primitive. `$w.NewLine = "\u0060r\u0060n"` (escaped backtick-r backtick-n) forces CRLF — default is `\n` only, which BREAKS HTTP. Always set `.NewLine` for protocol clients. For a one-liner: install `ncat` (`choco install nmap`) to get `nc HOST PORT` style on Windows. pwsh 7 cross-platform: same `TcpClient` works on Linux/macOS.

cmd.exewindows
powershell -NoProfile -Command "$c = New-Object Net.Sockets.TcpClient 'example.com', 80; $s = $c.GetStream(); $w = New-Object IO.StreamWriter $s; $w.NewLine = [char]13 + [char]10; $w.WriteLine('GET / HTTP/1.0'); $w.WriteLine('Host: example.com'); $w.WriteLine(''); $w.Flush(); (New-Object IO.StreamReader $s).ReadToEnd(); $c.Close()"

No native raw-TCP in cmd. `telnet HOST PORT` for INTERACTIVE; nothing for scripted send. Shell to pwsh for one-shot scripted requests, or use `curl.exe --raw -X "..."` (Windows 10 1803+ has `curl.exe` built-in — easier path for any HTTP-shaped request).

Equivalents listed for Bash, Zsh, Fish, PowerShell, cmd.exe.

Gotchas & notes

  • **`bash` has a built-in pseudo-device `/dev/tcp/HOST/PORT`** — no external `nc` required (Linux + macOS bash, NOT in fish, zsh, dash, or BusyBox-ash). `exec 3<>/dev/tcp/example.com/80; printf "GET / HTTP/1.0\r\nHost: example.com\r\n\r\n" >&3; cat <&3; exec 3<&-` opens fd 3 as a TCP socket, writes the request, reads the response, closes the fd. Works in containers/scratch images that don't have `nc`. Same for UDP: `/dev/udp/HOST/PORT` (rare but exists). Note: bash MUST be built with `--enable-net-redirections` (the default for Debian/Ubuntu/RHEL/Alpine; some hardened distros disable). Test with `bash -c "exec 3<>/dev/tcp/8.8.8.8/53" && echo "supported"`.
  • **`nc` flavors — three main variants, subtly different flags**: (a) **OpenBSD netcat** (default on macOS, Alpine, FreeBSD, modern Debian/Ubuntu): `nc HOST PORT`, `-z` zero-payload scan, `-l` listen, `-w SEC` timeout, NO `-e` (security: removed; can't spawn shell on connect). (b) **GNU netcat** (older Linux): `-e CMD` exists (DANGEROUS — used in reverse shells), `--ssl` for TLS. (c) **`ncat`** (Nmap project, modern replacement): `-c CMD`, `--ssl`, `--allow IP`, much richer feature set. Scripts that work on one flavor often need tweaks on another — `nc -e` simply doesn't exist on macOS. For portability, send-data-and-read pattern (`printf ... | nc HOST PORT`) works on all three.
  • **TLS-wrapped protocols need `openssl s_client`, not raw `nc`**. HTTPS, SMTPS, IMAPS, etc. all sit on TLS — sending raw HTTP to port 443 gets garbage. `openssl s_client -connect example.com:443 -servername example.com` opens a TLS session and gives you an interactive prompt; pipe input: `printf "GET / HTTP/1.0\r\nHost: example.com\r\n\r\n" | openssl s_client -connect example.com:443 -servername example.com -quiet 2>/dev/null`. `-servername` is SNI (CRITICAL for shared hosts — without it, the server may return the wrong cert + a default vhost). `-quiet` suppresses cert details. For STARTTLS protocols (SMTP, IMAP): `openssl s_client -starttls smtp -connect mail.example.com:587` does the STARTTLS upgrade then hands you a TLS session.
  • **Connection timeout, half-close, FIN handling — when the server doesn't close**: `nc HOST PORT` with stdin from a pipe sends + then closes the SEND side (half-close). Most servers respond + close their side. Some chatty servers (databases, certain SMTPs) HOLD the connection open expecting more input — `nc` hangs. Fix: `-w SECONDS` overall timeout (`nc -w 5 HOST PORT`), or `-q SECONDS` (OpenBSD nc) close after sending + waiting N seconds for response. pwsh: wrap in `Task.Wait(TimeSpan)` or set `$c.SendTimeout` / `$c.ReceiveTimeout` (in ms). For protocols that explicitly mark "response complete" (HTTP: Content-Length, Transfer-Encoding chunked terminator): parse the response and close from your end — don't rely on the server.
  • **Testing your own server with a listener** — `nc -l PORT` (OpenBSD) / `nc -lp PORT` (GNU) opens a listening socket and prints whatever comes in. Useful for "what bytes does my client ACTUALLY send?" debugging: `nc -l 8080` in one terminal, run your buggy HTTP client against `http://localhost:8080` in another, observe the raw request. For persistent listeners that survive a single connection: `ncat -k -l 8080` (`-k` keep-alive after each client). For multi-process serving: `socat TCP-LISTEN:8080,fork,reuseaddr - ` echoes input. tcpdump / Wireshark gives the same info AFTER-the-fact at packet level (`sudo tcpdump -i lo -A port 8080`) — useful when you can't change the destination port of the buggy client.

Related commands

Related tasks