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

Visão geral

Esta página abstrai técnicas práticas para exercitar e fuzzar o servidor SMB in-kernel do Linux (ksmbd) usando syzkaller. Ela foca em expandir a superfície de ataque do protocolo via configuração, construir um harness stateful capaz de encadear operações SMB2, gerar PDUs válidos segundo a gramática, direcionar mutações para caminhos de código pouco cobertos e aproveitar recursos do syzkaller como focus_areas e ANYBLOB. Enquanto a pesquisa original enumera CVEs específicos, aqui enfatizamos a metodologia reutilizável e trechos concretos que você pode adaptar ao seu próprio 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 teste. Habilite as seguintes funcionalidades para levar o servidor por 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 (análise/encaminhamento de comandos)
  • ndr.c (encode/decode NDR)
  • oplock.c (requisição/interrupt de oplock)
  • smbacl.c (parsing/aplicação de ACL)
  • vfs.c (operações VFS)
  • vfs_cache.c (cache de lookup)

Notas

  • Opções exatas dependem do userspace ksmbd da sua distro (ksmbd-tools). Revise /etc/ksmbd/ksmbd.conf e as seções per-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 bugs sob concorrência.

Ajustes de Autenticação e Limitação de Taxa para Fuzzing

SMB3 precisa de uma sessão válida. Implementar Kerberos nos 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 revertam para GUEST.
  • Aceite NTLMv2 (patch na policy se estiver desabilitado). Isso mantém o handshake simples enquanto exercita caminhos de código do SMB3.
  • Aplique patch para remover checagens estritas de credit quando estiver experimentando (hardening pós-CVE-2024-50285 tornou o crediting de operações simultâneas mais estrito). Caso contrário, limitações de taxa podem rejeitar sequências fuzzadas cedo demais.
  • Aumente max connections (por exemplo, para 65536) para evitar rejeições precoces durante fuzzing de alto throughput.

Atenção: Essas relaxações são apenas para facilitar o fuzzing. Não utilize essas configurações em produção.


Harness com Estado: Extrair Recursos e Encadear Requisições

SMB é stateful: muitas requisições dependem de identificadores retornados por respostas anteriores (SessionId, TreeID, pares FileID). Seu harness deve parsear respostas e reutilizar IDs dentro do mesmo programa para alcançar handlers profundos (ex.: smb2_create → smb2_ioctl → smb2_close).

Example snippet to process a response buffer (skipping the +4B NetBIOS PDU length) and cache IDs:

c
// 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;
}
}

Tips

  • Mantenha um único processo fuzzer compartilhando authentication/state: melhor estabilidade e cobertura com as global/session tables do ksmbd. syzkaller ainda injeta concorrência marcando ops como async e reexecutando internamente.
  • O experimental reset_acc_state do Syzkaller pode resetar o global state, mas pode introduzir forte slowdown. Prefira estabilidade e foque em fuzzing.

Geração SMB2 dirigida por gramática (PDUs válidos)

Traduza as estruturas SMB2 das Microsoft Open Specifications para uma fuzzer grammar, de modo que seu gerador produza PDUs estruturalmente válidos, que atinjam sistematicamente os dispatchers e 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ção cega.


Fuzzing direcionado com focus_areas

Use as focus_areas experimentais do syzkaller para atribuir mais peso a funções/arquivos específicos que atualmente têm cobertura fraca. Exemplo de JSON:

json
{
"focus_areas": [
{"filter": {"functions": ["smb_check_perm_dacl"]}, "weight": 20.0},
{"filter": {"files": ["^fs/smb/server/"]}, "weight": 2.0},
{"weight": 1.0}
]
}

Isto ajuda a construir ACLs válidas que atingem caminhos aritméticos/overflow em smbacl.c. Por exemplo, um Security Descriptor malicioso com um dacloffset superdimensionado reproduz um integer-overflow.

Construtor de reproducer (Python mínimo):

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)

Superando platôs de cobertura com ANYBLOB

Os anyTypes do syzkaller (ANYBLOB/ANYRES) permitem colapsar estruturas complexas em blobs que mutam de forma genérica. Alimente 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):

bash
# Extract SMB payloads to JSON
# tshark -r smb2_dac_sample.pcap -Y "smb || smb2" -T json -e tcp.payload > packets.json
python
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)"
)

Isso acelera a exploração e pode acionar imediatamente UAFs (por exemplo, em ksmbd_sessions_deregister), ao mesmo tempo em que aumenta a cobertura em alguns por cento.


Sanitizadores: Além do KASAN

  • KASAN continua sendo o detector principal para heap bugs (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 indexação de array. Exemplo:
c
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));

Setting num_subauth = 0 triggers an in-struct OOB read of sub_auth[-1], caught by UBSAN’s declared-bounds checks.


Observações sobre taxa de transferência e paralelismo

  • Um único processo de fuzzer (auth/state compartilhados) tende a ser significativamente mais estável para ksmbd e ainda revela races/UAFs graças ao executor async interno do syzkaller.
  • Com múltiplas VMs, você ainda pode atingir centenas de comandos SMB/segundo no total. Cobertura a nível de função em torno de ~60% de fs/smb/server e ~70% de smb2pdu.c é atingível, embora a cobertura de transição de estados seja subrepresentada 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. Remova os limites de crédito e aumente o número máximo de conexões para melhorar a estabilidade do fuzzer.
  • Implemente um harness stateful que faça cache de SessionId/TreeID/FileIDs e encadeie create → ioctl → close.
  • Use uma grammar para SMB2 PDUs para manter a validade estrutural.
  • Use focus_areas para sobreponderar funções com baixa cobertura (ex.: caminhos em smbacl.c como smb_check_perm_dacl).
  • Semeie com ANYBLOB de pcaps reais para quebrar platôs; empaquete seeds com syz-db para reutilização.
  • Execute com KASAN + UBSAN; triage os relatórios de declared-bounds do UBSAN com cuidado.

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 complementar: 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