Árboles de ataque
Cómo descomponer el objetivo de un atacante en caminos concretos, ponerles coste y decidir qué mitigar primero.
STRIDE te da amplitud: recorres cada elemento del diagrama y preguntas qué puede salir mal. Pero cuando una amenaza importa de verdad (por ejemplo, «alguien se lleva la PII de los pacientes») necesitas profundidad: ¿por qué caminos concretos podría conseguirlo, cuál es el más barato y qué control lo corta? Para eso existe el árbol de ataqueÁrbol de ataqueDiagrama que descompone el objetivo de un atacante en subobjetivos OR/AND hasta llegar a acciones concretas y evaluables., una técnica que Bruce Schneier popularizó en 1999 y que sigue siendo una de las formas más claras de razonar como un atacante sin perder el rigor.
Qué es un árbol de ataque#
Un árbol de ataque representa un único objetivo del atacante y todas las formas de alcanzarlo:
- Raíz: el objetivo. Debe ser concreto y valioso para el atacante: «exfiltrar la PII de pacientes», no «hackear Citas».
- Nodos intermedios: subobjetivos. Cada uno es de uno de estos dos tipos:
- OR: los hijos son alternativas. Basta con que una funcione.
- AND: los hijos son pasos que hacen falta todos. Si falla uno, el nodo falla.
- Hojas: acciones o condiciones concretas y evaluables: «enviar un phishing a una recepcionista», «la cuenta no tiene MFA». Si no puedes imaginar cómo probar una hoja, todavía no es una hoja.
El árbol se lee de abajo arriba: si las hojas necesarias se cumplen, su padre se cumple, y así hasta la raíz. Cada camino desde una combinación de hojas hasta la raíz es un escenario de ataque, a menudo llamado vector de ataqueVector de ataqueVía concreta por la que un atacante llega a un sistema para explotarlo: un phishing, una API expuesta, un bucket público, una credencial filtrada… cuando hablamos de la vía de entrada.
Paso 1 de 7Objetivo
La raíz es lo que quiere el atacante: exfiltrar la PII de los pacientes de Citas. Todo el árbol responde a «¿cómo podría conseguirlo?».
Atributos y cómo se propagan#
La potencia del árbol aparece cuando asignas atributos a las hojas y los propagas hacia arriba. Schneier usaba dos ejemplos: posible/imposible y coste en dólares. Las reglas son sencillas:
| Atributo (en la hoja) | Nodo OR | Nodo AND |
|---|---|---|
| Posible / imposible | posible si algún hijo lo es | posible si todos lo son |
| Coste para el atacante | mínimo de los hijos | suma de los hijos |
| Habilidad requerida | mínimo | máximo |
| Necesita acceso interno | sí si lo necesitan todos | sí si lo necesita alguno |
| Probabilidad (independientes) | 1 − ∏(1 − pᵢ) | ∏ pᵢ |
La idea clave: un atacante racional elige el camino más barato para él, que no tiene por qué coincidir con el más sofisticado ni con el que más te preocupa. Ese camino de valor mínimo hasta la raíz es el camino crítico, y es donde deberías actuar primero.
Construirlo paso a paso#
-
Elige la raíz
Sale de tu modelo de amenazas: un activo crítico (PII, la agenda, credenciales) o una amenaza STRIDE de severidad alta. Un árbol por objetivo.
-
Descompón en alternativas (OR)
Pregunta una y otra vez «¿de qué otra forma podría conseguirlo?». Piensa en personas, aplicación, infraestructura cloud y cadena de suministro.
-
Encuentra las condiciones conjuntas (AND)
Pregunta «¿qué más necesita para que esto funcione?». Aquí aparecen tus controles existentes: el phishing solo funciona y si no hay MFA.
-
Baja hasta hojas accionables
Para cuando cada hoja se pueda probar con un test, un ejercicio de pentest o una consulta a la configuración.
-
Asigna atributos y propaga
Coste, habilidad o detectabilidad. Propaga con las reglas OR/AND y marca el camino crítico.
-
Poda y documenta supuestos
Elimina ramas imposibles por diseño (y escribe por qué). Las ramas «imposibles» suelen apoyarse en un control: si ese control cambia, la rama vuelve.
-
Mitiga y recalcula
Corta o encarece el camino crítico, recalcula y repite hasta que el coste mínimo sea aceptable para tu nivel de riesgo.
El árbol de Citas#
Objetivo: exfiltrar la PII de los pacientes. Así queda en texto, que es como conviene guardarlo: en el repositorio, junto al código, revisable en cada PR.
OBJETIVO: Exfiltrar la PII de pacientes de Citas [OR] mín = 2├── 1. Credenciales de una recepcionista [AND] Σ = 2│ ├── 1.1 Phishing dirigido a la recepcionista coste 2│ └── 1.2 La cuenta no tiene MFA coste 0├── 2. SQL injection en la API (GET /citas?buscar=) coste 6├── 3. Copia de los datos dentro del proveedor cloud [OR] mín = 4│ ├── 3.1 Almacén de objetos de adjuntos con acceso público coste 4│ └── 3.2 Copia de la base de datos compartida con otra cuenta coste 5└── 4. Abuso del rol de despliegue de CI/CD (OIDC) [AND] Σ = 5 ├── 4.1 Trust policy sin condición sobre `sub` coste 0 └── 4.2 Workflow propio en cualquier repo de GitHub coste 5Si prefieres verlo dibujado, el mismo árbol en Mermaid se renderiza en GitHub, GitLab o Notion:
flowchart TD R["Exfiltrar PII de pacientes · OR"] A["1 · Credenciales de recepcionista · AND"] A1["1.1 Phishing dirigido · 2"] A2["1.2 Cuenta sin MFA · 0"] B["2 · SQLi en la API · 6"] C["3 · Copia de datos en el proveedor · OR"] C1["3.1 Almacén de objetos público · 4"] C2["3.2 Copia de BD compartida · 5"] D["4 · Abuso del rol de CI/CD · AND"] D1["4.1 Trust policy sin sub · 0"] D2["4.2 Workflow en otro repo · 5"] R --> A & B & C & D A --> A1 & A2 C --> C1 & C2 D --> D1 & D2El camino crítico es el 1: phishing a una cuenta sin MFA, coste 2. Fíjate en que dos de las hojas cuestan 0: no son acciones del atacante, sino condiciones que tú le regalas. Son las más rentables de corregir.
Mitigaciones que cortan ramas#
Una mitigación hace una de dos cosas: elimina una hoja (la rama se vuelve imposible) o la encarece (sube el coste del camino). Después hay que recalcular, porque el camino crítico se mueve.
| Hoja | Mitigación | Efecto en el árbol |
|---|---|---|
| 1.2 Cuenta sin MFA | MFA obligatorio en el proveedor de identidad gestionado; passkeys (WebAuthn) para el personal de las clínicas | Con TOTP, la hoja pasa a «eludir MFA» (proxy AiTM, fatiga): coste 7. Con passkeys, la rama queda prácticamente podada |
| 1.1 Phishing | Detección de credenciales comprometidas y autenticación adaptativa del proveedor de identidad (ejemplo: threat protection de Cognito) | Encarece el uso de credenciales robadas |
| 2 SQLi | Consultas parametrizadas, regla gestionada anti-SQLi en el WAF, SAST en CI | Elimina la hoja en el código y la detecta en el borde |
| 3.1 Almacén público | Bloqueo del acceso público a nivel de cuenta y una política de organización que impida desactivarlo (ejemplo: S3 Block Public Access + SCP) | Elimina la hoja |
| 3.2 Copia compartida | Cifrado con una clave gestionada por el cliente y política de clave sin cuentas externas; política de organización que prohíba compartir copias | Elimina la hoja (una copia cifrada no puede hacerse pública) |
4.1 Trust policy sin sub |
Condición sobre el sub del token OIDC restringida al repositorio y al entorno |
Elimina la hoja y con ella todo el AND |
La hoja 4.1 es un buen ejemplo de cómo una sola línea de política poda una rama entera. El patrón —restringir el sub del token OIDC— vale en cualquier nube; abajo la trust policy concreta como ejemplo en AWS:
Vulnerable
Seguro
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Federated": "arn:aws:iam::111122223333:oidc-provider/token.actions.githubusercontent.com" }, "Action": "sts:AssumeRoleWithWebIdentity", "Condition": { "StringEquals": { "token.actions.githubusercontent.com:aud": "sts.amazonaws.com" } } } ]}{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Federated": "arn:aws:iam::111122223333:oidc-provider/token.actions.githubusercontent.com" }, "Action": "sts:AssumeRoleWithWebIdentity", "Condition": { "StringEquals": { "token.actions.githubusercontent.com:aud": "sts.amazonaws.com", "token.actions.githubusercontent.com:sub": "repo:clinicas/citas:environment:prod" } } } ]}Y la hoja 3.2 se corta desde la organización: una política a nivel de organización (en AWS, una SCP; en Azure, Azure Policy; en Google Cloud, una política de organización) que deniegue la acción de compartir una copia de la base de datos salvo a un rol de emergencia (break-glass). Así, ni siquiera un administrador de la cuenta de producción puede exponer una copia sin pasar por ese rol, y la condición vive por encima de la cuenta donde está el dato.
Relación con STRIDE y con MITRE ATT&CK#
- STRIDE → árbol. STRIDE encuentra amenazas por elemento del DFD; las de severidad alta se convierten en raíces o ramas de un árbol. Por ejemplo, la Information disclosure sobre la base de datos gestionada es la rama 3.2.
- Árbol → ATT&CK. Las hojas se mapean a técnicas de MITRE ATT&CK. Así tu árbol habla el mismo idioma que el equipo de detección y puedes preguntar «¿qué log vería esta hoja?»:
| Hoja | Técnica ATT&CK |
|---|---|
| 1.1 Phishing dirigido | T1566 · Phishing |
| 1.2 Uso de la cuenta robada | T1078.004 · Valid Accounts: Cloud Accounts |
| 2 SQLi en la API | T1190 · Exploit Public-Facing Application |
| 3.1 Almacén de objetos público | T1530 · Data from Cloud Storage |
| 3.2 Copia de BD compartida | T1537 · Transfer Data to Cloud Account |
Errores comunes#
Tu turno
Modela una app de 3 capas que ya hayas construido
Elige una aplicación de tres capas que hayas construido o mantenido y construye el árbol de su objetivo más valioso para un atacante.
- ¿Cuál es el activo que más daño haría perder? Esa es tu raíz.
- ¿Contra qué atacante estimas los costes: externo oportunista, dirigido o interno?
- ¿Qué hojas cuestan 0 porque son condiciones que le regalas al atacante?
- ¿Cuál es el camino crítico y qué control concreto lo cortaría?
- Tras mitigarlo, ¿cuál es el nuevo camino crítico?
OBJETIVO: <qué quiere conseguir el atacante> [OR] mín = ?├── 1. <alternativa> [AND] Σ = ?│ ├── 1.1 <acción concreta> coste ?│ └── 1.2 <condición necesaria> coste ?├── 2. <alternativa> coste ?└── 3. <alternativa> [OR] mín = ? ├── 3.1 <acción concreta> coste ? └── 3.2 <acción concreta> coste ?
Atacante supuesto: ...Camino crítico: ... Mitigación: ...Nuevo camino crítico: ... Siguiente mitigación: ...Reto
Un nodo AND tiene dos hijos con coste 3 y 4, y un nodo OR tiene dos hijos con coste 3 y 4. ¿Qué valor propaga cada uno?
▸Mostrar solución
El AND propaga 7: el atacante tiene que hacer las dos cosas, así que paga ambas. El OR propaga 3: elige la alternativa más barata.
Reto
Mitigas una hoja que no está en el camino crítico. ¿Baja el riesgo frente a un atacante racional?
▸Mostrar solución
No cambia el coste mínimo hasta la raíz, así que ese atacante seguirá el mismo camino. La mitigación puede tener valor como defensa en profundidad o frente a otros perfiles de atacante, pero no debería ir antes que la del camino crítico.
En resumen#
- Un árbol de ataque modela un objetivo del atacante y todas las formas de alcanzarlo: nodos OR (alternativas) y AND (pasos necesarios), hasta hojas concretas y comprobables.
- Los atributos de las hojas se propagan: en coste, OR = mínimo y AND = suma. El camino de valor mínimo es el camino crítico.
- Las hojas con coste 0 son condiciones que regalas al atacante, y suelen ser las mitigaciones más rentables.
- Mitigar es eliminar o encarecer hojas. Después recalcula, porque el camino crítico se mueve.
- STRIDE aporta amplitud; el árbol, profundidad. Sus hojas se mapean a técnicas de ATT&CK y, de ahí, a detecciones.
Referencias#
- Bruce Schneier, Attack Trees, Dr. Dobb’s Journal, diciembre de 1999.
- Adam Shostack, Threat Modeling: Designing for Security (Wiley, 2014), capítulo 4: árboles de ataque.
- OWASP, Threat Modeling Cheat Sheet.
- MITRE ATT&CK: T1566 Phishing, T1190, T1530, T1537.
- AWS, Sharing a DB snapshot for Amazon RDS y Blocking public access to your Amazon S3 storage.
- AWS, Create a role for OpenID Connect federation (incluye la condición
subpara GitHub). - AWS, Threat protection en Amazon Cognito.