Análisis de Transcripciones de PowerShell

Por Raido Karro y Liisa Tallinn
28 de mayo 2020

Incluso si no está utilizando PowerShell en sus máquinas Windows, sus adversarios y pen-testers sí lo están. ¿Por qué usar herramientas hax0r personalizadas cuando cada máquina Windows viene con un entorno de scripting integrado? Powershell permite al atacante hacer prácticamente cualquier cosa sin dejar rastros en los discos. Es un error no amar a PowerShell como atacante y un error no amar los registros de PowerShell como defensor.

El siguiente tutorial de análisis y consulta utiliza el analizador de registros gratuito de SpectX para obtener estadísticas generales, así como información específica de los registros de transcripción de PowerShell que son notoriamente difíciles de analizar. No es necesario importar o ingerir los archivos de su directorio de salida actual: SpectX ejecuta consultas directamente en registros sin procesar. Crear una vista limpia a partir de los registros sin procesar solo toma un par de minutos.

Hemos subido un pequeño conjunto de archivos de transcripción a nuestro repositorio público S3 – no dude en ejecutar las consultas a continuación en estos datos de ejemplo. Las preguntas que hemos hecho en las consultas están dirigidas a explorar la línea de base y detectar el comportamiento anormal (potencialmente malicioso). ¿Cuáles fueron los comandos principales ejecutados? ¿Cuándo se ejecutaron la mayoría de los comandos? ¿Cuándo corrieron por primera vez? ¿Cuáles eran las salidas de comandos que aparecían en la consola al ejecutar el comando , algo inusual? ¿Quiénes son los principales usuarios? ¿Algún usuario ejecutando comandos que no debería estar ejecutando? Principales aplicaciones de host? ¿Cuántos comandos por hora / día / semana? ¿Qué hay de las órdenes confusas? Y así sucesivamente: una vez que se familiariza con las consultas de SpectX, las preguntas de seguimiento nunca se detienen.

Contenido

Acerca de las transcripciones
Cómo activar el registro de transcripciones
Formato de los registros de transcripciones
Lectura y análisis de los registros con SpectX
¿Quién? ¿Qué? ¿Cuando? ¿Cómo? – las transcripciones de consultas

Lo saben Todo… o Casi ∞

Hay 3 tipos de registro que se pueden habilitar para PowerShell: registro de módulos, bloque de script y transcripción. Como los dos primeros se pueden ver como eventos de Windows, a menudo se recomienda leer manualmente los archivos de texto de transcripción solo cuando surja un problema al monitorear los dos primeros. Al mismo tiempo, la información contenida en las transcripciones es la más completa de las tres y los archivos de texto planos son mucho más eficientes en almacenamiento que los eventos de Windows producidos por el registro de bloques de módulos y scripts. Por ejemplo, la ejecución de un host de escritura simple ‘hola mundo’ o, en este caso, ‘Todo lo que necesita son registros’ produce 22 eventos de Windows a partir del registro de bloques de módulos y scripts, pero la misma información más la salida de comandos también se registra en esta transcripción de PowerShell de 1 KB:

**********************
Windows PowerShell transcript start
Start time: 20200521135800
Username: DESKTOP-7KL6SCQ\Loki
RunAs User: DESKTOP-7KL6SCQ\Loki
Configuration Name:
Machine: DESKTOP-7KL6SCQ (Microsoft Windows NT 10.0.18363.0)
Host Application: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
Process ID: 5624
PSVersion: 5.1.18362.752
PSEdition: Desktop
PSCompatibleVersions: 1.0, 2.0, 3.0, 4.0, 5.0, 5.1.18362.752
BuildVersion: 10.0.18362.752
CLRVersion: 4.0.30319.42000
WSManStackVersion: 3.0
PSRemotingProtocolVersion: 2.3
SerializationVersion: 1.1.0.1
**********************
**********************
Command start time: 20200521135818
**********************
PS C:\Users\Loki> write-host "All You Need is Logs"
All You Need is Logs
**********************
Command start time: 20200521135821
**********************
PS C:\Users\Loki> exit
**********************
Windows PowerShell transcript end
End time: 20200521135821
**********************

El problema es que los registros de transcripción se diseñaron históricamente con fines de depuración, es decir, para que los humanos los leyeran en lugar de las máquinas. Su contenido es casi libre y notoriamente difícil de analizar. Al indagar en la web, puede encontrar algunos intentos en la web para ingerir transcripciones en una herramienta de procesamiento de registros, pero ninguno de ellos logra extraer comandos, así como salidas de comandos en campos separados. Esto es una lástima porque las salidas de comandos solo se registran en transcripciones y la información sobre lo que realmente sucedió como resultado de los comandos PS puede ser valiosa.
Ingrese SpectX. Omitiendo la fase de ingestión y utilizando bloques de construcción en el lenguaje de análisis, puede extraer no solo los campos de usuario y host/máquina en el prólogo, sino también las horas de inicio de los comandos, los comandos y las salidas. Como el analizador de SpectX se aplica a los archivos de registro sin procesar durante el tiempo de ejecución de la consulta, también significa que puede depurar, mejorar y corregir el analizador con cada consulta en caso de que cambie el formato de registro. Y los registros de transcripción de PowerShell son, de hecho, volátiles.
Al comenzar a escribir esta publicación, creímos que las transcripciones de PowerShell son poderosas y registran todo. Sin embargo, jugando con comandos y salidas, resultó que hay una excepción. Cuando se ejecuta un script PS desde una URL, la transcripción captura el comando (incluida la URL) y la salida, pero lo deja completamente ciego con respecto al contenido del script o los comandos ejecutados por el script. Por ejemplo, para saber qué hizo este script en particular ejecutado desde una url, debe recurrir a los eventos de Windows producidos por el registro de módulos.

**********************
Windows PowerShell transcript start
Start time: 20200521141014
Username: DESKTOP-7KL6SCQ\Loki
RunAs User: DESKTOP-7KL6SCQ\Loki
Configuration Name:
Machine: DESKTOP-7KL6SCQ (Microsoft Windows NT 10.0.18363.0)
Host Application: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
Process ID: 788
PSVersion: 5.1.18362.752
PSEdition: Desktop
PSCompatibleVersions: 1.0, 2.0, 3.0, 4.0, 5.0, 5.1.18362.752
BuildVersion: 10.0.18362.752
CLRVersion: 4.0.30319.42000
WSManStackVersion: 3.0
PSRemotingProtocolVersion: 2.3
SerializationVersion: 1.1.0.1
**********************
**********************
Command start time: 20200521141021
**********************
PS C:\Users\Loki> iex (New-Object "net.webclient").DownloadString("http://spectx.com/test.ps1")
All You Need is Logs!
**********************
Command start time: 20200521141023
**********************
PS C:\Users\Loki> exit
**********************
Windows PowerShell transcript end
End time: 20200521141023
**********************

Cómo activar el registro de Transcripciones de PowerShell∞

1. Abra el menú Inicio y escriba ‘gpedit’ para abrir una ventana del Editor de Directivas de Grupo Local

2. Vaya a Administrador de Plantillas > Componentes de Windows > Windows PowerShell

3. Haga clic en «Activar transcripción de PowerShell»‘

4. Seleccione ‘Habilitado’ y especifique la ruta al directorio de salida. Importante! Marque la casilla para activar los encabezados de invocación. Esto registrará cada comando ejecutado con una hora de inicio de comando.

5. Haga clic en Aceptar
6. Abra una ventana de PowerShell para comprobar si el registro funciona. Escriba un comando, por ejemplo. un simple host de escritura: ‘todo lo que necesita son registros’ seguido de ‘salir’.

7. Compruebe si el directorio de salida que especificó en el paso 4 contiene una transcripción con las marcas de tiempo y las acciones del paso 6.

A largo plazo, es una buena idea centralizar la colección de transcripciones de PowerShell para analizarlas a escala, p. ej. consulte este tutorial de @dan_franciscus en el blog de 4sysops.

Formato de registro de transcripción ∞

Unas pocas palabras sobre el formato de registro y la lógica del analizador. Si prefiere realizar consultas y no está tan interesado en la anatomía de los archivos de registro y el analizador, vaya a la siguiente sección. Aquí hay una muestra de un registro de transcripción PS v. 5.1 en bruto:

**********************
Windows PowerShell transcript start
Start time: 20171030223248
Username: WIN-FT17VBNL4B2\Administrator
RunAs User: WIN-FT17VBNL4B2\Administrator
Machine: WIN-FT17VBNL4B2 (Microsoft Windows NT 10.0.14393.0)
Host Application: C:\Windows\system32\WindowsPowerShell\v1.0\PowerShell.exe
Process ID: 4268
PSVersion: 5.1.14393.1770
PSEdition: Desktop
PSCompatibleVersions: 1.0, 2.0, 3.0, 4.0, 5.0, 5.1.14393.1770
BuildVersion: 10.0.14393.1770
CLRVersion: 4.0.30319.42000
WSManStackVersion: 3.0
PSRemotingProtocolVersion: 2.3
SerializationVersion: 1.1.0.1
**********************
**********************
Command start time: 20171030223255
**********************
PS C:\Users\Administrator> echo test
test
**********************
Command start time: 20171030223256
**********************
PS C:\Users\Administrator> exit
**********************
Windows PowerShell transcript end
End time: 20171030223256
**********************

Se crea un archivo de transcripción con cada sesión de PowerShell. La primera sección de la transcripción es un prólogo que contiene campos específicos de la sesión, como la hora de inicio de la sesión, el usuario, la versión de PowerShell, etc. Luego, después de una línea de asteriscos, la colección de comandos y salidas se ejecuta durante esta sesión. Por último, una sección de epílogo opcional al final del archivo con la hora de finalización de la sesión, pero solo si la sesión terminó con un comando de salida (y no cerrando la ventana).

El número de comandos entre el prólogo y el epílogo varía. Esta es la razón por la que hemos adoptado un enfoque de dos pasos: primero analizar el prólogo, el epílogo y las salidas de comandos en masa; luego extraer los comandos y las salidas en campos separados en la capa de consulta.

Cómo Leer y analizar las Transcripciones ∞

SpectX lee datos directamente de archivos de registro sin procesar y los analiza en tiempo de ejecución. En el patrón, asumimos que ha activado los encabezados de invocación, es decir, que cada comando de PowerShell se registra con una hora de inicio de comando. Para ver las transcripciones como una tabla limpia:

1. Descargue e instale SpectX gratis.

2. Copie esta consulta base (Github)en la ventana de consulta

3. Modifique la ruta en la línea 47 para que coincida con el directorio de salida de sus archivos de registro de transcripción. No cambie las variables de tiempo en la ruta de acceso: esto permitirá filtrar los registros en función de las marcas de tiempo en la ruta de acceso del archivo. Por ejemplo, si la ruta de acceso a uno de sus archivos de transcripción es

C:\Logs\powershell200405\PowerShell_transcript.WS01.5OoA7WLR.20200405152828.txt

, entonces el URI de la consulta SpectX apunta a todos los archivos de registro con una ruta similar en el C:\Logs\powershell la carpeta sería:

file:/C:/Logs/powershell/$yyyy$$MM$$dd$/PowerShell_transcript.*.$yyyy$$MM$$dd$$HH$$mm$$ss$.txt

4. Cambie el número de días en el script de inicio al principio del script (líneas 2-4) si desea echar un vistazo a los registros más antiguos/nuevos.

5. Presiona correr. Los resultados deberían ser similares a este:

Que? ¿Qué? ¿Cuando? ¿Cómo? Las consultas ∞

Al hacer preguntas desde los registros, está buscando lo conocido o lo desconocido. Buscar lo conocido es fácil, solo filtra los datos que necesitas. Por ejemplo:

| filter(lower(output) CONTAINS 'error') 

le da todos los comandos que contienen la cadena ‘error’ en la salida.

Si desea observar un período de tiempo específico, modifique el bloque de inicio que contiene las marcas de tiempo al principio del script de consulta base.

Se vuelve más interesante si estás buscando lo desconocido y quieres profundizar en algo inusual. El primer paso aquí es establecer la línea de base, lo habitual y luego filtrar como algo que no le interesa. Por ejemplo, un buen truco es observar cuándo se ejecutó por primera vez un comando y luego centrarse en los comandos que se vieron por primera vez más tarde que otros (consulte la consulta de ejemplo #2 a continuación).
Copie y pegue estas consultas una por una al final de la consulta base. Haga doble clic en un registro para ver todo su contenido, haga clic con el botón derecho en un campo para aplicar filtros (negativos).

Información sobre comandos y Salidas de comandos

1. Comandos superiores

| select(cnt:count(*), command)
| group(@2)
| sort(cnt DESC)

2. ¿Cuándo fue la primera vez que se ejecutó un comando?

| select(min(commandStartTime),count(*),command,*)
| group(command)
| sort(min_commandStartTime)

3. Principales pares de comandos de salida

| select(cnt:count(*), command,output)
| group(command,output)
| sort(cnt DESC)

4. Número de órdenes por hora

| select(count(*),trunc_cmd_start:commandStartTime)
| group(trunc_cmd_start)

5. Comandos que probablemente se escribieron manualmente, es decir, comandos que comienzan con ‘ c:\\’

| select(start_time, end_time, Username, RunAs_User, Machine, PID, PSVersion, commandText)
| filter(lower(commandText) contains 'c:\')

6. Analice el campo de salida una vez más para detectar direcciones IP en texto de comandos

| select(parse("DATA* IPADDR:ip DATA*", commandText), commandText, *)
| filter_out(ip IS NULL)

7. Encuentra la cadena ‘download’ dentro de command_output incluso si está ofuscada (eliminar puntuación). Por ejemplo, si el comando invoke tiene este aspecto:

| select(deobf_commandText:lower(REPLACEALL(commandText, "" , '')) ) 
| filter(deobf_commandText contains 'download')

Estadísticas genéricas

8. ¿Cuántas sesiones de PowerShell por hora?

| select(start_time:start_time,count(*))
| group(start_time)

9. Los 100 mejores Nombres de usuario

| select(Username, cnt:count(*))
| group(@1)
| sort(cnt DESC)
| limit(100)

10. ¿Cuántos registros generó un usuario por máquina?

| select(Username,Machine,cnt:count(*))
| group(@1,@2)
| limit(100)

11. Principales aplicaciones de host: lista de aplicaciones que ejecutan PowerShell, incluidos parámetros de comandos adicionales.

| select(cnt:count(*),Host_Application)
| group(@2)
| sort(cnt DESC)
| limit(100)

12. Las 100 mejores Aplicaciones Host por Usuario

| select(Host_Application, Username, cnt:count(*))
| group(@1,@2)
| sort(cnt DESC)
| limit(100)

13. Eche un vistazo más de cerca a la puntuación en los comandos. Los comandos que son valores atípicos (el recuento es pequeño) merecen una mirada detallada.

| select(PUNCT(command, 64, false), cnt:count(*),uniq_commands:ARRAY_LEN(ARRAY_UNIQ(ARRAY_AGG(command))),commands_array:ARRAY_UNIQ(ARRAY_AGG(command)))
| group(@1)
| sort(cnt)
| limit(100)

Conclusión

Aunque los registros de transcripción de PowerShell no son fáciles de leer para las máquinas, la información que contienen es exhaustiva y vale la pena analizarla. Después de todo, PowerShell es una herramienta para automatizar y configurar casi cualquier tarea en Windows – es un anillo para gobernarlos a todos». Una buena forma de asegurarse de que el anillo no esté en las manos equivocadas o no se utilice de forma negligente es echar un vistazo a las estadísticas, los comandos y sus salidas de PowerShell.
Agradecimientos
Gracias Taavi @ Clarified Security. Las transcripciones del curso Hunt the Hacker fueron un gran punto de partida para este artículo.

Volver a los artículos

Deja una respuesta

Tu dirección de correo electrónico no será publicada.