Recopilatorio de trucos en NTFS para pentesters

En un artículo impresionante René Freingruber (@ReneFreingruber) de SEC Consult Vulnerability Lab nos hablaba de diferentes técnicas o trucos sobre el sistema de archivos NTFS en Windows que fueron recopilados durante años. Algunas de las técnicas enumeradas ya fueron documentadas por James Forshaw (@tiraniddo) y Alex Inführ (@insertScript). No os los perdáis porque son muy interesantes y pueden resultar tremendamente útiles:

1.- Crear directorios sin tener permisos (CVE-2018-1036/NTFS EoP)

En Windows se pueden asignar "permisos especiales" a directorios para que un usuario pueda crear archivos dentro, pero no subdirectorios.
Un ejemplo es la carpeta C:\Windows\Tasks\:


Además, es posible que un administrador o un programa configure dichos permisos y asuma que los usuarios realmente no pueden crear carpetas en él.

Sin embargo, esta ACL puede saltarse fácilmente en el momento en que un usuario pueda crear archivos. Solo hay que agregar "::$INDEX_ALLOCATION" al final de un nombre de archivo y se creará una carpeta en lugar de un archivo:


Como podéis ver se pudo crear un directorio y el usuario puede crear archivos o carpetas arbitrariamente en este directorio (lo que puede derivar en escalada de privilegios si un administrador o programa supone que no es posible debido a los permisos que faltan).

También, el truco ::$INDEX_ALLOCATION se puede usar para eliminar directorios si una aplicación solo permite eliminar archivos.

2.- Evadir las restricciones de rutas con ADS (Alternate Data Streams)

Quizás te preguntes por qué funcionó la técnica anterior. Básicamente, los archivos en un volumen NTFS se almacenan de la siguiente forma:

<filename>:<stream-name>:<type>

Si creamos un archivo llamado test.txt, se almacenará internamente como test.txt ::$DATA porque el nombre del stream está vacío y $DATA es el tipo predeterminado. El primer truco abusa del hecho de que el tipo de stream puede cambiarse a INDEX_ALLOCATION que corresponde a un directorio y, por lo tanto, crea un directorio.


Pero también es posible almacenar datos en un stream diferente (ADS). Si escribimos, por ejemplo, "test.txt", escribimos en realidad "test.txt::$DATA" (el nombre del stream está vacío). Sin embargo, también podemos escribir "test.txt:foo" o "test.txt:foo:$DATA" (ambos son iguales porque $DATA es el tipo predeterminado).

Existen diferentes nombres de stream, por ejemplo, para almacenar el origen de un archivo. Si descargas un archivo de Internet (o lo recibe por correo electrónico), Windows agrega silenciosamente un identificador de zona a través de un nombre de stream (para mostrar luego un cuadro de diálogo de advertencia adicional si desea ejecutarlo). Por ejemplo, si descargamos "putty.exe", Windows también crea "putty.exe:Zone.Identifier:$DATA". Estos nombres de streams se pueden hacer visibles a través del parámetro /r con el comando dir: 


Como se puede observar, el identificador de zona no se puede leer a través del comando type (con el comando more funcionaría) y también es importante omitir el tipo $DATA si leemos el archivo con el bloc de notas. El mensaje importante es que podemos almacenar datos en un ADS (¡incluidas las aplicaciones!). Por ejemplo, putty puede copiarse a un ADS y luego ejecutarse a través de wmic (directamente no es posible).
 


Nota: tened en cuenta que Microsoft Windows Defender se actualizó para detectar las llamadas a procesos con WMIC.

¿Quizás te preguntes por qué alguien haría esto? En primer lugar, ADS se puede utilizar para ocultar datos (el comando dir sin el modificador /r no los mostrará; explorer.exe tampoco los mostrará; más adelante veremos cómo podemos ocultarlos incluso del dir /r ...) . Sin embargo, ADS tiene otra gran propiedad: se puede agregar un ADS a una carpeta. Para poder hacer esto, debemos tener los permisos de "crear carpetas" en el directorio (y el nombre de la carpeta no debe ser un número). El hecho importante es que un ADS en una carpeta ¡se parece a un archivo de la carpeta principal!

