news 2026/10/24 2:00:23

Suricata SDP 关键字完整指南:用 sdp.* sticky buffer 精确匹配 SIP 消息中的会话描述字段

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Suricata SDP 关键字完整指南:用 sdp.* sticky buffer 精确匹配 SIP 消息中的会话描述字段
  • 网络安全

【免费下载链接】suricata

Suricata is a network Intrusion Detection System, Intrusion Prevention System and Network Security Monitoring engine developed by the OISF and the Suricata community.

项目地址:https://gitcode.com/gh_mirrors/su/suricata
点击查看免费下载

SDP(Session Description Protocol)是 SIP 信令中承载媒体会话描述的载体,通常作为 SIP 请求(如 INVITE)或响应(如 200 OK)的消息体出现,描述会话发起人、会话名称、媒体类型、端口、编解码器、带宽等关键信息。Suricata 将 SDP 字段实现为一组sdp.*检测关键字,它们以 sticky buffer 形式工作,让规则可以直接匹配结构化解析后的 SDP 字段,而不是退化为对原始字节流的盲搜。读完本文,你将掌握全部 17 个sdp.*关键字的语法与语义、会话级与媒体级字段的区分、底层 Rust 解析器与检测注册机制的工作原理,并能编写针对 VoIP 会话劫持、媒体参数篡改等场景的检测规则。

一、SDP 关键字概览

SDP 关键字全部实现为sticky buffer(粘性缓冲),用于匹配 SDP 消息中的各个字段。Suricata 会先由 Rust 解析器将 SDP 消息体解析为结构化对象(对应 rust/src/sdp/parser.rs 中的SdpMessage结构体),再把各字段按需提供给检测引擎,规则中的content等关键字随后在这些字段内容上执行匹配。

当前仓库实现的关键字及其方向支持如下(所有关键字方向均为 Both,即对 SIP 请求与响应均可匹配):

关键字方向匹配字段(SDP 行)
sdp.originBotho= 发起人
sdp.session_nameBoths= 会话名称
sdp.session_infoBothi= 会话信息
sdp.uriBothu= 会话 URI
sdp.emailBothe= 邮箱地址
sdp.phone_numberBothp= 电话号码
sdp.connection_dataBothc= 连接数据
sdp.bandwidthBothb= 带宽信息
sdp.timeBotht= 会话激活时间
sdp.repeat_timeBothr= 重复时间
sdp.timezoneBothz= 时区调整
sdp.encryption_keyBothk= 加密密钥
sdp.attributeBotha= 会话属性
sdp.media.mediaBothm= 媒体描述(媒体级)
sdp.media.session_infoBothi= 媒体标题(媒体级)
sdp.media.connection_dataBothc= 连接数据(媒体级)
sdp.media.encryption_keyBothk= 加密密钥(媒体级)

说明:原文档的关键字汇总表未单列sdp.phone_number,但正文中该关键字有完整的语法与示例章节,且源码 rust/src/sdp/detect.rs 中明确注册了sdp.phone_number缓冲区,因此上表将其补全为 17 个关键字。

二、通用语法:sticky buffer 的书写方式

所有 SDP 关键字的用法一致:以sdp.xxx作为缓冲区修饰符(sticky buffer),后接content关键字指定要匹配的内容,以分号结尾。基本语法为:

sdp.<field>; content:<匹配内容>;

content中可同时指定多个内容片段(此时它们按顺序依次匹配),也可配合nocase、depth、offset、within、distance等标准的 Suricata content 修饰符细化匹配行为。由于字段值是解析后的精确内容(不含o=等行前缀),content必须与解析器产出的字段值一致——例如sdp.origin匹配的是o=行去掉前缀后的完整字符串。

三、会话级字段:逐个掌握全部关键字

3.1 sdp.origin

匹配 SDP 请求或响应中的发起人(Originator),对应 SDP 的o=行。该行包含用户名、会话 ID、会话版本、网络类型、地址类型和单播地址六段信息。

sdp.origin; content:<origin>;

其中<origin>是遵循 SDP Origin(o=)格式的发起人字符串。示例:

sdp.origin; content:"SIPPS 105015165 105015162 IN IP4 192.168.1.2";

从解析器看,o=行由parse_origin_line解析(rust/src/sdp/parser.rs),解析后将六个字段以空格重新拼接为完整字符串。测试用例o=Clarent 120386 120387 IN IP4 200.57.7.196得到"Clarent 120386 120387 IN IP4 200.57.7.196",与规则中content的写法完全对应。

3.2 sdp.session_name

匹配会话名称,对应s=行。

sdp.session_name; content:<session_name>;

其中<session_name>是遵循 SDP Session name(s=)格式的名称。示例:

sdp.session_name; content:"SIP call";

parse_session_name(rust/src/sdp/parser.rs)允许字母、数字和空格字符组成会话名,测试用例s=Clarent C5CM解析为"Clarent C5CM"。

3.3 sdp.session_info

匹配会话信息,对应可选的i=行,提供人类可读的会话说明。

sdp.session_info; content:<session_info>;

其中<session_info>是遵循 SDP Session information(i=)格式的描述。示例:

sdp.session_info; content:"Session Description Protocol";

3.4 sdp.uri

匹配会话描述中的 URI,对应可选的u=行。

sdp.uri; content:<uri>;

其中<uri>是遵循 SDP scheme 的 URI。示例:

sdp.uri; content:"https://www.sdp.proto"

原文档示例结尾未带分号;为保持规则语法一致,建议写作sdp.uri; content:"https://www.sdp.proto";。解析器通过parse_uri(rust/src/sdp/parser.rs)按 URI 合法字符集(is_request_uri_char)提取内容。

3.5 sdp.email

匹配联系人邮箱地址,对应可选的e=行,格式通常为地址 (姓名)。

sdp.email; content:<email>

其中<email>是遵循 SDP scheme 的邮箱地址(e=)。示例:

sdp.email; content:"j.doe@example.com (Jane Doe)";

3.6 sdp.phone_number

匹配联系人电话号码,对应可选的p=行。该关键字在原文档表格中未列出,但在正文与源码注册(rust/src/sdp/detect.rs)中均有完整定义。

sdp.phone_number; content:<phone_number>

其中<phone_number>是遵循 SDP scheme 的电话号码(p=)。示例:

sdp.phone_number; content:"+1 617 555-6011 (Jane Doe)";

3.7 sdp.connection_data

匹配连接数据,对应c=行,声明会话或媒体的连接地址(网络类型、地址类型、连接地址,可选 TTL 与地址数量)。

sdp.connection_data; content:<connection_data>;

其中<connection_data>是遵循 SDP scheme 的连接信息(c=)。示例:

sdp.connection_data; content:"IN IP4 192.168.1.2"

解析器parse_connection_data(rust/src/sdp/parser.rs)对地址做了类型校验:IP 地址必须是合法 IPv4/IPv6(通过IpAddr::from_str校验);多播地址要求至少带 TTL(如IN IP4 224.2.36.42/127),单播 IPv4 带 TTL/数量时格式为addr/ttl或addr/ttl/count,测试用例c=IN IP4 224.2.36.42/127/2解析为"IN IP4 224.2.36.42/127/2",而裸的多播地址c=IN IP4 224.2.36.42会被判为解析失败。

3.8 sdp.bandwidth

匹配带宽信息,对应b=行。SDP 规范允许会话级出现零到多条b=行,因此该关键字支持多值匹配(见第五节源码原理)。

sdp.bandwidth; content:<bandwidth>

其中<bandwidth>是遵循 SDP scheme 的带宽信息(b=)。示例:

sdp.bandwidth; content:"AS:64"

parse_bandwidth(rust/src/sdp/parser.rs)目前仅接受CT、AS、TIAS三种带宽修饰符,输出形如"AS:64"的修饰符:值字符串。

3.9 sdp.time

匹配会话激活时间,对应t=行,格式为起始时间与结束时间两个十进制数字(NTP 时间戳形式)。

sdp.time; content:<time>

其中<time>是遵循 SDP scheme 的时间(t=)。示例:

sdp.time; content:"3034423619 3042462419"

3.10 sdp.repeat_time

