
Ejercicio de detección en laboratorio para DirtyFrag (CVE-2026-43284) - escalada de privilegios del kernel de Linux mediante corrupción de caché de página xfrm-ESP. Informe completo que cubre la ejecución del exploit, brechas de detección y reglas EQL corregidas utilizando Elastic Stack.
Clasificación: Laboratorio Interno - CyberLAB
Fecha: 24 de mayo de 2026
Plataforma: Elastic Stack v9.4.1
Estado: Detección Confirmada
Un ejercicio controlado de explotación simulando un adversario posterior al acceso inicial utilizando DirtyFrag (CVE-2026-43284), una vulnerabilidad de escalada de privilegios del kernel de Linux. El escenario simulado del atacante: un usuario con pocos privilegios (saskia, uid=1001) obtenido mediante credenciales phishing intenta escalar a root en un host Linux interno. El laboratorio utilizó una máquina Ubuntu deliberadamente vulnerable (ubuntu-vuln, kernel 6.0.0-22-generic) aislada de las redes de producción.
El atacante obtuvo acceso completo como root (uid=0) dentro del entorno del laboratorio. La pila de detección de Elastic Security generó 3 alertas de ALTA gravedad (puntuación de riesgo 73) identificando correctamente la cadena de explotación. Sin embargo, la detección requirió ajustes manuales: la configuración predeterminada tenía carencias que habrían resultado en alertas omitidas.
Conclusión: Los hosts Linux sin parches que ejecutan kernel <= 6.x son vulnerables. Si un atacante ya tiene un punto de apoyo con pocos privilegios, este exploit les otorga root completo de forma silenciosa y rápida, sin dejar rastro en disco visible para las herramientas de integridad de archivos.
auditd no producen evidencia. Sin reglas explícitas de syscall para socket, splice y unshare, el exploit se ejecuta silenciosamente: sin registros, sin alertas. La implementación predeterminada de Elastic Agent no añade estas reglas automáticamente.process.parent.pid como clave de correlación. En la práctica, DirtyFrag bifurca procesos intermedios, rompiendo esa correlación. La solución —correlacionar por auditd.session— fue identificada e implementada durante este ejercicio./etc/shadow, accedió a las claves autorizadas de SSH, escribió un marcador de persistencia (/root/pwned.txt) e inició reconocimiento de red mediante nc. Todo ocurrió dentro de los 30 minutos posteriores al acceso inicial.Objetivo: Validar la cobertura de detección para la explotación de DirtyFrag en el SOC del laboratorio local, identificar brechas de detección y producir una regla de detección corregida basada en el comportamiento real observado del atacante.
Modelo de amenaza: Adversario simulado posterior al acceso inicial con credenciales phishing para una cuenta de usuario con pocos privilegios (saskia, uid=1001). Objetivo: escalada de privilegios a root mediante DirtyFrag usando la ruta de recepción xfrm-ESP. La ejecución en el laboratorio se realizó mediante consola de Proxmox, funcionalmente equivalente a SSH posterior al acceso.
Se consideraron dos niveles de capacidad del atacante:
Este ejercicio cubrió el nivel vanilla.
DirtyFrag es la tercera de una familia de errores relacionados del kernel de Linux que todos abusan de la misma causa raíz:
Causa raíz: Las rutas de anexado de datagramas IPv4/IPv6 no establecían SKBFL_SHARED_FRAG después de que skb_splice_from_iter() colocara una página de la caché de páginas en un búfer de socket (sk_buff). Luego, la ruta de entrada de ESP realizaba criptografía in situ en páginas de la caché de páginas controladas por el atacante, tratándolas como skbs no lineales normales no clonados.
Primitiva del exploit: Escritura controlada de 4 u 8 bytes en la caché de páginas. Determinista: no se requiere condición de carrera.
Cadena del exploit:
/usr/bin/su) en la caché de páginassplice() para que la página del archivo se ubique en frag[0] de struct sk_buffxfrm-ESPexecve() del kernel— devuelven bytes corruptosPropiedad crítica de evasión: El archivo en disco nunca se modifica. Las herramientas de monitoreo de integridad de archivos (AIDE, Tripwire, verificaciones hash) todas reportan el archivo objetivo como limpio.
Distribuciones vulnerables confirmadas: Ubuntu 24.04.4, RHEL 10.1, AlmaLinux 10, openSUSE Tumbleweed, CentOS Stream 10, Fedora 44.
Telemetría activa durante el ejercicio:
Red del laboratorio aislada antes del ejercicio. El alias de firewall Cyber_escape_door confirmado como deshabilitado, impidiendo el alcance lateral a otras VLANs o internet.

