Bind Shell ocultas

Para poder realizar una gestión adecuada de la seguridad de una empresa u organización, es imprescindible disponer de un inventario detallado de los activos conectados a la red así como de todos los servicios que éstos ofrecen. De este modo, en caso de detectar un activo o servicio desconocido, se debe averiguar su origen y evaluar si supone una amenaza para la organización.

Es recomendable habilitar sólo aquellos servicios que sean estrictamente necesarios para el funcionamiento de los sistemas y aplicaciones. En caso de equipamiento que esté expuesto en zonas DMZ o que deban ser accedidos desde Internet, se deben tomar medidas adicionales de protección asegurando previamente un bastionado de los equipos y limitando el acceso desde la red origen concertada.

Muchos troyanos utilizan habitualmente los mismos puertos, lo cual no significa que se tenga una infección de malware si se encuentra alguno de esos puertos abiertos, pero si ese puerto no es habitual que se use en una organización y de repente se detecta abierto nos debería generar una alerta para revisarlo cuanto antes. Una revisión periódica de los servicios ofrecidos al exterior podría ayudarnos a la hora de detectar un posible ataque, sea a través de un intento de explotación de una determinada vulnerabilidad, conexiones remotas no autorizadas, malware, exfiltración de datos o similar.

Como ya se publicó en el informe “Detección de APTs” (páginas 122 y siguientes), existen diferentes técnicas que una organización puede utilizar para llevar a cabo esa revisión periódica de servicios/puertos abiertos que se encuentren accesibles desde redes externas. Algunas de ellas son las siguientes:

  • Preprocesador para Snort: Passive Port Discovery: Es posible desarrollar un preprocesador para un IDS basado en Snort que nos permita alertarnos de nuevos equipos y nuevos servicios, tras analizar el tráfico de una red previamente conocida.
  • Monitorización de servicios sospechosos utilizando la herramienta Nessus: Como se explica en el informe “Detección de APTs” se puede configurar Nessus para que de manera diaria, semanal, mensual, etc. nos escanee nuestra red en busca solo de equipos levantados/puertos abiertos -se puede configurar para que no lance ningún plugin de forma que sea lo menos intrusivo- nos busque las diferencias entre un informe y otro y nos alerte al correo, por ejemplo. La opción de pago de Nessus permite la opción “Compare (Diff Results)” que nos compara entre dos informes de resultados y nos muestra las diferencias, sin embargo, también podemos ingeniárnoslas para comprobar la diferencia entre dos informes sin necesidad de tener la versión “pro” de esta herramienta.
  • Detección de servicios sospechosos con Nmap: Tal y como indicamos también en el informe mencionado anteriormente, también podemos ver que con Nmap y Ndiff podemos analizar de manera periódica nuestras redes y que nos alerten de posibles servicios sospechosos detectados o de servicios que inicialmente estaban disponibles pero han dejado de estar levantados.

Pero, ¿qué ocurre cuando, usando las técnicas de escaneo descritas anteriormente, somos incapaces de detectar un puerto a la escucha cuando realmente sí que lo está? Me hice esta pregunta tras leer recientemente un post en “Shell is coming…”, en el que Borja Merino publicaba una versión modificada de la bind shell “shell_bind_tcp” (incorporada en Metasploit), que él ha denominado “Hidden Bind Shell”. Dicho esto payload es una versión mejorada sobre otro payload que Borja también publicó anteriormente denominado ACL Bind Shell y que únicamente supone un incremento de unos 30 bytes.

El objetivo de la “hidden bind shell”, tal y como se describe en el blog, es crear una bind shell que responda paquetes RST ante cualquier intento de conexión originado desde una IP diferente a la embebida en el propio payload. De esta forma, cualquier herramienta que trate de escanear el equipo comprometido mostrará como CLOSED el puerto asociado al shellcode.

Para probar el funcionamiento de esta bind shell me he bajado el payload del pull request lanzado a Metasploit y me he creado una “hidden bind shell” que he denominado “backdoor_oculto.exe” y que solo será visible/accesible a través de la IP 192.168.1.2 en el puerto 1024:

Tras ello, en mi entorno de laboratorio voy a comprometer la máquina 192.168.1.46 ejecutando mi “backdoor_oculto.exe” en la misma. Si, como vemos a continuación, intento escanear vía Nmap mi máquina comprometida desde una IP diferente a la 192.168.1.2, en este caso me he puesto la IP 192.168.1.11, el resultado que me da en el puerto 1024 es que está cerrado (CLOSED). Cambiando mi IP a la del ‘atacante’ (192.168.1.2) comprobamos, tras hacer la misma operación, que en este caso el puerto 1024 aparecen como OPEN a ojos del atacante y el mismo puede obtener una shell en dicho equipo comprometido:

Un IDS bien configurado con las firmas adecuadas detectaría probablemente cuándo ha habido una conexión a esa bind shell por parte del atacante, sin embargo, no se me ocurre, utilizando las tradicionales técnicas de escaneos preventivas expuestas anteriormente (nessus, nmap, etc.) cómo detectar que ese puerto está a la escucha en mi equipo (si se os ocurre alguna por favor compartidla :) ). De hecho, he probado diversos escaneos con Nmap, con diferentes opciones de escaneo [1] y los resultados siempre han sido los mismos, como se muestra a continuación:

Una forma que podría ser viable para detectar los puertos “sospechosos” que están a la escucha sería de forma LOCAL en mis máquinas, ejecutando de manera periódica “netstat” en cada una de las máquinas de nuestra red, almacenando los resultados y comparando los mismos de un escaneo a otro para que nos alerte cuándo aparece un nuevo puerto a la escucha y que antes no lo estaba, para que podamos investigar el motivo por el que ahora se encuentra de esta forma. Este proceso puede ser muy lento si tenemos que ir equipo por equipo ejecutando netstat así que, dependiendo de la infraestructura que exista o diseño de la red podemos pensar en automatizar este proceso.

Por ejemplo, si nuestras máquinas forman parte de un Active Directory (AD) por el que podemos administrar de manera centralizada los equipos, inicios de sesión, establecer políticas a determinadas unidades organizativas (ou), grupos de usuarios, desplegar programas en muchos equipos a la vez, etc. Tal y cómo se explicó en el post “Recolección distribuida de IOCs”, podemos valernos de diversos métodos que podemos implementar con dicho AD para automatizar el proceso de ejecución de un script en varias máquinas a la vez de manera periódica. Powershell podría ayudarnos a elaborar un script de estas características, por ejemplo podríamos apoyarnos para realizarlo en la función Get-NeworkStatistics desarrollada por Shay Levi. La idea más simple por ejemplo -grosso modo- sería partir de un fichero origen en el que estuvieran todos los puertos que se supone que una determinada máquina debe tener a la escucha, ejecutar nuestro script por el que se obtengan vía netstat todos los puertos en LISTENING, y cuyo resultado sea volcado en un fichero. Este fichero se compararía con el original y en el caso de que se detecte un puerto nuevo a la escucha que nos notifique de la forma que le indiquemos. Finalmente, tras acabar el proceso de notificación, que se elimine el nuevo fichero creado. Comentar que, en caso de que aparezca un nuevo puerto cuyo estado no sea LISTENING sino que tiene establecida una conexión, no nos alertaría, pero en ese caso, si tenemos un IDS con las firmas adecuadas nos alertaría probablemente.

[1] Recordatorio:

-sS: SYN Stealth. Envía un SYN. Técnica usada por defecto. Si Closed: Recibe RST, Open: Recibe SYN/ACK, Filtered: ICMP unreachable o expira el timeout.
-sT: Connect. Envía un SYN, luego un RST para cerrar conexión. Si Closed: Recibe RST, Open: Recibe SYN/ACK, Filtered: ICMP unreachable o expira el timeout.
-sA: TCP ACK. Envía ACK vacío. Sólo determina si los puertos están o no filtrados. Si Unfiltered: Recibe RST, Filtered: ICMP error; expira el timeout.
-sN: TCP NULL. Envía TCP con todos los flags a 0. Closed: Recibe RST. Filtered: Recibe ICMP unreachable. Open|Filtered: expira el timeout.
-sF: TCP FIN. Envía TCP con el flag FIN a 1. Closed: Recibe RST. Filtered: Recibe ICMP unreachable. Open|Filtered: expira el timeout.
-sX: XMas Scan. Envía TCP con los flags FIN, PSH y URG a 1. Closed: Recibe RST. Filtered: Recibe ICMP unreachable. Open|Filtered: expira el timeout.

