Skip to content
KitploitKITPLOIT
HerramientasBlog
Enviar
HerramientasBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
Sentinel-Queries — Colección de consultas KQL | Kitploit
Herramientas/GitHubGitHub/reprise99/sentinel-queries
Herramientas DefensivasInteligencia de AmenazasAprendizaje y EducaciónRecursos CuradosDetección de AnomalíasAnálisis de Registros
GitHubreprise99/sentinel-queries

Sentinel-Queries

Colección de consultas KQL

Ver Repositorio
1.6k3826hace 7 mesesRevisado por Kitploit

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir

KQL para Microsoft Sentinel

Algunos consejos, trucos y ejemplos para usar KQL con Microsoft Sentinel.

  1. Introducción
  2. La anatomía de una consulta KQL
  3. Los fundamentos
    1. Fundamentos de tiempo
    2. Fundamentos de Where
    3. Fundamentos de Project
    4. Fundamentos de Summarize
    5. Fundamentos de Render
    6. Fundamentos de Parse y Split

Introducción

Kusto Query Language es el lenguaje utilizado en Azure Monitor, Azure Data Explorer y Azure Log Analytics (lo que Microsoft Sentinel utiliza internamente). Siempre he encontrado útil esta visualización sobre KQL -

KQL visualizado

Queremos usar KQL para crear consultas precisas y eficientes que permitan encontrar amenazas, detecciones, patrones y anomalías dentro de nuestro conjunto de datos más amplio.

La anatomía de una consulta KQL

Tomemos la siguiente consulta como ejemplo```kql SigninLogs | where TimeGenerated > ago(14d) | where UserPrincipalName == "[email protected]" | where ResultType == "0" | where AppDisplayName == "Microsoft Teams" | project TimeGenerated, Location, IPAddress, UserAgent

root@kitploit:~
Cuando ejecutamos una consulta como esta, la primera línea le indica a Microsoft Sentinel en qué tabla buscar los datos, así que en este caso queremos buscar en la tabla SigninLogs, que es donde se envían los datos de inicio de sesión de Azure AD. Puede ver una lista de tablas [aquí](https://docs.microsoft.com/en-us/azure/sentinel/data-source-schema-reference).

Microsoft Sentinel ejecutará la consulta de forma secuencial, por lo que procesará cada línea una por una hasta llegar al final, o hasta que haya un error. Así que vamos a desglosar nuestra consulta línea por línea.```kql
SigninLogs
Descargar herramienta

Así que primero hemos elegido nuestra tabla SigninLogs.```kql SigninLogs | where TimeGenerated > ago(14d)

root@kitploit:~
A continuación, le indicamos a Sentinel que revise los últimos 14 días de datos en esta tabla.```kql
SigninLogs
| where TimeGenerated > ago(14d)
| where UserPrincipalName == "[email protected]"

A continuación, le pedimos a Sentinel que solo busque registros donde UserPrincipalName sea igual a "[email protected]"```kql SigninLogs | where TimeGenerated > ago(14d) | where UserPrincipalName == "[email protected]" | where ResultType == "0"

root@kitploit:~
Luego buscamos solo los registros donde ResultType == 0, lo que indica un inicio de sesión exitoso en Azure AD.```kql
SigninLogs
| where TimeGenerated > ago(14d)
| where UserPrincipalName == "[email protected]"
| where ResultType == "0"
| where AppDisplayName == "Microsoft Teams"

A continuación, buscamos únicamente inicios de sesión en Microsoft Teams.```kql SigninLogs | where TimeGenerated > ago(14d) | where UserPrincipalName == "[email protected]" | where ResultType == "0" | where AppDisplayName == "Microsoft Teams" | project TimeGenerated, Location, IPAddress, UserAgent

root@kitploit:~
Nuestra última línea usa el operador `project`, para devolver solo 4 campos de nuestros registros, por lo que solo veremos `TimeGenerated`, `Location`, `IPAddress` y `UserAgent` devueltos de nuestros datos de `SigninLogs`.

Así es como se construyen las consultas, ahora los conceptos básicos.

## Los Fundamentos

### Fundamentos de Tiempo

Microsoft Sentinel y KQL están altamente optimizados para filtros de tiempo, por lo que si conoces el período de tiempo de los datos que deseas buscar, debes filtrar el rango de tiempo de inmediato. Recuperar los últimos 14 días de registros y luego buscar un nombre de usuario como la siguiente consulta -```kql
SigninLogs
| where TimeGenerated > ago(14d)
| where UserPrincipalName == "[email protected]"