Kernel vulnerable y cuenta con pocos privilegios confirmados en ubuntu-vuln:```
saskia@ubuntu-vuln:$ uname -r
6.0.0-22-generic
saskia@ubuntu-vuln:$ whoami
saskia
saskia@ubuntu-vuln:~$ id
uid=1001(saskia) gid=1001(saskia) groups=1001(saskia),27(sudo),100(users)

#### 4.3 Comprobación de salud de la pila
**Suricata: ejecutándose y capturando (systemctl status)**

**Kibana/Elasticsearch: verde/saludable (comprobación de API)**

**Capturas de instantáneas de VM tomadas antes de cualquier cambio**



#### 4.4 Captura de red
tcpdump iniciado en el host Suricata (`emp6s19`, longitud de instantánea 262144 bytes) para la captura completa de paquetes del tráfico de `172.66.66.27`.


---
### 5. Fase 2 - Ejecución del Exploit
#### 5.1 Preparación
Código fuente del exploit (`exp.c`) de V4bel/dirtyfrag PoC preparado en el host víctima.```bash
ubuntu-vuln@ubuntu-vuln:~/dirtyfrag$ ls
exp exp.c README.md
ubuntu-vuln@ubuntu-vuln:~/dirtyfrag$ cp exp.c /tmp/exp/
La terminal derecha muestra la copia preparada visible para el usuario saskia.

Compilado como root mediante sudo gcc (el usuario saskia está en sudoers):```
saskia@ubuntu-vuln:$ sudo gcc -o /tmp/exp/clean_frag /tmp/exp/exp.c
saskia@ubuntu-vuln:$ ls -la /tmp/exp/
-rwxr-xr-x 1 root root 62320 May 24 12:18 clean_frag
-rw-rw-r-- 1 ubuntu-vuln ubuntu-vuln 67803 May 24 12:13 exp.c
saskia@ubuntu-vuln:~$ id
uid=1001(saskia) gid=1001(saskia) groups=1001(saskia),27(sudo),100(users)
Binary: ELF 64-bit LSB executable, x86-64, dynamically linked.

#### 5.3 Ejecución - Root obtenido
El exploit se ejecutó como `saskia` (uid=1001). El proceso (`clean_frag`, pid=4326) abrió sockets `AF_RXRPC` y `AF_ALG`, luego llamó a `splice()` para plantar la página de caché en el búfer de red. La criptografía in-situ en la ruta ESP escribió bytes controlados por el atacante en la caché de páginas. Un proceso hijo (pid=4327) llamó a `unshare` con `a0=50000000` (CLONE_NEWUSER | CLONE_NEWNET) para obtener capacidades con alcance de espacio de nombres.```
saskia@ubuntu-vuln:~$ /tmp/exp/clean_frag
...
root@ubuntu-vuln:~# id
uid=0(root) gid=0(root) groups=0(root)
root@ubuntu-vuln:~# ls
Shell root completa obtenida a las 12:22 CEST (10:22 UTC), 24 de mayo de 2026.
Secuencia de llamadas al sistema registrada por auditd (UTC):
Todos los eventos comparten auditd.session=2.

Todas las acciones realizadas como root en ubuntu-vuln desde las ~12:22 CEST en adelante.
root@ubuntu-vuln:# echo "Dirty Frag PoC executed at $(date)" > /root/pwned.txt
root@ubuntu-vuln:# cat /root/pwned.txt
Dirty Frag PoC executed at Sun May 24 12:28:05 PM CEST 2026

#### 6.2 Acceso a Credenciales```bash
root@ubuntu-vuln:~# cat /etc/shadow | head -2
root:*:19823:0:99999:7:::
daemon:*:19823:0:99999:7:::
root@ubuntu-vuln:~# cat /home/ubuntu-vuln/.ssh/authorized_keys
ssh-ed25519 AAAA[...]
Archivo shadow y claves autorizadas SSH accedidas. En un compromiso real, esto permite el descifrado de contraseñas fuera de línea y el acceso persistente mediante backdoor SSH.

