Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Obtenga resultados más rápido y evite tiempos de espera al ejecutar consultas complejas mediante la optimización de las consultas. Para obtener instrucciones sobre cómo mejorar el rendimiento de las consultas:
- Sugerencias generales de optimización : en este artículo
-
Optimización del
joinoperador : en este artículo -
Optimización del
summarizeoperador : en este artículo - Escenarios de consulta : en este artículo
- Procedimientos recomendados de consulta de Kusto : incluye varios escenarios para que la consulta sea más eficaz
- Optimización de consultas de registro en Azure Monitor: contiene instrucciones adicionales para la optimización de consultas
- Optimización de consultas KQL (vídeo): formas más comunes de mejorar la consulta
Descripción de las cuotas de recursos de CPU
En función de su tamaño, cada inquilino tiene acceso a una cantidad establecida de recursos de CPU asignados para ejecutar consultas de búsqueda avanzadas. Para obtener información detallada sobre varios parámetros de uso, lea sobre las cuotas de búsqueda avanzadas y los parámetros de uso.
Después de ejecutar la consulta, puede ver el tiempo de ejecución y su uso de recursos (Bajo, Medio, Alto). High indica que la consulta tardó más recursos en ejecutarse y se pudo mejorar para devolver resultados de forma más eficaz.
Los clientes que ejecutan varias consultas con regularidad deben realizar un seguimiento del consumo y aplicar las instrucciones de optimización de este artículo para minimizar la interrupción resultante de superar las cuotas o los parámetros de uso.
Sugerencias generales de optimización
Ajustar el tamaño de las nuevas consultas: si sospecha que una consulta devolverá un conjunto de resultados grande, evaluela primero con el operador count. Use limit o su sinónimo
takepara evitar conjuntos de resultados grandes.Aplicar filtros al principio: aplique filtros de tiempo y otros filtros para reducir el conjunto de datos, especialmente antes de usar funciones de transformación y análisis, como substring(), replace(), trim(), toupper()o parse_json(). En el ejemplo siguiente, la función de análisis extractjson() se usa después de que los operadores de filtrado hayan reducido el número de registros.
DeviceEvents | where Timestamp > ago(1d) | where ActionType == "UsbDriveMount" | where DeviceName == "user-desktop.domain.com" | extend DriveLetter = extractjson("$.DriveLetter", AdditionalFields)Contiene latidos: para evitar buscar subcadenas en palabras innecesariamente, use el
hasoperador en lugar decontains. Más información sobre los operadores de cadenaBuscar en columnas específicas: busque en una columna específica en lugar de ejecutar búsquedas de texto completo en todas las columnas. No use
*para comprobar todas las columnas.Distingue mayúsculas de minúsculas para la velocidad: las búsquedas que distinguen mayúsculas de minúsculas son más específicas y, por lo general, tienen un mayor rendimiento. Los nombres de operadores de cadena que distinguen mayúsculas de minúsculas, como
has_csycontains_cs, suelen terminar con_cs. También puede usar el operador==equals que distingue mayúsculas de minúsculas en lugar de=~.Analizar, no extraer: siempre que sea posible, use el operador de análisis o una función de análisis como parse_json(). Evite el
matches regexoperador de cadena o la función extract(), que usan la expresión regular. Reserve el uso de la expresión regular para escenarios más complejos. Obtenga más información sobre el análisis de funcionesFiltrar tablas no expresiones: no filtre por una columna calculada si puede filtrar por una columna de tabla.
Sin términos de tres caracteres: evite comparar o filtrar mediante términos con tres caracteres o menos. Estos términos no se indexan y la coincidencia con ellos requerirá más recursos.
Proyecto de forma selectiva: haga que los resultados sean más fáciles de entender proyectando solo las columnas que necesita. La proyección de columnas específicas antes de ejecutar operaciones de combinación o similares también ayuda a mejorar el rendimiento.
Optimización del join operador
El operador join combina filas de dos tablas mediante la coincidencia de valores en columnas especificadas. Aplique estas sugerencias para optimizar las consultas que usan este operador.
Tabla más pequeña a la izquierda: el
joinoperador coincide con los registros de la tabla del lado izquierdo de la instrucción join con los registros de la derecha. Al tener la tabla más pequeña a la izquierda, será necesario buscar menos registros, lo que acelerará la consulta.En la tabla siguiente, se reduce la tabla
DeviceLogonEventsizquierda para cubrir solo tres dispositivos específicos antes de combinarla conIdentityLogonEventslos SID de cuenta.DeviceLogonEvents | where DeviceName in ("device-1.domain.com", "device-2.domain.com", "device-3.domain.com") | where ActionType == "LogonFailed" | join (IdentityLogonEvents | where ActionType == "LogonFailed" | where Protocol == "Kerberos") on AccountSidUsar el sabor de combinación interna: el sabor de combinación predeterminado o innerunique-join desduplica las filas de la tabla izquierda por la clave de combinación antes de devolver una fila para cada coincidencia a la tabla derecha. Si la tabla izquierda tiene varias filas con el mismo valor para la
joinclave, esas filas se desduplicarán para dejar una sola fila aleatoria para cada valor único.Este comportamiento predeterminado puede dejar fuera información importante de la tabla izquierda que puede proporcionar información útil. Por ejemplo, la consulta siguiente solo mostrará un correo electrónico que contenga datos adjuntos determinados, incluso si esos mismos datos adjuntos se enviaron mediante varios mensajes de correo electrónico:
EmailAttachmentInfo | where Timestamp > ago(1h) | where Subject == "Document Attachment" and FileName == "Document.pdf" | join (DeviceFileEvents | where Timestamp > ago(1h)) on SHA256Para abordar esta limitación, aplicamos el tipo de combinación interna especificando
kind=innerpara mostrar todas las filas de la tabla izquierda con valores coincidentes a la derecha:EmailAttachmentInfo | where Timestamp > ago(1h) | where Subject == "Document Attachment" and FileName == "Document.pdf" | join kind=inner (DeviceFileEvents | where Timestamp > ago(1h)) on SHA256Combinar registros desde un período de tiempo: al investigar eventos de seguridad, los analistas buscan eventos relacionados que se produzcan alrededor del mismo período de tiempo. La aplicación del mismo enfoque cuando se usa
jointambién beneficia al rendimiento al reducir el número de registros que se van a comprobar.La consulta siguiente comprueba si hay eventos de inicio de sesión en un plazo de 30 minutos después de recibir un archivo malintencionado:
EmailEvents | where Timestamp > ago(7d) | where ThreatTypes has "Malware" | project EmailReceivedTime = Timestamp, Subject, SenderFromAddress, AccountName = tostring(split(RecipientEmailAddress, "@")[0]) | join ( DeviceLogonEvents | where Timestamp > ago(7d) | project LogonTime = Timestamp, AccountName, DeviceName ) on AccountName | where (LogonTime - EmailReceivedTime) between (0min .. 30min)Aplicar filtros de tiempo en ambos lados: incluso si no está investigando un período de tiempo específico, la aplicación de filtros de tiempo en las tablas izquierda y derecha puede reducir el número de registros para comprobar y mejorar
joinel rendimiento. La consulta siguiente se aplicaTimestamp > ago(1h)a ambas tablas para que se una solo a los registros de la última hora:EmailAttachmentInfo | where Timestamp > ago(1h) | where Subject == "Document Attachment" and FileName == "Document.pdf" | join kind=inner (DeviceFileEvents | where Timestamp > ago(1h)) on SHA256Usar sugerencias para el rendimiento: use sugerencias con el
joinoperador para indicar al back-end que distribuya la carga al ejecutar operaciones que consumen muchos recursos. Obtenga más información sobre las sugerencias de combinación.Por ejemplo, la sugerencia de orden aleatorio ayuda a mejorar el rendimiento de las consultas al combinar tablas mediante una clave con una cardinalidad alta (una clave con muchos valores únicos), como en la
AccountObjectIdconsulta siguiente:IdentityInfo | where JobTitle == "CONSULTANT" | join hint.shufflekey = AccountObjectId (IdentityDirectoryEvents | where Application == "Active Directory" | where ActionType == "Private data retrieval") on AccountObjectIdLa sugerencia de difusión ayuda cuando la tabla izquierda es pequeña (hasta 100 000 registros) y la tabla derecha es extremadamente grande. Por ejemplo, la consulta siguiente está intentando unirse a algunos correos electrónicos que tienen asuntos específicos con todos los mensajes que contienen vínculos en la
EmailUrlInfotabla:EmailEvents | where Subject in ("Warning: Update your credentials now", "Action required: Update your credentials now") | join hint.strategy = broadcast EmailUrlInfo on NetworkMessageId
Optimización del summarize operador
El operador summarize agrega el contenido de una tabla. Aplique estas sugerencias para optimizar las consultas que usan este operador.
Buscar valores distintos: en general, use
summarizepara buscar valores distintos que puedan ser repetitivos. Puede ser innecesario usarlo para agregar columnas que no tienen valores repetitivos.Aunque un único correo electrónico puede formar parte de varios eventos, el ejemplo siguiente no es un uso eficaz de porque un identificador de mensaje de
summarizered para un correo electrónico individual siempre viene con una dirección de remitente única.EmailEvents | where Timestamp > ago(1h) | summarize by NetworkMessageId, SenderFromAddressEl
summarizeoperador se puede reemplazar fácilmente porproject, lo que produce potencialmente los mismos resultados y consume menos recursos:EmailEvents | where Timestamp > ago(1h) | project NetworkMessageId, SenderFromAddressEl ejemplo siguiente es un uso más eficaz de
summarizeporque puede haber varias instancias distintas de una dirección de remitente que envía correo electrónico a la misma dirección de destinatario. Estas combinaciones son menos distintas y es probable que tengan duplicados.EmailEvents | where Timestamp > ago(1h) | summarize by SenderFromAddress, RecipientEmailAddressOrden aleatorio de la consulta: aunque
summarizese usa mejor en columnas con valores repetitivos, las mismas columnas también pueden tener una cardinalidad alta o un gran número de valores únicos. Al igual que eljoinoperador , también puede aplicar la sugerencia de orden aleatorio consummarizepara distribuir la carga de procesamiento y potencialmente mejorar el rendimiento cuando se trabaja en columnas con alta cardinalidad.La consulta siguiente usa
summarizepara contar una dirección de correo electrónico de destinatario distinta, que se puede ejecutar en los cientos de miles de organizaciones grandes. Para mejorar el rendimiento, incorporahint.shufflekey:EmailEvents | where Timestamp > ago(1h) | summarize hint.shufflekey = RecipientEmailAddress count() by Subject, RecipientEmailAddress
Escenarios de consulta
Identificación de procesos únicos con identificadores de proceso
Los Id. de proceso (PID) se reciclan en Windows y se reutilizan para los nuevos procesos. Por sí solos, no pueden servir como identificadores únicos para procesos específicos.
Normalmente, la única manera de identificar de forma única un proceso en un dispositivo específico era combinar su identificador de proceso con su tiempo de creación del proceso, junto con el identificador de dispositivo (o DeviceIdDeviceName). Por ejemplo, la consulta de ejemplo siguiente busca procesos que acceden a más de 10 direcciones IP a través del puerto 445 (SMB), posiblemente buscando recursos compartidos de archivos.
DeviceNetworkEvents
| where RemotePort == 445 and Timestamp > ago(12h) and InitiatingProcessId !in (0, 4)
| summarize RemoteIPCount=dcount(RemoteIP) by DeviceName, InitiatingProcessId, InitiatingProcessCreationTime, InitiatingProcessFileName
| where RemoteIPCount > 10
La consulta anterior resume por y InitiatingProcessIdInitiatingProcessCreationTime para que examine un único proceso, sin mezclar varios procesos con el mismo identificador de proceso.
Este enfoque sigue siendo válido, especialmente para sistemas que no son de Windows. Sin embargo, en Windows, hay un método más directo mediante el ProcessUniqueId campo . Aunque tanto el método anterior como el descrito a continuación producen instancias de proceso únicas, como procedimiento recomendado se recomienda usar ProcessUniqueId cuando esté disponible, ya que simplifica las consultas y elimina la necesidad de controlar escenarios de reutilización de PID.
Esta consulta muestra cómo usar los ProcessUniqueId campos y InitiatingProcessUniqueId para vincular un proceso primario específico a sus procesos secundarios. Al hacer coincidir los elementos secundarios InitiatingProcessUniqueId con los del elemento primario ProcessUniqueId, aísla solo los procesos secundarios iniciados por esa instancia primaria exacta, incluso si los identificadores de proceso se reutilizan con el tiempo.
Consulta de ejemplo:
// Step 1: Select a specific parent process instance (for instance, powershell.exe).
let parentProcess =
DeviceProcessEvents
| where FileName =~ "powershell.exe" // For your specific use case, consider modifying the FileName and adding more identifying properties to specify your query.
| where isnotempty(ProcessUniqueId)
| top 1 by Timestamp asc
| project DeviceId, DeviceName, ParentProcessUniqueId = ProcessUniqueId, ParentFileName = FileName;
// Step 2: Find all child processes started by this unique parent.
DeviceProcessEvents
| where isnotempty(InitiatingProcessUniqueId)
| join kind=inner (
parentProcess
) on DeviceId
| where InitiatingProcessUniqueId == ParentProcessUniqueId
| project
DeviceName,
ParentProcessUniqueId,
ParentFileName,
ChildProcessName = FileName,
ChildProcessId = ProcessId,
ChildProcessUniqueId = ProcessUniqueId,
Timestamp
Del mismo modo, la consulta resume por y InitiatingProcessIdInitiatingProcessCreationTime para que examine un único proceso, sin mezclar varios procesos con el mismo identificador de proceso.
Líneas de comandos de consulta
Hay varias formas de crear una línea de comandos para llevar a cabo una tarea. Por ejemplo, un atacante podría hacer referencia a un archivo de imagen sin una ruta de acceso, sin una extensión de archivo, usando variables de entorno o entre comillas. El atacante también podría cambiar el orden de los parámetros o agregar varias comillas y espacios.
Para crear consultas más duraderas en torno a las líneas de comandos, aplique las siguientes prácticas:
- Identifique los procesos conocidos (como net.exe o psexec.exe) mediante la coincidencia en los campos de nombre de archivo, en lugar de filtrar en la propia línea de comandos.
- Análisis de secciones de línea de comandos mediante la función parse_command_line()
- Al consultar argumentos de la línea de comandos, no busque una coincidencia exacta en varios argumentos no relacionados en un orden determinado. En su lugar, use expresiones regulares o use operadores de contenedores separados múltiples.
- Use coincidencias que no distinga mayúsculas de minúsculas. Por ejemplo, use
=~,in~ycontainsen lugar de==,inycontains_cs. - Para mitigar las técnicas de ofuscación de línea de comandos, considere la posibilidad de quitar comillas, reemplazar comas por espacios y reemplazar varios espacios consecutivos por un solo espacio. Hay técnicas de ofuscación más complejas que requieren otros enfoques, pero estos ajustes pueden ayudar a abordar los más comunes.
En los ejemplos siguientes se muestran varias maneras de construir una consulta que busca el archivo net.exe para detener el servicio de firewall "MpsSvc":
// Non-durable query - do not use
DeviceProcessEvents
| where ProcessCommandLine == "net stop MpsSvc"
| limit 10
// Better query - filters on file name, does case-insensitive matches
DeviceProcessEvents
| where Timestamp > ago(7d) and FileName in~ ("net.exe", "net1.exe") and ProcessCommandLine contains "stop" and ProcessCommandLine contains "MpsSvc"
// Best query also ignores quotes
DeviceProcessEvents
| where Timestamp > ago(7d) and FileName in~ ("net.exe", "net1.exe")
| extend CanonicalCommandLine=replace("\"", "", ProcessCommandLine)
| where CanonicalCommandLine contains "stop" and CanonicalCommandLine contains "MpsSvc"
Ingesta de datos de orígenes externos
Para incorporar listas largas o tablas grandes en la consulta, use el operador externaldata para ingerir datos de un URI especificado. Puede obtener datos de archivos en TXT, CSV, JSON u otros formatos. En el ejemplo siguiente se muestra cómo puede usar la amplia lista de hashes SHA-256 de malware proporcionados por MalwareBazaar (abuse.ch) para comprobar los datos adjuntos en los correos electrónicos:
let abuse_sha256 = (externaldata(sha256_hash: string)
[@"https://bazaar.abuse.ch/export/txt/sha256/recent/"]
with (format="txt"))
| where sha256_hash !startswith "#"
| project sha256_hash;
abuse_sha256
| join (EmailAttachmentInfo
| where Timestamp > ago(1d)
) on $left.sha256_hash == $right.SHA256
| project Timestamp,SenderFromAddress,RecipientEmailAddress,FileName,FileType,
SHA256,ThreatTypes,DetectionMethods
Análisis de cadenas
Hay varias funciones que puede usar para controlar de forma eficaz las cadenas que necesitan análisis o conversión.
| Cadena | Función | Ejemplo de uso |
|---|---|---|
| Líneas de comandos | parse_command_line() | Extraiga el comando y todos los argumentos. |
| Paths | parse_path() | Extraiga las secciones de una ruta de acceso de archivo o carpeta. |
| Números de versión | parse_version() | Deconstruye un número de versión con hasta cuatro secciones y hasta ocho caracteres por sección. Use los datos analizados para comparar la antigüedad de la versión. |
| Direcciones IPv4 | parse_ipv4() | Convierta una dirección IPv4 en un entero largo. Para comparar direcciones IPv4 sin convertirlos, use ipv4_compare(). |
| Direcciones IPv6 | parse_ipv6() | Convierta una dirección IPv4 o IPv6 en la notación IPv6 canónica. Para comparar direcciones IPv6, use ipv6_compare(). |
Para obtener información sobre todas las funciones de análisis admitidas, lea acerca de las funciones de cadena de Kusto.
Nota:
Es posible que algunas tablas de este artículo no estén disponibles en Microsoft Defender para punto de conexión. Active Microsoft Defender XDR para buscar amenazas mediante más orígenes de datos. Puede mover los flujos de trabajo de búsqueda avanzados de Microsoft Defender para punto de conexión a Microsoft Defender XDR siguiendo los pasos descritos en Migración de consultas de búsqueda avanzadas desde Microsoft Defender para punto de conexión.
Temas relacionados
- Documentación del lenguaje de consulta de Kusto
- Parámetros de uso y cuotas
- Controlar errores de búsqueda avanzados
- Información general sobre la búsqueda avanzada de amenazas
- Aprender el lenguaje de consulta
Sugerencia
¿Desea obtener más información? Participe con la comunidad de Seguridad de Microsoft en nuestra Tech Community: Tech Community de Microsoft Defender XDR.