CVE-2016-6271 影响 libbzrtp,这是 Belledonne Communications 开发的 ZRTP 库。
该库被嵌入到终端用户应用程序中,例如 linphone,其作为 Play 商店中的 Android 应用 提供。当前版本 3.2.7 内嵌的 libbzrtp 版本 不应 存在 CVE-2016-6271 漏洞。
cd vulnerable-bzrtp && docker build -t vulnerable-bzrtp .
cd mitm-bzrtp && docker build -t mitm-bzrtp .
docker-compose -f cve-2016-6271.yaml up
ZRTP 是一种保护 IP 语音通话安全的解决方案。
以下内容摘自 IETF rfc6189:
ZRTP is a key agreement protocol that performs a Diffie-Hellman key
exchange during call setup in the media path and is transported over
the same port as the Real-time Transport Protocol (RTP) [RFC3550]
media stream which has been established using a signaling protocol
such as Session Initiation Protocol (SIP) [RFC3261]. This generates
a shared secret, which is then used to generate keys and salt for a
Secure RTP (SRTP) [RFC3711] session. ZRTP borrows ideas from
[PGPfone]. A reference implementation of ZRTP is available in
[Zfone].
The ZRTP protocol has some nice cryptographic features lacking in
many other approaches to media session encryption. Although it uses
a public key algorithm, it does not rely on a public key
infrastructure (PKI). In fact, it does not use persistent public
keys at all. It uses ephemeral Diffie-Hellman (DH) with hash
commitment and allows the detection of man-in-the-middle (MiTM)
attacks by displaying a short authentication string (SAS) for the
users to read and verbally compare over the phone.
总而言之:
存在漏洞的 ZRTP 代理由单个 C 文件编译而成:
ctx = bzrtp_createBzrtpContext(self_ssrc); assert(ctx != NULL);
ret = bzrtp_setCallbacks(ctx, &bzrtp_callbacks); assert(ret == 0);
bzrtp_initBzrtpContext(ctx);
bzrtp_setClientData(ctx, self_ssrc, ctx);
ret = bzrtp_startChannelEngine(ctx, self_ssrc); assert(ret == 0);
for (now = 0; now += 50;) { usleep(500000);
ret = recv(sd, buffer, sizeof(buffer), MSG_DONTWAIT);
if (ret > 0) {
received = ret;
bzrtp_processMessage(ctx, self_ssrc, buffer, received);
}
bzrtp_iterate(ctx, self_ssrc, now);
}
要体验它,请使用 cd vulnerable-bzrtp && docker build -t vulnerable-bzrtp . 构建 Docker 镜像。请注意,Dockerfile 将 start.sh 定义为入口点,它会通过 mallory 设置路由——稍后再详述。
该漏洞于 2016 年 3 月 30 日披露给 Belledone Communications,并已通过此提交迅速修复。
ZRTP 通过两条称为 DHPart1 和 DHPart2 的消息执行 Diffie-Hellman。Bob 在收到 Alice 的 DHPart1 后,承诺 将发送的 DHPart2 消息。
| Commit (Bob's ZID, options, hash value) F5 |
|<--------------------------------------------------|
| F6 DHPart1 (pvr, shared secret hashes) |
|-------------------------------------------------->|
| DHPart2 (pvi, shared secret hashes) F7 |
|<--------------------------------------------------|
在 bzrtp 中发现的漏洞在于缺少哈希承诺验证,这为攻击者留出了伪造具有特殊属性的 pvi 的空间。
此概念验证实现了 rfc6189 中描述的弱点:
The use of hash commitment in the DH exchange constrains the attacker
to only one guess to generate the correct Short Authentication String
(SAS) (Section 7) in his attack, which means the SAS can be quite
short. A 16-bit SAS, for example, provides the attacker only one
chance out of 65536 of not being detected. Without this hash
commitment feature, a MiTM attacker would acquire both the pvi and
pvr public values from the two parties before having to choose his
own two DH public values for his MiTM attack. He could then use that
information to quickly perform a bunch of trial DH calculations for
both sides until he finds two with a matching SAS. To raise the cost
of this birthday attack, the SAS would have to be much longer. The
Short Authentication String would have to become a Long
Authentication String, which would be unacceptable to the user. A
hash commitment precludes this attack by forcing the MiTM to choose
his own two DH public values before learning the public values of
either of the two parties.
当 Mallory 作为主动攻击者时,上述 DH 交换变为:
Bob Mallory Alice | | Commit (Alice's ZID...) | | |<------------------------| | Commit (Alice's ZID...) | | |<------------------------| | | | | | DHPart1 (pvr...) | | |------------------------>| | | | DHPart1 (pvr'...) | | |------------------------>| | | DHPart2 (pvi...) | | |<------------------------| | * SAS(Mallory, Alice) is known at this time * | | * now find a pvi' such as SAS(Bob, Mallory) * | | * equals SAS(Mallory, Alice) * | | DHPart2(pvi'...) | | |<------------------------| |
| * SAS(Mallory, Bob) = SAS(Alice, Mallory) * |
| * Both parties will confirm they share the same * |
| * SAS value * |
| * Note that SRTP material (Alice, Mallory) will * |
| * not match SRTP material (Mallory, Bob) * |
| * However, Mallory will be able to handle SRTP * |
| * flows from both Bob and Alice, giving * |
| * interception and tampering capabilities. * |
它基于 Python3 和 asyncio 构建。原始 IP 数据包使用 PF_PACKET 套接字捕获,仅监听 IPv4 帧。Scapy 用于解析原始帧。它会分析 ZRTP 数据包并重写它们,尤其是重新计算 HMAC 认证标签。
SAS 暴力破解器基于 C 语言,其输入为:
Hello of responder || Commit || DHPart1DHPart1 中发送的公共值使用 cd mitm-bzrtp && docker build -t mitm-bzrtp . && cd .. 构建 Docker 镜像。
中间人环境将借助以下内容搭建:
Alice 和 Bob 将通过 Mallory 通信,Mallory 会伺机执行中间人攻击。
归根结底就是测试各种 svi,并验证派生的 SAS 是否与已获取的 SAS 匹配。所有详细实现可在暴力破解源码中找到。
ZRTP 消息使用反转的迭代哈希链作为密钥进行认证。如果 DHPart2 被 Mallory 实时修改,Alice 将检测到 Mallory 篡改的 DHPart2 并非真实消息,因为计算出的 HMAC 与收到的 HMAC 不匹配。为了通过此项检查,Mallory 必须使用一整条迭代哈希链,并使用该链对她发送的所有消息进行签名。