- 网络安全
- 网络
- IDS
【免费下载链接】zeek
Zeek is a powerful network analysis framework that is much different from the typical IDS you may know.
Zeek 内置的 SMB(Server Message Block)协议分析器针对 SMB/CIFS 版本 1 的每一条命令,都会在脚本层暴露对应的事件接口。本文聚焦其中的 NT Cancel 命令:它由客户端在会话中主动发送,用于取消一个尚未完成(仍处于 pending 状态)的 SMB 请求。全文以官方事件文档(doc/scripts/base/bif/plugins/Zeek_SMB.smb1_com_nt_cancel.bif.zeek.rst)为骨架,结合分析器源码与脚本层状态机实现,讲清楚该事件的事件签名、触发时机、底层解析流程,以及如何用它在 Zeek 脚本中编写取消请求的检测与追踪逻辑。
事件总览:smb1_nt_cancel_request
在 Zeek 的脚本接口中,该事件定义于全局命名空间(GLOBAL),完整签名如下:
event smb1_nt_cancel_request(c: connection, hdr: SMB1::Header)| 参数 | 类型 | 含义 |
|---|---|---|
c | connection | 承载该 SMB 消息的连接对象 |
hdr | SMB1::Header | 该 SMB 版本 1 消息的已解析头部 |
事件触发语义(来自官方文档):每当客户端发送类型为nt cancel的 SMB/CIFS 版本 1 请求时生成。NT Cancel 请求的作用是让客户端请求服务器取消某个当前正处于 pending 状态(已提交但尚未完成)的请求。协议细节可参考 MS-CIFS 规范 2.2.4.65。
事件声明本体位于 src/analyzer/protocol/smb/smb1_com_nt_cancel.bif(bif 文件是 Zeek 桥接 C++ 解析器与脚本层的声明源),文档中与该事件建立互见(zeek:see)关系的是smb1_message事件,后者在每条 SMB1 消息被解析时统一触发,是观察所有 SMB1 命令总览的最佳切入点。
NT_CANCEL 在 SMB1 命令空间中的位置
SMB 版本 1 的消息体由一个单字节的 Command 字段标识。在脚本层,命令号到命令名的映射表定义于 scripts/base/protocols/smb/consts.zeek:
[0xA4] = "NT_CANCEL",即 NT Cancel 的命令码为0xA4(十进制 164)。它隶属于 NT 系列命令家族(0xA0~0xA5),同族还包括 NT_TRANSACT、NT_TRANSACT_SECONDARY、NT_CREATE_ANDX、NT_RENAME 等。分析器侧的 C++ 分发逻辑位于 src/analyzer/protocol/smb/smb1-protocol.pac,请求方向被完整支持:
SMB_COM_NT_CANCEL -> nt_cancel : SMB1_nt_cancel_request(header);值得注意的是,响应方向(SMB_COM_NT_CANCEL -> nt_cancel : SMB1_nt_cancel_response)在源码中是被注释掉的(同文件第 284 行),这是因为 NT Cancel 在协议语义上本身没有对应的响应消息——它只是单向的“取消”指令。这也解释了为什么 Zeek 只为该命令暴露了*_request事件、而没有*_response事件。
解析器底层:请求结构体与事件入队
smb1_nt_cancel_request事件的触发源头位于 src/analyzer/protocol/smb/smb1-com-nt-cancel.pac。该文件用 binpac 语言定义了解析逻辑,核心结构如下:
type SMB1_nt_cancel_request(header: SMB_Header) = record { word_count : uint8; byte_count : uint16; } &let { proc : bool = $context.connection.proc_smb1_nt_cancel_request(header, this); };解析要点:
- 字段布局:NT Cancel 请求体仅包含
word_count(1 字节)和byte_count(2 字节)两个字段,是 SMB1 命令族中载荷最轻的命令之一。协议头由调用方通过header: SMB_Header参数传入。 - 事件派发:
&let块中的proc字段在解析完成后立即调用连接对象上的处理函数,其内部实现为:
function proc_smb1_nt_cancel_request(header: SMB_Header, val: SMB1_nt_cancel_request): bool %{ if ( smb1_nt_cancel_request ) zeek::BifEvent::enqueue_smb1_nt_cancel_request(zeek_analyzer(), zeek_analyzer()->Conn(), SMBHeaderVal(header)); return true; %}即:当脚本层注册了smb1_nt_cancel_request事件处理器时,分析器会把当前连接与解析出的 SMB 头(经由SMBHeaderVal转换为脚本层的SMB1::Header记录值)入队触发该事件。若脚本未注册该事件,则整个请求体解析后不产生任何脚本层开销——这是 Zeek 分析器"按需派发"的一贯设计。
SMB1::Header结构与头部字段说明
事件参数中的hdr类型为SMB1::Header,其记录定义位于 scripts/base/init-bare.zeek,与 SMB 版本 1 协议头的标准字段一一对应:
type SMB1::Header : record { command : count; ##< The command number status : count; ##< The status code flags : count; ##< Flag set 1 flags2 : count; ##< Flag set 2 tid : count; ##< Tree ID pid : count; ##< Process ID uid : count; ##< User ID mid : count; ##< Multiplex ID };在 NT Cancel 场景中,最重要的两个字段是:
command:恒为0xA4,可用SMB1::commands[hdr$command]反查得到字符串"NT_CANCEL";mid(Multiplex ID):客户端用它标识被取消的目标请求——取消命令正是通过匹配服务器端 pending 请求的 MID 来定位目标。因此,在脚本层把hdr$mid与先前观察到的请求 MID 关联起来,是追踪"哪个请求被取消"的核心手段。
实战:编写 NT Cancel 检测脚本
下面给出一个可直接运行的 Zeek 脚本示例,演示如何订阅该事件、过滤无关噪声、并借助SMB::CmdInfo状态与smb1_message事件还原被取消的请求上下文:
@load base/protocols/smb export { redef enum Log::ID += { LOG }; } event zeek_init() &priority=5 { Log::create_stream(LOG, [$columns=Info, $path="smb1_nt_cancel"]); } event smb1_nt_cancel_request(c: connection, hdr: SMB1::Header) { # 仅记录命令码确实为 NT_CANCEL 的消息,作为防御性校验。 if ( SMB1::commands[hdr$command] != "NT_CANCEL" ) return; local rec: Info; rec$ts = network_time(); rec$uid = c$uid; rec$id = c$id; rec$mid = hdr$mid; rec$pid = hdr$pid; rec$command = SMB1::commands[hdr$command]; rec$orig = T; # 若此前已记录过该 MID 的请求,则补充其命令名以标识被取消的目标。 if ( c?$smb_state && hdr$mid in c$smb_state$pending_cmds ) rec$canceled_cmd = c$smb_state$pending_cmds[hdr$mid]$command; Log::write(LOG, rec); }配套的日志类型定义(Info)可按需包含ts / uid / id / mid / pid / command / canceled_cmd / orig等字段。实际部署时建议将脚本放入站点目录(如 scripts/site/local.zeek 同级或@load引用)后,用zeek -i eth0 local.zeek或zeek -r trace.pcap local.zeek加载。
结合状态机理解 MID 的语义
smb1_nt_cancel_request并非孤立事件——Zeek 的 SMB 脚本层通过smb_state$pending_cmds表维护"已发送、未完成"的请求集合,其维护逻辑在 scripts/base/protocols/smb/smb1-main.zeek:
- 每个新 MID 的请求到达时,
smb1_message(优先级 +5)会为该 MID 创建SMB::CmdInfo记录并放入pending_cmds; - 收到对应响应后,优先级 -5 的
smb1_message处理器会执行delete c$smb_state$pending_cmds[hdr$mid],将已完成请求移出集合(同文件第 61-67 行)。
由此可以推断:当smb1_nt_cancel_request触发时,若目标 MID 仍存在于pending_cmds中,说明该请求确实处于未完成状态,取消操作语义上有效;若 MID 已被移除,则说明请求在取消到达前已得到响应,属于"迟到取消"或重复取消。把这一判定写进检测脚本,可有效降低误报,也为异常取消行为(如取消不存在的请求)的检测提供了依据。
与其他 SMB1 事件的关系
smb1_nt_cancel_request是 SMB1 分析器对外暴露的众多命令级事件之一,与它相邻的同族事件包括(均在 src/analyzer/protocol/smb/ 下,各自对应一个.bif声明文件与一个解析文件):
smb1_negotiate_request/smb1_negotiate_response(smb1_com_negotiate.bif)smb1_nt_create_andx_request/smb1_nt_create_andx_response(smb1_com_nt_create_andx.bif)smb1_transaction_request、smb1_transaction2_request(smb1_com_transaction.bif、smb1_com_transaction2.bif)smb1_read_andx_request、smb1_write_andx_request、smb1_close_request等
所有命令级事件都遵循同一模式:bif 文件声明签名 →.pac文件定义解析结构 → 解析完成后按需派发事件。与smb1_message的区别在于粒度:smb1_message在每条 SMB1 消息上都会触发(适合全局会话重建与统计),而smb1_nt_cancel_request只在特定命令上触发(适合针对性检测,且未被订阅时几乎零开销)。
小结
smb1_nt_cancel_request是 Zeek 针对 SMB1SMB_COM_NT_CANCEL(命令码0xA4)暴露的请求级事件,签名固定为(c: connection, hdr: SMB1::Header),规范依据为 MS-CIFS 2.2.4.65。- 该命令无响应消息,因此 Zeek 侧也没有对应的
*_response事件;请求体仅含word_count与byte_count两个字段。 - 事件中的
hdr$mid是关联"取消目标请求"的关键线索,配合pending_cmds状态表(scripts/base/protocols/smb/smb1-main.zeek)可判断取消是否针对真正处于 pending 状态的请求。 - 检测脚本只需订阅事件并记录
SMB1::Header关键字段,即可产出独立日志流,用于异常取消行为分析与 SMB 会话审计。
- 网络安全
- 网络
- IDS
【免费下载链接】zeek
Zeek is a powerful network analysis framework that is much different from the typical IDS you may know.
相关推荐
用 GetQzonehistory 导出全部 QQ 空间历史说说:一次扫码,拿到 6 张 Excel 和一个网页相册
用 GetQzonehistory 导出全部 QQ 空间历史说说:一次扫码,拿到 6 张 Excel 和一个网页相册 GetQzonehistory 是一个在本
网络安全网络IDS语音AI智能体落地实战:从三十秒Demo到7×24语音客服系统的避坑指南
语音AI智能体落地实战:从三十秒Demo到7×24语音客服系统的避坑指南 你搭的语音AI智能体——语音客服系统、博物馆导览都算——多半卡在同一处:本地演示挺顺,
网络安全网络IDSZeek 文件传输事件 file_transferred 深度解析:原理、参数与脚本实战
Zeek 文件传输事件 file_transferred 深度解析:原理、参数与脚本实战 导读 file_transferred 是 Zeek 网络分析框架中用
网络安全网络IDS
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考