Comando nc: testar portas e ligações de rede no Linux

Terminal com o comando nc -zv a verificar se uma porta TCP de um servidor de laboratório está aberta

«O servidor não responde.» Antes de culpar a aplicação, a rede ou a firewall, há uma pergunta que se responde em segundos: a porta está aberta? O nc — o netcat — responde-lhe numa linha e ainda monta ouvintes, transfere ficheiros e fala com serviços em protocolo escrito à mão. Não é por acaso que lhe chamam o canivete suíço do TCP/IP.

Seguimos a ordem do vídeo: -z e -v, intervalos de portas e -n, ouvintes com -l, -p e -k, transferência de ficheiros, -u e -w, e HTTP à mão. No fim, o ângulo defensivo: reconhecer, com ss e lsof, um nc à escuta ou uma shell reversa que não deviam estar na máquina.

Veja o guia em vídeo

Prefere ver antes de experimentar? No canal HJFR-IT no YouTube mostramos o nc (netcat) opção a opção, com o resultado de cada comando no ecrã — narrado em português e com legendas.

nc (netcat) — Guia Completo: o canivete suíço do TCP/IP — canal HJFR-IT no YouTube. Se o áudio não arrancar em português, abra as definições do vídeo (ícone da roda dentada) → Faixa de áudio → Português.

O que faz o nc

O nc lê e escreve dados em bruto numa ligação TCP ou UDP, sem interpretar nada: o que entra pelo teclado (ou por um pipe) sai pela rede, e o que chega da rede sai no ecrã. Tem dois modos — cliente, que se liga a um destino e a uma porta, e ouvinte (-l), que espera ligações.

nc [opções] DESTINO PORTA        # cliente: liga-se a DESTINO:PORTA
nc -l [opções] [-p] PORTA        # ouvinte: espera ligações em PORTA

No Debian e no Ubuntu, o nc é normalmente a variante netcat-openbsd, a usada aqui; a netcat-traditional e o ncat (projeto Nmap) diferem em pormenores.

Testar uma porta: -z e -v

O -z (zero I/O) manda o nc só verificar se a ligação se estabelece, sem enviar dados; o -v (verbose) mostra o resultado.

$ nc -zv srv-web01 443
Connection to srv-web01 (192.0.2.10) 443 port [tcp/https] succeeded!
$ nc -zv srv-web01 8080
nc: connect to srv-web01 port 8080 (tcp) failed: Connection refused

Responde à pergunta clássica do diagnóstico — o serviço está a atender, ou o problema está pelo caminho? —, desde que saiba ler as três respostas:

  • succeeded — aberta: o handshake TCP completou-se e há um processo à escuta.
  • Connection refused — fechada: a máquina respondeu com um RST, mas não há serviço. O problema não é a rede.
  • timed out (com -w) — filtrada: ninguém respondeu, quase sempre por causa de uma firewall.

Em scripts, basta o código de saída: 0 se a ligação teve êxito, 1 se falhou.

Varrer um intervalo de portas

O nc aceita um intervalo, separado por um traço, e testa as portas uma a uma:

$ nc -zv srv-web01 20-25 2>&1
nc: connect to srv-web01 port 20 (tcp) failed: Connection refused
nc: connect to srv-web01 port 21 (tcp) failed: Connection refused
Connection to srv-web01 (192.0.2.10) 22 port [tcp/ssh] succeeded!
nc: connect to srv-web01 port 23 (tcp) failed: Connection refused
nc: connect to srv-web01 port 24 (tcp) failed: Connection refused
nc: connect to srv-web01 port 25 (tcp) failed: Connection refused

Só a 22, o ssh, atende — assim se confirma o que um servidor expõe. O 2>&1 junta ao stdout as mensagens do -v, que vão para o stderr, para as podermos filtrar num pipe. E varrer portas faz-se apenas em máquinas suas ou com autorização explícita: em sistemas alheios é intrusivo e pode ter consequências legais.

Sem DNS: -n

