Superficie de ataque de ksmbd y fuzzing del protocolo SMB2/SMB3 (syzkaller)
Reading time: 9 minutes
tip
Aprende y practica Hacking en AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP:
HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Hacking en Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Revisa los planes de suscripción!
- Únete al 💬 grupo de Discord o al grupo de telegram o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud repositorios de github.
Resumen
Esta página abstrae técnicas prácticas para ejercitar y fuzzear el servidor SMB en el kernel de Linux (ksmbd) usando syzkaller. Se centra en ampliar la superficie de ataque del protocolo mediante la configuración, construir un harness stateful capaz de encadenar operaciones SMB2, generar PDUs válidos según la gramática, sesgar las mutaciones hacia rutas de código con cobertura débil y aprovechar características de syzkaller como focus_areas y ANYBLOB. Mientras que la investigación original enumera CVEs específicos, aquí enfatizamos la metodología reutilizable y fragmentos concretos que puedes adaptar a tus propios entornos.
Alcance objetivo: SMB2/SMB3 sobre TCP. Kerberos y RDMA quedan intencionalmente fuera de alcance para mantener el harness simple.
Amplía la superficie de ataque de ksmbd mediante la configuración
Por defecto, una configuración mínima de ksmbd deja muchas partes del servidor sin probar. Habilita las siguientes características para forzar al servidor a atravesar parsers/handlers adicionales y alcanzar rutas de código más profundas:
- A nivel global
- Durable handles
- Multi-channel del servidor
- SMB2 leases
- A nivel por share
- Oplocks (activado por defecto)
- Objetos VFS
Habilitar esto incrementa la ejecución en módulos como:
- smb2pdu.c (command parsing/dispatch)
- ndr.c (NDR encode/decode)
- oplock.c (oplock request/break)
- smbacl.c (ACL parsing/enforcement)
- vfs.c (VFS ops)
- vfs_cache.c (lookup cache)
Notas
- Las opciones exactas dependen del userspace ksmbd de tu distro (ksmbd-tools). Revisa /etc/ksmbd/ksmbd.conf y las secciones por share para habilitar durable handles, leases, oplocks y objetos VFS.
- Multi-channel y durable handles alteran las máquinas de estado y las lifetimes, con frecuencia sacando a la superficie UAF/refcount/OOB bugs bajo concurrencia.
Ajustes de autenticación y rate-limiting para fuzzing
SMB3 necesita una sesión válida. Implementar Kerberos en los harnesses añade complejidad, por lo que se prefiere NTLM/guest para fuzzing:
- Permitir acceso guest y establecer map to guest = bad user para que usuarios desconocidos caigan en GUEST.
- Aceptar NTLMv2 (parcha la policy si está deshabilitado). Esto mantiene el handshake simple mientras se ejercitan las rutas de código de SMB3.
- Elimina las comprobaciones estrictas de credit cuando experimentes (el hardening posterior para CVE-2024-50285 endureció la contabilización de credit para operaciones simultáneas). De lo contrario, los rate-limits pueden rechazar secuencias fuzzed demasiado pronto.
- Incrementa max connections (p. ej., a 65536) para evitar rechazos tempranos durante fuzzing de alto rendimiento.
Precaución: Estas relajaciones son solo para facilitar el fuzzing. No desplegues estas configuraciones en producción.
Harness con estado: extraer recursos y encadenar solicitudes
SMB es stateful: muchas requests dependen de identificadores devueltos por respuestas previas (SessionId, TreeID, pares FileID). Tu harness debe parsear las respuestas y reutilizar los IDs dentro del mismo programa para alcanzar handlers profundos (p. ej., smb2_create → smb2_ioctl → smb2_close).
Ejemplo de snippet para procesar un buffer de respuesta (saltando los +4B de longitud del PDU NetBIOS) y cachear los IDs:
// process response. does not contain +4B PDU length
void process_buffer(int msg_no, const char *buffer, size_t received) {
uint16_t cmd_rsp = u16((const uint8_t *)(buffer + CMD_OFFSET));
switch (cmd_rsp) {
case SMB2_TREE_CONNECT:
if (received >= TREE_ID_OFFSET + sizeof(uint32_t))
tree_id = u32((const uint8_t *)(buffer + TREE_ID_OFFSET));
break;
case SMB2_SESS_SETUP:
// first session setup response carries session_id
if (msg_no == 0x01 && received >= SESSION_ID_OFFSET + sizeof(uint64_t))
session_id = u64((const uint8_t *)(buffer + SESSION_ID_OFFSET));
break;
case SMB2_CREATE:
if (received >= CREATE_VFID_OFFSET + sizeof(uint64_t)) {
persistent_file_id = u64((const uint8_t *)(buffer + CREATE_PFID_OFFSET));
volatile_file_id = u64((const uint8_t *)(buffer + CREATE_VFID_OFFSET));
}
break;
default:
break;
}
}
Consejos
- Mantén un único proceso fuzzer que comparta autenticación/estado: mejor estabilidad y cobertura con las tablas global/session de ksmbd. syzkaller aún inyecta concurrencia marcando ops como async y hace rerun internamente.
- El experimental reset_acc_state de syzkaller puede restablecer el estado global, pero puede introducir una fuerte ralentización. Prefiere la estabilidad y céntrate en fuzzing.
Generación SMB2 guiada por gramática (PDUs válidos)
Traduce las estructuras SMB2 de Microsoft Open Specifications a una gramática de fuzzer para que tu generador produzca PDUs estructuralmente válidos, que alcancen sistemáticamente los dispatchers y los IOCTL handlers.
Ejemplo (SMB2 IOCTL request):
smb2_ioctl_req {
Header_Prefix SMB2Header_Prefix
Command const[0xb, int16]
Header_Suffix SMB2Header_Suffix
StructureSize const[57, int16]
Reserved const[0, int16]
CtlCode union_control_codes
PersistentFileId const[0x4, int64]
VolatileFileId const[0x0, int64]
InputOffset offsetof[Input, int32]
InputCount bytesize[Input, int32]
MaxInputResponse const[65536, int32]
OutputOffset offsetof[Output, int32]
OutputCount len[Output, int32]
MaxOutputResponse const[65536, int32]
Flags int32[0:1]
Reserved2 const[0, int32]
Input array[int8]
Output array[int8]
} [packed]
Este estilo fuerza tamaños/desplazamientos de estructuras correctos y mejora drásticamente la cobertura frente a la mutación ciega.
Directed Fuzzing With focus_areas
Utiliza el experimental focus_areas de syzkaller para dar mayor peso a funciones/archivos específicos que actualmente tienen cobertura débil. Ejemplo JSON:
{
"focus_areas": [
{"filter": {"functions": ["smb_check_perm_dacl"]}, "weight": 20.0},
{"filter": {"files": ["^fs/smb/server/"]}, "weight": 2.0},
{"weight": 1.0}
]
}
Esto ayuda a construir ACLs válidas que alcanzan las rutas arithmetic/overflow en smbacl.c. Por ejemplo, un Security Descriptor malicioso con un dacloffset sobredimensionado reproduce un integer-overflow.
Reproducer builder (minimal Python):
def build_sd():
import struct
sd = bytearray(0x14)
sd[0x00] = 0x00; sd[0x01] = 0x00
struct.pack_into('<H', sd, 0x02, 0x0001)
struct.pack_into('<I', sd, 0x04, 0x78)
struct.pack_into('<I', sd, 0x08, 0x00)
struct.pack_into('<I', sd, 0x0C, 0x10000)
struct.pack_into('<I', sd, 0x10, 0xFFFFFFFF) # dacloffset
while len(sd) < 0x78:
sd += b'A'
sd += b"\x01\x01\x00\x00\x00\x00\x00\x00" # minimal DACL
sd += b"\xCC" * 64
return bytes(sd)
Superar mesetas de cobertura con ANYBLOB
Las anyTypes de syzkaller (ANYBLOB/ANYRES) permiten colapsar estructuras complejas en blobs que mutan de forma genérica. Siembra un nuevo corpus a partir de pcaps SMB públicos y convierte los payloads en programas de syzkaller que llamen a tu pseudo-syscall (p. ej., syz_ksmbd_send_req):
# Extract SMB payloads to JSON
# tshark -r smb2_dac_sample.pcap -Y "smb || smb2" -T json -e tcp.payload > packets.json
import json, os
os.makedirs("corpus", exist_ok=True)
with open("packets.json") as f:
data = json.load(f)
# adjust indexing to your tshark JSON structure
packets = [e["_source"]["layers"]["tcp.payload"] for e in data]
for i, pkt in enumerate(packets):
pdu = pkt[0]
pdu_size = len(pdu) // 2 # hex string length → bytes
with open(f"corpus/packet_{i:03d}.txt", "w") as f:
f.write(
f"syz_ksmbd_send_req(&(&(0x7f0000000340))=ANY=[@ANYBLOB=\"{pdu}\"], {hex(pdu_size)}, 0x0, 0x0)"
)
Esto acelera la exploración y puede desencadenar inmediatamente UAFs (p. ej., en ksmbd_sessions_deregister) mientras aumenta la cobertura en unos pocos puntos porcentuales.
Sanitizadores: Más allá de KASAN
- KASAN sigue siendo el detector principal para heap bugs (UAF/OOB).
- KCSAN a menudo produce falsos positivos o data races de baja severidad en este objetivo.
- UBSAN/KUBSAN pueden detectar errores de límites declarados que KASAN pasa por alto debido a la semántica de índices de array. Ejemplo:
id = le32_to_cpu(psid->sub_auth[psid->num_subauth - 1]);
struct smb_sid {
__u8 revision; __u8 num_subauth; __u8 authority[NUM_AUTHS];
__le32 sub_auth[SID_MAX_SUB_AUTHORITIES]; /* sub_auth[num_subauth] */
} __attribute__((packed));
Configurar num_subauth = 0 provoca una lectura OOB dentro de la estructura de sub_auth[-1], capturada por las comprobaciones de límites declarados de UBSAN.
Notas sobre rendimiento y paralelismo
- Un solo proceso fuzzer (auth/state compartido) suele ser significativamente más estable para ksmbd y aun así revela races/UAFs gracias al ejecutor asíncrono interno de syzkaller.
- Con múltiples VMs aún puedes alcanzar cientos de comandos SMB/segundo en total. Se puede lograr cobertura a nivel de función de ~60% de fs/smb/server y ~70% de smb2pdu.c, aunque la cobertura de transiciones de estado está infrarepresentada por tales métricas.
Lista de verificación práctica
- Habilita durable handles, leases, multi-channel, oplocks y VFS objects en ksmbd.
- Permite guest y map-to-guest; acepta NTLMv2. Quita los credit limits y aumenta max connections para la estabilidad del fuzzer.
- Construye un stateful harness que cachee SessionId/TreeID/FileIDs y encadene create → ioctl → close.
- Usa una gramática para SMB2 PDUs para mantener la validez estructural.
- Usa focus_areas para sobreponderar funciones con cobertura débil (p. ej., rutas en smbacl.c como smb_check_perm_dacl).
- Siembra con ANYBLOB desde pcaps reales para romper mesetas; empaqueta los seeds con syz-db para reutilización.
- Ejecuta con KASAN + UBSAN; realiza triage de los informes declared-bounds de UBSAN con cuidado.
Referencias
- Doyensec – ksmbd Fuzzing (Part 2): https://blog.doyensec.com/2025/09/02/ksmbd-2.html
- syzkaller: https://github.com/google/syzkaller
- ANYBLOB/anyTypes (commit 9fe8aa4): https://github.com/google/syzkaller/commit/9fe8aa4
- Async executor change (commit fd8caa5): https://github.com/google/syzkaller/commit/fd8caa5
- syz-db: https://github.com/google/syzkaller/tree/master/tools/syz-db
- KASAN: https://docs.kernel.org/dev-tools/kasan.html
- UBSAN/KUBSAN: https://docs.kernel.org/dev-tools/ubsan.html
- KCSAN: https://docs.kernel.org/dev-tools/kcsan.html
- Microsoft Open Specifications (SMB): https://learn.microsoft.com/openspecs/
- Wireshark Sample Captures: https://wiki.wireshark.org/SampleCaptures
- Lectura adicional: pwning.tech “Tickling ksmbd: fuzzing SMB in the Linux kernel”; Dongliang Mu’s syzkaller notes
tip
Aprende y practica Hacking en AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP:
HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Hacking en Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Revisa los planes de suscripción!
- Únete al 💬 grupo de Discord o al grupo de telegram o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud repositorios de github.
HackTricks