Comments

  1. Gracias pos la mención Maite :)
    Si observas algunos campos TCP en la respuesta RST del shellcode hay algunos valores “extraños”, por ejemplo, el tamaño de ventana. Sin embargo, las herramientas de scanning valoran los flag de la conexión para determinar el estado del socket. Ya que contesta con un RST, el puerto figurará como CLOSED.
    La solución que planteas en local puede ser una buena opción para detectarla.

    Un saludo.

  2. A ver si nos obsequias con una de tus colaboraciones, Borja :)

  3. Un equipo local que ha sido comprometido no es fiable. Por lo tanto cualquier sistema local de revisión queda completamente fuera de confianza. Una pregunta. Entiendo que si quieres sacar una bind shell hacia fuera necesitas que el firewall permita conexiones salientes. ¿No sería más inteligente detectar que puertos estaban filtrados y cuales están ahora sospechosamente cerrados? Por otra parte, interesante trabajo Borja, buen artículo Maite.

  4. Hola Mr.D,
    gracias por el comentario :) Creo que te refieres a una reverse shell en cuyo caso, tal como dices, requiere que se realice una conexión saliente bien para descargar otro stage o bien para ofrecer directamente una shell (inline). En ese caso el atacante necesitaría saber de antemano que puertos salientes no están filtrados (aunque generalmente utilizará puertos comunes como el 80 o el 443). Otra opción, si esta utilizando un exploit con dicho payload para explotar un servicio remoto, es utilizar un loader que reutilice el socket de la conexión, pero eso es otra historia :D

    En este caso, el payload es una bind shell; es decir que dejará un socket en estado LISTEN a la espera de que el atacante se conecte a el. Mientras no conecte nadie, no generará ruido en la red y por tanto no será detectado. Además, si alguien escanea la máquina para detectar puertos sospechosos, no verán el utilizado por el shellcode; algo que si ocurre con cualquier otra bind shell. De esta forma, únicamente será accesible/visible desde la IP que tu quieras; esto es lo que caracteriza a la hidden bind shell frente a la clásica bind shell.

    Inconvenientes: aparte del incremento en bytes del payload (no llega a 50), restringes la shell a una única IP tal y como haces con un reverse shell.

    Obviamente si se sospecha que el equipo puede estar comprometido su detección en local es trivial.

    En mi blog explico más en detalle su funcionamiento tanto de la acl como de la hidden bind shell:

    http://www.shelliscoming.com/2014/03/hidden-bind-shell-keep-your-shellcode.html
    http://www.shelliscoming.com/2014/02/dont-touch-my-shell-acl-bind-shellcode.html

    Un saludo.

  5. @Manuel eso está hecho :D

  6. Lo primero felicitar a Maite por el artículo y a Borja por la bind shell.

    Si tal como dice Borja las diferencias en las respuestas son muy sutiles yo le tiraría un scan de “más bajo nivel” y compararía las respuestas de las diferentes peticiones. Se me ocurre algo como hping3. ¿Que opinais?

    Saludos

  7. Que buena informacion… Excelente

  8. Muchas gracias a todos por leer el post y comentarlo!

    @Mr.D creo que Borja con su comentario ya te ha contestado. Muchas gracias a los dos por el intercambio de información. Este tipo de comentarios son los que realmente enriquecen un post.

    @neofito Gracias por la propuesta, tomo nota de estudiar el comportamiento de esta bind shell con hping3 y te comento :)

    @Andrea cadavid, muchas gracias por tu comentario y por leernos.

    Un saludo

  9. Interesante tema, siento no poder aportar ideas al respecto :)