2. SIP协议消息结构:深入理解协议的心脏

大家好,我是你们的网络安全讲师。今天我们来聊聊SIP协议的消息结构。说实话,搞模糊测试这么多年,我最大的体会就是:不懂消息结构,你连漏洞的影子都摸不着。SIP协议看似简单,但里面的门道可不少。咱们一步步来拆解。

2.1 SIP请求消息:六种核心方法

SIP请求消息,说白了就是客户端发给服务器的指令。RFC 3261定义了六种基本方法,我习惯把它们分成两类:会话控制类辅助类

核心要点:模糊测试时,INVITE和REGISTER是最容易出问题的两个方法。我曾在INVITE的Content-Length字段上挖到过堆溢出漏洞。

2.1.1 INVITE — 发起会话

这是SIP协议里最复杂、也最容易被攻击的方法。它负责邀请对方加入会话。为什么复杂?因为它既要携带SDP消息体描述媒体能力,又要处理各种重定向和认证。

INVITE sip:bob@biloxi.com SIP/2.0
Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bK776asdhds
Max-Forwards: 70
To: Bob <sip:bob@biloxi.com>
From: Alice <sip:alice@atlanta.com>;tag=1928301774
Call-ID: a84b4c76e66710@pc33.atlanta.com
CSeq: 314159 INVITE
Contact: <sip:alice@pc33.atlanta.com>
Content-Type: application/sdp
Content-Length: 142

v=0
o=alice 2890844526 2890844526 IN IP4 pc33.atlanta.com
s=Session SDP
c=IN IP4 pc33.atlanta.com
t=0 0
m=audio 49170 RTP/AVP 0
a=rtpmap:0 PCMU/8000

嗯,这里要注意:Content-Length字段的值必须和实际SDP长度一致。我曾经见过一个案例,攻击者把Content-Length改成0,但实际SDP有200字节,结果服务器解析时直接崩溃了。

2.1.2 ACK — 确认响应

ACK只用于确认INVITE的最终响应。它不能携带消息体,也不能被重传。你想想看,如果ACK可以被重传,那会话状态管理就乱套了。

2.1.3 BYE — 结束会话

BYE可以由任何一方发起。我个人习惯在模糊测试时重点关注BYE的Call-ID字段——如果服务器没有正确校验这个字段,攻击者可以伪造BYE来强制断开别人的通话。

2.1.4 CANCEL — 取消请求

CANCEL只能取消尚未收到最终响应的请求。我记得有一次,一个厂商的SIP服务器在处理CANCEL时没有检查CSeq序列号,导致可以无限次取消同一个请求,最终引发拒绝服务。

2.1.5 REGISTER — 注册

REGISTER是用户代理向注册服务器登记联系地址的方法。这里有个坑:Expires头域控制注册有效期。如果服务器没有对Expires做上限校验,攻击者可以注册一个永不过期的绑定,或者设置超短有效期来耗尽服务器资源。

2.1.6 OPTIONS — 查询能力

OPTIONS用于查询服务器或用户代理支持的方法和扩展。它不改变任何状态,但可以用来做信息收集。我在渗透测试时,经常先用OPTIONS探路,看看目标支持哪些方法。

2.2 SIP响应消息:1xx到6xx的状态码

SIP响应消息和HTTP很像,但有些细微差别。我整理了一个表格,方便大家对照:

分类 范围 典型例子 模糊测试要点
1xx 临时响应 100-199 100 Trying, 180 Ringing 检查服务器是否正确处理非标准状态码
2xx 成功响应 200-299 200 OK 关注Contact头域的格式校验
3xx 重定向 300-399 302 Moved Temporarily 测试重定向循环检测机制
4xx 客户端错误 400-499 401 Unauthorized, 404 Not Found 认证头域的解析漏洞
5xx 服务器错误 500-599 500 Server Internal Error 触发服务器异常后是否泄露敏感信息
6xx 全局错误 600-699 603 Decline 检查全局错误是否影响其他会话

