
Proof of concept for ZRTP man-in-the-middle
CVE-2016-6271 betrifft libbzrtp, eine ZRTP-Bibliothek, die von Belledonne Communications entwickelt wurde.
Diese Bibliothek wird in Endbenutzeranwendungen eingebettet, z. B. in linphone, das als Android-App im Play Store verfügbar ist. Die aktuelle Version 3.2.7 enthält eine Version von libbzrtp, die nicht anfällig für CVE-2016-6271 sein sollte.
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 ist eine Lösung zur Sicherung von VoIP-Anrufen.
Das Folgende ist ein Auszug aus 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.
Zusammenfassung:
Ein verwundbarer ZRTP-Agent wird aus einer einzigen C-Datei kompiliert:
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);
}
Baue das Docker-Image mit cd vulnerable-bzrtp && docker build -t vulnerable-bzrtp .. Beachte, dass das Dockerfile start.sh als Einstiegspunkt definiert, welches das Routing über Mallory einrichtet – dazu später mehr.
Am 30. März 2016 an Belledonne Communications gemeldet, wurde diese Schwachstelle schnell mit diesem Commit behoben.
ZRTP führt Diffie-Hellman in zwei Nachrichten durch, die DHPart1 und DHPart2 genannt werden. Bob committed die DHPart2-Nachricht, die er senden wird, nachdem er Alice' DHPart1 erhalten hat.
| Commit (Bob's ZID, options, hash value) F5 |
|<--------------------------------------------------|
| F6 DHPart1 (pvr, shared secret hashes) |
|-------------------------------------------------->|
| DHPart2 (pvi, shared secret hashes) F7 |
|<--------------------------------------------------|
Die in bzrtp entdeckte Schwachstelle ist das Fehlen einer Überprüfung des Hash-Commitments, was einem Angreifer Spielraum lässt, pvi mit interessanten Eigenschaften zu fälschen.
Dieser Proof of Concept setzt die in rfc6189 beschriebene Schwäche um:
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.
Mit Mallory als aktivem Angreifer wird der obige DH-Austausch zu:
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. * |
Es ist auf Python3 und asyncio aufgebaut. Rohe IP-Pakete werden mit einem PF_PACKET-Socket erfasst, wobei nur auf IPv4-Frames gehört wird. Scapy hilft bei der Zerlegung roher Frames.
Es analysiert ZRTP-Pakete und schreibt sie neu, insbesondere werden HMAC-Authentifizierungstags neu berechnet.
Der SAS-Bruteforcer ist in C geschrieben und nimmt als Eingabe:
Hello of responder || Commit || DHPart1DHPart1 gesendeter öffentlicher WertBaue das Docker-Image mit cd mitm-bzrtp && docker build -t mitm-bzrtp . && cd ...
Der Man-in-the-Middle wird mit Hilfe von:
Alice und Bob werden über Mallory kommunizieren, die opportunistisch einen Man-in-the-Middle-Angriff durchführt.
Es läuft darauf hinaus, verschiedene svi zu testen und zu überprüfen, ob die abgeleitete SAS mit der bereits erhaltenen SAS übereinstimmt. Alle grausigen Details finden sich im Bruteforce-Quellcode.
ZRTP-Nachrichten werden mit einer umgekehrten Kette iterierter Hashes als Schlüssel authentifiziert. Wenn DHPart2 von Mallory spontan modifiziert wird, wird Alice Mallorys verfälschtes DHPart2 als nicht authentisch erkennen, da der berechnete HMAC nicht mit dem empfangenen HMAC übereinstimmt. Um diese Prüfung zu bestehen, muss Mallory eine ganze Kette iterierter Hashes verwenden und alle gesendeten Nachrichten mit dieser Kette signieren.