资讯详情 Zeek 网络分析框架 SMB 协议分析脚本包(base/protocols/smb)完全指南
📅 2026/10/9 4:39:42
网络安全网络IDS【免费下载链接】zeekZeek is a powerful network analysis framework that is much different from the typical IDS you may know.项目地址https://gitcode.com/gh_mirrors/ze/zeek点击查看免费下载SMBServer Message Block/CIFS 是 Windows 环境中最常见也最常被攻击者利用的文件共享协议对它的深度解析是 Zeek 网络分析框架的核心能力之一。本文以 doc/scripts/base/protocols/smb/index.rst 所定义的base/protocols/smb脚本包为主体系统讲解该包的文件组成、加载机制、日志输出smb_files.log、smb_mapping.log、可选smb_cmd.log、SMB1/SMB2 命令解析逻辑、文件分析与 C 底层实现帮助读者理解并二次开发 Zeek 的 SMB 检测能力。包概览base/protocols/smb 提供了什么base/protocols/smb是 Zeek 内置基础脚本包base scripts中负责 SMB 协议分析的部分其包索引文档 index.rst 的核心描述只有一句话——Support for SMB protocol analysis为 SMB 协议分析提供支持。这背后实际是一整套由 8 个 Zeek 脚本文件与 1 个 DPD 签名文件构成的完整分析管线文件作用load.zeek包加载入口依次加载其余全部脚本与签名main.zeek核心模块SMB日志流注册、端口注册、日志记录类型定义、连接状态机smb1-main.zeekSMB1CIFS专用解析逻辑模块SMB1smb2-main.zeekSMB2 专用解析逻辑模块SMB2files.zeek与 Zeek 文件分析框架File Analysis Framework的集成consts.zeek命令名、方言、共享类型、RPC 端点等常量映射表const-dos-error.zeekSMB1 时代遗留的 DOS 错误码映射表const-nt-status.zeekNT 状态码NTSTATUS映射表约 1790 行dpd.sig动态协议检测DPD签名该脚本包所依赖的协议解析器C/binpac 实现位于 src/analyzer/protocol/smb二者配合完成从字节流到结构化事件与日志的完整转换。加载机制与端口注册包加载入口load.zeek 的内容非常直观load ./consts load ./const-dos-error load ./const-nt-status load ./main load ./smb1-main load ./smb2-main load ./files load-sigs ./dpd.sig加载顺序体现了依赖关系先加载常量表consts、const-dos-error、const-nt-status因为后续脚本会redef扩充这些表再加载核心main随后是 SMB1/SMB2 各自的逻辑最后是文件分析集成与 DPD 签名。在 Zeek 脚本中load base/protocols/smb或由init-default.zeek经由 scripts/base/init-default.zeek 间接加载即可启用该包。启用后main.zeek 的zeek_init()事件会完成两件事event zeek_init() priority5 { Log::create_stream(SMB::FILES_LOG, Log::Stream($columnsSMB::FileInfo, $pathsmb_files, $policylog_policy_files)); Log::create_stream(SMB::MAPPING_LOG, Log::Stream($columnsSMB::TreeInfo, $pathsmb_mapping, $policylog_policy_mapping)); Analyzer::register_for_ports(Analyzer::ANALYZER_SMB, ports); }注册两个日志流smb_files文件操作日志与smb_mapping共享目录树映射日志将内置 SMB 分析器注册到已知端口。ports常量定义如下且允许redefconst ports { 139/tcp, 445/tcp } redef;其中 445 端口为 SMB 直接承载于 TCPSMB-over-TCP139 端口为 NetBIOS 会话服务承载的 SMBSMB-over-NetBIOS这在 smb1_events.bif 的事件文档中有明确说明。除了端口注册dpd.sig 还提供了动态协议检测签名使 Zeek 能在任意端口上识别 SMBsignature dpd_smb { ip-proto tcp payload /^....[\xfe\xff]SMB/ enable smb }该签名匹配 TCP 载荷中以 4 字节长度前缀加\xfe\xffSMBSMB1 协商魔数开头的报文从而在非标准端口上也能启用 SMB 分析器。核心状态管理连接级的 SMB 状态机SMB 是一个有状态协议——命令请求与响应需要关联文件 IDfid、树 IDtid、消息 IDmid需要跨报文追踪。Zeek 的做法是在每条连接上挂载一个SMB::State记录定义于 main.zeektype State: record { current_cmd : CmdInfo optional; current_file : FileInfo optional; current_tree : TreeInfo optional; pending_cmds : table[count] of CmdInfo optional; fid_map : table[count] of FileInfo optional; tid_map : table[count] of TreeInfo optional; pipe_map : table[count] of string optional; recent_files : set[string] defaultset() read_expire3min; };各字段的含义current_cmd/current_file/current_tree当前正在处理的命令、文件与共享树pending_cmds以消息 IDmid为键的在途命令表用于把请求与响应配对从而计算 RTT 与状态码fid_map以文件 ID 为键的文件信息表跨命令追踪同一文件tid_map以树 ID 为键的共享树信息表pipe_map命名管道named pipe文件 ID 到 RPC UUID 的映射recent_files最近 3 分钟read_expire3min内见过的文件指纹集合用于避免在单条连接中反复记录同一文件防止过度日志化。该状态通过redef record connection { smb_state : State optional; }挂载到connection记录上。SMB1 与 SMB2 的事件处理器smb1-main.zeek、smb2-main.zeek都会在收到首条消息时惰性创建该状态初始化四个映射表后再赋给c$smb_state。请求-响应配对与 RTT 计算以 SMB1 为例smb1-main.zeek 中smb1_message事件以priority5处理消息头若 mid 尚未出现在pending_cmds中则新建CmdInfo版本标记为SMB1命令名从SMB1::commands[hdr$command]查表得到当收到服务端响应!is_orig时填充rttnetwork_time() - current_cmd$ts与status从SMB::statuses[hdr$status]$id查表。priority-5的版本负责在响应后把命令从pending_cmds中删除完成生命周期收尾。SMB2 的逻辑类似smb2-main.zeek区别在于使用tree_id与message_id替代 SMB1 的tid/mid增加了PENDING状态处理若当前命令状态为PENDING则跳过清理等待后续真正的非 pending 的应答这是为了兼容 SMB2 异步操作。日志记录类型三张日志的数据模型main.zeek 定义了三个日志记录类型分别对应三张日志。smb_files.log文件操作日志FileInfomain.zeek记录文件操作行为字段包括ts、uid、id、fuid文件唯一 ID由文件分析框架生成、action、path、name、size、prev_name重命名前的旧文件名、timesMACTimes 修改时间。此外脚本内部还通过redef record FileInfo { fid: count; uuid: string; }附加文件 ID 与 DCE/RPC UUID 字段用于命名管道识别。日志中的action字段来自Action枚举main.zeek它将 SMB 的各类操作抽象为三类资源的 14 种动作type Action: enum { FILE_READ, FILE_WRITE, FILE_OPEN, FILE_CLOSE, FILE_DELETE, FILE_RENAME, FILE_SET_ATTRIBUTE, PIPE_READ, PIPE_WRITE, PIPE_OPEN, PIPE_CLOSE, PRINT_READ, PRINT_WRITE, PRINT_OPEN, PRINT_CLOSE, };哪些动作会被写入日志由可配置的option logged_file_actions控制main.zeek默认记录文件打开、重命名、删除以及打印队列的打开与关闭而读/写动作默认不记入文件日志以避免日志爆炸option logged_file_actions: set[Action] { FILE_OPEN, FILE_RENAME, FILE_DELETE, PRINT_OPEN, PRINT_CLOSE, };smb_mapping.log共享树映射日志TreeInfomain.zeek记录一次树连接Tree Connect操作即客户端挂载共享资源的行为。字段包括path共享路径、service资源类型磁盘共享/打印机/命名管道等、native_file_system底层文件系统如 NTFS、share_type共享类型SMB2 直接来自协议字段SMB1 则由脚本推导默认DISK。share_type与SMB2::share_typesconsts.zeek对应取值含义1DISK磁盘共享2PIPE命名管道IPC$3PRINT打印机共享共享类型决定了后续文件操作被归类为FILE_*、PIPE_*还是PRINT_*动作见下文 SMB2 create/read/write/close 的处理。smb_cmd.log命令级日志可选策略包CmdInfomain.zeek记录每一条命令的完整信息command、sub_command如 Trans2 子命令、argument、status服务端返回状态、rtt请求响应往返时间、versionSMB1/SMB2、username认证用户名、tree与tree_service、以及关联的referenced_fileFileInfo与referenced_treeTreeInfo。其中referenced_file字段带log标记因此smb_cmd.log会把文件细节以嵌套形式一并记录。CmdInfo虽然已在基础包中定义但其对应日志smb_cmd.log并不默认启用——需要加载策略脚本 scripts/policy/protocols/smb/log-cmds.zeek。该脚本注释明确指出Load this script to generate an SMB command log, smb_cmd.log. This is primarily useful for debugging.加载它以生成 SMB 命令日志主要供调试使用。它通过Log::create_stream(SMB::CMD_LOG, ...)注册smb_cmd日志流并提供两个可调选项option ignored_command_statuses: set[string] { MORE_PROCESSING_REQUIRED, };忽略指定状态码的命令如 SMB2 会话建立过程中的中间状态同时定义deferred_logging_cmdsNEGOTIATE、READ_ANDX、SESSION_SETUP_ANDX、TREE_CONNECT_ANDX这些命令不立即在smbX_message中记日志而是等待更具体的事件如smb1_negotiate_response或错误事件smb1_error发生时再记录以保证日志字段完整。SMB1 解析细节smb1-main.zeek 在模块SMB1中扩展了SMB::CmdInfo增加smb1_offered_dialects字段用于暂存客户端协商阶段提供的方言列表。其核心事件处理协商Negotiatesmb1_negotiate_request记录客户端提供的方言smb1_negotiate_response根据响应中的dialect_index回查客户端方言列表把选中的方言如LANMAN1.0、NT LM 0.12写入argument字段树连接Tree Connect AndXsmb1_tree_connect_andx_request创建TreeInfo记录路径与 service响应到达时若未见到请求则上报Reporter::conn_weird(smb_tree_connect_andx_response_without_tree, ...)这种异常service 为IPC时share_type置为PIPE随后在priority-5阶段写入smb_mapping.log创建文件NT Create AndX请求阶段把文件名写入current_file并标记FILE_OPEN响应阶段填充fid、size、times对 IPC 传输出现的负数时间戳做了过滤仅当modified as double 0.0才记录并将文件按 fid 存入fid_map读/写Read/Write AndX通过SMB::set_current_file(c$smb_state, file_id)依据 fid 从fid_map恢复文件上下文标记FILE_READ/FILE_WRITE动作若当前文件缺 path 而树有 path则用树路径补全smb1-read-andx的priority-5处理器关闭Close AndX关闭时从fid_map删除文件并写日志对未知 fid 的关闭操作源码中以 TODO 注释保留attempting to close an unknown file!说明该场景处理策略仍未定型Trans/Trans2 子命令smb1_transaction_request用SMB1::trans_sub_commands表解析命名管道子命令如TRANSACT_NMPIPE、RAW_READ_NMPIPE等smb1_transaction2_request用SMB1::trans2_sub_commands表解析如FIND_FIRST2、QUERY_PATH_INFORMATION、GET_DFS_REFERRAL等命名管道启发式smb1_write_andx_request会把管道文件 ID 与 RPC UUID 关联进pipe_map供 DCE/RPC 层识别。SMB1::commands常量表consts.zeek完整映射了 SMB1 命令码到命令名覆盖CREATE_DIRECTORY(0x00)、OPEN_ANDX(0x2D)、READ_ANDX(0x2E)、WRITE_ANDX(0x2F)、TRANSACTION2(0x32)、TREE_CONNECT_ANDX(0x75)、NT_CREATE_ANDX(0xA2)、OPEN_PRINT_FILE(0xC0) 等 70 余个命令未识别码由默认函数生成unknown-code字符串保证日志不中断。SMB2 解析细节smb2-main.zeek 在模块SMB2中扩展SMB::CmdInfo增加smb2_offered_dialects与smb2_create_options暂存 Create 请求的选项位供删除检测使用。核心处理协商与方言smb2_negotiate_request记录客户端方言索引响应到达时通过SMB2::dialects[response$dialect_revision]把方言修订号转为可读字符串写入argument。SMB2::dialects表consts.zeek覆盖2.0.2(0x0202)、2.1(0x0210)、3.0(0x0300)、3.0.2(0x0302)、3.1.1(0x0311) 与2.1(0x02FF)树连接Tree Connect请求记录路径响应把share_type从SMB2::share_types查表填充并在priority-5阶段写smb_mapping.logsmb2_tree_disconnect_request负责从tid_map清理创建Create文件名空时以share_root代替表示操作针对共享根目录根据当前树的share_type决定动作是FILE_OPEN、PIPE_OPEN还是PRINT_OPENswitch 语句见 smb2-main.zeek响应阶段用file_id$persistent file_id$volatile作为 fid 存入fid_map特别地若 Create 请求携带FILE_DELETE_ON_CLOSE选项掩码0x00001000且响应状态为成功则触发smb2_file_delete事件读/写Read/Write同样按share_type将动作归类为FILE_READ/PIPE_READ/PRINT_READ或FILE_WRITE/PIPE_WRITE/PRINT_WRITE并写文件日志设置属性Set Info / File SAttrsmb2_file_sattr标记FILE_SET_ATTRIBUTE重命名Renamesmb2_file_rename把原文件名存入prev_name更新name为dst_filename标记FILE_RENAME删除Deletesmb2_file_delete仅在delete_pending为真即请求中确实设置了删除位时标记FILE_DELETE否则返回——源码注释说明未设删除位却触发删除事件属于异常情况关闭Close按share_type标记FILE_CLOSE/PIPE_CLOSE/PRINT_CLOSE从fid_map删除文件并写日志。SMB2::commands表consts.zeek映射 SMB2 命令码 0-18NEGOTIATE_PROTOCOL、SESSION_SETUP、TREE_CONNECT、CREATE、READ、WRITE、IOCTL、QUERY_DIRECTORY、OPLOCK_BREAK等。丢弃消息状态与脚本状态清理SMB2 消息可能因解析失败或流量异常而被丢弃。smb2_discarded_messages_state事件smb2-main.zeek会先通过Reporter::conn_weird(SMB_discarded_messages_state, ...)上报一个 weird附带 fid_map/tid_map/pending_cmds/pipe_map 的当前大小便于判断状态膨胀程度随后根据配置决定是否清空连接级脚本状态option enable_clear_script_state T;该选项定义于 main.zeek默认开启用于在高丢包率或流量异常环境中防止脚本状态无限增长。清理时重置fid_map与pending_cmds而tid_map与pipe_map由于预计不会过度膨胀而被保留源码注释明确说明了这一点并引用早期 zeek-smb-clear-state 包的做法。文件分析集成files.zeek 与文件提取files.zeek 将 SMB 协议与 Zeek 的 File Analysis Framework 桥接使得 SMB 传输的文件可以被提取、哈希、进行 MIME 检测等。其核心是zeek_init()中的注册event zeek_init() priority5 { Files::register_protocol(Analyzer::ANALYZER_SMB, Files::ProtoRegistration($get_file_handle SMB::get_file_handle, $describe SMB::describe_file )); }get_file_handlefiles.zeek为文件生成唯一句柄拼接分析器 ID、源/目的 IP、共享路径、文件名与最后修改时间使用modified_raw原始时间戳以避免跨架构双精度差异再用clean()去除内嵌空字节——源码注释说明这是为了规避文件分析层CheckString对空字节的处理缺陷describe_filefiles.zeek返回文件名作为文件的人类可读描述。file_over_new_connection事件files.zeek在文件关联到新连接时把文件分析框架生成的f$id写入current_file$fuid、把已知文件大小同步给f$total_bytes、把文件名写入f$info$filename并写一次文件日志从而让smb_files.log中的fuid与files.log中的条目能够关联。文件生命周期的收尾由 main.zeek 的file_state_remove事件完成仅处理f$source SMB的文件遍历其关联连接若有smb_state则调用write_file_log落盘。防重复日志机制write_file_logmain.zeek体现了对日志质量的精细控制对同一文件的重复读操作访问时间会变化因此先复制时间字段并把accessed_raw置零再用动作fuid文件名路径大小时间拼成指纹存入recent_files若指纹已存在则直接返回避免单条连接内对同一文件反复记日志。常量与错误码映射状态码体系SMB::statusesconsts.zeek是一个table[count] of StatusCode其中StatusCode记录包含id与desc人类可读描述两个字段。初始表中只有一个条目SUCCESS0x00000000随后被两个文件扩充const-dos-error.zeek132 行SMB1 时代的 DOS 错误码如badfile、badpw、access、noaccess、invnid、badfid、nomem等错误码带0x0001xxxx前缀const-nt-status.zeek1793 行Windows NT 状态码全集包括TIMEOUT、PENDING、MORE_PROCESSING_REQUIRED、ACCESS_DENIED、OBJECT_NAME_NOT_FOUND、SHARING_VIOLATION、INVALID_HANDLE等带0xC000xxxx/0x8000xxxx前缀。未识别的状态码由defaultfunction生成unknown-code占位保证任何响应都能映射出可读结果。状态码的可读化直接支撑了smb_cmd.log中的status字段。RPC 端点与命名管道consts.zeek还定义了命名管道与 DCE/RPC 端点的关联信息pipe_filenames用于在未看到管道映射时启发式识别命名管道包含spoolss、winreg、samr、srvsvc、netdfs、lsarpc、wkssvc、MsFteWdsrpc_uuidsRPC 端点 UUID 到服务名的映射如4b324fc8-1670-01d3-1278-5a47bf6ee188→ Server Servicesrvsvc、6bffd098-a112-3610-9833-46c3f87e345a→ Workstation Servicewkssvcsrv_cmds与wksta_cmds分别映射 Server Service 与 Workstation Service 的 RPC 子命令号到函数名如NetrSessionEnum、NetrShareEnum、NetrWkstaGetInfo等rpc_sub_cmds把 UUID 与对应命令表关联。这些常量支撑了 Zeek 在 IPC 命名管道流量上对 SMB 内嵌 RPC 调用的解读。C 底层解析器事件从何而来脚本层消费的事件由 src/analyzer/protocol/smb 下的 binpac 解析器产生。核心文件包括smb.pac分析器入口声明analyzer SMB及 SMB1/SMB2 两个协议变体smb1-protocol.pac、smb2-protocol.pac并 include 所有命令的.bif头文件SMB.cc 与 SMB.hC 分析器实现事件声明文件smb1_events.bifsmb1_message、smb1_error、smb1_empty_response等、smb2_events.bif以及各命令专属.bif如smb2_com_create.bif、smb1_com_nt_create_andx.bif这些.bif经 bifcl 工具见 tools/bifcl生成 C 事件触发代码解析定义文件smb1-com-*.pacNEGOTIATE、SESSION_SETUP_ANDX、TREE_CONNECT_ANDX、NT_CREATE_ANDX、READ_ANDX、WRITE_ANDX、TRANSACTION2 等与smb2-com-*.pacNEGOTIATE、SESSION_SETUP、TREE_CONNECT、CREATE、READ、WRITE、SET_INFO、IOCTL、TRANSFORM_HEADER 等另有smb-gssapi.pac认证数据、smb-time.pac时间格式、smb-pipe.pac管道等公共子模块。因此脚本层 main.zeek 中state$current_cmd$ts的填充、SMB1::Header/SMB2::Header的字段command、status、tid/tree_id、mid/message_id均直接来自这些底层解析器。用户在脚本层编写event smb2_create_request(c, hdr, request)处理器即可拿到解析后的结构化请求这是二次开发的基础。验证与测试仓库的 btest 测试框架提供了针对本脚本包的回归测试位于 testing/btest/scripts/base/protocols/smb例如smb2-read-write.zeek与smb2-create-delete-on-close.zeek验证 SMB2 读写与删除时关闭DELETE_ON_CLOSE文件删除检测smb1-long-andx-chain.zeek、smb1-non-advancing-andx-offset.zeek验证 SMB1 AndX 链式命令的解析健壮性后者针对 AndX 偏移不推进的畸形流量smb1-negotiate-lanman.zeek验证 LANMAN 方言协商named-pipe-fragment.zeek验证命名管道流量的分片处理compression-cap.zeek验证 SMB2 压缩能力协商相关字段。这些测试可作为理解脚本行为与边界情况的参考样例也可以作为自己编写 SMB 检测脚本的起点。实践要点与扩展建议启用方式基础包随 Zeek 默认加载init-default.zeek无需额外配置即可获得smb_files.log与smb_mapping.log如需命令级日志追加load policy/protocols/smb/log-cmds对应 scripts/policy/protocols/smb/log-cmds.zeek。调整端口集非标准端口上的 SMB 可由 DPD 签名 dpd.sig 识别无需改ports若确需显式指定可redef SMB::ports { ... };。控制日志量通过redef SMB::logged_file_actions增删需要记录的动作enable_clear_script_state控制高丢包环境下的脚本状态清理默认开启一般无需改动。观察状态细节smb2_discarded_messages_state产生的SMB_discarded_messages_stateweird 带有各映射表大小可用于诊断丢包导致的协议状态异常。二次开发脚本层可订阅smb1_*/smb2_*事件完整事件清单见 src/analyzer/protocol/smb/smb1_events.bif 与smb2_events.bif基于SMB::CmdInfo/FileInfo/TreeInfo扩展字段或增加自定义日志需要注意事件处理函数的priority约定——基础包在priority5建立状态、priority-5收尾写日志自定义逻辑应选择合适优先级以避免与状态机冲突。总结base/protocols/smb是 Zeek SMB 分析能力在脚本层的完整表达它用连接级状态机SMB::State把 SMB1/SMB2 的请求-响应配对、文件/树/管道映射组织起来用三张日志smb_files、smb_mapping、可选的smb_cmd把抽象后的文件操作、共享挂载与命令行为呈现给分析师并通过files.zeek与文件分析框架无缝衔接支持文件提取与后续检测。理解这份脚本包是深入使用 Zeek 检测 Windows 内网横向移动、SMB 恶意文件传输与异常共享访问的前提。赞分享网络安全网络IDS【免费下载链接】zeekZeek is a powerful network analysis framework that is much different from the typical IDS you may know.项目地址https://gitcode.com/gh_mirrors/ze/zeek点击查看免费下载相关推荐Zeek 中 SMB 协议分析包base/protocols/smb加载机制与脚本架构深度解析Zeek 中 SMB 协议分析包base/protocols/smb加载机制与脚本架构深度解析 本文以 Zeek 仓库中的 doc/scripts/base网络安全网络IDSZeek 网络流量分析框架中的 PostgreSQL 协议分析base/protocols/postgresql 脚本深入解读Zeek 网络流量分析框架中的 PostgreSQL 协议分析base/protocols/postgresql 脚本深入解读 Zeek 内置的 Postgr网络安全网络IDSZeek HTTP 分析框架深入指南base/protocols/http 脚本包全解析Zeek HTTP 分析框架深入指南base/protocols/http 脚本包全解析 Zeek 的内置 HTTP 分析能力由 scripts/base/p网络安全网络IDS上一篇Joystream 开源项目常见问题解决方案下一篇无缝融合 Rust 与 PythonInline Python 实战指南与常见问题解决方案创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考