Com -n, o nc não resolve nomes nem traduz portas em serviços: é mais rápido e não depende de um DNS que pode estar avariado. Daí o [tcp/*]:

$ nc -zvn 192.0.2.10 20-25 2>&1 | grep succeeded
Connection to 192.0.2.10 22 port [tcp/*] succeeded!

Correr um ouvinte: -l, -p e -k

Com -l (listen), uma máquina espera ligações numa porta — o lado servidor; noutra, o nc sem -l liga-se — o lado cliente. O que se escreve num lado aparece no outro: é a base de quase tudo o que o netcat faz.

# no srv-web01 (ouvinte)
$ nc -lv -p 9000
Listening on 0.0.0.0 9000
Connection received on 192.0.2.25 51560

# no hjfr (cliente)
$ nc srv-web01 9000
olá do hjfr
  • -p PORTA — com -l, a porta de escuta (a openbsd aceita também nc -l 9000, mas -l -p funciona em todas); sem -l, a porta de origem do cliente.
  • -k — o ouvinte não termina com a primeira ligação e aceita a seguinte. Prático, e perigoso se ficar esquecido.

Transferir ficheiros entre máquinas

Se o cano liga dois terminais, podemos empurrar um ficheiro por ele: no destino, o nc ouve e a saída vai para um ficheiro (>); na origem, o nc é alimentado pelo ficheiro (<). O -N fecha a ligação no fim — sem ele, os dois lados ficam à espera de um Ctrl+C.

$ nc -l -p 9000 > recebido.tar.gz            # no destino
$ nc -N srv-web01 9000 < backup.tar.gz        # na origem

# o mesmo par com pipes: uma pasta inteira, sem ficheiro intermédio
$ nc -l -p 9000 | tar xzvf -                 # no destino
$ tar czf - site/ | nc -N srv-web01 9000     # na origem

É prático num laboratório, mas o nc simples não cifra nem verifica nada: confirme com sha256sum dos dois lados e, em redes não confiáveis, use scp ou rsync sobre ssh.

UDP e tempos limite: -u e -w

-u: serviços UDP

O -u passa de TCP para UDP, necessário para serviços como o DNS (53):

$ nc -zvu srv-web01 53
Connection to srv-web01 (192.0.2.10) 53 port [udp/domain] succeeded!

Cautela: o UDP não tem handshake. O nc só sabe que a porta está fechada se voltar um ICMP port unreachable; o silêncio quer dizer «aberta ou filtrada». Para ter a certeza, fale o protocolo — por exemplo, dig @192.0.2.10 example.com.

-w: não ficar pendurado

O -w define um tempo limite em segundos. Sem ele, uma porta filtrada deixa o nc pendurado enquanto o núcleo retransmite o SYN — no Linux, perto de dois minutos:

$ nc -zv -w 3 srv-web01 3306
nc: connect to srv-web01 port 3306 (tcp) timed out: Operation now in progress

É essencial em scripts. E repare: o MySQL está à escuta, mas a firewall descarta o tráfego da rede local — à escuta não é o mesmo que acessível.

Falar HTTP à mão

Como o nc é um cano em cru, podemos escrever nós o protocolo. Um pedido HTTP mínimo — um GET e uma linha em branco — devolve a resposta crua, com cabeçalhos e o início da página:

$ printf 'GET / HTTP/1.0\r\n\r\n' | nc srv-web01 80
HTTP/1.1 200 OK
Server: nginx/1.24.0 (Ubuntu)
Content-Type: text/html
Connection: close

<!DOCTYPE html>
...

É didático e um bom diagnóstico quando o curl esconde pormenores: o nc mostra tudo, tal como vai na rede (para HTTPS, use openssl s_client). O mesmo princípio dá o banner grabbing — no SSH, é o servidor que fala primeiro:

$ nc -v -w 2 srv-web01 22
Connection to srv-web01 (192.0.2.10) 22 port [tcp/ssh] succeeded!
SSH-2.0-OpenSSH_9.6p1 Ubuntu-3ubuntu13.5

Nos seus servidores, serve para inventariar as versões expostas — e o Server: acima mostra que convém esconder a do nginx (server_tokens off;).

nc em cibersegurança

Uma ferramenta de dupla utilização. O nc que valida uma firewall serve a um atacante para reconhecimento ou para manter acesso. A regra é a do vídeo: testar só sistemas seus ou com autorização explícita, de preferência escrita e com âmbito definido.

Validar firewalls e segmentação. Depois de cada alteração de regras, confirme a partir de cada segmento de rede que só respondem as portas previstas. Com -z, -w e o código de saída, um pequeno script torna a verificação repetível e deteta portas abertas sem aviso.

Reconhecer um nc que não devia lá estar. Numa máquina comprometida, o netcat surge como ouvinte inesperado (bind shell) ou como ligação de saída para um IP externo (shell reversa). O sudo ss -tlnp mostra os sockets à escuta e o processo dono — um nc numa porta alta, com backlog 1, é alarme. O sudo ss -tnp state established revela o sinal clássico de uma shell reversa: uma sh com os descritores 0, 1 e 2 num socket. O lsof -nP -i acrescenta o utilizador; se for www-data, suspeite da aplicação web. Não mate os processos à pressa: registe as saídas, preserve /proc/<PID>, isole a máquina e siga o procedimento de resposta a incidentes.

Experimente no simulador interativo

O simulador recria um laboratório com o posto aluno@hjfr (192.0.2.25) e o servidor srv-web01 (192.0.2.10), com uma firewall a bloquear a 3306 e dois processos que não deviam lá estar. Cada comando desenha a ligação pacote a pacote e mostra os sockets do servidor por dentro; no terminal, as linhas com barra dourada são o ecrã do servidor. Demonstrar tudo percorre a sequência pela ordem do vídeo, Anterior e Seguinte avançam ao seu ritmo, os botões de cada grupo executam uma opção e Repor estado volta ao início.

Erros comuns e boas práticas

  • Esquecer o -w em scripts: uma porta filtrada prende o nc durante minutos. Ponha sempre um tempo limite.
  • Ler «succeeded» em UDP como certeza: só quer dizer que não chegou nenhum erro.
  • Confundir fechada com filtrada: refused é falta de serviço; timed out aponta para uma firewall.
  • Enviar dados sensíveis em claro: o nc não cifra. Fora do laboratório, use scp ou rsync sobre ssh.
  • Deixar ouvintes esquecidos: um nc -lk a correr é uma porta aberta que ninguém vigia; confirme com ss -tlnp.
  • Varrer o que não é seu: sem autorização explícita, um varrimento de portas é intrusivo e pode ter consequências legais.

Conclusão

O nc faz uma coisa simples — ler e escrever dados numa ligação — e daí tira o resto: -zv, intervalos e -n para testar portas, -l, -p e -k para ouvir, redirecionamentos para ficheiros, -u, -w e protocolos à mão. Use-o só onde tem autorização. Para ver o outro lado das ligações, junte-lhe o comando ss, que mostra os sockets da própria máquina, e o comando tcpdump, que mostra os pacotes tal como passam na rede.

Workshop — Linha de Comandos Linux

Quer passar da leitura à prática, com exercícios reais e acompanhamento? No workshop Linha de Comandos Linux da HJFR trabalha estes e outros comandos da série — da administração do dia a dia à resposta a incidentes.

Este artigo faz parte da série «Comandos Linux, um a um» do blog HJFR — fique atento aos próximos comandos.