Durante las pruebas de auditoría web, uno de los principales objetivos es identificar vulnerabilidades que nos den acceso al sistema y hacernos más amena la auditoría 😀 . Una de ellas es la subida de Shells, que a través de un LFI, RMI o una subida vulnerable de ficheros nos permita tener un acceso no autorizado a un servidor y poder ejecutar comandos. En este artículo vamos entender como funcionan las WebShells, Bind Shells y Reverse Shells.
DISCLAIMER
Todas las pruebas realizadas a continuación tienen un propósito meramente educativo e informativo, por lo que cualquier uso malintencionado de las mismas no sería nuestra responsabilidad.
QUÉ ES UNA SHELL
Una Shell es un script utilizado por un usuario malintencionado con el objetivo de acceder a los recursos de un equipo y tener control del sistema mediante la persistencia y el uso de backdoors. Por lo general, suelen subirse a servidores a través de funcionalidades de subida de ficheros, aunque también se utilizan exploits o vulnerabilidades específicas como Remote File Inclusion de PHP.
TIPOS DE SHELL
Existen varios tipos de shell:
- Bind Shell: shell de conexión directa desde un equipo atacante (A) a un equipo vícima (B) a través de Sockets. Establece un puerto a la escucha para recibir conexiones.
- Reverse shell: shell de conexión reversa desde un equipo víctima (B) a un equipo atacante (A) a través de Sockets. Crea una conexión a la dirección IP y puerto especificado.
- WebShell: shell basada en web a la que se accede a través del navegador, por lo que no disponen del estilo interactivo de un terminal y en la que no existe comunicación entre equipos a través de Sockets.
La mayoría de las veces estas WebShells se encuentran protegidas por credenciales para que sólo el usuario pueda acceder a ellas. Además, para dejar el menor rastro posible, los comandos se transmiten a través de cabeceras específicas o de valores de cookies mediante el uso del método POST.
QUÉ ES UN SOCKET
Antes de seguir con las Shells, entendamos que son los sockets. Un socket no es más que la comunicación entre dos aplicaciones a través de un protocolo (en este caso TCP o UDP) utilizando una dirección ip y un puerto. Existen dos tipos de socket:
- Basados en TCP: son el tipo de socket SOCK_STREAM que nos asegurarán que los mensajes serán recibidos en el orden en el que los hemos enviado.
- Basados en UDP: son el tipo de socket SOCK_DGRAM que NO nos aseguran que los mensajes serán recibidos en el orden en el que los hemos enviado.
A la hora de crear un socket, aparte de indicar el tipo que queremos utilizar, tendremos que indicar la familia de direcciones con las que se va a comunicar. Existen varios tipos pero los más utilizados son los siguientes:
- AF_INET: familia para direcciones IPv4.
- AF_INET6: familia para direcciones IPv6.
Un ejemplo sencillo para entender el uso de los sockets es la herramienta Netcat, imprescindible en el ámbito de la seguridad informática para el análisis de red sobre servicios TCP/IP. Su uso es muy sencillo, pues sólo tendremos que indicarle la dirección ip y el puerto al que nos queremos conectar:
Esta instrucción crearía un socket hacia la dirección y puerto especificados para establecer un canal de comunicación. Veamoslo con el siguiente gráfico:
CREANDO NUESTRAS SHELLS
Contexto: nos encontramos realizando una auditoría web y durante las pruebas encontramos un formulario con una subida de ficheros, que parece ser vulnerable. Aprovechándonos de esta debilidad, intentaremos subir varios tipos de shell.
WEBSHELL
Enfocándonos en la subida de ficheros, observamos que no se están validando de forma correcta los ficheros, ya que sólo se está comprobando la extensión y no el contenido, lo que nos permitiría hacer un Bypass de la funcionalidad y subir cualquier fichero:
De esta forma, conseguimos subir una WebShell, aunque desconocemos el directorio al que se ha subido. Conocer este directorio es necesario para poder invocar a la WebShell y poder pasarle los comandos a ejecutar. Después de hacer uso de una herramienta como wfuzz o dirb, localizamos un directorio denominado uploads.
La WebShell que hemos subido está escrita en PHP, ya que la aplicación está en ese lenguaje. Su contenido es muy simple <?php system($_GET[“a”]); ?> . El código $_GET[“a”] recuperará el valor pasado a través de la url en el parámetro de nombre a y la función system() ejecutará el comando en el sistema. Como ejemplo, en la siguiente imagen se muestra el resultado del comando systeminfo :
Un ejemplo muy interesante sobre este tema se puede leer en el siguiente post de HackPlayers .
BIND SHELL
Aparte de utilizar una WebShell, también se nos podría ocurrir la idea de subir una Shell directa (bind shell) que abriría un puerto en el servidor al que nos conectaríamos directamente. Aunque parece algo sencillo, existen varios obstáculos que podrían bloquear la conexión como son el Firewall/NAT :
Al intentar conectarnos desde nuestra máquina hacia el servidor en el que se encuentra la Shell, ubicado en la DMZ, el Firewall/NAT detectará la petición entrante y la bloqueará. Para poder utilizar este tipo de Shells tendría que existir una regla que permitiese pasar la petición y una redirección de puertos para llegar a nuestro destino. Debido a esto, este tipo de Shells es el menos utilizado.
Ya que hemos nombrado a los Firewall, no viene mal tener en cuenta dos tipos:
Saltaremos este tipo de Shells y pasaremos a las Shell reversas.
REVERSE SHELL
Este caso es el que más se da. Subiríamos al servidor, ubicado en la DMZ, una Shell reversa que al invocarla intentará realizar una conexión a nuestra máquina, evitando así cualquier tipo de bloqueo por parte del Firewall/NAT ya que las peticiones realizadas desde la máquina hacia internet están permitidas :
Al invocarla, intentará conectarse a nosotros (línea verde punteada) a través del puerto indicado. Si se establece la comunicación de forma correcta, se establecerá el canal de comunicación (línea morada punteada) y se mostrará una consola de Windows al hacer uso del parámetro -e cmd.exe . La Shell reversa que hemos subido es la siguiente:
Antes de invocarla, tendremos que poner en nuestra máquina el puerto 4456 a la escucha para que se establezca la comunicación:
Con el puerto en escucha, procedemos a invocar a la Shell reversa a través del directorio uploads de la siguiente forma:
De esta forma se abrirá un socket desde el servidor contra la dirección IP 192.168.1.8 a través del puerto 4456 . Al establecerse el canal de comunicación se ejecuta la aplicación definida por el parámetro -e , que en este caso es una cmd de Windows :
El único inconveniente es que el antivirus de la máquina, al hacer uso de un proceso de comunicación remota como es netcat, muestra una alerta de que se va a hacer uso del mismo:
Los antivirus utilizan varios métodos para la detección de programas maliciosos:
- Detección basada en firmas: es el método más común que se basa en la comparación de patrones sospechosos del fichero analizado con una gran base de datos de patrones conocidos. Debido a que se basa en patrones estáticos es fácilmente evadido.
- Detección heurística: este método, más costoso en cuanto a recursos de la máquina, se basa en el análisis del comportamiento del fichero (escritura en memoria, conexión externas a servidores no identificados…). Con este método se pueden identificar programas que no serían identificables a través de la detección basada en firmas.
- Detección por comportamiento: el antivirus analiza todas aquellas peticiones de ejecución solicitadas al procesador del equipo.
En el caso de que se tratase de un Malware del que no se tenía constancia, se añade su firma a la base de datos para poder ser identificado en próximas ocasiones. Pero este no es el caso.
Entonces, ¿qué podríamos hacer con el antivirus?. ¿Podríamos intentar hacer lo mismo sin usar netcat y que no muestra una alerta?. Probemos a ver si lo conseguimos. Haremos uso de Powershell que será invocado desde este fichero PHP (https://github.com/Dhayalanb/windows-php-reverse-shell/blob/master/Reverse%20Shell.php) que hemos modificado un poco :
Seguramente esta no sea la mejor opción y hay muchísimas formas y mejores de conseguir nuestro objetivo. Vamos a detallar el contenido de este fichero:
- Línea 2 : payload codificado en Base64 que se ejecutará desde Powershell (https://github.com/trustedsec/social-engineer-toolkit/blob/master/src/powershell/reverse.powershell).
- Línea 3 : decodificación del payload.
- Líneas 4 y 5 : cambio de directorio a C:\Windows\Temp .
- Línas 6, 7 , 8 y 9 : creación de un fichero .ps1 cuyo contenido será el payload anterior decodificado.
- Línea 10 : ejecución del fichero creado C:\Windows\Temp\darko.ps1 desde Powershell .
Para ver cuántos antivirus nos detectan, pasaremos el fichero por Virustotal :
Sólo uno detecta el fichero. Ahora sólo nos queda poner a la escucha el puerto 5545 que hemos configurado en el payload, invocar al fichero shell_reversa_powershell.php y esperar a que nos devuelva una shell :
Parece que el fichero que hemos subido cumple su objetivo. Tenemos Shell reversa :
Esta vez el antivirus esta vez no ha saltado:
Un comentario sobre “Highway to Shell”