[Tutorial] Túneis cifrados com SSH

O que é e como funciona um túnel?

Um túnel nada mais é do que dois programas ligados um no outro. Um deles será a entrada do túnel e o outro será a saída. Os dados podem ser cifrados ao entrar no túnel e decifrados ao sair dele, mas um túnel não precisa realmente usar criptografia. Na maioria dos casos é uma insanidade não usar criptografia, mas não existe obrigatoriedade em seu uso.

Uma VPN (Virtual Private Network) não é o mesmo que túnel. Contudo, a VPN, para criar a ilusão de máquinas distantes estarem na mesma rede, faz uso de túneis, preferencialmente cifrados. No caso se abre uma entrada da VPN, digamos, na porta 4000 UDP do roteador. Tudo que entrar na porta 4000 será cifrado e levado até a porta 4000 de outro roteador distante. Lá este roteador irá decifrar o pacote e injetá-lo na rede local destino (existem diversas formas de se criar uma VPN. Este não é o único exemplo).

Existe muitos programas para a criação e manutenção de túneis, alguns até bem sofisticados, como é o caso do todo poderoso stunnel. Ele permite até mesmo negociar certificados SSL, ou seja, podes ter o teu servidor HTTP normal, que não sabe nada de SSL, mas por stunnel dar aos usuários da Internet acesso seguro via SSL. Neste caso o cliente negocia SSL com o stunnel e este repassa os dados decifrados ao servidor HTTP. Muito útil quando o servidor é antigo e não suporta SSL, ou quando ele é lento, havendo problemas de desempenho ao se implantar SSL. Pode ser útil também quando o servidor HTTP é gerenciado por outra pessoa e você não deseja dar a esta pessoa seu certificado e a chave privada dele.

Linux: Túneis cifrados com SSH

Mas não é realmente necessário usar programas específicos para criar um túnel. Certamente é conveniente usá-los, pois eles já tem recursos próprios para isto, mas para casos mais simples e rápidos, muitas outras formas, até criativas, podem ser usadas para este fim. Bastaria um programa que escutasse em uma porta e que permitisse enviar dados para outra, e pronto, tem-se os ingredientes para criar um túnel.

Para provar esta teoria, mais com a intenção de ser didático do que ser prático, que tal criar um túnel no braço usando o netcat?

Construindo um túnel tosco com netcat

O netcat, ou simplesmente nc em muitas distribuições, é “apenas” um programa que permite enviar ou receber pacotes TCP ou UDP em qualquer porta. O “apenas” é porque ele também permite realizar coisinhas um tanto perversas. No Windows, por exemplo, basta colocar para executar o comando:

C:\> netcat -p 8000 -l -e cmd.exe

Que agora, ao se conectar na porta 8000 desta máquina, você terá um prompt do DOS. Hoje esta brincadeira já não dá tão certo, pois o firewall do Windows bloqueia portas! Era o comando preferido dos hackers quando podiam executar comandos remotos através de um IIS bugado.

Aproveitando o exemplo anterior, alguns parâmetros do netcat merecem destaque:

  • -u: indica ser pacotes UDP;
  • -t: indica ser tcp. Na ausência de -u ou -t, será considerado TCP;
  • -l: indica escutar (listen) na porta;
  • -p: número da porta em que se escutará;

A figura a seguir mostra o uso do netcat para apenas enviar dados da máquina para a mesma máquina usando a porta 8000:

Linux: Túneis cifrados com SSH

Então, depois desta rápida explicação do netcat, pode-se agora criar o túnel no braço, pois administrador que é administrador não fica usando “ferramentinha” de túnel.😀

Para tornar mais divertido e ilustrativo, considera-se que a máquina 172.20.1.132 (uma máquina virtual nos meus testes) não consegue acessar o site vivaolinux.com.br em sua porta 80. Parece que o roteador está, por alguma razão, bloqueando este acesso, conforme pode ser visto na figura a seguir.

Linux: Túneis cifrados com SSH

Observe a figura. Aparentemente a máquina cliente não tem acesso a página do Viva o Linux, mas tem acesso a máquina 172.20.1.1 (está pingando). Como o usuário desta máquina tem uma conta na 172.20.1.1, pronto, ele pode usar um túnel para acessar o Viva o Linux.

