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多个头域,但核心的就那么几个。我按重要性排个序:
- From — 标识发起者。注意tag参数,它是会话标识的一部分。
- To — 标识接收者。和From一样,可以包含显示名和URI。
- Call-ID — 全局唯一标识一个会话。我建议用UUID格式,但很多实现用IP+时间戳,容易碰撞。
- CSeq — 命令序列号。由整数和方法名组成,用于保证消息顺序。
- Via — 记录消息路径。每个代理服务器都会添加自己的Via头域。
- 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消息结构拆成了三个维度:请求、响应和头域,再加上底层的SDP消息体。你想想看,每个维度都有各自的模糊测试切入点。我个人习惯从头域开始,因为头域的解析代码往往是最先被调用的,出问题的概率也最大。
实战建议:刚开始做SIP模糊测试时,别贪多。先盯着INVITE请求的Via头域和SDP的m=行,把这两个点摸透了,再扩展到其他方法。我曾经用这个策略,一周内就在三个不同的SIP实现里找到了漏洞。
好了,SIP消息结构就讲到这里。记住:协议的结构就是攻击者的地图。你越熟悉它,就越能找到那些开发者疏忽的角落。
公众号:蓝海资料掘金营,微信deep3321