匹配重复时间,对应r=行,说明会话的重复周期,包含间隔、时长等四个参数,支持d/h/m/s后缀(如7d 1h 0 25h)。

sdp.repeat_time; content:<repeat_time>

其中<repeat_time>是遵循 SDP scheme 的重复时间(r=)。示例:

sdp.repeat_time; content:"604800 3600 0 90000"

3.11 sdp.timezone

匹配时区调整,对应z=行,格式为时间 偏移对的序列。

sdp.timezone; content:<timezone>

其中<timezone>是遵循 SDP scheme 的时区(z=)。示例:

sdp.timezone; content:"2882844526 -1h 2898848070 0"

3.12 sdp.encryption_key

匹配加密密钥,对应k=行,用于在 SDP 承载于安全通道时传递加密密钥信息。

sdp.encryption_key; content:<encryption_key>

其中<encryption_key>是遵循 SDP scheme 的密钥(k=)。示例:

sdp.encryption_key; content:"prompt"

3.13 sdp.attribute

匹配会话属性,对应a=行。属性是 SDP 的扩展点,可为零到多条,因此同样支持多值匹配。属性可带属性名:属性值形式(如rtpmap:8 PCMA/8000/1),也可只有属性名(如sendrecv)。

sdp.attribute; content:<attribute>

其中<attribute>是遵循 SDP scheme 的属性(a=)。示例:

sdp.attribute; content:"sendrecv"

parse_attributes(rust/src/sdp/parser.rs)会把a=sendrecv解析为"sendrecv"、a=rtpmap:8 PCMA/8000/1解析为"rtpmap:8 PCMA/8000/1"。

四、媒体描述级字段:m= 行的子字段

SDP 会话可以包含零或多个媒体描述(Media Description),每个媒体描述以m=行开始,其后可跟媒体级的i=、c=、b=、k=、a=行。Suricata 提供四个媒体级子字段关键字,用于区分"会话级"与"媒体级"的同类信息(例如会话级c=与媒体级c=含义不同,匹配时必须使用对应关键字)。

4.1 sdp.media.media

匹配媒体描述中的媒体子字段,对应m=行,包含媒体类型、端口(可带/端口数)、传输协议及格式列表。

sdp.media.media; content:<media>

其中<media>是遵循 SDP scheme 的媒体(m=)。示例:

sdp.media.media; content:"audio 30000 RTP/AVP 0 8 97 2 3"

解析器parse_media_description(rust/src/sdp/parser.rs)对m=行做了较严格的约束:媒体类型仅接受audio、video、text、application、message五种;端口为 1~5 位数字(测试中70000因超范围解析失败);传输协议仅接受udp、RTP/AVP、RTP/SAVP。测试用例m=audio 40392 RTP/AVP 8 0解析为"audio 40392 RTP/AVP 8 0"。

4.2 sdp.media.session_info

匹配媒体描述中的会话信息子字段,对应媒体级i=行(媒体标题)。

sdp.media.session_info; content:<session_info>

其中<session_info>是遵循 SDP scheme 的描述(i=)。示例:

sdp.media.session_info; content:"Session Description Protocol"

4.3 sdp.media.connection_data

匹配媒体描述中的连接数据子字段,对应媒体级c=行。

sdp.media.connection_data; content:<connection_data>

其中<connection_data>是遵循 SDP scheme 的连接(c=)。示例:

sdp.media.connection_data; content:"IN IP4 192.168.1.2"

4.4 sdp.media.encryption_key

匹配媒体描述中的加密密钥子字段,对应媒体级k=行。

sdp.media.encryption_key; content:<encryption_key>

其中<encryption_key>是遵循 SDP scheme 的密钥(k=)。示例:

sdp.media.encryption_key; content:"prompt"

五、源码级原理:解析、注册与匹配链路

理解底层实现有助于判断匹配内容的边界条件与适用场景。SDP 支持链路贯穿以下几个文件:

1. Rust 解析器:rust/src/sdp/parser.rs 基于 nom 解析库实现。入口函数sdp_parse_message(rust/src/sdp/parser.rs)严格按照 RFC 4566 的会话描述格式顺序解析:v=(协议版本)→o=→s=→ 可选i=/u=/e=/p=/c=/b=→ 一个或多个t=/r=时间描述 → 可选z=/k=/a=→ 可选多个媒体描述(每个m=行后可跟媒体级i=/c=/b=/k=/a=)。解析结果保存在SdpMessage结构体中,其中bandwidths、attributes、media_description为列表字段,time_description为TimeDescription结构体数组(每个包含time与可选的repeat_time)。同文件内还包含覆盖各字段的单元测试(rust/src/sdp/parser.rs),可直接作为字段解析语义的参考。

2. SIP 消息体挂接:SDP 解析发生在 SIP 事务层。在 rust/src/sip/parser.rs 中,parse_request与parse_response在解析完请求行/状态行与头部后,对消息体调用opt(sdp_parse_message),因此Request.body/Response.body的类型是Option<SdpMessage>。这也印证了 SDP 关键字对 SIP 请求与响应(Direction: Both)均可生效。

3. 检测引擎注册:rust/src/sdp/detect.rs 中的SCDetectSdpRegister(rust/src/sdp/detect.rs)完成全部关键字的注册。每个关键字注册时:

  • 使用SigTableElmtStickyBuffer声明名称、描述与文档锚点 URL;
  • 调用SCDetectSignatureSetAppProto(s, ALPROTO_SIP)将签名绑定到 SIP 应用层协议,意味着使用sdp.*关键字的规则只会在 SIP 流量上生效;
  • 通过SCDetectHelperBufferMpmRegister或SCDetectHelperMultiBufferMpmRegister注册缓冲获取回调(*_get函数),后者依据方向从tx.request.body或tx.response.body取出对应字段内容交给 MPM 匹配。

值得注意的差异:sdp.origin、sdp.session_name、sdp.session_info、sdp.uri、sdp.email、sdp.phone_number、sdp.connection_data、sdp.timezone、sdp.encryption_key属于单值字段,使用helper_keyword_register_sticky_buffer注册;而sdp.bandwidth、sdp.time、sdp.repeat_time、sdp.attribute、sdp.media.media、sdp.media.session_info、sdp.media.connection_data、sdp.media.encryption_key由于字段本身可多次出现,注册为多缓冲区(multi buffer):local_id参数用于索引第 N 个字段值,规则可以对列表中的每个值分别匹配(如多组b=或a=行、多个媒体描述)。

4. 日志联动:解析出的 SDP 结构化数据同样用于 EVE JSON 日志输出。在 rust/src/sip/log.rs 中,SCSipLogJson会为请求与响应分别调用sdp_log输出sdp对象;其字段结构(attributes、bandwidths、connection_data、email、encryption_key、media_descriptions、origin、session_name、time_description等)定义在 etc/schema.json。检测与取证日志共享同一份解析结果。

六、实战:组合规则编写示例

将多个sdp.*关键字与 SIP 关键字组合,可以精确刻画 VoIP 会话特征。以下规则检测携带特定会话名、发起人与媒体类型组合的 SIP INVITE 请求:

alert sip any any -> any any (msg:"SDP: suspicious SIP call setup"; sdp.session_name; content:"SIP call"; sdp.origin; content:"SIPPS 105015165 105015162 IN IP4 192.168.1.2"; sdp.media.media; content:"audio 30000 RTP/AVP 0 8 97 2 3"; sid:1000001; rev:1;)

编写时需注意的约束:

  • 必须匹配解析后的完整字段值:content匹配的是去掉行前缀(o=、s=等)之后的字符串,且多字段以空格分隔。例如sdp.origin匹配"SIPPS 105015165 105015162 IN IP4 192.168.1.2",而不是o=SIPPS ...。
  • 字段边界由解析器决定:如连接数据中的地址必须合法(IP 校验)、媒体端口必须为 1~5 位数字、带宽修饰符仅CT/AS/TIAS。与解析器语义不符的报文可能直接解析失败,规则自然不会命中。
  • 仅作用于 SIP 流量:sdp.*规则自动绑定ALPROTO_SIP,不会在其他协议上误报。
  • 区分会话级与媒体级:同一字段名(如i=、c=、k=)在会话级与媒体级存在两套关键字,规则需要按目标信息所在层级选择。
  • 多值字段的匹配语义:sdp.bandwidth、sdp.attribute、sdp.media.media等会针对字段列表中的每一项逐一提供缓冲,因此content命中任意一条即视为命中。