个人经验:模糊测试时,别只盯着2xx和4xx。1xx响应往往被开发者忽略,但恰恰是这些"临时"状态码,处理逻辑最薄弱。我曾经在100 Trying的解析代码里找到过一个空指针解引用漏洞。

2.3 SIP消息头域:协议的骨架

SIP头域是消息的元数据。RFC 3261定义了40多个头域,但核心的就那么几个。我按重要性排个序:

  1. From — 标识发起者。注意tag参数,它是会话标识的一部分。
  2. To — 标识接收者。和From一样,可以包含显示名和URI。
  3. Call-ID — 全局唯一标识一个会话。我建议用UUID格式,但很多实现用IP+时间戳,容易碰撞。
  4. CSeq — 命令序列号。由整数和方法名组成,用于保证消息顺序。
  5. Via — 记录消息路径。每个代理服务器都会添加自己的Via头域。
  6. Contact — 后续直接联系的地址。这个头域在NAT穿透场景下特别容易出问题。

避坑指南:我曾经在测试一个开源SIP服务器时,发现它对Via头域的branch参数校验不严格。攻击者可以注入特殊字符,导致服务器在解析Via时发生缓冲区溢出。所以,所有头域的参数都要做严格的输入校验

2.4 SIP消息体:SDP协议基础

SIP的消息体通常承载SDP(Session Description Protocol)。SDP描述会话的媒体信息,比如音频编码、IP地址、端口号等。一个典型的SDP结构如下:

v=0                    // 协议版本
o=alice 2890844526 2890844526 IN IP4 pc33.atlanta.com  // 会话发起者
s=Session SDP          // 会话名称
c=IN IP4 pc33.atlanta.com  // 连接信息
t=0 0                  // 会话时间
m=audio 49170 RTP/AVP 0   // 媒体描述
a=rtpmap:0 PCMU/8000      // 媒体属性

SDP的每一行都有严格的格式要求。模糊测试时,我重点关注:

  • m=行:媒体类型、端口、传输协议、格式列表。端口号可以改成0或65535吗?格式列表可以重复吗?
  • a=行:属性行。rtpmap、fmtp这些属性如果包含畸形数据,解析器很容易崩溃。
  • c=行:连接信息。IP地址格式校验不严会导致注入攻击。

2.5 知识体系结构图

下面这张图展示了SIP消息结构的整体框架。我建议你把它打印出来,贴在工位上:

SIP消息结构知识体系 SIP消息 请求消息 响应消息 消息头域 六种方法 INVITE | ACK | BYE CANCEL | REGISTER | OPTIONS 模糊测试重点:INVITE、REGISTER 状态码分类 1xx临时 | 2xx成功 | 3xx重定向 4xx客户端 | 5xx服务器 | 6xx全局 模糊测试重点:1xx、4xx 核心头域 From | To | Call-ID CSeq | Via | Contact 模糊测试重点:Via、Contact 消息体:SDP协议 媒体描述 (m=) 属性行 (a=) 连接信息 (c=) 模糊测试核心:边界值、畸形数据、协议状态机

这张图把SIP消息结构拆成了三个维度:请求、响应和头域,再加上底层的SDP消息体。你想想看,每个维度都有各自的模糊测试切入点。我个人习惯从头域开始,因为头域的解析代码往往是最先被调用的,出问题的概率也最大。

实战建议:刚开始做SIP模糊测试时,别贪多。先盯着INVITE请求的Via头域和SDP的m=行,把这两个点摸透了,再扩展到其他方法。我曾经用这个策略,一周内就在三个不同的SIP实现里找到了漏洞。

好了,SIP消息结构就讲到这里。记住:协议的结构就是攻击者的地图。你越熟悉它,就越能找到那些开发者疏忽的角落。


公众号:蓝海资料掘金营,微信deep3321