E como ele faz isto com um simples netcat? Claro, seria mais fácil usar uma ferramenta própria para criar o túnel, mas agora deseja-se provar que com um pouco de criatividade, saca-se um túnel até mesmo com o netcat.

No caso ele precisa colocar o netcat para escutar em uma porta alta na máquina 172.20.1.1. Porta alta, pois portas baixas apenas o usuário root pode usar. Ele precisa fazer com que tudo que for enviado a esta porta alta seja reenviado para o http://www.vivaolinux.com.br na porta 80. Este é o princípio de um túnel.

Na máquina 172.20.1.1 o nosso criativo usuário pode executar:

$ mkfifo vol.fifo
$ while true; do netcat -l -p 7000 < vol.fifo | netcat vivaolinux.com.br 80 > vol.fifo ;done

(se você estiver reproduzindo isto em seu computador, talvez tenhas problemas para cancelar o laço, pois um Control+C irá cancelar apenas o netcat. Para fazer o cancelamento, proceda da seguinte forma: pressione Control+Z no terminal onde está executando o laço. Você verá uma mensagem de Stopped. Após digite, no mesmo terminal, o comando fg, o que fará ele voltar a executar o último netcat. Agora sim pressione Control+C para cancelar este netcat)

Como o netcat não foi desenvolvido para isto, um pouco de criatividade se fez necessário, criando um arquivo do tipo pipe para intermediar a comunicação dos dois comandos. São recursos disponíveis no Linux e que qualquer usuário pode usar. A criação deste arquivo é necessária pois quero que a saída do primeiro netcat seja a entrada do segundo (isto o “|” faz), mas também quero que a saída do segundo seja a entrada do primeiro (e isto o “vol.fifo” faz).

Prender o netcat dentro de um laço é necessário, pois a cada conexão o netcat encerra e para montar uma página podem ser necessárias várias conexões.

É uma solução esquisita, mas funciona. Veja como ficou o navegador da máquina cliente com este comando em execução:

Linux: Túneis cifrados com SSH

As imagens não foram carregadas. Fui investigar o porque disto e vi que as imagens são lidas de outro site, o img.vivaolinux.com.br. Teria que ter um túnel para este também. Mas, tudo bem, este exemplo não era para ser perfeito mesmo, era para ser ilustrativo.

Qualquer aplicação que permite se conectar em uma porta e escutar em outra poderia ser usado como túnel.

A figura a seguir ilustra como a comunicação ocorreu entre todas as partes, o que já demonstra o funcionamento de um túnel.

Linux: Túneis cifrados com SSH

Bom, claro, para que sofrer, não é? Minha intenção foi apenas mostrar o que é um túnel, como ele funciona e como ele pode ser construído usando criatividade e algumas ferramentas já existentes. Este túnel “xinfrim” tem sérios problemas, seja por sua implementação complexa e esquisita, seja pelas limitações de uso (não funcionou para img.vivaolinux.com.br).

Mas sua maior limitação é o de não fazer uso de criptografia. Os dados não estão cifrados em momento algum. Poderia incrementar os pipes sacando um gnupg da manga e ligando ele na sequência de pipes (deixo como desafio aos leitores), mas, simplificando: que tal o ssh para isto?

Usando o recurso de túnel do SSH

Para que o ssh aceite ser usado como túnel, o parâmetro PermitTunnel deve estar ativo no arquivo de configurações (/etc/ssh/sshd_config). O padrão do ssh é permitir o uso de túneis, então, a menos que este parâmetro esteja com “no” o teu ssh está trabalhando com túneis.

A vantagem de se usar o ssh é que os dados enviados para o túnel serão cifrados desde a entrada do túnel até a sua saída. E cifrados com o mesmo algoritmo forte que o ssh usa para qualquer conexão.

Para explicar o uso do ssh como túnel, que tal refazer o exemplo do cliente que não consegue acessar o site Viva o Linux?

Linux: Túneis cifrados com SSH

Só que agora nenhum comando será executado na máquina 172.20.1.1. Apenas será aberto um túnel, via ssh, de 172.20.1.132 na porta 7000 para 172.20.1.1 na porta 22. O server ssh de lá será a saída do túnel.

No caso basta executar, na máquina cliente, o comando:

$ ssh -TL 7000:www.vivaolinux.com.br:80 laboratorio@172.20.1.1

A imagem a seguir mostra o efeito do comando e a saída do navegador:

Linux: Túneis cifrados com SSH

A explicação dos comandos ssh é a seguinte:

  • -T: ao contrário do que possa parecer, isto não quer dizer Túnel. Não é T de túnel, mas sim T de tty. Serve para desabilitar o suporte a tty. Sim isto você terá o login na máquina, o túnel funcionará, mas ao tentar fechar você poderá ficar travado e deverá executar Control+C no ssh cliente;
  • -L: indica abrir uma porta local, que será a entrada do túnel. O -L precisa de três parâmetros: portal local, endereço IP remoto, porta remota. Como no exemplo do 7000:www.vivaolinux.com.br:80 usado no comando. 7000 é a entrada do túnel (a saída será a porta 22 de 172.20.1.1). http://www.vivaolinux.com.br é para qual IP os pacotes devem ser enviados ao saírem do túnel e 80 é a porta destino;
  • laboratorio@172.20.1.1 são apenas os parâmetros normais de autenticação, que se deseja autenticar no servidor 172.20.1.1 com o usuário laboratório. A senha do usuário, evidentemente, é solicitada.

A figura a seguir mostra como este túnel funcionou, quem conversou com quem.

Linux: Túneis cifrados com SSH

Situações práticas onde um túnel SSH pode ser uma saída

Um túnel SSH pode ser muito útil em muitos casos, principalmente quando a necessidade não justifica sacar ferramentas mais sofisticadas de criação de túnel ou tampouco a criação de uma VPN.

Como ilustração, pode-se citar três cenários reais de uso, sendo que eu mesmo os uso com extrema frequência. Um deles todo o dia.

Primeiro cenário:

Este não é um cenário que eu uso, mas sim que um conhecido meu usa. Na rede dele tem um servidor de banco de dados MYSQL. Na verdade este serviço encontra-se em execução na mesma máquina onde se encontra o serviço de HTTP e de SSH. A porta na qual o serviço MYSQL escuta é a 3306/TCP.

Evidente que por questões óbvias de segurança, o firewall iptables deste servidor HTTP/SSH/MYSQL não aceita conexões na porta 3306, até porque, como mencionado, apenas a própria máquina usa o banco de dados.

Frequentemente, porém, se desenvolve aplicações em casa, ou em outro lugar que não fisicamente no servidor, e estas aplicações precisam, mesmo que por teste, acessar o banco de dados do servidor.

O que se pode fazer?

Uma saída seria liberar temporariamente a porta 3306 para o máquina cliente quando estiver fazendo testes, mas isto traz sérios problemas de segurança, além de ser não muito prático. Abrir uma VPN com o servidor nem sempre se justifica, pois só se quer realmente acessar o MYSQL por tempo limitado.

Então, pode-se tranquilamente sacar o ssh em seu modo túnel apontando-a para o servidor. Supondo que o IP do servidor seja 10.1.2.3, o seguinte comando executado no cliente resolve:

$ ssh -TL 33060:localhost:3306 usuario@10.1.0.1

Agora basta apontar as ferramentas locais que usam o BD para o servidor localhost na porta 33060 (se colocou um zero a mais, pois a máquina local poderia ter também o seu próprio BD).

Segundo cenário:

Na faculdade que administro os equipamentos de rede, como switches, tem ips privados. Assim não tem como chegar neles através da Internet. A partir dos consoles da sala de administração, existe rotas que permitem acessar, por exemplo, o switch 192.168.34.100, seja até mesmo por sua interface gráfica sobre HTTP.

Porém, algumas vezes, estou em minha casa e preciso realizar uma pequena manutenção em um dos switches. Novamente, poderia criar uma VPN, mas quero uma solução mais imediata. Então, saco novamente o ssh em modo túnel e digito na linha de comando:

$ ssh -TL 8080:192.168.34.100:80 elgio@IPdoMeuConsole

Feito isto, apenas abro um navegador e acesso a URL http://localhost:8080. Como já demonstrado nas seções anteriores, todos os pacotes que entrarem na porta 8080 do meu notebook, sairão cifrados de minha máquina, viajando rumo a porta 22 do servidor IPdoMeuConsole, sendo que chegando lá, o ssh decifra os dados e os repassa ao IP 192.168.34.100 na porta 80, sem criptografia.