七、适用前提与版本说明

本文所述关键字以当前仓库文档 doc/userguide/rules/sdp-keywords.rst 为准,实现代码位于 rust/src/sdp/detect.rs 与 rust/src/sdp/parser.rs,属于 Rust 实现的 SIP/SDP 解析与检测模块(源码注释标明编写于 2024 年)。要使用这些关键字,需保证构建的 Suricata 包含 Rust 支持且启用了 SIP 应用层协议解析。规则调试时,可结合suricata -T(规则语法检查)与 EVE JSON 日志中输出的sip.sdp对象核对字段实际解析值,再据此调整content内容。

  • 网络安全

【免费下载链接】suricata

Suricata is a network Intrusion Detection System, Intrusion Prevention System and Network Security Monitoring engine developed by the OISF and the Suricata community.

项目地址:https://gitcode.com/gh_mirrors/su/suricata
点击查看免费下载
上一篇:技术深度解析:STL到STEP转换的核心算法与工程实现
下一篇:Windows-universal-samples 之 CameraOpenCV:UWP 中基于 MediaFrameReader 与 OpenCV 逐帧图像处理的完整实现解析

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/15 13:55:09

PWM从原理到实战:占空比、频率、死区与STM32/HC32F460配置避坑指南

1. 从一次电机抖动排查说起&#xff1a;PWM到底在解决什么问题前阵子帮一个做小型云台的朋友排查问题&#xff0c;他反馈电机在低速转动时抖得厉害&#xff0c;换了驱动芯片、改了电源滤波都没用。我让他把示波器接到驱动板的输入脚上&#xff0c;波形一出来问题就很明显了——…

作者头像 李华
网站建设 2026/10/19 5:23:28

RAG进阶实战专栏策划:知识库形态、检索优化与本地部署全解析

RAG这个赛道&#xff0c;我盯着已经快两年了。从早先铺天盖地的“RAG入门教程”&#xff0c;到如今大家在认真讨论图片进不进得去知识库、本体建模怎么跟向量检索结合、本地部署到底能不能扛住真实业务&#xff0c;这中间的变化其实很能说明问题&#xff1a;RAG已经过了“讲概念…

作者头像 李华
网站建设 2026/10/23 20:23:42

四架构设计实战|全网独家复现4A一体化架构、端到端拆解、分层落地助力企业数字化转型、业务提效、系统复用、数据贯通

目录 一、前言 二、企业4A一体化架构核心认知与协同逻辑 2.1 四大架构核心定义 2.2 四大架构端到端协同关系 2.3 4A架构整体落地价值 三、业务架构(BA)精细化设计实战 3.1 设计核心思路与标准化步骤 3.2 电商行业业务架构落地案例 四、数据架构(DA)精细化设计实战…

作者头像 李华
网站建设 2026/10/15 21:52:55

扫地机器人双脑架构:安全脑独立于Linux,从源头守护机器人与用户

你拆开一台扫地机器人&#xff0c;最值得看的不是激光雷达转得有多欢快&#xff0c;而是它内部那张 PCB 上到底睡了几颗主控芯片。很多中高端机型用的是“双脑架构”&#xff1a;一颗带着 Linux 的 SoC 负责地图、避障、App 交互这些“聪明事”&#xff0c;旁边另一颗小小的 MC…

作者头像 李华
网站建设 2026/10/23 6:11:14

e2e Bug Bash 实战指南:并行 explore 章程、缺陷分流与复现测试验证

测试测试智能体人工智能浏览器控制CLI 【免费下载链接】e2e Next generation e2e testing framework for web and mobile apps. 项目地址&#xff1a; https://gitcode.com/GitHub_Trending/e2e6/e2e 点击查看 免费下载 导读 本指南以仓库内技能文档 bug-bash.md 为核心&…

作者头像 李华