Superfície de Ataque do ksmbd & Fuzzing do Protocolo SMB2/SMB3 (syzkaller)
Reading time: 9 minutes
tip
Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
Aprenda e pratique Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporte o HackTricks
- Confira os planos de assinatura!
- Junte-se ao 💬 grupo do Discord ou ao grupo do telegram ou siga-nos no Twitter 🐦 @hacktricks_live.
- Compartilhe truques de hacking enviando PRs para o HackTricks e HackTricks Cloud repositórios do github.
Visão Geral
Esta página sintetiza técnicas práticas para exercitar e fazer fuzzing do servidor SMB in-kernel do Linux (ksmbd) usando syzkaller. O foco é expandir a superfície de ataque do protocolo via configuração, construir um stateful harness capaz de encadear operações SMB2, gerar PDUs gramaticamente válidos, direcionar mutações para caminhos de código pouco cobertos e aproveitar recursos do syzkaller como focus_areas e ANYBLOB. Enquanto a pesquisa original lista CVEs específicos, aqui enfatizamos a metodologia reutilizável e trechos concretos que você pode adaptar ao seu ambiente.
Escopo alvo: SMB2/SMB3 sobre TCP. Kerberos e RDMA estão intencionalmente fora do escopo para manter o harness simples.
Expandir a Superfície de Ataque do ksmbd via Configuração
Por padrão, uma configuração mínima do ksmbd deixa grandes partes do servidor sem testar. Habilite as seguintes funcionalidades para forçar o servidor a percorrer parsers/handlers adicionais e alcançar caminhos de código mais profundos:
- Global-level
- Durable handles
- Server multi-channel
- SMB2 leases
- Per-share-level
- Oplocks (ativado por padrão)
- VFS objects
Habilitar isso aumenta a execução em módulos como:
- smb2pdu.c (parsing/dispatch de comandos)
- ndr.c (encode/decode NDR)
- oplock.c (requisição/break de oplock)
- smbacl.c (parsing/aplicação de ACL)
- vfs.c (ops do VFS)
- vfs_cache.c (lookup cache)
Notas
- Opções exatas dependem do userspace ksmbd da sua distro (ksmbd-tools). Revise /etc/ksmbd/ksmbd.conf e as seções por-share para habilitar durable handles, leases, oplocks e VFS objects.
- Multi-channel e durable handles alteram máquinas de estado e tempos de vida, frequentemente expondo UAF/refcount/OOB sob concorrência.
Ajustes de Autenticação e Rate-Limiting para Fuzzing
SMB3 precisa de uma sessão válida. Implementar Kerberos em harnesses adiciona complexidade, então prefira NTLM/guest para fuzzing:
- Permita acesso guest e configure map to guest = bad user para que usuários desconhecidos caiam em GUEST.
- Aceite NTLMv2 (patch na política se estiver desabilitado). Isso mantém o handshake simples enquanto percorre caminhos de código SMB3.
- Remova checagens estritas de credit quando estiver experimentando (o hardening pós-CVE-2024-50285 tornou o crediting de ops simultâneas mais rígido). Caso contrário, rate-limits podem rejeitar sequências fuzzed cedo demais.
- Aumente max connections (por exemplo, para 65536) para evitar rejeições prematuras durante fuzzing de alta vazão.
Cuidado: Essas relaxações são apenas para facilitar o fuzzing. Não implante com essas configurações em produção.
Stateful Harness: Extrair Recursos e Encadear Requests
SMB é stateful: muitas requests dependem de identificadores retornados por respostas anteriores (SessionId, TreeID, pares FileID). Seu harness deve parsear respostas e reutilizar IDs dentro do mesmo programa para atingir handlers profundos (por exemplo, smb2_create → smb2_ioctl → smb2_close).
Exemplo de snippet para processar um buffer de resposta (pulando os +4B do NetBIOS PDU length) e armazenar 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;
}
}
Dicas
- Mantenha um processo fuzzer único compartilhando autenticação/estado: melhor estabilidade e cobertura com ksmbd’s global/session tables. O syzkaller ainda injeta concorrência marcando ops async, rerun internamente.
- Syzkaller’s experimental reset_acc_state pode resetar o estado global, mas pode introduzir uma lentidão significativa. Prefira estabilidade e foque no fuzzing.
Geração SMB2 guiada por gramática (PDUs válidos)
Traduza as estruturas SMB2 do Microsoft Open Specifications para uma fuzzer grammar para que o seu gerador produza PDUs estruturalmente válidos, que alcancem sistematicamente os dispatchers e os IOCTL handlers.
Exemplo (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 força tamanhos/deslocamentos corretos das estruturas e melhora dramaticamente a cobertura em comparação com mutações cegas.
Directed Fuzzing With focus_areas
Use o experimental focus_areas do syzkaller para dar mais peso a funções/arquivos específicos que atualmente têm cobertura fraca. Exemplo JSON:
{
"focus_areas": [
{"filter": {"functions": ["smb_check_perm_dacl"]}, "weight": 20.0},
{"filter": {"files": ["^fs/smb/server/"]}, "weight": 2.0},
{"weight": 1.0}
]
}
Isso ajuda a construir ACLs válidas que atingem caminhos aritméticos/overflow em smbacl.c. Por exemplo, um Security Descriptor malicioso com um dacloffset sobredimensionado reproduz um integer-overflow.
Construtor do reproducer (Python mínimo):
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)
Superando Platôs de Cobertura com ANYBLOB
Os anyTypes do syzkaller (ANYBLOB/ANYRES) permitem reduzir estruturas complexas a blobs que são mutadas de forma genérica. Popule um novo corpus a partir de pcaps SMB públicos e converta payloads em programas syzkaller que chamem seu pseudo-syscall (por exemplo, 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)"
)
Isto acelera a exploração e pode imediatamente disparar UAFs (por exemplo, em ksmbd_sessions_deregister) enquanto aumenta a cobertura alguns por cento.
Sanitizadores: Além do KASAN
- KASAN continua sendo o detector principal para bugs de heap (UAF/OOB).
- KCSAN frequentemente gera falsos positivos ou data races de baixa gravidade neste alvo.
- UBSAN/KUBSAN podem detectar erros de limites declarados que o KASAN perde devido à semântica de índices de array. Exemplo:
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));
Definir num_subauth = 0 dispara uma leitura OOB dentro da struct de sub_auth[-1], detectada pelas verificações de declared-bounds do UBSAN.
Notas sobre throughput e paralelismo
- Um único processo fuzzer (auth/state compartilhados) tende a ser significativamente mais estável para ksmbd e ainda expõe races/UAFs graças ao executor assíncrono interno do syzkaller.
- Com múltiplas VMs, ainda é possível atingir centenas de comandos SMB/segundo no total. Cobertura ao nível de função em torno de ~60% de fs/smb/server e ~70% de smb2pdu.c é alcançável, embora a cobertura de transições de estado seja sub-representada por tais métricas.
Checklist Prático
- Ative durable handles, leases, multi-channel, oplocks e VFS objects no ksmbd.
- Permita guest e map-to-guest; aceite NTLMv2. Faça patch para remover credit limits e aumente max connections para estabilidade do fuzzer.
- Construa um harness stateful que faça cache de SessionId/TreeID/FileIDs e encadeie create → ioctl → close.
- Use uma gramática para SMB2 PDUs para manter a validade estrutural.
- Use focus_areas para dar mais peso a funções com baixa cobertura (p.ex., caminhos em smbacl.c como smb_check_perm_dacl).
- Semeie com ANYBLOB a partir de pcaps reais para quebrar platôs; empacote seeds com syz-db para reutilização.
- Execute com KASAN + UBSAN; trate com cuidado os relatórios UBSAN declared-bounds.
Referências
- 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
- Leitura adicional: pwning.tech “Tickling ksmbd: fuzzing SMB in the Linux kernel”; Dongliang Mu’s syzkaller notes
tip
Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
Aprenda e pratique Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporte o HackTricks
- Confira os planos de assinatura!
- Junte-se ao 💬 grupo do Discord ou ao grupo do telegram ou siga-nos no Twitter 🐦 @hacktricks_live.
- Compartilhe truques de hacking enviando PRs para o HackTricks e HackTricks Cloud repositórios do github.