root@ubuntu-vuln:~# nc -vz 172.66.66.1 100-8000
Escaneo de puertos de la puerta de enlace del laboratorio (`172.66.66.1`, puertos 100-8000) ejecutado desde contexto root a las 12:51 CEST. Esto demuestra capacidad de movimiento lateral y mapeo de red desde una sesión escalada.

#### 6.4 Visibilidad de Red de Suricata
Suricata capturó **105 eventos** asociados a `172.66.66.27` durante la ventana del ejercicio (88 mdns, 17 flow). En el momento en que se tomó la captura de pantalla (durante el escaneo nc a las ~12:53 CEST), 29 eventos eran visibles en el tablero.
La explotación DirtyFrag en sí misma es interna al kernel y no produce firma de red; la primitiva de escalada no genera tráfico anómalo en la red. Se utilizó Suricata para recolectar pcaps del tráfico posterior a la explotación y los intentos de enumeración, en lugar de detectar la explotación en sí.
| Tipo de Evento | Recuento |
| -------------- | -------- |
| mdns | 88 |
| flow | 17 |
| **Total** | **105** |
Los eventos flow se agrupan alrededor de la ventana de escaneo de puertos nc (10:50-11:10 UTC / 12:50-13:10 CEST).

---
### 7. Fase 4 - Ingeniería de Detección
#### 7.1 Reglas de Detección Desplegadas
Se crearon dos reglas de secuencia EQL en el Motor de Detección de Kibana basadas en el artículo de Elastic Security Labs.
**Regla 1 - AF_RXRPC or AF_ALG Socket with Splice Followed by Execution** (no se disparó - ver brecha a continuación)```eql
sequence with maxspan=60s
[any where host.os.type == "linux" and
(
(event.category == "process" and auditd.data.syscall == "socket"
and auditd.data.a0 in ("26", "21")) or
(event.category == "process" and auditd.data.syscall == "splice") or
(event.category == "network" and event.action == "bound-socket"
and data_stream.dataset == "auditd_manager.auditd"
and auditd.data.socket.family == "38")
)
and user.id != "0"] by process.pid, host.id, user.id with runs=10
[process where host.os.type == "linux" and event.action == "executed" and
(
(user.effective.id == "0" and user.id != "0") or
(process.name in ("bash", "sh", "zsh", "dash", "fish", "ksh", "busybox")
and process.args in ("-c", "--command", "-ic", "-ci", "-cl", "-lc",
"-bash", "-sh", "-zsh", "-dash", "-fish", "-ksh"))
)] by process.parent.pid, host.id, user.id
Regla 2 - Manipulación de Namespace seguida de Escalada de Privilegios (activado después de la corrección)```eql sequence by host.id, auditd.session with maxspan=30s [process where host.os.type == "linux" and auditd.data.syscall == "unshare" and auditd.data.a0 in ("10000000", "50000000", "70000000", "10020000", "50020000", "70020000") and user.id != "0" and user.id != null] [process where host.os.type == "linux" and user.id == "0" and user.id != null and (process.name in ("bash", "sh", "zsh", "dash", "fish", "ksh", "su", "sudo", "pkexec", "busybox", "mksh") or process.name like ("python*", "perl*", "ruby*", "php*", "lua*"))]
#### 7.2 Brecha de Detección Inicial - Cobertura de Syscall Faltante
La Regla 1 devolvió cero resultados. La configuración predeterminada de auditd en `ubuntu-vuln` capturó: `write`, `bpf`, `openat`, `unshare` únicamente.
Faltantes: `socket`, `splice`, `bind` - las primitivas centrales del exploit.
**Corrección:** Agregado a `/etc/audit/rules.d/dirtyfrag.rules`:```
-a always,exit -F arch=b64 -S socket -k socket_syscall
-a always,exit -F arch=b32 -S socketcall -k socket_syscall
-a always,exit -F arch=b64 -S splice -k splice-syscall
-a always,exit -F arch=b32 -S splice -k splice-syscall
-a always,exit -F arch=b64 -S unshare -k unshare-syscall
-a always,exit -F arch=b32 -S unshare -k unshare-syscall
272 nuevos eventos de auditd llegaron a Elasticsearch en segundos después de la ejecución del exploit.
A pesar de que se capturaron eventos, la Regla 2 devolvió 0 coincidencias.
Causa raíz - árbol de procesos real (desde Elasticsearch):
La regla original correlacionaba por process.parent.pid. El evento unshare tenía ppid=4326, pero el shell root tenía un padre diferente - DirtyFrag bifurca procesos intermedios, rompiendo la correlación.
Solución: Correlacionar por auditd.session. Todos los eventos en la cadena de exploit compartían session=2, enlazando correctamente la secuencia independientemente de la profundidad de la bifurcación.
3 alertas de ALTA gravedad, puntuación de riesgo 73, en Kibana Security - Alertas a las 2026-05-24T10:25:57Z UTC (12:25:57 CEST).
| Alerta | Marca de tiempo (UTC) | Señal |
|---|---|---|
| Coincidencia de secuencia - evento unshare | 10:25:57.869 | process=clean_frag, user=saskia (uid=1001) |
| Coincidencia de secuencia - shell root | 10:25:57.881 | process=bash, user=root (uid=0) |
DirtyFrag - Namespace Manipulation Followed by Privilege Escalationubuntu-vuln

Todos los eventos de auditd relacionados con dirtyfrag:```kql data_stream.dataset: "auditd_manager.auditd" and auditd.summary.how: dirtyfrag
**Manipulación de espacios de nombres por parte de un usuario no root:**```kql
data_stream.dataset: "auditd_manager.auditd" and auditd.data.syscall: "unshare" and auditd.data.a0: "50000000"
Actividad de root posterior a la escalada en la misma sesión:```kql data_stream.dataset: "auditd_manager.auditd" and user.id: "0" and auditd.session: "2"
**Todos los eventos de auditd durante la ventana de exploit:**```kql
data_stream.dataset: "auditd_manager.auditd" and @timestamp >= "2026-05-24T10:20:00Z" and @timestamp <= "2026-05-24T10:30:00Z"
Llamadas al sistema Socket y splice desde el proceso de explotación:```kql data_stream.dataset: "auditd_manager.auditd" and auditd.summary.how: "/tmp/exp/clean_frag"
---
### 9. Resumen de Hallazgos Clave
| # | Hallazgo | Severidad | Remedida |
| - | ------- | -------- | ---------- |
| 1 | Las reglas predeterminadas de auditd omiten `socket`, `splice`, `unshare` - sin evidencia sin reglas explícitas | Crítica | Sí - se desplegaron reglas personalizadas en `/etc/audit/rules.d/dirtyfrag.rules` |
| 2 | La correlación EQL por `process.parent.pid` falla para cadenas de exploits bifurcados | Alta | Sí - cambiado a `auditd.session` |
| 3 | El monitoreo de integridad de archivos es ciego a DirtyFrag - los archivos en disco permanecen sin cambios | Alta | No hay remediación dentro del alcance - parchear el kernel es la solución |
| 4 | Post-explotación: archivo shadow, claves SSH y reconocimiento de red ejecutados como root antes de cualquier respuesta basada en alertas | Alta | Detectado mediante logs de auditd; no se activó ninguna regla dedicada para acceso a credenciales o fase de reconocimiento |
---
### 10. Referencias
- Elastic Security Labs: [Copy Fail y DirtyFrag: Errores de Página de Linux en la Naturaleza](https://www.elastic.co/security-labs/copy-fail-dirtyfrag-linux-page-bugs-in-the-wild)
- PoC público: [V4bel/dirtyfrag en GitHub](https://github.com/V4bel/dirtyfrag)
- MITRE ATT&CK: [T1068 - Explotación para Elevación de Privilegios](https://attack.mitre.org/techniques/T1068/)
- MITRE ATT&CK: [TA0004 - Elevación de Privilegios](https://attack.mitre.org/tactics/TA0004/)
- MITRE ATT&CK: [T1003.008 - /etc/passwd y /etc/shadow](https://attack.mitre.org/techniques/T1003/008/)
| Elemento | Detalle |
|---|
| Vulnerabilidad | DirtyFrag - CVE-2026-43284 (ruta xfrm-ESP), CVE-2026-43500 (ruta RxRPC) |
| Impacto CVSS | Escalada completa de privilegios local a root |
| Kernels afectados | Linux kernel >= enero 2017 (9 años de vida) |
| Distribuciones afectadas | Ubuntu 24.04.4, RHEL 10.1, AlmaLinux 10, openSUSE, CentOS Stream 10, Fedora 44 |
| Omisión de integridad de archivos | Archivos en disco sin cambios - AIDE, Tripwire, monitoreo de hash reportan todo limpio |
| PoC público | Disponible (V4bel/dirtyfrag en GitHub) |
| Tiempo para root | < 10 minutos desde un punto de apoyo con pocos privilegios |
| Prioridad | Acción |
|---|
| Inmediata | Parchear el kernel de Linux a una versión corregida en todos los hosts. Aplicar los avisos de seguridad del proveedor para Ubuntu, RHEL, AlmaLinux, openSUSE, CentOS, Fedora. |
| Corto plazo | Implementar reglas explícitas de syscall de auditd para socket, splice y unshare en todos los hosts Linux monitoreados por Elastic Agent. |
| Corto plazo | Actualizar las reglas de detección EQL para correlacionar por auditd.session en lugar de process.parent.pid para secuencias de manipulación de espacios de nombres. |
| Continuo | Tratar las alertas de escalada de privilegios con puntuación de riesgo >= 73 como prioridad alta de triaje. La regla actual se activa en segundos después de la escalada. |
| CVE | Apodo | Introducido | Ruta |
|---|
| CVE-2022-0847 | Dirty Pipe | - | pipe |
| CVE-2026-31431 | Copy Fail | - | splice |
| CVE-2026-43284 | DirtyFrag | Ene 2017 (commit cac2661c53f3) | xfrm-ESP |
| CVE-2026-43500 | DirtyFrag | Jun 2023 (commit 2dc334f1a63a) | RxRPC |
| Componente | Detalles |
|---|
| Servidor Fleet / host ELK | ubuntu-tm / elk-docker - 172.66.66.30 (interno del laboratorio) |
| Elastic Stack | v9.4.1 (Elasticsearch, Kibana, Logstash - Docker) |
| Host objetivo (víctima) | ubuntu-vuln - 172.66.66.27 |
| Kernel de la víctima | 6.0.0-22-generic (vulnerable) |
| Usuario de la víctima | saskia - uid=1001, grupos=1001(saskia),27(sudo),100(users) |
| Elastic Agent | v9.4.1 con auditbeat |
| IDS de red | Suricata 8.0.5 en sensor dedicado |
| Kibana | http://172.66.66.30:5601 (interno del laboratorio) |
| Conjunto de datos | Participación |
|---|
suricata.eve | 75.2% |
elastic_agent.fleet_server | 10.8% |
elastic_agent | 9.1% |
elastic_agent.filebeat | 1.9% |
elastic_agent.auditbeat | 1.4% |
auditd_manager.auditd | 0.5% |
system.auth | 0.2% |
system.syslog | 0.1% |
| Marca de tiempo (UTC) | Syscall | Argumento | Proceso (pid) | Usuario |
|---|
| 10:21:11.054 | unshare | a0=50000000 | clean_frag (4327) | saskia (1001) |
| 10:21:11.055 | socket | a0=21 (AF_RXRPC) | clean_frag (4326) | saskia (1001) |
| 10:21:17.403 | socket | a0=26 (AF_ALG) | clean_frag (4326) | saskia (1001) |
| 10:21:17.419 | splice | a0=4 | clean_frag (4326) | saskia (1001) |
| 10:21:17.419 | splice | a0=7 | clean_frag (4326) | saskia (1001) |
| Proceso | PID | PPID | UID | auditd.session |
|---|
| shell (saskia) | 4182 | - | 1001 | 2 |
clean_frag (principal) | 4326 | 4182 | 1001 | 2 |
clean_frag (hijo de unshare) | 4327 | 4326 | 1001 | 2 |
bash (root) | - | 4451 | 0 | 2 |
| Alerta de secuencia compuesta | 10:25:57.893 | host=ubuntu-vuln |
| Táctica | Técnica | ID |
|---|
| Escalada de Privilegios | Explotación para Escalada de Privilegios | T1068 |
| Escalada de Privilegios | Escape al Host | T1611 |
| Acceso a Credenciales | Volcado de Credenciales del SO: /etc/passwd y /etc/shadow | T1003.008 |
| Descubrimiento | Descubrimiento de Servicios de Red | T1046 |
| Syscall | Argumento | Significado |
|---|
unshare | a0=50000000 | CLONE_NEWUSER | CLONE_NEWNET |
socket | a0=26 | AF_ALG (subsistema criptográfico del kernel) |
socket | a0=21 | AF_RXRPC (ruta RxRPC) |
bind | socket.family=38 | Enlace AF_ALG |
splice | - | Inyección de páginas en buffers de red |