Es mucho más eficiente que buscar primero un nombre de usuario y luego buscar el período de tiempo así -```kql SigninLogs | where UserPrincipalName == "[email protected]" | where TimeGenerated > ago(14d)

root@kitploit:~
KQL tiene muchas opciones para consultar períodos de tiempo específicos.```kql
SigninLogs
| where TimeGenerated > ago(14d)

Como en el primer ejemplo, esto buscará los últimos 14 días.```kql SigninLogs | where TimeGenerated > ago(14h)

root@kitploit:~
También puedes hacer horas.```kql
SigninLogs
| where TimeGenerated > ago(14m)

Y minutos.

KQL también permite realizar consultas entre rangos de tiempo -```kql SigninLogs | where TimeGenerated between (ago(14d) .. ago(7d))

root@kitploit:~
Esto encontrará datos de SigninLogs entre hace 14 días y hace 7 días.```kql
SigninLogs
| where TimeGenerated between (ago(14h) .. ago(7h))

Entre hace 14 horas y hace 7 horas.```kql SigninLogs | where TimeGenerated between (ago(14m) .. ago(7m))

root@kitploit:~
Y entre hace 14 minutos y hace 7 minutos.

### Conceptos básicos de Where

Where es un operador que usarás en prácticamente todas las consultas que escribas. Así es como le indicas a Microsoft Sentinel que busque datos específicos. La sintaxis es muy importante con el operador where. Si usamos nuestro mismo ejemplo.```kql
SigninLogs
| where TimeGenerated > ago(14d)
| where UserPrincipalName == "[email protected]"

Esto buscará en nuestra tabla SigninLogs, durante los últimos 14 días, coincidencias exactas donde nuestro UserPrincipalName sea igual a [email protected]. En KQL, == distingue entre mayúsculas y minúsculas, por lo que si buscas [email protected] y el nombre de usuario es en realidad [email protected], no obtendrás ningún resultado. El equivalente que no distingue entre mayúsculas y minúsculas es =```kql SigninLogs | where TimeGenerated > ago(14d) | where UserPrincipalName = "[email protected]"

root@kitploit:~
Esto encontrará cualquier coincidencia para [email protected] independientemente de la distinción entre mayúsculas y minúsculas.

En lugar de 'igual a', también podemos usar 'contiene'.```kql
SigninLogs
| where TimeGenerated > ago(14d)
| where UserPrincipalName contains "reprise_99"

Esto encontrará cualquier entrada de registro donde el UserPrincipalName contenga reprise_99; si tuvieras datos de [email protected] y [email protected], encontraría ambos. El operador contains no distingue entre mayúsculas y minúsculas, pero puedes usar contains_cs para que distinga entre mayúsculas y minúsculas.

Puedes usar startswith o endswith si estás buscando patrones concretos.```kql SigninLogs | where TimeGenerated > ago(14d) | where UserPrincipalName startswith "reprise_99"

SigninLogs | where TimeGenerated > ago(14d) | where UserPrincipalName endswith "testdomain.com"

root@kitploit:~
Tanto startswith como endswith no distinguen entre mayúsculas y minúsculas, pero puedes usar startswith_cs o endswith_cs para que distingan entre mayúsculas y minúsculas.

Si estás buscando palabras completas (de más de cuatro caracteres), en KQL puedes usar el operador has. Usar 'has' es más eficiente que 'contains' ya que los datos están indexados para ti.```kql
SigninLogs
| where TimeGenerated > ago(14d)
| where AppDisplayName has "Teams"

