🛡️ sandbox-labs GitHub ↗

14 · Análisis de binarios de terceros#

En una frase, para cualquiera: un programa compilado no se puede leer. La única forma de saber qué hace es ejecutarlo y mirar — en una máquina que no te importe perder.

Estado real: 🟡 building — hay código y 6 comprobaciones automáticas, sin levantarse bajo bwrap en CI · Carpeta: cases/14-binary-analysis/ · Puerto: 8814


Por qué se realiza este caso#

Con código fuente puedes leer antes de ejecutar. Con un binario no: es un fichero de instrucciones de máquina. Puedes analizarlo estáticamente, y quien lo escribió puede haberlo previsto —empaquetado, cifrado, con código que se genera al vuelo.

Y a la vez, ejecutar binarios de terceros es completamente normal:

Situación cotidianaQué se ejecuta sin poder leerlo
Un instalador descargadoUn binario con permisos de instalación
Un driver o una utilidad de fabricanteCódigo con acceso privilegiado
Un juego o una aplicación de escritorioCientos de megas de binario
Una herramienta de línea de comandos de un repositorioCon tus permisos, sin revisión

La idea que enseña, y que ningún otro caso enseña#

Análisis dinámico con destrucción garantizada. No se trata de impedir que el binario actúe —entonces no se aprendería nada—, sino de dejarlo actuar en un sitio donde actuar no tiene consecuencias, y quedarse con el registro.

Comparte frontera con el caso 06, pero la pregunta es otra: allí se observa una muestra sospechosa, aquí se caracteriza un programa que probablemente quieras usar. El resultado no es «peligroso o no», es «esto es lo que hace».

Las muestras del repositorio son sintéticas e inofensivas. Para binarios reales de origen dudoso: una máquina dedicada, desconectada y desechable, nunca el equipo de trabajo.

Casos de uso reales#

Cómo funcionará#

flowchart LR
  B["⚙️ Binario"] --> ST["🔎 Análisis estático<br/>cabeceras, símbolos, cadenas"]
  ST --> V
  subgraph V["💻 microVM desechable"]
    E["▶️ Ejecutar"]
    O["👁️ syscalls · ficheros · red · procesos"]
    E --> O
  end
  V --> P["📊 Perfil de comportamiento"]
  V --> D["🗑️ Destrucción de la VM"]

Esquemas#

Salida — el perfil#

{
  "static": {
    "format": "ELF x86-64",
    "linkedLibraries": ["libc.so.6", "libssl.so.3"],
    "suspiciousStrings": ["/etc/shadow"]
  },
  "dynamic": {
    "syscalls": { "openat": 240, "connect": 3, "execve": 1 },
    "filesRead": ["/etc/hosts"],
    "filesWritten": ["~/.config/app/config.toml"],
    "networkAttempts": [{ "host": "203.0.113.4:443", "outcome": "simulada, no salió" }],
    "processesSpawned": ["sh -c uname -a"]
  },
  "vmDestroyed": true
}

Los tres datos que más valen: a qué se conecta, qué escribe fuera de su carpeta y qué otros programas lanza.

Software necesario#

ComponentePara qué¿Obligatorio?
KVMVirtualización por hardware
Firecracker o Kata ContainersLa microVM desechable
strace / eBPFRegistro de llamadas al sistema dentro del invitado
Herramientas de análisis estático (readelf, strings)La primera pasada, sin ejecutarRecomendado
Rust 1.75+El supervisor y el perfil
LinuxWSL2 no expone KVM anidado por defecto

Instalación#

ls /dev/kvm                    # si no existe, este caso no puede correr aquí
sudo apt install firecracker binutils
cargo build --release
cargo run -p sandboxctl -- doctor

Procesos que se crearán#

sandboxctl analyze <binario>
  │
  ├─ análisis estático        ← sin ejecutar nada
  │
  ├─ jailer
  │   └─ firecracker
  │       └─ [kernel invitado]
  │           ├─ el binario
  │           └─ trazador de syscalls
  │
  └─ colector                 ← fuera de la VM

Tiempo de carga estimado#

OperaciónCoste esperado
Análisis estático50–500 ms
Arranque de la microVM100–200 ms
Ejecución observadalo que dure, con techo
Destrucción de la VM< 50 ms

Qué hace falta para construirlo#

  1. Reutilizar el adaptador de microVM del caso 06.
  2. Análisis estático de cabeceras, bibliotecas enlazadas y cadenas.
  3. Trazado de llamadas al sistema dentro del invitado.
  4. Red simulada que registre destinos sin dejar salir tráfico.
  5. Perfil comparable entre ejecuciones, para detectar cambios entre versiones.

Si algo falla#

El caso ya tiene código: el núcleo en core.py y el servicio en app.py. Lo que sigue son sus fallos, la causa y la salida:

SituaciónCausaCómo se resuelve
/dev/kvm no existeIgual que en el caso 06: sin virtualización por hardware no hay microVMActivar la virtualización anidada, o ejecutar el caso en una máquina Linux con KVM. doctor lo dice antes de intentarlo
El binario no arranca dentro de la VMFalta una biblioteca en el rootfsstatic.linkedLibraries dice cuáles necesita. Se añaden al rootfs, que se genera de forma reproducible
No se registra ninguna llamada al sistemaEl trazador no arrancó, o el binario terminó antes1. Comprobar que el trazador está en el rootfs. 2. Un binario que termina de inmediato es un dato: aparece en syscalls.execve y poco más
El perfil cambia entre dos ejecuciones del mismo binarioPuede ser legítimo —el binario usa el reloj o la red— o deliberadoComparar los dos perfiles: un binario que se comporta distinto cuando cree que lo observan es exactamente lo que interesa detectar
La VM no se destruyeEl peor fallo posible de este casoLa destrucción va en el camino de salida pase lo que pase, y hay barrido de huérfanas

Los fallos que afectan a cualquier caso —no se puede crear el sandbox, no hay cgroups, un puerto ocupado, procesos huérfanos, la compilación en Windows— están resueltos uno a uno en Cuando algo falla.

Cómo se comprueba#

node scripts/verify-cases.mjs

Llama al núcleo del caso con situaciones concretas y comprueba qué hizo con ellas, no cómo está escrito. Son 6 comprobaciones, y corren en cada commit.

cargo run -p sandboxctl -- service up binary-analysis

Levanta el caso como producto en 127.0.0.1:8814. POST /api/run acepta el cuerpo que describen los esquemas de arriba.

Sigue en building, no en functional. El núcleo se comprueba, pero el servicio no se levanta bajo bwrap dentro de CI y el caso no emite evidencia firmada. La regla completa está en el ROADMAP.

Ver también: Catálogo completo · Caso 06 · detonación · Caso 15 · cadena de suministro