Por ejemplo, en Windows, un usuario normal no puede crear archivos en C:\Windows\ (solo los administradores pueden escribir en esta carpeta). Por lo tanto, es posible que las aplicaciones supongan que los archivos en C:\Windows\ pueden ser confiables porque solo los administradores pueden crear dichos archivos. Sin embargo, C: \Windows\Tracing es una carpeta en la que los usuarios normales pueden crear archivos y carpetas: un usuario normal puede, por lo tanto, crear un ADS en esta carpeta.

Digamos que el usuario escribe en el archivo C:\Windows\Tracing:test.dll. Si esta ruta ahora se pasa a una API de Windows que calcula la carpeta base, esta API se iniciará al final de la ruta y retrocederá hasta que se encuentre la primera "\". Luego, todo lo que quede de "\" se devolverá como la carpeta base. Para C:\Windows\Tracing:test.dll esto devolverá C:\Windows\ como carpeta base, sin embargo, como ya se mencionó, un usuario normal no puede crear archivos en esta carpeta, pero utilizando este truco creamos un archivo que parece que está almacenado en C:\Windows ;)

Aquí está el resultado de las diferentes funciones de Windows que calculan la carpeta base (podemos ver que siempre es C:\windows):
 

Este comportamiento se puede utilizar para eludir algunas soluciones de listas blancas de aplicaciones pero también puede eludir las comprobaciones de seguridad en diversas situaciones donde el programador supone que es suficiente comprobar si un archivo está almacenado en una carpeta base específica porque supone que solo los administradores pueden escribir en esta carpeta por la ACL.

Otro hecho interesante es que los nombres de ADS pueden contener símbolos que normalmente están prohibidos para nombres de archivos como " o * (es decir, si quieres crear estos archivos tienes que usar la API nativa de Windows; cmd.exe filtra los caracteres de estos archivos):


3.- Crear archivos que no se pueden encontrar usando la carpeta "..."

Cada carpeta contiene por defecto dos entradas especiales: el directorio "." que se refiere al directorio actual y ".." que se refiere al directorio padre. En Windows no es posible crear archivos/carpetas con solo puntos en el nombre, más que nada para evitar ataques que confunden a los parsers.


La captura de pantalla anterior muestra que no es posible crear una carpeta "..." o "...". Sin embargo, se puede evitar con el truco ::$INDEX_ALLOCATION:


La carpeta "..." se creó con el truco mencionado anteriormente, sin embargo, dichas carpetas también se pueden crear pasando el nombre dos veces como se muestra también en el ejemplo "...." (mkdir "....\....\" crea el directorio "....", pero también un directorio "...." en él. Sin embargo, si ejecutamos mkdir "....\Xyz\" no funciona.).

Usando el segundo truco también se pueden crear estas carpetas, almacenar archivos allí o incluso ejecutar programas desde esa ubicación:
 

Como se puede ver, no se puede entrar a la carpeta solo con el nombre (por ej.: "cd ..." o "cd ...\" o "cd ...\..." no funciona), así que se tiene que usar la sintaxis "cd ...\...\". Después de eso podemos crear archivos en esta carpeta. (Nota interesante: si ejecutas "cd ." en esa carpeta, subirás un directorio, porque la ruta está "confundida").

Además, tampoco es posible abrir este directorio desde el explorer. Se pueden dar dos casos: a veces al hacer doble clic en dicha carpeta no tiene impacto (se permanece en el directorio actual y la ruta sigue igual), en otros casos se queda en la carpeta pero la ruta en el explorador cambia. Por ejemplo, después de "abrir" la carpeta 17 veces, se ve así (observa los "..." directorios en la ruta):


Se puede intentar entrar a la carpeta tantas veces como desee, no se verán los archivos en la carpeta en el explorer. Tampoco es posible abrir la carpeta pasando "C:\test\...\...\" en el cuadro de la ruta en la imagen de arriba.

Nota: si se intenta eliminar esta carpeta desde el explorer.exe se bloqueará; se verá un cuadro de diálogo donde Windows está contando los archivos en la carpeta y donde cuenta "una gran cantidad de archivos". Luego la búsqueda de archivos en esta carpeta a través del explorer tampoco funciona, por ejemplo, si buscas el archivo "123.txt" con el explorer, se bloqueará / buscará para siempre, sin encontrar realmente los archivos.

Ten en cuenta que la búsqueda mediante la consola si funciona sin problemas:


Sin embargo, si usamos Powershell se quedará "atrapado" en un bucle:

 
La salida se trunca porque el comando imprimirá los dos directorios para siempre ...).

Una búsqueda de "123.txt" (Por ej.: con "Get-ChildItem -Path C:\test -Filter 123.txt -Recurse -ErrorAction SilentlyContinue -Force") nunca encontrará el archivo (y nunca terminará).

También se probó ésto con diferentes productos AntiVirus y la mayoría parecía funcionar correctamente (colocó muestras de malware en este directorio y las soluciones antivirus probadas las encontraron). Algunos quedaban "confundidos" por ejemplo, cuando buscaban virus dentro de "C:\prueba\...\" buscaban en "C:\prueba\". También el código python con os.walk () parece funcionar correctamente.

Tener en cuenta que la creación de un junction de un directorio que apunta a su propia carpeta principal no conduce a un bucle infinito en cmd o Powershell.

4.- "Ocultar" el destino de una unión o junction de directorio

Las uniones o junctions de directorios son una característica NTFS muy útil para encontrar vulnerabilidades de seguridad. Utilizándolo, se puede crear (con privilegios de usuario normales) un enlace simbólico a una carpeta de destino.

La mejor vulnerabilidad de seguridad para explicar las uniones de directorios es, en mi opinión, AVGater, donde el atacante coloca un archivo en la carpeta x. Luego marca el archivo como un virus y la solución AntiVirus instalada lo moverá a la cuarentena. Después de eso, el atacante elimina la carpeta x y la reemplaza con un junction de directorio llamada "x" que apunta a C:\windows\System32\. Si el atacante ahora hace clic en el botón "restaurar", la solución AntiVirus copiará el archivo en la carpeta x que ahora apunta a system32 con privilegios de SYSTEM (lo que conduce directamente a una elevación de privilegios).

A menudo se puede abusar de las uniones de directorio si la aplicación específica contiene vulnerabilidades de condición de carrera (vulnerabilidades de TOCTOU - hora de comprobación de uso).

Se puede crear una unión de directorio con la utilidad mklink y el parámetro /J. Es posible combinar esto con el truco ::$INDEX_ALLOCATION para crear una unión de directorio con el nombre "...":


La primera unión de directorio "test1" se creó con un nombre normal y, por lo tanto, el destino se muestra correctamente en la salida "dir". Sin embargo, en el caso de la unión de directorio "...", el objetivo ya no se muestra (en cambio se muestra, ver el recuadro rojo). Tened en cuenta también que se puede dejar que junction1 apunte a junction2 que a su vez apunte a junction3 y así sucesivamente hasta que el último apunte al destino real.

Debido a que las rutas son confusas, se puede entrar con el truco "cd ...\...\" mencionado anteriormente (para estar en la carpeta system32), pero "." Apuntará a "C:\pruebas1" en su lugar:


Como veis, el comando dir muestra los archivos desde la carpeta system32. Pero sin embargo también se puede ejecutar "hola.bat" desde el directorio actual (".\").


Dado que las rutas son confusas, esto ejecutará C:\pruebas1\hola.bat y no C:\windows\system32\hola.bat. Esto podría usarse para eludir las soluciones de listas blancas de algunas aplicaciones.

5.- Ocultar ADS

Como ya se habló, es posible ver ADS a través del modificador /r en el comando dir. Además, streams.exe es una herramienta de Sysinternals que también puede mostrarlos:


En versiones anteriores de Windows, era posible ocultar ADS utilizando nombres reservados como CON, NUL, COM1, COM2, LPT1, .... Sin embargo, en Windows 10 ya no es posible, pero "..." todavía funciona:


El ADS en "..." se crea con éxito, pero no se muestra con las anteriores herramientas. Al crear un ADS en COM1 se produce un error, la creación de un ADS en NUL no tiene ningún efecto (no se crearán ADS).

Tened en cuenta que también se puede crear un ADS en el disco con "echo 123> C:\:abc.txt". Esto se ocultará del comando "dir /r" dentro de C:\. Sin embargo, mostrará los ADS dentro de las subcarpetas de C: \ para el directorio "..". Por ejemplo:


El ADS marcado en rojo fue creado por el comando C:\:abc.txt ADS. Este ADS también es visible a través de la herramienta streams.exe de Sysinternals si se llama directamente a C:\. Por lo tanto, para esconderse de ambas herramientas, se debe usar el truco "...".

Existe un segundo truco que puede usarse para ocultarte también de las herramientas. En Windows se puede agregar ". Espacios." al final de un archivo y Windows lo eliminará automáticamente (la canonización lo elimina).


Sin embargo, podemos crear dicho archivo con un ADS. La característica graciosa de un archivo de este tipo es que las herramientas no podrán abrirlo porque una ruta como "xyz". ."Se cambiará automáticamente a " xyz " y este archivo no existe.

Aquí está la prueba:


El ADS foobar.txt creado no puede ser encontrado por las herramientas:



nota 1: Estos archivos también se pueden crear a través de:  echo test > “test. .::$DATA”

nota 2: ten en cuenta que los ADS  "..: abc.txt" son los ADS que se crearon en "C: \: abc.txt".

También podemos crear un directorio con el nombre ". ." como se muestra a continuación:


Entonces no es posible entrar a esa carpeta:


Además, la técnica ya mencionada (como cd . .\. .\ no funciona), pero cd ". . ::$ INDEX_ALLOCATION" si funciona (las comillas dobles son importantes).

Si podemos agregar espacios entre un nombre de directorio, también podemos agregarlo al final como  "b " o ".. " o ". ".


Explicación: Hay una "b" y una carpeta "b", un archivo llamado "a" y un archivo llamado "a", los dos directorios predeterminados "." y ".." más el ". " y " .. " y el directorio ". .".

Se puede entrar a los directorios con el nombre "..." con la técnica comentada anteriormente:


Nota 1: esta carpeta se puede abrir a través del explorer si hace clic dos veces en la carpeta, también el contenido de la carpeta se mostrará correctamente. Sin embargo, los archivos en él no se pueden abrir debido a ruta incorrecta (explorer.exe usa C:\test22\..\..\123.txt en lugar de C:\test22\..\ 123.txt). Powershell volverá a quedarse pillado en un bucle al buscar dichas carpetas.

Nota 2: también se puede crear un ADS en una carpeta con un nombre como "abc". Luego se puede cambiar el nombre de la carpeta a un nombre que solo contenga números (por ejemplo, "1"). Después de eso, aún se pueden ver los ADS, pero no se pueden abrir (un ADS en un directorio con un número ya que el nombre no funciona). Para abrir los datos de ADS, primero se debe cambiar el nombre de la carpeta a, por ejemplo, "abc".

Trucos del sistema de archivos vs. productos AntiVirus / software forense:

Se hizo una verificación rápida de los trucos mencionados anteriormente contra los productos AntiVirus para verificar si estos pueden detectar malware que abusa de estos trucos. El hallazgo más notable fue con archivos/carpetas que terminan con ". .". Por ejemplo, se guardó el virus de prueba eicar en una carpeta y se copió con los siguientes comandos:

copy eicar.com > "123. .::$DATA"
copy eicar.com > tester
echo 123 > "foo. .::INDEX_ALLOCATION"
cd "foo. .::$INDEX_ALLOCATION"
copy ..\eicar.com .
copy ..\eicar.com .\eicar

Después de eso, se volvieron a habilitar las soluciones de Antivirus y se escaneó la carpeta. Todas las soluciones de Antivirus identificaron "eicar.com" y "tester" en esa carpeta, pero no el virus de eicar en "123". ." o en los dos archivos en la carpeta " foo. .". Sin embargo, cuando se entra a esa carpeta y se ejecutan los archivos, los productos AntiVirus los identifican (porque el contenido se carga desde el sistema de archivos a la memoria).

La acción "eliminar" de Windows Defender no pudo eliminar los archivos y, por lo tanto, no tuvo ningún impacto, sin embargo, la acción "eliminar" de, por ejemplo, Emsisoft podía eliminar el virus de prueba en la carpeta. Emsisoft eliminó el archivo "eicar.com" en "foo. .". El archivo" eicar "no se eliminó y el contenido se puede leer sin problemas (Emsisoft les respondió que solo se escanean los archivos que se asignan como ejecutables, con la excepción de algunas extensiones de archivo específicas como .com. Este comportamiento puede modificarse en la configuración del protector de archivos cambiando a "Completo" para también escanear en los archivos leídos, Windows Defender por otro lado también bloqueó la lectura del archivo de texto "eicar").

También se realizó una breve prueba corta contra Autopsy 4.6.0 (un software forense gratuito) cargando "archivos lógicos" en la herramienta (desde el sistema en ejecución, no desde una imagen de disco). Se podía entrar en la carpeta "..." pero no en "foo. .". Además, se creó un archivo llamado "valid" con el contenido "valid" y un archivo llamado "valid. ." con el contenido "secret". Autopsy muestra para ambos archivos el contenido "valid" (y nunca el contenido "secret"). Además de eso, la carpeta ".. " (con un espacio al final) se interpreta como ".." y, por lo tanto, sube un directorio con un doble clic. Esto solo se aplica al modo "archivos lógicos", en el modo de imagen de disco (en raw) todo se muestra correctamente (en el modo directo, Autopsy usa la API de Windows para acceder a los datos y, por lo tanto, se producen problemas).

6.- Ocultar el binario del proceso

Como ya se discutió anteriormente: Windows elimina automáticamente ". ." al final de un archivo. ¿Qué pasa si de alguna manera podemos comenzar un proceso con un nombre como "file1. ."? Bueno, entonces puede suceder que las comprobaciones (por ejemplo, comprobaciones de firmas de productos AntiVirus) se realicen en "file1". Intentemos esto:


Creamos 3 archivos:

- "file" con la firma de Microsoft de taskmgr
- "file. ." que es nuestro" malware falso que debe ocultarse pero ejecutarse
- "filex x" que contiene la firma de WinSCP. Este archivo se volverá importante más adelante.

Ahora necesitamos una forma de comenzar un proceso desde el binario "file. .". lo cual no es una tarea trivial porque todas las llamadas al API de Microsoft Windows eliminan automáticamente el". ." del nombre del archivo y empezaría por "file" (taskmgr) en su lugar. Para lidiar con este problema usamos el siguiente código:


El código anterior solo llama a CreateProcessA para crear un proceso desde "filex x" (WinSCP). Si compilamos esta aplicación y la iniciamos, se iniciará WinSCP. Sin embargo, no vamos a comenzarlo normalmente. En cambio, iniciamos la aplicación dentro de un depurador (por ejemplo, WinDbg). Ahora establecemos un punto de interrupción en la función que hace que la llamada al sistema asociado: "bp ntdll! NtCreateUserProcess". Con "g" (ir) podemos iniciar nuestro programa en el depurador y llegar al punto de interrupción. En el punto de interrupción, la pila actual se puede descargar ("dq rsp"). El 12º puntero en la pila es importante y debe ser dumpeado. El 4to valor en esta dirección es el puntero a nuestro nombre de archivo.


El nombre de archivo (cuadro verde) ahora está normalizado (comienza con \??\C:\...). Exactamente esta normalización también habría eliminado el ". ." desde el final del nombre de archivo - es por eso que el código C anterior no usó" archivo ". ." como nombre del proceso. Sin embargo, dado que ya se ha normalizado, este valor ahora puede modificarse. Vamos a sobrescribir los caracteres "x" con "." (Comando "eb" para editar bytes):


Después de eso simplemente continuamos la ejecución con "g". ¿Adivinas que pasará?

Correcto, "file. ." (el malware) se ejecuta. Sin embargo, si un usuario hace clic derecho en el proceso en el administrador de tareas y selecciona "propiedades", se mostrarán las propiedades de "archivo" (taskmgr) con la firma válida de Microsoft.



Pero, ¿qué pasa con "filex x" (WinSCP)? Sí, este archivo también se muestra como el proceso en ejecución, es decir, en el explorador de procesos (porque la ruta se estableció antes de llamar a NtCreateUserProcess):


¿Y qué pasa con Powershell? Sí, también el binario incorrecto:


¿Es esto un problema? Bueno, eso depende. En primer lugar, un atacante puede iniciar un proceso (el malware), renombrarlo / eliminarlo luego y luego renombrar un archivo válido con el mismo nombre. Entonces también se producirán los efectos anteriores en el administrador de tareas y el explorador de procesos. Sin embargo, la diferencia es que con el truco mencionado anteriormente, esto ocurre exactamente al mismo tiempo cuando se inicia el proceso.

Por ejemplo, considerar que la protección instalada en el endpoint comprueba cada proceso iniciado si el hash del binario ya se conoce en la nube. Con este truco, la protección del endpoint puede usar el binario incorrecto para verificar si el hash ya es conocido. Tened en cuenta también que no se requiere un debugger para crear dichos procesos. Una aplicación puede conectar la función NtCreateUserProcess e implementar las modificaciones en el hook.

Trucos del CMD de Windows

Estos trucos no tienen nada que ver con los trucos del sistema de archivos, sin embargo, encajan bien en esta entrada. En el cmd de Windows, es posible escribir ^ en cualquier ubicación del comando y el cmd lo ignorará por completo. Por ejemplo, "calc.exe" es lo mismo que "ca^l^c". Es importante que ^ no sea el último símbolo y que dos ^ símbolos no se utilicen uno después del otro. En lugar de ^ también se puede usar la comilla doble, que no tiene restricciones (puede ser el último carácter o usarse varias veces). Por ejemplo, ^ca^"^"^lc^" levantará la calculadora.

Lo mismo se aplica a las variables de entorno de longitud cero. Se puede acceder a una variable de entorno a través %name%. Si la variable de entorno tiene una longitud cero, "cal%name%c" sería lo mismo que "calc". Como las variables de entorno no tienen una longitud predeterminada de cero, esto no se puede usar directamente. Sin embargo, es posible llamar a subcadena en la variable de entorno con una sintaxis especial (:~start,end). La siguiente imagen muestra la variable de entorno "windir" y cómo la subcadena se puede usar con valores negativos para obtener una variable de longitud cero:


La siguiente imagen muestra una combinación de estas técnicas para ocultar que Powershell se inició en versión 2 (lo que fue útil durante mucho tiempo pero que ya no se debe hacer en la versión más reciente de Windows 10):


Ya habéis visto el uso de ^ y el truco de la variable de entorno (%os:~0,-56%), pero también se puede usar "00000000002.0000" (en lugar de solo 2) como versión y el argumento "?ver" y no "-ver" (tened en cuenta que este no es un símbolo ? normal, es U+2015; usando solo ? no funcionaría).

En Windows "/" también se puede usar en rutas en lugar de "\". Por ejemplo, C:\Windows/\//\system32\calc.exe es lo mismo que C:\Windows\system32\calc.exe. Además, también se puede acceder al binario a través de la ruta UNC para evitar el "C:\" con el patrón "\\127.0.0.1\C$\windows\system32\calc.exe".

También se pueden utilizar distintos trucos para evadir los distintos enfoques de lista negra (por ejemplo, si powershell.exe está prohibido un atacante puede llamar a power^shell.exe para eludir la restricción. O bien, si está prohibido, puede ejecutar:

^”%Localappdata:~-3%^%SystemRoot:~0,1%^”

para iniciar calc.exe y así sucesivamente).

Referencias:

Comentarios