Esto encontrará cualquier SigninLogs donde el nombre para mostrar de la aplicación contenga la palabra Teams, lo que podría incluir "Microsoft Teams" y "Microsoft Teams Web Client", ambos satisfacen la consulta.

Si buscas varias palabras, puedes usar has_any o has_all.```kql SigninLogs | where TimeGenerated > ago(14d) | where AppDisplayName has_any ("Teams","Outlook")

root@kitploit:~
Esto devolverá resultados donde el nombre para mostrar de la aplicación contenga \"Teams\" o \"Outlook\"```kql
SigninLogs
| where TimeGenerated > ago(14d)
| where AppDisplayName has_all ("Teams","Outlook")

Esto devolverá resultados donde el nombre para mostrar de la aplicación tenga "Teams" y "Outlook".

Si no sabes en qué campos buscar, también puedes usar comodines; es ineficiente, pero puede ponerte en el camino correcto para encontrar lo que deseas.```kql SigninLogs | where TimeGenerated > ago(14d) | where * contains "reprise_99"

root@kitploit:~
Esto buscará en la tabla SigninLogs cualquier campo que contenga reprise_99.

Varias de estas opciones también admiten el uso de ! para invertir la consulta y encontrar resultados donde no sea verdad.```kql
SigninLogs
| where TimeGenerated > ago(14d)
| where UserPrincipalName != "[email protected]"

Esta consulta encontraría todos los SigninLogs donde el UserPrincipalName no sea igual a [email protected]```kql SigninLogs | where TimeGenerated > ago(14d) | where UserPrincipalName !contains "reprise_99"

root@kitploit:~
Esta consulta encontraría todos los SigninLogs donde el UserPrincipalName no contenga reprise_99```kql
SigninLogs
| where TimeGenerated > ago(14d)
| where AppDisplayName !has "Teams"

Esta consulta encontraría SigninLogs donde el nombre para mostrar de la aplicación no contenga "Teams".

Conceptos básicos de Project

Project nos permite seleccionar qué columnas se devuelven en nuestra consulta y en qué orden.```kql SigninLogs | where TimeGenerated > ago(14d) | where UserPrincipalName == "[email protected]" | where ResultType == "0" | where AppDisplayName == "Microsoft Teams" | project TimeGenerated, Location, IPAddress, UserAgent

root@kitploit:~
Esta consulta busca datos de SigninLogs de los últimos 14 días, donde el UserPrincipalname sea igual a [email protected], donde el ResultType sea 0, donde el nombre para mostrar de la aplicación sea igual a "Microsoft Teams", y para cada coincidencia de esa consulta devuelve el TimeGenerated, la Location, la IPAddress y el UserAgent.

Podemos renombrar columnas como parte de la misma función.```kql
| project LogTime=TimeGenerated, SigninLocation=Location, IP=IPAddress, Agent=UserAgent

Esto devuelve los mismos datos, pero renombra las columnas a LogTime, SigninLocation, IP y Agent.

Incluso podemos manipular la salida en línea con el operador project.```kql | project LocalTime=TimeGenerated+5h, Location, IPAddress, UserAgent

root@kitploit:~
Esto devuelve los mismos datos, pero cambia el nombre de TimeGenerated a LocalTime y convierte a una zona horaria de +5h si trabajas en esa zona horaria.

project-away es lo opuesto a project y eliminará columnas de tu consulta.```kql
SigninLogs
| where TimeGenerated > ago(14d)
| project-away UserAgent
| where UserPrincipalName == "[email protected]"
| where ResultType == "0"
| where AppDisplayName == "Microsoft Teams"

En esta consulta eliminamos UserAgent. Recuerda, si eliminas una columna, ya no podrás acceder a ella más adelante en tu consulta.

Conceptos básicos de Summarize