Terceiro cenário:

Este eu realmente uso todos os dias a anos. Meu notebook tem seu próprio servidor SMTP. Um Postfix instalado para realizar relay em um IP inexistente, algo como 10.2.3.4 que não existe em nenhuma das redes que conheço. Assim, meu servidor SMTP/Postfix ficaria sem poder repassar os emails. Digo ficaria, pois tenho alguns truques na manga.

O conforto de ter um servidor SMTP no meu próprio notebook é que posso eu mesmo criar meus aliases de emails ou mesmo listas. Uso isto diariamente para enviar as notas dos alunos, durante o período letivo. Posso gerar os emails mesmo sem acesso a Internet, pois eles ficam na fila de espera do Postfix.

Porém, quando tenho acesso a Internet, saco o par iptables + ssh para fazer a mágica acontecer. Uso como relay um servidor que gerencio, que é MX do meu domínio. Claro, ele não aceita relay, evidentemente, a menos que seja de um ip autorizado. Tipo, conexões vindas dele mesmo, localhost.

Então eu abro um túnel SSH para este meu servidor:

$ ssh -TL 2525:localhost:25 elgio@IpdoMeuServidor

Agora todo o pacote jogado na porta local 2525, viajará cifrado até meu servidor e lá será enviado a porta 25 de localhost. Haverá aceitação de relay, pois para o servidor Postfix do MeuServidor o acesso por feito por ela mesmo!

Feito este túnel, eu agora insiro uma regra iptables desviando o tráfego que tentar sair pela porta 25 para a 2525 local, ou seja, quando o Postfix do meu notebook tentar entregar os emails para o falso IP 10.2.3.4 na porta 25, o iptables o irá pegar e jogar na porta 2525 local, que é a entrada do túnel.

Uso tanto isto que até fiz um script que coloca tudo no ar até com uma telinha de status. Caso seja do interesse de alguns, deixo este script como anexo.

ANEXO: script que uso para realizar um túnel SMTP

#!/bin/bash

# Troque para seu usuário
USER=”elgio”

# porta local que será a entrada do túnel
PLOCAL=2525

# troque para o IP ou DNS do seu servidor SSH
SERV=”IpOuNomeDNSdoMeuServidor”

# troque para o IP do servidor SMTP do outro lado
SERVSMTP=”localhost:25″

# Caminho para restartar o Postfix (pois ele fica parado no meu caso)
POST=”/usr/sbin/postfix”

# Caminho do iptables
IPT=”iptables”

# tosco: se for passado off era para desfazer o túnel
# tosco porque estou dando um flush na tabela nat. DESACONSELHAVEL
# isto precisa ser melhorado
if [ “X$1” == “Xoff” ]
then
sudo $IPT -t nat -F
PID=`ps x|grep “ssh.\+$PLOCAL”|cut -d ‘ ‘ -f1`

[ “X$PID” == “X” ] || kill $PID 2>/dev/null

exit 0;
fi

# Crio um terminalzinho pequeno, que ficara no canto da tela, apenas para manter o túnel aberto
(xterm -geometry 50×2 -T “SMTP TUNEL $PLOCAL $USER@$SERV” -e ssh -TL $PLOCAL:$SERVSMTP $USER@$SERV) &

# Insiro uma regra iptables desviando tentativas de conexão na porta 25
# para a porta local, entrada do túnel
sudo $IPT -t nat -A OUTPUT -p tcp -d ! 127.0.0.1 –dport 25 -j REDIRECT –to-port $PLOCAL

# reinicio o Postfix, caso esteja parado
sudo /etc/init.d/postfix restart

# dou um tempinho. As vezes, devido a conexões lentas, o túnel criado demora alguns
# segundos para ficar disponível
sleep 4

# peço para o Postfix trabalhar a fila de espera agora
sudo $POST flush

# Pronto. Apos a execução deste programinha, ficará na tela uma mensagem
# dizendo que o túnel esta aberto. Veja que se você executar um
# telnet localhost 2525 estará conversando com a porta 25 do seu servidor

Créditos: elgio
  1. No trackbacks yet.

Deixe uma resposta

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s

%d blogueiros gostam disto: