🔒 Registro cerrado · Apertura oficial próximamente · Acceso exclusivo para alumnos activos
Iniciar SesiónUnir inicios de sesión con cambios con join
5 tareas · 42 min · Principiante
Un cambio sospechoso casi nunca se entiende solo. Para saber si una persona que cambió un rol en el directorio entró de forma normal hay que cruzar el cambio (AuditLogs) con el inicio de sesión (SigninLogs), y para saber qué más hizo desde esa dirección hay que cruzar con AzureActivity. `join` une dos tablas por una clave. En la Clínica Veterinaria Mastranto, el 9 de marzo, un cambio de rol de madrugada lleva a un cruce con un inicio de sesión desde otro país. Aprendes qué clave elegir, por qué el tipo de join cambia el resultado y qué significa que una operación no tenga inicio de sesión. Todo es lectura del extracto, en UTC.
Objetivo de la sala
Un cambio sospechoso casi nunca se entiende solo. Para saber si una persona que cambió un rol en el directorio entró de forma normal hay que cruzar el cambio (AuditLogs) con el inicio de sesión (SigninLogs), y para saber qué más hizo desde esa dirección hay que cruzar con AzureActivity. `join` une dos tablas por una clave. En la Clínica Veterinaria Mastranto, el 9 de marzo, un cambio de rol de madrugada lleva a un cruce con un inicio de sesión desde otro país. Aprendes qué clave elegir, por qué el tipo de join cambia el resultado y qué significa que una operación no tenga inicio de sesión. Todo es lectura del extracto, en UTC.En AuditLogs, quién hizo el cambio está en InitiatedBy, una columna dynamic que guarda un objeto: {"user":{"userPrincipalName":"...","ipAddress":"..."}}. Para compararla con otra tabla hay que sacar los campos: InitiatedBy.user.userPrincipalName entra al objeto con puntos y tostring(...) lo convierte en texto, que es lo que join necesita para comparar. extend Actor = tostring(InitiatedBy.user.userPrincipalName) crea una columna con la cuenta.
Prueba la consulta que filtra OperationName == "Add member to role" (agregar a alguien a un rol) y deja la hora, la operación, la cuenta y la dirección. Es la mitad izquierda del cruce.
Responde para continuar
¿Desde qué dirección IP se hizo el cambio de membresía de rol del día?
Ver pista de ayuda
Escribe `AuditLogs | where OperationName == "Add member to role" | extend Actor = tostring(InitiatedBy.user.userPrincipalName), IP = tostring(InitiatedBy.user.ipAddress) | project TimeGenerated, OperationName, Actor, IP`.
join une las filas de dos tablas que comparten un valor, la clave. Se escribe join kind=inner (tabla2) on $left.ColumnaA == $right.ColumnaB, donde $left es la tabla que viene de la izquierda del join y $right la del paréntesis. Para unir por más de una columna se separan las condiciones con and.
Si no escribes kind=, KQL usa por defecto innerunique: antes de unir, deduplica la tabla izquierda por la clave, y solo queda una fila por cada valor distinto. Con kind=inner se conservan todas las filas que tienen pareja. Compara dos consultas que cuentan las operaciones hechas desde la dirección que inició sesión desde otro país. Sin kind=: AzureActivity | join (SigninLogs | where ResultType == "0" and Location != "CO" | project IPAddress, Location) on $left.CallerIpAddress == $right.IPAddress | count. Con kind=inner: la misma, escribiendo join kind=inner ( en lugar de join (.
Responde para continuar
Una consulta con join sin `kind=` devuelve una fila y la misma con `kind=inner` devuelve cuatro. ¿Qué explica la diferencia?
Ver pista de ayuda
Sin kind=, el sabor es innerunique: «inner con deduplicación de la tabla izquierda».
Unir solo por la cuenta trae todos los inicios de sesión de esa cuenta durante el día, no el que corresponde al cambio. En el extracto la cuenta tiene tres entradas correctas; unir por cuenta devuelve tres filas para un solo cambio y obliga a adivinar cuál era. Con la cuenta y la dirección como clave (on $left.Actor == $right.UserPrincipalName and $left.IP == $right.IPAddress) la unión señala la entrada que corresponde.
Una clave de unión demasiado floja produce filas de más que parecen evidencia y no lo son. Una clave demasiado estricta pierde las coincidencias. La lectura honesta dice con qué claves se unió y qué no prueba esa unión.
Responde para continuar
Al unir el cambio de rol con el inicio de sesión por cuenta y dirección, ¿qué código de país (Location) tiene esa entrada?
Ver pista de ayuda
Escribe `AuditLogs | where OperationName == "Add member to role" | extend Actor = tostring(InitiatedBy.user.userPrincipalName), IP = tostring(InitiatedBy.user.ipAddress) | join kind=inner (SigninLogs | where ResultType == "0" | project UserPrincipalName, IPAddress, SigninTime = TimeGenerated, Location) on $left.Actor == $right.UserPrincipalName and $left.IP == $right.IPAddress | project TimeGenerated, OperationName, Actor, IP, SigninTime, Location`.
kind=leftanti devuelve las filas de la tabla izquierda que NO tienen pareja en la derecha, y solo con las columnas de la izquierda. Aplicado a AzureActivity contra los inicios de sesión correctos, por dirección, muestra operaciones de gestión hechas desde direcciones sin ninguna entrada correcta registrada en SigninLogs.
Que una operación no tenga inicio de sesión en esa tabla no significa que sea ilegítima, y menos que sea un ataque. Antes de concluir hay que preguntarse qué puede explicarlo. Lee el resultado y fíjate en el nombre de la cuenta.
Responde para continuar
¿Qué cuenta aparece haciendo operaciones desde una dirección sin ningún inicio de sesión correcto en SigninLogs?
Ver pista de ayuda
Escribe `AzureActivity | join kind=leftanti (SigninLogs | where ResultType == "0") on $left.CallerIpAddress == $right.IPAddress | summarize Operaciones = count() by Caller, CallerIpAddress`.
La cuenta del resultado anterior es de servicio: hace copias programadas y no entra a una consola. SigninLogs recoge los inicios de sesión interactivos de personas; los inicios no interactivos y los de entidades de servicio se guardan en otras tablas de inicios de sesión del espacio. Por eso la ausencia en una tabla es una pregunta, no un hallazgo: falta mirar las otras tablas y comprobar con el responsable de la cuenta que esas copias son las esperadas.
Responde para continuar
Una operación de una cuenta de servicio no tiene inicio de sesión en SigninLogs. ¿Cuál es la lectura prudente?
Ver pista de ayuda
Una tabla sin la fila es una pregunta sobre dónde más buscar, no una conclusión.
Whoami-Labs Pro
Whoami-Labs Pro utiliza cookies
Utilizamos cookies y almacenamiento local para el funcionamiento del sitio, seguridad de sesión y, si lo autorizas, analítica y marketing. Puedes aceptar, rechazar o personalizar. Política de Privacidad
Preferencias
Configuraciones de cookies
Elige qué categorías permitir. Las esenciales siempre están activas. Consulta la Política de Privacidad.
Esenciales
Siempre activas · sesión, CSRF, tema y esta preferencia
Necesarias para iniciar sesión, proteger formularios (CSRF) y recordar tu elección de cookies y tema. Sin ellas la plataforma no funciona de forma segura.
Analíticos
Hoy no activos en la plataforma; listos para cuando se conecten
Nos ayudan a entender uso de cursos y páginas. Si los activas, se usarán cuando conectemos analítica; hasta entonces no se carga ningún tracker.
Marketing
Hoy no activos; campañas futuras solo con tu permiso
Comunicaciones o campañas. No activos hoy en la plataforma; quedarán listos si los conectamos y solo si los permites.