Summarize produce una tabla que agrega el contenido de tu consulta. Summarize tiene una serie de funciones de agregación subyacentes. Si tomamos de nuevo nuestra consulta de ejemplo, podemos manipular los resultados de varias formas usando summarize.```kql SigninLogs | where TimeGenerated > ago(14d) | where UserPrincipalName == "[email protected]" | where ResultType == "0" | summarize count() by AppDisplayName

root@kitploit:~
Esta consulta buscará en la tabla SigninLogs cualquier evento de los últimos 14 días, con coincidencias para [email protected], donde el resultado sea un éxito (ResultType == 0) y luego resumirá esos eventos por el nombre para mostrar de la aplicación.

Opcionalmente, puede asignar un nombre a la columna de resultados.```kql
SigninLogs
| where TimeGenerated > ago(14d)
| where UserPrincipalName == "[email protected]"
| where ResultType == "0"
| summarize AppCount=count() by AppDisplayName

Esto devuelve los mismos datos pero actualiza el nombre de la columna devuelta a AppCount.

En lugar de un recuento total, puedes resumir un recuento distinto.```kql SigninLogs | where TimeGenerated > ago(14d) | where UserPrincipalName == "[email protected]" | where ResultType == "0" | summarize DistinctAppCount=dcount(AppDisplayName) by AppDisplayName

root@kitploit:~
Esto devolverá un único registro por cada aplicación distinta en la que [email protected] haya iniciado sesión.

Puedes usar las funciones arg_max y arg_min para devolver el registro más nuevo o el más antiguo que coincida con tu consulta.```kql
SigninLogs
| where TimeGenerated > ago(14d)
| where UserPrincipalName == "[email protected]"
| where ResultType == "0"
| summarize arg_max(TimeGenerated, *) by UserPrincipalName

Esta consulta busca todos los registros de inicio de sesión de los últimos 14 días que tengan [email protected] como UserPrincipalname, que hayan sido exitosos y luego devuelve el registro más reciente.```kql SigninLogs | where TimeGenerated > ago(14d) | where UserPrincipalName == "[email protected]" | where ResultType == "0" | summarize arg_min(TimeGenerated, *) by UserPrincipalName

root@kitploit:~
Esto es lo mismo, pero devuelve el registro más antiguo.

Puedes usar countif para proporcionar lógica a tus sumas.```kql
SigninLogs
| where TimeGenerated > ago(14d)
| where UserPrincipalName == "[email protected]"
| where ResultType == "0"
| summarize TeamsLogons=countif(AppDisplayName has "Teams"), SharePointLogons=countif(AppDisplayName has "SharePoint")

Esto resume los datos en dos nuevas columnas, TeamsLogons donde el nombre para mostrar de la aplicación tiene "Teams" y SharePointLogons donde el nombre para mostrar de la aplicación tiene "SharePoint"

Puedes manipular aún más tus datos indicando a KQL que coloque tus datos en 'bins' de tiempo.```kql SigninLogs | where TimeGenerated > ago(14d) | where UserPrincipalName == "[email protected]" | where ResultType == "0" | summarize AppCount=count() by AppDisplayName, bin(TimeGenerated, 1d)

root@kitploit:~
Esto devuelve los mismos datos que nuestro primer ejemplo de resumen y luego agrupa esos datos en contenedores de 1d.

Puedes combinar estas funciones cuando sea útil.```kql
SigninLogs
| where TimeGenerated > ago(14d)
| where UserPrincipalName == "[email protected]"
| where ResultType == "0"
| summarize TeamsLogons=countif(AppDisplayName has "Teams"), SharePointLogons=countif(AppDisplayName has "SharePoint") by bin(TimeGenerated, 1d)

Esta es una combinación de nuestras funciones countif y bin, donde resumimos según el nombre para mostrar de nuestra aplicación y también colocamos los resultados en bins 1d.

Puedes crear un conjunto de elementos dentro de una consulta.```kql SigninLogs | where TimeGenerated > ago(14d) | where UserPrincipalName == "[email protected]" | where ResultType == "0" | summarize AppList=make_set(AppDisplayName) by UserPrincipalName

root@kitploit:~
Esto generará una lista de aplicaciones en las que [email protected] ha iniciado sesión, en una lista llamada AppList.

Puedes combinar esto con nuestro time bin.```kql
SigninLogs
| where TimeGenerated > ago(14d)
| where UserPrincipalName == "[email protected]"
| where ResultType == "0"
| summarize AppList=make_set(AppDisplayName) by UserPrincipalName, bin(TimeGenerated, 1d)

