Port Scanning with Bash
Bash’s /dev/tcp/$HOST/$PORT pseudo-device lets you attempt a TCP connection with nothing but the shell — no nc, nmap, or curl required. If the connection succeeds, the port is open; if it fails, it’s closed or filtered.
(: </dev/tcp/$IP_ADDRESS/$PORT) &>/dev/null && echo "OPEN" || echo "CLOSED"How it works
/dev/tcp/$IP/$PORTis a Bash feature (not a real device file) that opens a TCP socket when redirected to.(: </dev/tcp/$IP/$PORT)tries to open the socket for reading inside a subshell. The&>/dev/nullsuppresses both stdout and stderr.- If the open succeeds, the subshell exits 0 and the
&&branch runs; if it fails, the||branch runs.
A minimal scanner loop
for port in 21 22 23 53 80 88 135 139 389 443 445 3389; do
(timeout 1 bash -c "echo >/dev/tcp/$TARGET/$port") 2>/dev/null && \
echo "[+] $TARGET:$port OPEN"
donetimeout 1 prevents filtered ports from hanging the loop on the kernel’s TCP connect timeout.
Trade-offs vs. a real scanner
Bash /dev/tcp | nmap | |
|---|---|---|
| Prerequisites | None (Bash is everywhere) | Binary upload or install |
| Speed | Serial, one connect at a time | Parallel, engineered for scale |
| Stealth | Looks like shell activity — until it touches 500 hosts | Instantly recognizable |
| UDP support | None (/dev/udp exists but is unreliable) | Full UDP scan engine |
Detection
A Bash process fanning out TCP connects is a high-signal anomaly. Defenders can alert on:
- Rapid sequential connections from a single PID to many destination ports.
/dev/tcpappearing in shell history or audit logs.- Absence of a corresponding listening service on the scanning host.
Related
- powershell-port-scanning — the Windows PowerShell equivalent
- udp — the protocol Bash’s
/dev/tcpdoes not scan reliably - netcat — the classic next step when you have a binary to upload
- unix-file-descriptors —
/dev/tcpis Bash’s file-descriptor abstraction over TCP