
ZRTP 중간자 공격 개념 증명
CVE-2016-6271은 Belledonne Communications가 개발한 ZRTP 라이브러리인 libbzrtp에 영향을 미칩니다.
이 라이브러리는 최종 사용자 애플리케이션에 내장되어 있으며, 예를 들어 Play 스토어의 Android 앱으로 제공되는 linphone이 있습니다. 현재 버전 3.2.7은 CVE-2016-6271에 취약하지 않아야 하는 libbzrtp 버전을 내장하고 있습니다.
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는 VoIP 통화를 보호하기 위한 솔루션입니다.
다음은 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를 통해 통신하게 됩니다.
이는 다양한 svi를 테스트하고 파생된 SAS가 이미 얻은 SAS와 일치하는지 확인하는 것으로 귀결됩니다. 모든 복잡한 세부 사항은 무차별 대입 소스에서 확인할 수 있습니다.
ZRTP 메시지는 반복 해시의 역방향 체인을 키로 사용하여 인증됩니다. DHPart2가 Mallory에 의해 즉석에서 수정되면, Alice는 계산된 HMAC이 수신된 HMAC과 일치하지 않기 때문에 Mallory가 변조한 DHPart2를 인증되지 않은 것으로 감지합니다. 이 검사를 통과하려면 Mallory는 반복 해시 체인 전체를 사용해야 하며, 이 체인을 사용하여 전송하는 모든 메시지에 서명해야 합니다.