Esto hará una lista de aplicaciones en las que [email protected] ha iniciado sesión, separadas en una lista por día.

Conceptos básicos de Render

El operador render permite a KQL visualizar datos en diferentes formatos, como gráficos circulares, gráficos de tiempo o de área, y gráficos de columnas y de barras.

Si usamos nuestro mismo ejemplo de la tabla Signinlogs, podemos ver cómo podemos visualizar los datos de diversas maneras.```kql SigninLogs | where TimeGenerated > ago(14d) | where UserPrincipalName == "[email protected]" | where ResultType == "0" | summarize AppCount=count()by AppDisplayName | render piechart

root@kitploit:~
Esta consulta resume todas las aplicaciones a las que [email protected] ha iniciado sesión en los últimos 14 días y luego renderiza el resultado como un gráfico circular.

![KQL Gráfico circular](https://raw.githubusercontent.com/reprise99/Sentinel-Queries/main/Diagrams/render-piechart.png?raw=true)

También puedes renderizarlo como un gráfico de columnas.```kql
SigninLogs
| where TimeGenerated > ago(14d)
| where UserPrincipalName == "[email protected]"
| where ResultType == "0"
| summarize AppCount=count()by AppDisplayName
| render columnchart

Gráfico de columnas KQL

O un gráfico de barras.```kql SigninLogs | where TimeGenerated > ago(14d) | where UserPrincipalName == "[email protected]" | where ResultType == "0" | summarize AppCount=count()by AppDisplayName | render barchart

root@kitploit:~
![KQL Gráfico de Barras](https://raw.githubusercontent.com/reprise99/Sentinel-Queries/main/Diagrams/render-barchart.png?raw=true)

Para datos de tiempo, primero resume tus datos en 'bins' de tiempo como se indica en la sección summarize, y luego puedes visualizar tus datos a lo largo de un período de tiempo.```kql
SigninLogs
| where TimeGenerated > ago(14d)
| where UserPrincipalName == "[email protected]"
| where ResultType == "0"
| summarize SigninCount=count() by bin(TimeGenerated, 1d)
| render timechart

Esto visualiza todos los inicios de sesión de [email protected] por día durante los últimos 14 días y lo muestra como un timechart.

KQL Timechart

También puedes usar render como un areachart.```kql SigninLogs | where TimeGenerated > ago(14d) | where UserPrincipalName == "[email protected]" | where ResultType == "0" | summarize SigninCount=count() by bin(TimeGenerated, 1d) | render areachart

root@kitploit:~
![KQL Areachart](https://raw.githubusercontent.com/reprise99/Sentinel-Queries/main/Diagrams/render-areachart.png?raw=true)

Los gráficos de columnas y de barras también se pueden usar con datos de tiempo. Obtendrás una columna o barra por 'bin' de tiempo a lo largo de tu período de tiempo más amplio.```kql
SigninLogs
| where TimeGenerated > ago(14d)
| where UserPrincipalName == "[email protected]"
| where ResultType == "0"
| summarize SigninCount=count() by bin(TimeGenerated, 1d)
| render columnchart

Esta es la misma consulta que nuestro timechart, pero representada como un gráfico de columnas con una columna por día.

Gráfico de columnas de tiempo KQL```kql SigninLogs | where TimeGenerated > ago(14d) | where UserPrincipalName == "[email protected]" | where ResultType == "0" | summarize SigninCount=count() by bin(TimeGenerated, 1d) | render barchart

root@kitploit:~
Y un gráfico de barras.

![Gráfico de barras de tiempo KQL](https://raw.githubusercontent.com/reprise99/Sentinel-Queries/main/Diagrams/render-timebarchart.png?raw=true)

Con los gráficos de columnas o de barras puedes tenerlos apilados (que es lo predeterminado).```kql
SigninLogs
| where TimeGenerated > ago(14d)
| where UserPrincipalName == "[email protected]"
| where ResultType == "0"
| summarize SigninCount=count() by AppDisplayName, bin(TimeGenerated, 1d)
| render columnchart

Esta consulta busca todos los inicios de sesión de nuestra cuenta, cuenta los inicios de sesión por aplicación y luego crea una sola columna para cada día.

KQL Time Column Chart Stacked

Si quieres que cada aplicación tenga su propia columna, puedes configurarla para que no esté apilada.```kql SigninLogs | where TimeGenerated > ago(14d) | where UserPrincipalName == "[email protected]" | where ResultType == "0" | summarize SigninCount=count() by bin(TimeGenerated, 1d) | render columnchart with (kind=unstacked)

root@kitploit:~
![Gráfico de columnas de tiempo KQL sin apilar](https://raw.githubusercontent.com/reprise99/Sentinel-Queries/main/Diagrams/render-timecolumnchartunstacked.png?raw=true)

También puedes renombrar el eje y el título de tu gráfico de acuerdo con KQL.```kql
SigninLogs
| where TimeGenerated > ago(14d)
| where UserPrincipalName == "[email protected]"
| where ResultType == "0"
| summarize SigninCount=count() by AppDisplayName, bin(TimeGenerated, 1d)
| render columnchart with (kind=unstacked, ytitle="Total Sign Ins", xtitle="Day", title="Application Signins Per Day")

KQL Time Column Chart Unstacked Renamed

Puedes combinar lógica en tus acciones de summarize para crear contenido dinámico para tu operador de render.```kql SigninLogs | where TimeGenerated > ago(14d) | where ResultType == "0" | summarize TeamsCount=countif(AppDisplayName has "Teams"), OneDrive=countif(AppDisplayName has "OneDrive"), SharePointCount=countif(AppDisplayName has "SharePoint") by bin(TimeGenerated, 1d) | render columnchart with (kind=unstacked, ytitle="Sign In Count", xtitle="Day", title="Teams vs OneDrive vs SharePoint Sign Ins Per Day")

root@kitploit:~
Esta consulta busca todos los inicios de sesión en su inquilino y luego cuenta tres grupos: uno donde el nombre para mostrar de la aplicación contiene "Teams", otro donde el nombre para mostrar de la aplicación contiene "OneDrive" y otro donde el nombre para mostrar de la aplicación contiene "SharePoint" para cada día de los últimos 14 días, y luego se muestra como un gráfico de columnas no apiladas.

![KQL Time Column Chart Outlook, OneDrive, SharePoint](https://raw.githubusercontent.com/reprise99/Sentinel-Queries/main/Diagrams/render-timecolumn-outlookonedrivesharepoint.png?raw=true)

### Conceptos básicos de Parse y Split

Parse y split son dos formas diferentes de extender una cadena de datos a varias columnas según las coincidencias. Muchos registros ingeridos en Microsoft Sentinel pueden venir como una sola cadena larga (como sysmon); parse y split le permiten manipularlos para convertirlos en datos legibles.

Para estos ejemplos, utilizaremos los siguientes datos de prueba```kql
let ExampleText = datatable(TestData:string)
[
'Name=Reprise99,UPNSuffix=testdomain.com,AadTenantId=345c1234-a833-43e4-1d34-123440a5bcdd1,AadUserId=cf6f2df6-b754-48dc-b7bc-c8339caf211,DisplayName=Test User,Type=account'
];

This data is just a single string that looks like this.

Parse

Podemos extraer coincidencias de datos específicas con lo siguiente.```kql let ExampleText = datatable(TestData:string) [ 'Name=Reprise99,UPNSuffix=testdomain.com,AadTenantId=345c1234-a833-43e4-1d34-123440a5bcdd1,AadUserId=cf6f2df6-b754-48dc-b7bc-c8339caf211,DisplayName=Test User,Type=account' ]; ExampleText | parse TestData with * 'Name=' DisplayName ',' * | project DisplayName

root@kitploit:~
Esto analizará todos los datos entre Name= y , en una nueva columna llamada 'DisplayName'.

![Parse 1](https://raw.githubusercontent.com/reprise99/Sentinel-Queries/main/Diagrams/parse1.png?raw=true)

Puedes extraer varias columnas dentro del mismo comando haciendo coincidencias a lo largo de la cadena.```kql
let ExampleText = datatable(TestData:string)
[
'Name=Reprise99,UPNSuffix=testdomain.com,AadTenantId=345c1234-a833-43e4-1d34-123440a5bcdd1,AadUserId=cf6f2df6-b754-48dc-b7bc-c8339caf211,DisplayName=Test User,Type=account'
];
ExampleText
| parse TestData with * 'Name=' DisplayName ',UPNSuffix=' DomainSuffix ',AadTenantId=' AzureADTenantId ',' *
| project DisplayName, DomainSuffix, AzureADTenantId

Esto analiza tres nuevas columnas - DisplayName, DomainSuffix y AzureADTenantId

Parse 2

Recordando que KQL ejecuta sus operaciones secuencialmente, una vez que analizamos, podemos analizar de nuevo sobre la columna recién creada.```kql let ExampleText = datatable(TestData:string) [ 'Name=Reprise99,UPNSuffix=testdomain.com,AadTenantId=345c1234-a833-43e4-1d34-123440a5bcdd1,AadUserId=cf6f2df6-b754-48dc-b7bc-c8339caf211,DisplayName=Test User,Type=account', ]; ExampleText | parse TestData with * 'Name=' DisplayName ',UPNSuffix=' DomainSuffix ',AadTenantId=' AzureADTenantId ',' * | project DisplayName, DomainSuffix, AzureADTenantId | parse DomainSuffix with * '.' TopLevelDomain | project DisplayName, DomainSuffix, TopLevelDomain, AzureADTenantId

root@kitploit:~
Esto analiza aún más nuestro dominio para encontrar el dominio de nivel superior, en este caso un .com

![Parse 3](https://raw.githubusercontent.com/reprise99/Sentinel-Queries/main/Diagrams/parse3.png?raw=true)

Al usar el operador parse, KQL recorrerá todas tus filas de datos y devolverá incluso resultados donde no haya coincidencia. Así que dependiendo de la estructura de tus datos, podrías terminar con muchas filas de datos vacíos. Si ampliamos nuestros datos de ejemplo para incluir otra fila de datos, con nombres diferentes, y ejecutamos la misma consulta, verás resultados vacíos.```kql
let ExampleText = datatable(TestData:string)
[
'Name=Reprise99,UPNSuffix=testdomain.com,AadTenantId=345c1234-a833-43e4-1d34-123440a5bcdd1,AadUserId=cf6f2df6-b754-48dc-b7bc-c8339caf211,DisplayName=Test User,Type=account',
'Display=Reprise99,UPN=testdomain.com,AadDirectoryId=345c1234-a833-43e4-1d34-123440a5bcdd1,AadObjectId=cf6f2df6-b754-48dc-b7bc-c8339caf211,Name=Test User,AccountType=account'
]
;
ExampleText
| parse TestData with * 'Name=' DisplayName ',UPNSuffix=' DomainSuffix ',AadTenantId=' AzureADTenantId ',' *
| project DisplayName, DomainSuffix, AzureADTenantId
| parse DomainSuffix with * '.' TopLevelDomain
| project DisplayName, DomainSuffix, TopLevelDomain, AzureADTenantId

Parse 4

