This document was uploaded by user and they confirmed that they have the permission to share it. If you are author or own the copyright of this book, please report to us by using this DMCA report form. Report DMCA
style="font-weight: bold;"># tar xfzv corkcrew_2.0.orig.tar.gz # cd corkcrew_2.0.orig # ./configure # make # make install
Instalando o HTTPTunnel O HTTPTunnel é nossa ferramenta mestra (principal) para atravessar um firewall típico com sua legitimação. Como o protocolo HTTP costuma ser habilitado em conexões que saem da rede, podemos, com o HTTPTunnel, transitar todo tipo de dado em protocolos bloqueados em forma de HTTP. Para instalá-lo, vamos proceder passos idênticos aos das outras instalações com os seguintes comandos: # wget http://ftp.gnu.org/gnu/httptunnel/httptunnel-3.3.tar.gzstyle="font-weight: bold;"># tar xfzv httptunnel-3.3.tar.gz # cd httptunnel-3.3 # ./configure # make # make install
Iniciação prática - Netcat Netcat - Introdução O Netcat, como já devem saber, é uma ferramenta profundamente útil e versátil. Seria difícil e inapropriado apresentar aqui os diversos usos nativos e criativos que se pode fazer do canivete suíço. Uma listagem de suas utilidades, até onde meu conhecimento vai pode ser:
•
Conexões simples: o Acessar um serviço; o Pegar o banner de um serviço;
•
Servir conexões: o Estabelecer chats; o Disponibilizar acesso remoto à aplicativos locais:
o •
Acesso à própria shell;
Disparar um processo qualquer; Repassar dados pela rede para monitoramento remoto em tempo real para a máquina local ou para outra(s);
Tunelar conexões;
Como consequência temos funções criativas que podemos dar ao Netcat como:
• • •
Varrer máquinas para listagem de portas abertas; Vasculhar pacotes da rede sem permissão de super-usuário; Clonar HDs via rede;
Sabendo que 'nc' é o comando do Netcat, vamos agora realizar algumas de suas operações básicas para ganharmos alguma familiaridade com ele. Note que daqui para frente, o texto que estiver em negrito corresponde os dados que forem inseridos e comandos digitados (exceto o caractere cifrão $, que indica a linha de comando do shell), enquanto o texto em itálico corresponderá ao texto impresso na tela como resposta do aplicativo. Netcat - Conectando O Netcat deve receber dois parâmetros para realizar uma conecção simples: o endereço da máquina e a porta a se conectar, exemplo: $ nc google.com 80 Quando conectados, experimentem passar a requisição " GET / HTTP/1.0 ": $ nc google.com 80 GET / HTTP/1.0 <Enter> Outro exemplo pode ser uma conexão a um servidor SSH: $ nc servidor-ssh 22 Em minha máquina eu fiz:
$ nc localhost 22 SSH-2.0-OpenSSH_4.3p2 Debian-3 qualquer coisa <Enter> Protocol mismatch. É claro, o próprio cliente OpenSSH espera que reconheçamos o certificado do servidor, mas não 'falamos SSH' e ao digitarmos qualquer coisa (literalmente, no exemplo) aparece, naturalmente, a mensagem Protocol Mismatch, indicando o erro de protocolo. Netcat - Servindo Para servir em uma porta dada com o Netcat precisamos indicar que queremos escutar com a opção ' -l ' (de listen) e indicar a porta em que queremos escutar com a opção ' -p ' (de port). Como as portas que vão de 1024 para baixo são reservadas, somente o superusuário poderá escolhê-las para servir, mas todo as outras podem ser teoricamente indicadas por um usuário regular. Exemplo: $ nc -l -p 1025 Abra outro terminal e se conecte à porta aberta: $ nc localhost 1025
Agora experimente digitar qualquer coias pelas duas pontas da conexão e verá que tem um chat pessoal funcionando!
Uma boa prática, especialmente ao abrir portas para escuta, é setar o parâmetro ' -v ', que, previsivelmente significa verbose e serve para nos informar do que estiver acontecendo com o serviço. Pode-se setar o parâmetro verbose duas vezes com ' -vv ' para solicitar ainda mais informação. Experimente o msmo comando com ' -vv ': T1 (terminal 1) - Servidor
T2 (terminal 2) - Cliente
$ nc -l -vv -p 1025 listening on [any] 1025 ... connect to [127.0.0.1] from localhost.localdomain [127.0.0.1] 46699 alo oi sent 3, rcvd 4
$ nc localhost 1025 alo oi
$ Como último comentário a montagem de serviços com Netcat, gostaria de ressaltar que o Netcat transfere dados em claro, o que permite que alguém facilmente capture os dados trasferidos. Para se utilizar dos recursos que o Netcat oferece em situações em que a segurança dos dados for importante experimente o tal Cryptcat, que dizem ser o Netcat criptografado. Existe, porém, maneiras de tornar serviços Netcat um pouco mais seguros do que da forma como vimos acima. Podemos, por exemplo, restringir o acesso ao serviço posto designando os IPs específicos dos quais esperamos a conexão, assim como podemos especificar uma porta de origem de conexão como critério de filtro. Essas medidas não protegem, é claro, uma conexão Netcat de ser observada clandestinamente com uma ferramente de sniffing. Caso queiramos utilizar o próprio Netcat e ainda assim proteger os dados com criptografia podemos também simplismente tunelar o Netcat em um túnel criptográfico, como vamos aprender a fazer até o final deste curso. Netcat - Piruetas (opcional) Atenção: A leitura desta página da lição é opcional, visto que seu conteúdo não é fundamental para a prática do tunelamento como será vista mais adiante. O seu aprendizado não será, portanto, cobrado nas questões ou na avalição. Praticar o que é apresentado abaixo pode servir à criatividade de cada um na solução de 'problemas' que se possa encontrar. Aqui vamos conhecer rascunhar algumas maneiras de potencializar o uso no Netcat. Caso não tenha tempo ou interesse, passe para a próxima página. Piruetas do Netcat O Netcat foi desenvolvido com a referência de ser o cat para redes. O cat basicamente tem a função de jogar conteúdos de texto para um lado e para o outro. De fato, o Netcat faz as mesmas estripulias só que através de conexões estabelecidas. Vamos experimentar agora alguns desses usos do cat utilizando o Netcat para conhecermos melhor suas utilidades. Um deles acabamos de conhecer na página anterior. Se chamamos o cat sem qualquer parâmetro, ele entra em modo interativo e tudo o que digitarmos será ecoado na tela. $ cat alo alo eco eco sair sair-d O mesmo vimos acontecer quando estabelecemos a conexão entre o Netcat escutando em uma porta e o Netcat cliente. Ao digitarmos 'alo' em uma ponta da conexão víamos o conteúdo 'alo' aparecendo na outra. Outro uso do cat é o que fazemos para ler o conteúdo de um arquivo e jogar para a saída padrão, o terminal. Para tanto vamos antes criar um arquivo simples. $ echo 'olá' > mensagem Podemos jogar o conteúdo do arquivo para a saída padrão de duas formas: $ cat arquivo ou $ cat < arquivo A segunda forma também funciona com o Netcat. Vamos lá. Primeiro abrimos uma porta para escuta por um terminal e em seguida nos
conectamos com o comando simples que do nome do arquivo '< mensagem', ou seja:
estabelece
a
conexão,
que
já
conhecemos,
seguido
do
redirecionador
e
$ nc servidor porta < arquivo Confira os passos na tabela a seguir: Caso 1 T1 (Terminal 1) - Servidor $ nc -l -vv -p 1025 listening on [any] 1025 ... connect to [127.0.0.1] from localhost.localdomain [127.0.0.1] 50480 olá sent 0, rcvd 4 $
T2 (Terminal 2) - Cliente $ nc localhost 1025 < mensagem-c
O mesmo acontece se passarmos o arquivo pela ponta do servidor: Caso 2 T1 (Terminal 1) - Servidor $ nc -l -vv -p 1025 < mensagem listening on [any] 1025 ... connect to [127.0.0.1] from localhost.localdomain [127.0.0.1] 35064 sent 4, rcvd 0 $
T2 (Terminal 2) - Cliente $ nc localhost 1025 olá-c $
Pense agora que se podemos passar o conteúdo de um arquivo para dentro de uma conexão Netcat, como faríamos com o próprio cat, e se o Netcat joga os dados que chegam da outra ponta para a saída padrão, o terminal, então podemos também jogar o conteúdo de saída, que iria para o terminal, igualmente para dentro de um arquivo. Observe então a seguinte cena. Antes de mais nada: $ echo 'Mas porquê você não come carne?' > pergunta-chata
Caso 3 T1 (Terminal 1) - Servidor $ nc -l -vv -p 1025 < pergunta-chata > resposta-obvia-No1 listening on [any] 1025 ... connect to [127.0.0.1] from localhost [127.0.0.1] 3456 sent 35, rcvd 210 $
T2 (Terminal 2) - Cliente $ nc localhost 1025 Mas porquê você não come carne? Eu não como carne, leite, ovo e seus derivados porque não quero corroborar os hábitos (e os valores) mantidos e incitados por uma indústria especista que lucra explorando e massacrando animais.-c $
Ora, se podemos passar conteúdo de um arquivo e também podemos repassar conteúdo recebido para um arquivo na outra ponta, devemos poder passar um arquivo em uma ponta e recebê-lo em outra! Sim, podemos. Observe a cena a seguir: Caso 4 T1 (Terminal 1) - Servidor
T2 (Terminal 2) - Cliente
$ nc -l -vv -p 1025 < /bin/nc listening on [any] 1025 ... connect to [127.0.0.1] from localhost [127.0.0.1] 3325 sent 20192, rcvd 0 $ md5sum /bin/nc 8be0c375b01da07206c070b3e7d72084 /bin/nc
$ nc localhost 1025 > copia-nc
$
$
-c $ md5sum copia-nc 8be0c375b01da07206c070b3e7d72084 copia-nc
Enviamos o executável de uma ponta da conexão (do servidor) para outra (para o cliente). Checamos que o conteúdo dos arquivo é idêntico. O Netcat simplismente estabelce uma conexão, o que faz com ela não interessa a ele (na próxima página, na verdade, vamos conhecer algumas opções do Netcat que podem sofisticar suas funções). Podemos preparar todo tipo de serviço útil combinando as milhares de funções úteis do bash com o uso do Netcat. Mais um exemplo simples, mas útil, é o uso do pipe ( | ). Pense que assim como podemos passar o conteúdo de um arquivo pela conexão também podemos passar o conteúdo resultante de um procedimento qualquer, com um comando qualquer. Por exemplo, podemos passar uma lista de ítems pela conexão ordenando-a antes de enviá-la. Caso 5 $ cat lista | sort | nc localhost 1025 Essa é uma saída estática de um comando, mas imagine o envio permanente de dados de saída de um pipe qualquer. Por exemplo, podemos monitorar remotamente os processos que mais consomem recursos de nosso sistema com a seguinte manobra: Servidor: $ top | nc -l -vv -p 1025 Cliente: $ nc servidor 1025 Uau! Agora mais que isso, podemos repassar pela conexão a própria execução de um comando interativo qualquer. E ainda mais, esse aplicativo pode ser o próprio shell! O Netcat pode, ora se não poderia, estabelecer um servidor de shell remota. Observe essa maravilha: Caso 6 T1 (Terminal 1) - Servidor $ nc -l -vv -p 1025 | /bin/bash listening on [any] 1025 ... connect to [127.0.0.1] from localhost [127.0.0.1] 4572 copia-nc exemplo1 lista mensagem pergunta-chata piruetas-netcat piruetas-netcat~ resposta-obvia-No1 sent 0, rcvd 6 $
T2 (Terminal 2) - Cliente $ nc localhost 1025 ls -1-c $
Da maneira que foi feita acima o cliente, que passa o comando, não pode ver a sua saída. No caso de um comando como o ls este fato é relevante, mas diversos comandos poderiam ser dados pelo lado do cliente sem que se esperasse qualquer resposta, como 'init 0', por exemplo, para desligar a máquina. Mas e se precisássemeos da saída do comando dado? Como podemos fazer para vê-la do lado do cliente? Ora, se podemos, via pipe, passar quaisquer comandos tanto para dentro da conexão Netcat quanto podemos podemos passar da conexão Netcat afora para dentro de um comando, então podemos redirecionar as saídas do shell no servidor para dentro de outra conexão Netcat! Observe a manobra olímpica: Caso 7
T1 - Servidor 1 e 2 $ nc -l -vv -p 1025 | /bin/bash | nc -l -vv -p 1026 listening on [any] 1026 ... listening on [any] 1025 ... connect to [127.0.0.1] from localhost [127.0.0.1] 3560 connect to [127.0.0.1] from localhost [127.0.0.1] 3445
T2 - Cliente 1
T2 - Cliente 2
$ nc localhost 1025 ls
$ nc localhost 1026 copia-nc exemplo1 lista mensagem pergunta-chata piruetas-netcat piruetas-netcat~ resposta-obvia resposta-obvia-No1
$
-c sent 115, rcvd 0 sent 0, rcvd 3
$
$ Ainda assim temos de ficar trocando de terminais para em um passar um comando e em outro ver sua saída. Uma alternativa funcional é no T3, ao invés de simplismente nos conectarmos, nos conectarmos e enviarmos os dados que chegarem para o T2 usando redirecionamento e o identificador do terminal do diretório /dev. Por exemplo: T2: $ nc localhost 1026 > /dev/pts/1 Isso que vimos acima é a solução crua para a implementação de um servidor de shell remoto. O Netcat oferece várias opções passadas em parâmetros para tar seu uso mais funcional e otimizado. O conhecimento de como se realizar as manobras acima ainda se mostrará importante, no entanto, para que você encontre soluções criativas quando precisar. Como informei, o domínio deste trecho da lição não é fundamental para o aprendizado e uso do tunelamento, e por isso este curso não espera que tenha aprendido a realizar as piruetas do Netcat. Opções Brevemente, vamos ver agora algumas das opções Abaixo está a lista de opções obtida com o comando 'nc -h' e traduzida por mim. -c, --close fecha conexão ao encontrar EOF do stdin -e, --exec=PROGRAM programa a executar depois de conectar -g, --gateway=LIST nós de 'route-sourcing', até 8 -G, --pointer=NUM ponteiro de 'source-routing': 4, 8, 12, ... -h, --help apresenta este menu e sai -i, --interval=SECS intervalo de espera
para
que
linhas
o
enviadas
Netcat
e
para
nos
porta
oferece.
escaneadas
-l, --listen modo de escuta, para conexões que chegam -L, --tunnel=ADDRESS:PORT repassa porta local para um endereço remoto -n, --dont-resolve somente endereços de IP numéricos, sem DNS -o, --output=FILE imprime o tráfico hexdump para ARQUIVO (implica em -x) -p, --local-port=NUM número da porta local -r, --randomize randomiza portas locais e remotas -s, --source=ADDRESS endereço do 'source' local (ip o hostname) -t, --tcp modo TCP (padrão) -T, --telnet responder usando negociação TELNET -u, --udp modo UDP -v, --verbose modo verboso (utilizar duas vezes para ser ainda mais verboso) -V, --version mostra informações sobre a versão e sai -x, --hexdump faz um hexdump tanto do tráfico que chega quanto do que sai -w, --wait=SECS tempo limite para tentativas de conexões e para 'final net reads' -z, --zero modo zero-I/O (utilizado para escaneamento) Marquei em negrito as 2 opções que vou comentar neste resto de página. Como podem ver já conhecemos algumas opções como -h, -l, -p, -v e -vv. A opção que nos é central neste curso é, é claro, a -L. Outras são muito interessantes, como a -u, para realizar conexões UDP, -z, -r, -w e -i para escaneamento de portas e -o para sniffing. A opção -c permite que automaticamente fechemos uma conexão ao término da transferência de um arquivo. Isso pode ser útil caso não possamos manualmente interromper o netcat com-c, por exemplo. Especialmente útil se estivermos mantendo o serviço em pé com um while ou com outra manobra. Experimente refazer o caso 4 apresentado acima com a opção -c. Esta opção funciona sempre quando informada do lado da conexão que vai inserir dados. A opção -e soluciona de forma elegante e nativa o problema que só "resolvemos" com a manobra completa apresentada no Caso 7. A opção -e passa a execução de um comando especificado para a outra ponta da conexão, e ao recebere dados, retorna a saída do comando, caso responda, devolta para a ponta remota. Experimente escutar uma porta como fazíamos nos casos apresentados e passar o parâmetro -e seguido do caminho, digamos, do shell bash, -e /bin/bash. Pimba, um servidor de shell remoto perfeito. Uma última dica:
Para realizar as mesmas peripércias que fazemos com o Netcat, mas com segurança de dados, pode-se utilizar o tal Criptcat, que se diz ser o Netcat com conexões criptografadas. Uma alternativa, no entanto, seria tunelar as conexões Netcat por dentro de SSH, é claro! Iniciação prática - OpenSSH OpenSSH - Conectando Assim como o Netcat, o OpenSSH é tanto capaz de servir em uma dada porta quanto capaz de conectar a uma porta especificada, mas todas conexões que o OpenSSH estabelece funcionam sobre o protocolo criptográfico SSH. O cliente OpenSSH pode acessar qualquer porta dada, mas uma conexão só será estabelecida se o serviço a escutar na porta em vista falar o protocolo SSH. Suponho aqui que cada de nós já tenhamos acesso a ao menos uma máquina por SSH, mas caso alguém não tenha, estes exercícios poderão ser feitos na máquina local depois de colocarmos o sshd para rodar como veremos na página seguinte. Bom, o modelo de comando a seguir é o formato do acesso padrão mais simples possível por SSH com o OpenSSH: $ ssh servidor Simples assim. Quando não especificamos com que nome de usuário vamos ser autenticados pelo servidor, o OpenSSH tenta logar com o nosso nome de usuário local, com o qual lançamos o cliente OpenSSH. Acontece que geralmente o nome de usuário com o qual nos logaremos no servidor não é o mesmo que usamos para dar o comando. Nestes casos, precisamos especificá-lo adicionando 'usuario@' antes do nome do servidor. Modelo: $ ssh usuário@servidor Uma segunda alternativa para a especificação do nome de usuário com o qual logarmos no shell remoto é a utilização do parâmetro ' -l ', provavelmente de login. Observe, o seguinte comando faz o mesmo que o anterior: $ ssh -l usuário servidor Da maneira como foi apresentado acima, o comando não especifica a porta à qual tentará se conectar. O OpenSSH, neste caso, assume que queremos nos conectar à porta padrão dos servidores SSH, que é a 22. Um serviço de protocolo SSH, ao contrário de um servidor Netcat, possui uma porta padrão vastamente conhecida. Para especificar a porta à qual tentaremos nos conectar por SSH passamos o parâmetro identificado por ' -p ' para o nosso comando. Modelo: $
ssh
usuário@servidor
-p
22
Fazendo conexões com esses parâmetros somos levados ao shell da máquina remota. Podemos, entretanto, passarmos diretamente um comando para ser execuatado ao conecatarmos. Por exemplo, podemos fazer uma conexão que retorna a saída do comando 'who', listando os usuários logados no sistema: $ ssh usuário@servidor -p 22 "who" Autenticação do usuário O protocolo SSH implementa uma série de cerimônias tcp para estabelecer uma conexão. Isso acontece porque além de querer ser um protocolo seguro, uma conexão SSH liga um cliente de um lado à shell da máquina servidora do outro. Um servidor SSH padrão espera que somente pessoas reconhecidas possam se conectar à sua máquina. O método de autenticação do OpenSSH é pelo nome de usuário, que deve estar presente no arquivo /etc/passwd do sistema que serve. Ao contrário do estebelecimente de uma conexão Netcat, portanto, uma conexão SSH envolve a informação de um nome de usuário e sua senha. Legitimação do servidor # ssh localhost The authenticity of host 'localhost (127.0.0.1)' can't be established. RSA key fingerprint is 05:99:21:19:92:7c:d2:02:3b:1a:14:46:1c:7d:63:e1. Are you sure you want to continue connecting (yes/no)? Esta mensagem será aprensentada à primeira vez que nos conectarmos a cada servidor a partir de uma mesma máquina. Essa mensagem acusa que o serviço ao qual o cliente OpenSSH está prestes a se conectar não pode ser autenticado, ou seja, ou ele não pode garantir que à máquina à qual estamos nos conectando é realmente aquela que apontamos no comando ou (nem) que a máquina que apontamos é a que pensamos que é. Tipicamente essa operação não é arriscada porquanto não estamos fazendo uma conexão de sigilo coorporativo. A partir da primeira conexão autorizada por nós, através do 'yes', o OpenSSH armazenará no arquivo ~/.ssh/know_hosts a chave de identificação do servidor que legitimamos. Na próxima vez que nos conectarmos ao mesmo servidor, o OpenSSH vai poder comparar a chave dada pelo servidor encontrado com a chave armazenada associada ao servidor que pensamos estar encontrando. Com o nível de segurança setado por padrão, a conexão será interrompida caso as chaves não batam. Sobre o risco corrido na primeira conexão, podemos anteriormente requerer do administrador da máquina servidora, por uma via que pensamos ser mais segura, como por email ou pessoalmente, a chave do servidor para comparação. Existem também maneiras de checar a legitimidade do servidor após logados, o que nem sempre é conveniente e seguro. Importante: Caso venhamos a nos conectar mais de uma vez a uma mesma máquina, pode ser o caso que o OpenSSH não reconheça a chave ou o IP do servidor, caso tenham mudado. Isso pode acontecer por um motivo ou outro, e é provável que ao longo dos exercícios tenhamos nosso acesso bolqueado a máquinas seguras pelo nosso próprio cliente OpenSSH por essa razão de segurança. Existem várias saídas elegantes para este problema, como, por exemplo, alterar as medidas de segurança do cliente OpenSSH no arquivo de configaração. No entanto, não faria sentido nos envolver aqui com a soução de como implementar essa ou outra solução adequada. Sugiro, portanto, que aquelas pessoas que tiverem esses problemas de autenticação simplismente removam o arquivo ~/.ssh/known_hosts, onde ficam armazenadas as chaves e as identificações dos hosts autorizados. Lembrem, entretanto, que essa prática não é segura para todas as máquinas em qualquer instituição.
Iniciação prática - OpenSSH OpenSSH - Servindo Vamos agora, brevemente, conhecer o passos básicos com os quais podemos colocar o OpenSSH para escutar conexões pelo protocolo SSH. Se instalou o OpenSSH na mão, você pode iniciar o serviço com o seguinte comando: $ /usr/local/sbin/sshd
Caso tenha instalado o OpenSSH pelo sistema de pacotes debian podemos iniciar o serviço através do init.d com o comando $ /etc/init.d/sshd start Como dizíamos, a porta padrão para serviços SSH é a 22, e o OpenSSH escutará nesta mesma porta caso não setemos outra. Tentemos pois nos conectar à porta 22 de nossa própria máquina com o comando que aprendemos na página anterior: $ ssh localhost Porta de escuta e outras configurações Muitas vezes queremos alterar a porta em que nosso serviço escutará, ou porque queremos evitar ataques brute force automático de bots, ou para passar ao largo de scannings de porta mais estreitos, ou porque a porta padrão é bloqueada para acesso externo pelo nosso provedor, por exemplo, ou por qualquer outro motivo mais exótico. Para alterar a porta em o OpenSHH vai escutar temos de editar o arquivo de configuração do sshd, o /etc/ssh/sshd_config. 1 # Package generated configuration file 2 # See the sshd(8) manpage for details 3 4 # What ports, IPs and protocols we listen for 5 Port 22
Logo na quinta linha do arquivo está indicada a porta em que o OpenSSH vai abrir o socket para conexão. Podemos setar qualquer outro valor no lugar de 22, e o sshd funcionará com a nova configuração contanto que o reiniciemos. Para tanto, podemos interromper o processo do serviço e o reiniciarmos da mesma maneira. Caso se utilize o init.d, o fazemos da mesma maneira como antes mas com restart no lugar de start. Outras linhas deste mesmo arquivo de configuração são interessantes, mesmo para quem não quer montar um servidor profissional. Por exemplo, podemos decidir, através da seguinte diretiva, 26 PermitRootLogin , se será permito que a autenticação se dê com o nome de usuário do próprio root, o que poderia ser uma fraqueza na segurança. A diretiva 62 X11Forwarding decide se será possível o estabelecimente de conexões com redirecionamento dos aplicativos gráficos pela conexão. Estas opções e outras, no entanto, não nos interessam neste curso. Tunelamento - Netcat Tunelando com o Netcat - Parte 1 Vamos enfim utilizar nossa breve experiência para tentar montar nossos primeiros túneis. Para começar, vamos utilizar o querido canivete suiço Netcat, que em suas novas versões oferece o recurso de tunelamento. Como devemos todos lembrar, o tunelamente envolve pelo menos três nós conectados e, portanto, elos de conexão. Um desses, em princípio sempre o primeiro, é estabelecido com uma conexão regular, já o segundo elo é o próprio túnel, por dentro do qual a primeira conexão vai ser levada até a saída na terceira ponta. Apesar da prensença necessária dos três nós de que falo, podemos envolver somente duas ou até mesmo uma máquina no processo de tunelamento. Vamos ver alguns casos diferentes ao longo deste curso, inclusive porque a maior parte das utilidades de um túnel se dá em configurações de rede específicas entre duas ou mais máquinas.
Para apresentar os exemplos com mais consistência, no entanto, farei os testes de tunelamento em uma única máquina. Mas, novamente, nada impede que façam os mesmos testes em rede envolvendo mais de uma máquina. Abram três terminais. A idéia é que um primeiro terminal vai escutar em uma porta de forma regular, um segundo vai abrir um túnel de uma porta arbitrária até a porta em que o servidor do primeiro terminal estiver escutando e o terceiro terminal vai se conectar, também de maneira regular, à porta arbitrária do tunel, que levará essa conexão até a sua saída no serviço do primeiro terminal. Um comando será dado para cada uma das três partes do processo. Esse processo, quando realizado no console, é completamente evidente, transparente. T 1 (servidor): $ nc -l -vv -p 1026 T 2 (túnel): $ nc -L localhost:1026 -p 1025 T 3 (cliente): $
nc
localhost
1025
Este teste mostra que a conexão que entra na porta aberta pelo túnel, no caso a 1025, atravessa o túnel e cai na porta do serviço para o onde o túnel leva, no caso a 1026. Este é um cenário bastante semelhante ao que vimos na lição sobre escutar em portas com o Netcat. Aqui é estabelecida uma conexão clara em que tudo que for passado em uma ponta sai na outra, sem que o nó intermediário, o túnel, interfira na passagem. Experimente portanto digitar qualquer coisa em quaisquer das duas pontas, e observe que os dados saem na outra. Aquilo que for escrito no terminal do túnel parece não ir a lugar algum. Observe: T1 - Servidor
T2 - Túnel
$ nc -l -vv -p 1026 Listening on any address 1026 Connection from 127.0.0.1:50454 ola, sou o terminal 1 oi, sou o terminal 3 Total received bytes: 21 Total sent bytes: 22 $
$ nc -L localhost:1026 -p 1025 $
T 3 - Cliente $ nc localhost 1025 ola, sou o terminal 1 oi, sou o terminal 3 $-c
Tunelando com o Netcat - Parte 2 Repare que nenhum dado ficou no nó intermediário da conexão entre as duas pontas, e que, isto é importante, ao pressionarno lado cliente do túnel, o próprio servidor terminou a escuta, como acontecia quando cortávamos a conexão do lado do cliente em nossos testes de escuta com o Netcat, e o servidor fechava. É importante ver que a relação entre o servidor e cliente mediada pelo túnel Netcat mantém este detalhe, que revela um elo entre as pontas diferente daquele existente em um redirecionamento de conexão simples. Tipicamente em um redirecionamento de conexão, na verdade, duas conexões simples são estabelecidas, sendo que os dados de uma são passados para a outra como em um pipe (às vezes com o próprio pipe). Assim o término de uma conexão em um lado não pode ser reconhecido pelo outro, e não é a toa que em um redirecionamento simples de conexão o repasse de dados é unidirecional, que não é o caso, é claro, da conectividade em um tunelamento. O mesmo teste pode ser realizado, como disse, envolvendo três máquina diferentes, o que pode tornar a operação apresentada acima uma pirueta das mais úteis. A adaptação do tunelamento acima envolvendo três máquinas poderia ser como o seguinte: Servidor na internet: (servidor-x) $ nc -l -vv -p porta-x Servidor de túnel na internet: (servidor-tunel) $
nc
-L
servidor-x:porta-x
-p
porta-inocente
Cliente em rede interna que bloqueia saídas para a porta-x: $ nc servidor-tunel porta-inocente E o cliente acessa a porta-x na internet que, em um acesso direto, seria bloqueada pelo firewall ou pelo proxy da rede interna. PS.: Uma maneira de acompanhar um pouco mais do que acontece em nosso sistema enquanto fazemos esses exercícios de tunelamento é utilizar o netstat ou outra ferramenta de rede que apresente as conexões estabelecidas com a máquina. As seguintes duas linhas foram tiradas da saída do comando netstar -a | grep localhost ao montar um túnel simples como mostrado na página anterior. tcp tcp
0 0
0 0
localhost:1025 localhost:4186
localhost:2702 localhost:1026
ESTABELECIDA ESTABELECIDA
Quem estiver mais a vontade com redes e interessado, pode também, e isso sim eu recomendo fortemente, acompanhar os testes com uma ferramenta de sniffing, como o wireshark (que antes era o ethereal), o snort ou o próprio tcpdump. Um acompanhamento deste tipo permite que vejam o papel que tem um túnel criptográfico, por exemplo, assim como a origem aparente de cada pacote e outras informações. Não posso, no entanto, fazer esse acompanhamento para os testes que fizermos aqui. Tunelando com o Netcat - Parte 3
Note, e isso é muito importante mesmo, que os exemplos apresentados até então assumiram cenários com servidores e clientes Netcat tunelados por Netcat. Um túnel pode, no entanto, tunelar todo tipo de conexão. Para um tunelamento funcionar basta que o cliente e o servidor nas pontas sejam compatíveis entre si. O túnel é, nos termos que nos interessa aqui, cego ao protocolo falado entre o cliente e o servidor. Para ilustrar, vamos conhecer alguns casos de um tunelamento Netcat de uma conexão SSH, que já conhecemos. Assumindo que tanto a máquina de tunelamento quanto a máquina cliente são a mesma: (T1) $ nc -L servidor-ssh:porta-ssh -p 1025 (T2) $ ssh localhost -p 1025 No primeiro terminal o Netcat faz a sua única participação: aponta para um servidor SSH, escuta na porta 1025 e espera por uma conexão SSH. No segundo terminal, um cliente SSH se conecta à porta aberta pelo túnel Netcat. A conexão SSH acontece normalmente, e por dentro do túnel até o seu fim os dados aparecem criptografados. Um exemplo talvez mais surpreendente e aparentemente útil seja o tunelamento de uma conexão HTTP. Considere uma rede interna em que um site específico seja bloqueado. Se temos acesso a uma máquina externa, na internet, podemos nela montar um túnel que aponte para o servidor web na internet que queremos ver e em seguida nos conectar ao túnel com, é claro, um browser, capaz de falar o protocolo do servidor, o HTTP. Faça o teste em uma rede interna. Comece inicializando o Apache (caso não tenha um rodando, ou teste logo com um site na internet) na porta que quiser, mas suponhamos que tenha sido na porta padrão 80. De uma segunda máquina, monte um túnel Netcat que aponte para o servidor Apache, escutando por conexões que entrem. De uma terceira máquina, o cliente, abra um browser e se conecte à porta aberta pelo túnel na máquina em que está escutando. Veja o resultado! Simulando um túnel com redirecionamentos Netcat (opcional) Redirecionamentos Netcat Nota 1: Quem acompanhou a página da lição anterior que apresentou algumas piruetas com o Netcat vai certamente poder acompanhar melhor o que é mostrado nesta página. Sua leitura não é obrigatória neste curso, e deve ser lida por aquelas pessoas que tiverem curiosidade e interesse em sofisticar suas técnicas de manipulação de conexões com o Netcat. As técnicas apresentadas nesta página têm suas utilidades superadas, ao menos de forma geral, pela possibilidade de um túnelamento, agora nas novas versões do Netcat. Nota 2: Note que o redirecionamento de que falo não é um controle de roteamento, como o que o módulo redirect do Iptables faz. Estou, com 'redireciomento', me referindo à operação de passar os dados que chegam de uma conexão para dentro de outra. Existe, como dizia a pouco, a possibilidade de simplismente redirecionarmos os dados que chegam de uma conexão para dentro de outra, o que estabelece uma conectividade unilateral, ou seja, uma conexão indireta na qual só uma das pontas pode enviar dados à outra. É claro que podemos, no entanto, determinar para que lado da conexão o redirecionamente vai estar virado, o que nos leva a dois cenários diferentes. Com o Netcat podemos montá-los das seguintes maneiras: Sentido 1 (O servidor fala): T1 * recebe: * envia: para o cliente somente
do
Servidor somente
redirecionador
$ nc -l -vv -p 1025
T2 * recebe: do cliente * envia: para o servidor somente $ nc localhost 1025 | nc -l -vv -p 1026 T3 * recebe: * envia: para o redirecionador somente $ nc localhost 1026
somente
-
(e
não
repassa
para
o
Redirecionador servidor)
do
servidor
Cliente somente
do
cliente
Servidor somente
Sentido 2 (O cliente fala): T1 * recebe: * envia: para o redirecionador somente
$ nc -l -vv -p 1025 T2 * recebe: do servidor * envia: para o cliente somente $ nc -l -vv -p 1026 | nc localhost 1025 T3 * recebe: * envia: para o servidor somente $ nc localhost 1026
somente
do
(e
-
não
repassa
redirecionador
para
o
Redirecionador cliente)
Cliente somente
Podemos combinar esses dois sentidos estabelecendo duas rotas simultâneas entre um cliente e um servidor. Cada um com duas conexões estabelecidas, uma para ouvir e outra para falar. Essa operação inflada desenpenharia um papel bastante semelhante ao papel de um túnel, e pode satisfazer as necessidades daquelas pessoas cujo Netcat não possui o recurso de tunelamento. Existe, ainda, uma maneira mais eficaz de simular um túnel com o Netcat envolvendo quatro terminais (e não seis, como no caso acima), em que a ponta do servidor escuta e fala através de um centro de redirecionamento com dois clientes, um que fala e outro que escuta. É claro, permitindo a conectividade bidirecional que buscamos aqui (e que um tunelamento oferceria). Observe: T 1 - Servidor $ nc -l -vv -p 1025 T 2 - Redirecionador $ nc -l -vv -p 1026 | nc localhost 1025 | nc -l -vv -p 1027 T 3 - Cliente 1 $ nc localhost 1026 T 4 - Cliente 2 $ nc localhost 1027 Repare que em um redirecionamento de conexões, cada uma delas envolvidas é estabelecida independentemente, ainda que quando uma termine outras se comprometam por problema de bronken pipe (pipe quebrado). Ainda assim elas são independentes na medida em que cada uma se estabecelem em momentos diferentes. Um túnel, por sua vez, só se conecta ao servidor quando receber a conexão do cliente, ligando as duas pontas. Tunelamento - OpenSSH e algumas idéias Tunelando com o OpenSSH - Parte 1 O OpenSSH, como já enfatizei, é um aplicativo que só faz conexões que respeitem o protocolo SSH, e este nos serve para nos permitir acessarmos shell de máquinas remotas com segurança (tanto de dados quanto de legitimidade do servidor, entre outras dúzias de recursos que promovem segurança - que usuários podem logar remotamente, que endereços IP podem se conectar, que restrições um acesso tem, etc.). O que temos de lembrar agora, depois de tantos exemplos com o Netcat, é que quando nos conectarmos com o OpenSSH a um servidor SSH, este servidor vai estar servindo um shell remoto e vai estar, provavelmente, na porta 22 - mas isso somente se o servidor na ponta do túnel estiver escutando em SSH. Assim estarei assumindo nos próximos exercícios. Os testes vão envolver, em geral, três máquinas - uma para cada nó da operação. Nada me impediria de forjar a operação toda em uma única máquina (ou duas), como vimos acontecer nos experimentos com o Netcat. Naquele testes, entretanto, era importante que víssemos o tunelamento de forma transparente, com os seus integrantes (cliente, servidor e túnel) lado a lado em terminais. Penso que podemos, estudando agora o tunelamento com o OpenSSH, envolver em nossos estudos de caso máquinas diferentes, inclusive para representarmos cenários reais com mais fidelidade. Já sabemos colocar o OpenSSH para escutar em portas, então caso já não tenham acesso a um servidor SSH nós mesmos podemos montar o nosso (lembre que podemos tunelar em SSH conexões não SSH até um servidor qualquer, não SSH). Acontece que, naturalmente, a máquina que vai fazer o túnel também deve ter o OpenSSH instalado, mesmo que o comando que estabelece o túnel seja dado a partir da máquina cliente. O fato de que o comando que estabelece o túnel seja dado pelo cliente é algo relevante. Nos exemplos que conhecemos e nas experiências que fizemos com o Netcat, o túnel era sempre estabelecido a partir da própria máquina que intermediaria as duas pontas. Como fazíamos a conexão da máquina local para a própria máquina local, não precisamos sentar em outra cadeira ou logar remotamente para fazer o túnel, mas nos casos sugeridos de tunelamento real precisaríamos de dar o comando de tunelamento em uma outra máquina (presencialmente ou por acesso remoto). Com o OpenSSH não é diferente, mas o próprio comando de tunelamento traz imbutido na sintaxe uma conexão remota, de forma que podemos montar o túnel na máquina intermediária diretamente a partir da máquina cliente. (Como sugeri, o mesmo poderia ser feito com o Netcat, ainda que não tenhamos visto este caso). O túnel do OpenSSH tem uma característica especial para nós. Quando estabelecemos o túnel com um comando remoto, a porta que abrimos para o túnel escutar fica na nossa própria máquina local, o que é uma mudança de estratégia com relação ao tunelamento regular do Netcat. Essa estratégia permite que a conexão desde o cliente até o servidor receba o mesmo tratamento de protocolo, segurança e etc., tendo em vista que uma conexão tunelada normalmente possui duas fases - a entre o cliente e a entrada do túnel e deste até o servidor. A consequência desta característica é que quando formos nos conectar ao túnel com o cliente vamos apontar a conexão para a própria máquina local, na porta que setamos. Outro detalhe é que quando passado o comando desde o cliente, o túnel é montado e o terminal do cliente recebe a shell deste sistema intermediário. Mas não se passarmos um comando como aprendemos na página sobre o cliente OpenSSH. Como devem lembrar, podemos passar um comando para execução automática no lugar de receber uma shell do sistema remoto. Nos exemplos que mostrarei aqui vou utilizar esse recurso de execução remota automática com o comando 'sleep', para contar em segundos o tempo em que o túnel se manterá aberto.
Tunelando com o OpenSSH - Parte 2 Vamos começar com um exemplo inócuo, mas didático. Ele não representa nenhuma sistuação real, nem parece poder nos servir de qualquer coisa, mas ainda assim me soa conveniente. Vamos fazer estabelecer uma conexão entre um cliente e um servidor SSH através de um túnel SSH estando todos na mesma máquina, como fazíamos nos experimentos com Netcat. Com o OpenSSH já servindo na porta 22, podemos nos livrar de abrir um terminal só para escutar na porta, como antes (nos exemplos com Netcat) e abrimos somente dois terminais, ambos representando a máquina cliente. A sintaxe do comando de tunelamento é explicada logo após o exemplo. T1 (Cliente) - Se conecta à máquina que intermediará a conexão e abre um túnel: $ ssh localhost -L 1025:localhost:22 -t sleep 120 T2 (Cliente) - Se conecta ao túnel (que abre na máquina local) e sai na ponta do servidor: $ O
ssh comando
dado
Parte
localhost no
terminal 1:
T1
pode
-p ser
dividido
ssh
1025 em
três
partes: localhost
Este trecho do comando indica a máquina que intermediará a conexão entre as pontas, fazendo o túnel. Esta passagem também poderia ser escrita como ssh usuario_atual@localhost -p 22, que são os valores padrões assumidos quando não especificados. Já vimos isso na página do cliente OpenSSH, mas vamos entender melhor o papel do nome de usuário no tunelamento SSH na próxima página. Parte 2: -L 1025:localhost:22 Esta passagem é o comando de tunelamento propriamente dito. Como foi explicado, o túnel aberto com OpenSSH começa na própria máquina cliente, e então atravessa a máquina intermediária (no caso, a máquina local) até chegar ao servidor (no caso, também a máquina local). Antes de atingir a máquina intermediária fazemos uma conexão à própria máquina local, na porta que setamos para abrir o túnel, identificada depois do parâmetro de modo de tunelamento -L, no exemplo a porta 1025. Ou seja, esta porta foi aberta na máquina local, e a máquina indicada a seguir é o servidor para onde o tunelamento leva, que também é a máquina local, no exemplo, na porta indicada em seguida (no caso a porta padrão de um servidor SSH mesmo). Parte 3: -t sleep 120 O parâmetro -t permite a execução de um comando associado à conexão cliente-maq.intermediária para o estabeleciemento do túnel. Quando um comando é executado, como vimos na página do cliente OpenSSH, ao término do qual a conexão se fecha naturalmente. Como o comando executado no exemplo é um contador de tempo, a conexão será fechada (e com ela também o túnel feito) ao término da contagem dos segundos dados, no caso 120. Esse recurso permite que vejamos o terminal (no cliente) que dá o comando de tunelamento ficar em stand by, esperando, como tínhamos nossos terminais de tunelamento com Netcat. Além disso, podemos terminar a conexão, e assim também o túnel, com um simples-c e realizarmos um novo teste. No primeiro terminal, no momento que executamos o primeiro comando, o OpenSSH, se já tendo reconhecido o servidor (intermediário), pedirá uma senha para o login. Como não especificamos nome de usuário, temos de oferecer a senha que o usuário com o mesmo nome que o nosso possui na máquina remota. Esse é o acesso que precisamos ter à máquina do meio para executar o comando de tunelamento propriamente dito. Como essa máquina é a própria máquina local, no exemplo dado, então o usuário com o mesmo nome que o nosso é o nosso próprio usuário! A senha a ser fornecida é, portanto, a nossa senha. No segundo terminal, ao nos conectarmos através da entrada do túnel na máquina local ao servidor, neste caso particular também na máquina local, é requerida a senha do usuário com nosso nome no servidor, que normalmente seria remoto, mas que, mais uma vez, está em nosso própria máquina. Logo, mais um vez, a senha a ser fornecida no segundo terminal também é a nossa própria senha, a senha do nosso usuário (com o qual executamos o comando). Em um caso típico, envolvendo três máquinas, o comando de tunelamento teria o seguinte formato: T1 (Cliente = máquina local) - Se conecta à máquina que intermediará a conexão e abre um túnel: $ ssh máquina-túnel -L porta-cliente:servidor:porta-servidor -t sleep 120 T2 (Cliente) - Se conecta ao túnel (que abre na máquina local) e sai na ponta do servidor: $ ssh cliente -p porta-cliente Observe como é curioso que, pelo túnel OpenSSH partir do cliente, para nos conectarmos ao servidor acabamos por fazer um acesso SSH para a nossa própria máquina! Tunelando com o OpenSSH - Parte 3
No exemplo que vimos na página anterior, assumiu-se que o usuário com que nos logaríamos na(s) máquina(s) dos três nós envolvidos porderia e seria o mesmo - e de fato pôde ser, visto que os três nós estavam na mesma máquina. Como o OpenSSH assume, se não for especificado, que o usuário a se conectar no shell remoto tem o mesmo nome que o usuário que o executa, não precisamos em nenhum momento indicar que usuário vamos utilizar, se vamos justamente, como no exemplo, logar com o nosso próprio nome. Acontece que muitas vezes não é o caso que o acesso que temos às diferentes máquinas seja feito através de exatamente os mesmos nomes de usuários. Podemos inclusive ter motivos para querer nos conectar à nossa própria máquina por algum motivo com outro usuário que não o nosso, caso o servidor ou o nó intermediário esteja na mesma máquina que o cliente. Estrito senso, cinco usuários diferentes podem participar do processo de tunelamento com OpenSSH. Desses, somente dois são especificáveis nos próprios comandos de tunelamento, e os outros três são:
• • •
O usuário que inicializou o servidor OpenSSH, provavelmente o root; O usuário que rodar o comando do T1; O usuário que rodar o comando do T2;
Os dois especificáveis nos comandos são:
• •
O usuário com o qual logar na máquina intermediária; O usuário com o qual logar no servidor quando dentro da conexão tunelada, cujo login é logicamente posterior ao login do da máquina intermediária.
No primeiro comando, podemos determinar com que usuário vamos nos autenticar na máquina intermediária, a que nos tunelará. Lembre que só precisamos nos autenticar nela para estabelecer o túnel de forma confortável, a partir do cliente. Podemos definí-lo com duas sintaxes diferentes: Podemos utilizar a sintaxe usual: (T1) $ ssh usuário@maquina-tunel porta-cliente:servidor:porta-servidor Ou indicá-lo com o parâmetro ' -l ' que já conhecemos: (T1) $ ssh -l usuário máquina-tunel porta-cliente:servidor:porta-servidor No segundo comando, podemos determinar com que usuário vamos nos autenticar no servidor, observe: (T2) $ ssh usuário@localhost -p porta-cliente Ou, da mesma maneira, como já vimos: (T2) $ ssh -l usuário localhost -p porta-cliente Análogamente, como exisetm três nós envolvidos no tunelamento, podemos envolver até três diferentes portas de escuta na operação:
• • •
A - A porta em que máquina intermediária escuta para a fazermos um servidor de túnel, tipicamente a 22; B - A porta de entrada do túnel, que vamos designar à nossa máquina, de valor arbitrário. C - A porta em que o servidor escuta, tipicamente a 22;
Tendo as letras acima como identificadores das portas descritas, eis aqui a posição em que cada porta é especificada no primeiro comando: (T1) $ ssh -l usuário máquina-tunel -p AB:servidor:C O porta apontada no segundo comando tem , naturalmente, de ser a especificada no T1 para a entrada do túnel: (T2) $ ssh -l usuário localhost -p B PS.: Depois que o túnel for estabelecido com o primeiro comando em um primeiro terminal, podemos no lugar de fazer uma conexão SSH simples, fazer outro tipo de conexão que fale o protocolo SSH, como conexões scp, sftp, slogin etc. Podemos, depois que o túnel estiver pronto, dar um comando no T2 como o seguinte, para, como no exemplo, copiar uma pasta remota por inteira na máquina local: $ scp -r -P 1025 localhost:"/pasta-remota/" /pasta-local/ Esta manobra, como sugerida acima, é claramente útil quando se quer copiar arquivos de uma máquina a qual não se tem acesso direto. Isso pode acontecer, por exemplo, em razão de problemas de DNS. De qualquer forma, com a técnica acima conseguimos copiar de uma vez o que em outro caso precisaríamos de primeiramente passar para a máquina intermediária e só então copiar para a máquina local.
Tunelando com o OpenSSH - Parte 4 Múltiplos túneis com OpenSSH O OpenSSH tem é preparado para em um único comando poder abrir mais de um túnel através de uma mesma rota intermediária. Ou seja, sabendo que eu tenho acesso à máquina M e que esta tem acesso à serviços aos quais não tenho, eu posso estabelecer em um comando vários túneis que saem da minha máquina e passam pela máquina M, um para cada serviço que desejo acessar. O comando utilizado seja uma sintaxe intuitiva para quem entendeu a de um túnel simples. Primeiramente a conexão à máquina intermediária, depois os comandos de tunelamento. Dado que Pl é Porta Local, Ps é Porta do Serviço, S é Serviço, o túnel e L é login: $
ssh
servidor-tunel
-L
Pl1:S1:Ps1
-L
Pl2:S2:Ps2
-L
Pl3:S3:Ps3
...
Tunelando outros protocolos
Quando começamos a Parte 1 de nossos estudos sobre tunelamento com o OpenSSH, propus que utilizássemos o OpenSSH para tunelar conexões SSH, portanto envolvendo um cliente e um servidor também SSH. Como já havia sugerido desde o começo do curso, podemos utilizar o OpenSSH (assim como vimos com o Netcat) para tunelar todo tipo de conexão de quaisquer protocolos, o que pode ser bem útil caso precisemos de segurança de dados, por exemplo, ou simplismente de um túnel mais consistente e seguro do que um túnel Netcat. Para tanto precisamos, da mesma maneira, tanto de um servidor quanto de um cliente falando a mesma língua, enquanto o OpenSSH os conecta em um túnel SSH sem que os dados sejam afetados. Lembrem-se que o túnel não precisa compreender o que está passando por ele, ao menos no sentido que nos cabe aqui. Na lição de tunelamento com Netcat experimentamos tunelar SSH por dentro de um túnel Netcat. Agora vamos fazer o contrário. Vamos experimentar tunelar em SSH uma conexão simples de Netcat, utilizando ambas as ferramentas de que ficamos tão íntimos recentemente. Abra três terminais e, se puder, se conecte à três máquinas distintas com o OpenSSH. Vamos dizer que na máquina 3 é mantido consistentemente um servidor de protocolo em claro na porta 2000, com o Netcat. Queremos nos conectar a este serviço de nossa máquina local, a máquina 1, e para isso precisamos de ser tunelados lá de fora de nossa rede interna através da máquina 2, que está livre e à qual temos acesso. Imagine. Poderíamos fazê-lo logo com um tunelamento Netcat, mas especificamente agora vamos transferir dados pessoais ou sigilosos que alguém da nossa rede interna pode querer capturar. Preferimos, portanto, enviar os dados por SSH ao menos até a máquina 2, a partir da qual não temos problema em tranferir dados em claro até o servidor Netcat. Então: Terminal 2: * Se conecta à máquina 2, por SSH, e estabelece um tuńel para o serviço (porta 2000) na máquina três a partir de uma porta arbitrária da máquina 1 (digamos, 1025). $ ssh máquina2 -L 1025:máquina3:2000 -t cat Terminal 1: * Estabelece uma conexão em claro com o túnel criptogrado na máquina local (1) na porta 1025 e sai no serviço Netcat na porta 2000 da máquina 3. $ nc localhost 1025 Observe o uso de '-t cat -' no comando do terminal 2 no lugar de '-t sleep n'. É uma alternativa para quem quiser manter o túnel aberto indefinidademente sem que haja uma contagem tempo para o fechamento da conexão. O mesmo que fizemos na lição de tunelamento com o Netcat pode ser repetido aqui com um túnel SSH, que era o exercício de tunelar uma conexão que um aplicativo que não seja modo texto, como uma conexão HTTP, que um browser fala. Concatenado túneis Nem precisaria dizer que podemos, se quisermos, concatenar a saída de um túnel com a entrada de outro. Ou seja, re-tunelar a conexão que chegar de um túnel em outro túnel. Para tanta basta, já é claro, que a porta do serviço para onde um túnel leva seja a porta de entrada de um outro túnel. Isso não é também uma capacidade exclusiva do OpenSSH, já que um túnel não precisa saber se a conexão que recebe é tunelada ou não. Todo tipo de túneis podem estar envolvidos, desde que o cliente fale o mesmo protocolo do servidor na ponta final para que a conexão aconteca adequadamente. Como um exercício desta idéia, vamos concatenar um túnel SSH com um túnel Netcat e atravessar por eles uma conexão SSH até um servidor na ponta do túnel Netcat. Essa operação poderia envolver até quatro máquinas, mas vamos fazer deixar o servidor SSH na nossa própria máquina, a máquina cliente e ao conectarmos seremos tunelados por outras duas de volta a máquina local. Para tanto vamos precisar de três máquinas. Vamos assumir que a máquina 1 é a máquina local, cliente e servidora, a máquina 2 é a que tunela em SSH e a máquina 3 a que tunela em Netcat. Vou assumir que abrimos três terminais, cada qual associado a uma máquina. No entanto, vamos dar os comandos todos remotamente às duas máquinas a partir da máquina local. Assumo também que o servidor OpenSSH já está rodando na máquina 1 na porta 22. Terminal 2 (túnel SSH): $ ssh máquina2 -L 1025:maquina3:1026 -t cat Terminal 3 (túnel Netcat):
$ ssh máquina3 "nc -L máquina1:22 -p 1026 && -t cat -" Terminal 1 (Cliente SSH): $ ssh localhost -p 1025 E eis é uma forma bastante sofisticada e confusa de se utilizar o console de uma máquina: caímos em uma sessão modo texto de nossa própria máquina! Tunelando em HTTP Corkscrew - Parte 1 Como já foi comentado, tanto na introdução quanto na instalação, o Corkscrew é uma ferramenta que tunela conexões SSH para além e para aquém do proxy em HTTP. Depois que o Corkcrew estiver configurado, se estiver bem configurado, nem precisamos lembrar que ele está operando para conectar, simplismente fazemos nossas conexões com OpenSSH normalmente, e elas vão ser tratadas automática e invisivelmente pelo Corkscrew. Corkscrew significa, em inglês, 'saca-rolhas', que sugere seu papel de abrir uma rota. Segundo o site de seu criador, os proxies em que o Corkscrew já foi testado com sucesso são:
• • • • •
Gauntlet CacheFlow JunkBuster Squid Apache's mod_proxy
Para automatizar a tarefa do Corkscrew, precisamos editar um único arquivo que vai fazer o OpenSSH sempre chamá-lo antes de tentar estabelecer a conexão por conta própria. Com o Corkscrew já instalado e logados com o usuário com que pretendemos nos conectar, vamos criar o arquivo ~/.ssh/config: $ vim ~/.ssh/config E completem com os dados: Host ProxyCommand
corkscrew
http-proxy.com
porta
* %p
%h
Com a diretiva host definimos para quais máquinas a configuração que se segue vai valer. Podemos, em geral, simplismente setar *, que vale para quaisquer hosts. ProxyCommand é a diretiva que vai chamar o Corkscrew par tunelar a conexão atual pelo proxy dado na sua porta (que também deve ser indicada). %h e %p são variáveis recebidas como argumentos do comando OpenSSH que estamos dando, respectivamente, o host e a porta de destino. O normal é que possamos simplismente utilizar o comando ssh como se não houvesse proxy algum em nosso caminho. Experimente. Corkscrew - Parte 2 Note que este arquivo de configuração não é do Corkscrew, e sim do próprio OpenSSH. Ele é, na verdade, simplismente o arquivo de configuração pessoal de cada usuário, em complemento ao /etc/ssh/ssh_config, onde podemos setar diretivas suplementares ao arquivo global, e personalizar algumas opções. Naturalmente, outros programas que se utilizam do OpenSSH vão requerer uma configuração especial no ~/.ssh/config, como por exemplo o proxytunnel, que não cobrimos neste curso. A diretiva ProxyCommand é, é claro, do próprio OpenSSH, e chama o Corkscrew para atravessar o proxy dado (no modelo dado, o httpproxy.com) na porta indicada (por exemplo, 8080 ou 3128 que o Squid poderia usar, etc.). %h e %p são variáveis recebidas por parâmetro transparentemente, e correspondem respectivamente ao host e à porta visados na conexão a ser tunelada para fora. PS.: Quem tiver interesse pode aproveitar o embalo e aprender a utilizar o ~/.ssh/config para configurações úteis no dia-a-dia, como automatizar tunelamentos SSH ou conexões simples. Por exemplo, as linhas abaixo automatizam a conexão para minha-casa.no-ip.org. Quando digitarmos ssh casa o comando é convertido adequadamente: Host
casa HostName
minha-casa.no-ip.org Port User
443 tomas
Adicinando a linha a baixo estaremos a um passo de uma automatização igualmente grande de um comando de tunelamento (no caso utilizaria o Host casa como máquina intermediária para o túnel. Para terminar de fazê-lo, os interessados(as) podem consultar o manual da configurações do OpenSSH com o comando ' man ssh_config '. LocalForward localhost:1025 servidor:porta HTTPTunnel - Parte 1 A função deste software é basicamente mesma que a do Corkscrew, encapsular uma conexão em HTTP para atravessar um proxy HTTP restritivo. A diferença é que o Corkscrew é distinado ao tunelamento exclusivamente de SSH, enquanto o HTTPTunnel se propõe a tunelar todo tipo de protocolo em HTTP. Para que o HTTPTunnel funcione, é necessário que tanto o servidor quanto o cliente estejam atrás de uma interface do HTTP. Ou seja, ambas as máquina devem ter o software instalado e rodando. Isso certamente é uma restrição ao uso se lembrarmos de como podíamos nos tunelar para qualquer canto sem que o servidor sequer imaginasse por onde passara a conexão do cliente. O comando do lado do servidor tem o formato: hts -F host:porta_do_serviço porta_do_túnel_serv O comando do lado do cliente tem o formato: htc -F porta_do_tunel_cliente -P proxy:porta_do_proxy servidor:porta_do_tunel_serv
Invistam algum tempo tentando intuir os dois comando acima. HTTPTunnel - Parte 2 Vamos dizer que queiramos realizar uma conexão qualquer cujo protocolo ou porta de destino sejam bloqueados. Como um modelo didático, vamos usar o Netcat. Desejamos acessar um servidor na internet, o servidor.externo.net que escuta na porta 1027. O serviço pode ter sido inciado com um comando como: $ nc -l -p 1027 Desejamos acessá-lo com nosso Netcat cliente. No entanto, existe um proxy restritivo na saída de nossa rede, o proxy.rede.local.org, pelo qual só passam conexões HTTP, todas pela porta, digamos 3128. Nosso servidor deve iniciar o HTTP-Tunnel com o comando hts (http tunnel server), abrindo uma porta de escuta (arbitrária, digamos, 3000) associada a porta real do serviço, que, como sabemos, é a porta 1027. O cliente, nós, devemos iniciar o HTTP-Tunnel com o comando htc (http tunnel client), abrindo uma porta (arbitrária, digamos, 1500) local, de onde a conexão vai ser enviada para a porta de escuta do servidor passando pelo proxy na sua porta, no caso, a porta 3128 do lado interno do proxy proxy.rede.local.org. Os comandos de tunelamento serão: HTTPTunnel
-
SERVIDOR
$ hts -F localhost:1027 3000 HTTPTunnel - CLIENTE $ htc -F 1500 -P proxy.rede.local.org:3128 servidor.externo.net:3000 Por fim, com o esquema de túneis preparado, fazemos a conexão propriamente dita, (como clientes, obviamente): $
nc
-vv
localhost
1500
É claro que em um cenário típico, se a conexão a ser realizada tem o ser regularmente, o esquema de túneis já vai estar preparado, estático. Essa estrutura não precisa ser desmontada porque uma conexão foi fechada. Um servidor, especialmente, pode manter o seu túnel funcionando permanentemente e divulgar sua porta já como sendo a porta aberta com o hts. Últimas notas Tunelamento reverso Como já explicamos brevemente, a técnica de tunelamento reverso permite que, de uma máquina, setemos um túnel não para reapontar uma porta para o serviço de uma terceira máquima, mas sim para que uma máquina monte um túnel que retorna a conexão para ela mesma. Podemos, com tunelamento reverso, permitir acesso à uma rede interna a partir de fora e atraveś de um firewall restritivo, visto que a conexão autorizada é aquela do tunelamento entre a máquina intermediária, fora da rede, e o servidor, que dispara o túnel reverso. O túnel reverso deve ser iniciado, portanto, do lado do servidor.
O parâmetro do OpenSSH que constitui um tunelamento reverso é -R, claramente de Reverse. O uso do parâmetro -R exclui a possibilidade do uso o -L regular, que vem de Local. Enfim, a ordem de um comando de tunelamento reverso com o OpenSSH é inversa à de um comando de tunelamento regular: primeiro a porta a ser aberta na máquina intermediária, depois a porta do serviço local que vai receber as conexões tuneladas e, por fim, o comando de conexão à máquina intermediária. Para fazer um túnel reverso com o OpenSSH, a partir do servidor dê um comando do formato:
SERVIDOR: $ ssh -R 1025:localhost:22 maquina-intermediaria -t sleep 999 E,
com
o
túnel
montado,
experimente,
a
partir
da
máquina
intermediária,
conectar-se
ao
túnel
com:
MÁQUINA INTERMEDIÁRIA: $ ssh localhost -p 1025 E paramos diretamente no servidor. O mesmo pode ser feito a partir de outras máquinas clientes, desde que uma diretriz esteja presente no arquivo de configuração do servidor OpenSSH, o /etc/ssh/sshd_config, da máquina intermediária. Experimente adicionar a linha GatewayPorts e tente fazer o mesmo a partir de outras máquinas. A utilidade é auto-evidente. Existem outras ferramentas capazes de realizar tunelamento reverso, como a rrs.
yes