Para combatir esto, puedes usar el operador 'parse-where', que solo devuelve resultados cuando hay coincidencias con tu consulta.```kql let ExampleText = datatable(TestData:string) [ 'Name=Reprise99,UPNSuffix=testdomain.com,AadTenantId=345c1234-a833-43e4-1d34-123440a5bcdd1,AadUserId=cf6f2df6-b754-48dc-b7bc-c8339caf211,DisplayName=Test User,Type=account', 'Display=Reprise99,UPN=testdomain.com,AadDirectoryId=345c1234-a833-43e4-1d34-123440a5bcdd1,AadObjectId=cf6f2df6-b754-48dc-b7bc-c8339caf211,Name=Test User,AccountType=account' ] ; ExampleText | parse-where TestData with * 'Name=' DisplayName ',UPNSuffix=' DomainSuffix ',AadTenantId=' AzureADTenantId ',' * | project DisplayName, DomainSuffix, AzureADTenantId | parse DomainSuffix with * '.' TopLevelDomain | project DisplayName, DomainSuffix, TopLevelDomain, AzureADTenantId

root@kitploit:~
Podemos ver que hemos vuelto a un único resultado donde tuvimos una coincidencia en nuestro análisis.

![Parse 5](https://raw.githubusercontent.com/reprise99/Sentinel-Queries/main/Diagrams/parse5.png?raw=true)

Split separa una cadena de texto en un array basándose en un delimitador. Si volvemos a nuestros datos de prueba originales, podemos separar basándonos en el signo de coma.```kql
let ExampleText = datatable(TestData:string)
[
'Name=Reprise99,UPNSuffix=testdomain.com,AadTenantId=345c1234-a833-43e4-1d34-123440a5bcdd1,AadUserId=cf6f2df6-b754-48dc-b7bc-c8339caf211,DisplayName=Test User,Type=account',
]
;
ExampleText
| extend SplitData = split(TestData,',')
| project SplitData

Se nos devolverá un array con nuestra cadena dividida.

Split 1

Split es consciente de los índices, por lo que si tus datos están en el mismo orden, puedes dividir directamente en nuevas columnas.```kql let ExampleText = datatable(TestData:string) [ 'Name=Reprise99,UPNSuffix=testdomain.com,AadTenantId=345c1234-a833-43e4-1d34-123440a5bcdd1,AadUserId=cf6f2df6-b754-48dc-b7bc-c8339caf211,DisplayName=Test User,Type=account', ] ; ExampleText | extend Name = split(TestData,',')[0] | extend DomainSuffix = split(TestData,',')[1] | extend AzureADTenantId = split(TestData,',')[2] | extend AzureADUserId = split(TestData,',')[3] | extend DisplayName = split(TestData,',')[4] | extend AccountType = split(TestData,',')[5] | project Name, DomainSuffix, AzureADTenantId, AzureADUserId, DisplayName, AccountType

root@kitploit:~
Si conocemos la ubicación de nuestros datos dentro de la cadena, podemos dividirla directamente en columnas con nombre.

![Split 2](https://raw.githubusercontent.com/reprise99/Sentinel-Queries/main/Diagrams/split2.png?raw=true)

Una vez que hemos dividido nuestros datos, podemos consultarlos como si hubieran sido estructurados desde el principio. Entonces, si agregamos un segundo registro a nuestros datos y consultamos coincidencias específicas, encontraremos lo que buscamos.```kql
let ExampleText = datatable(TestData:string)
[
'Name=Reprise99,UPNSuffix=testdomain.com,AadTenantId=345c1234-a833-43e4-1d34-123440a5bcdd1,AadUserId=cf6f2df6-b754-48dc-b7bc-c8339caf211,DisplayName=Test User,Type=account',
'Name=Reprise103,UPNSuffix=testdomain.com,AadTenantId=331c1234-a841-43e5-1d31-12220a5bcee1,AadUserId=cf6f2df6-b754-48dc-b7bc-c8339caf211,DisplayName=Test User 2,Type=account'
]
;
ExampleText
| extend Name = split(TestData,',')[0]
| extend DomainSuffix = split(TestData,',')[1]
| extend AzureADTenantId = split(TestData,',')[2]
| extend AzureADUserId = split(TestData,',')[3]
| extend DisplayName = split(TestData,',')[4]
| extend AccountType = split(TestData,',')[5]
| project Name, DomainSuffix, AzureADTenantId, AzureADUserId, DisplayName, AccountType
| where Name contains "Reprise99"

Obtenemos solo una coincidencia, donde Name contiene "Reprise99"; nuestro segundo registro, donde Name contiene "Reprise103", no se encuentra.

Split 3