
Preuve de concept pour l'attaque de l'homme du milieu sur ZRTP.
CVE-2016-6271 impacte libbzrtp, qui est une bibliothèque ZRTP développée par Belledonne Communications.
Cette bibliothèque est intégrée dans des applications utilisateur final, par exemple linphone, qui est disponible en tant qu'application Android sur le Play Store. La version actuelle 3.2.7 intègre une version de libbzrtp ne devrait pas être vulnérable à 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 est une solution pour sécuriser les appels vocaux sur IP.
Ce qui suit est un extrait de l'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.
Pour résumer :
Un agent ZRTP vulnérable est compilé à partir d'un fichier C unique :
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);
}
Pour l'utiliser, construisez l'image docker avec cd vulnerable-bzrtp && docker build -t vulnerable-bzrtp .. Attention, le Dockerfile définit start.sh comme point d'entrée, qui configure le routage via mallory – plus de détails plus tard.
Divulguée le 30 mars 2016 à Belledonne Communications, cette vulnérabilité a été rapidement corrigée avec ce commit.
ZRTP effectue l'échange Diffie-Hellman en deux messages appelés DHPart1 et DHPart2. Bob s'engage sur le message DHPart2 qu'il enverra après avoir reçu le DHPart1 d'Alice.
| Commit (Bob's ZID, options, hash value) F5 |
|<--------------------------------------------------|
| F6 DHPart1 (pvr, shared secret hashes) |
|-------------------------------------------------->|
| DHPart2 (pvi, shared secret hashes) F7 |
|<--------------------------------------------------|
La vulnérabilité découverte dans bzrtp est l'absence de vérification de l'engagement de hachage, laissant la place à un attaquant pour forger pvi avec des propriétés intéressantes.
Cette preuve de concept implémente la faiblesse décrite dans la 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.
Avec Mallory comme attaquant actif, l'échange DH ci-dessus devient :
Bob Mallory Alice
| | Commit (Alice's ZID...) |
| |<------------------------|
| Commit (Alice's ZID...) | |
|<------------------------| |
| | |
| DHPart1 (pvr...) | |
|------------------------>| |
| | DHPart1 (pvr'...) |
| |------------------------>|
| | DHPart2 (pvi...) |
| |<------------------------|
| * SAS(Mallory, Alice) est connu à ce moment * |
| * trouvez un pvi' tel que SAS(Bob, Mallory) * |
| * soit égal à SAS(Mallory, Alice) * |
| DHPart2(pvi'...) | |
|<------------------------| |
| * SAS(Mallory, Bob) = SAS(Alice, Mallory) * |
| * Les deux parties confirmeront partager la même * |
| * valeur SAS * |
| * Notez que le matériel SRTP (Alice, Mallory) ne * |
| * correspondra pas au matériel SRTP (Mallory, Bob)* |
| * Cependant, Mallory pourra gérer les flux SRTP * |
| * de Bob et Alice, offrant des capacités * |
| * d'interception et de falsification. * |
Il est construit sur Python3 et asyncio. Les paquets IP bruts sont capturés à l'aide d'une socket PF_PACKET, en écoutant uniquement les trames IPv4. Scapy aide à disséquer les trames brutes. Il analyse les paquets ZRTP et les réécrit, en particulier, il recalcule les balises d'authentification HMAC.
Le brute-forceur SAS est basé sur C et prend en entrée :
Hello of responder || Commit || DHPart1DHPart1Construisez l'image docker avec cd mitm-bzrtp && docker build -t mitm-bzrtp . && cd ...
L'attaque de l'homme du milieu sera mise en place à l'aide de :
Alice et Bob échangeront via Mallory, qui effectue opportunément une attaque de l'homme du milieu.
Cela revient à tester différents svi et vérifier si le SAS dérivé correspond au SAS déjà obtenu. Tous les détails sanglants se trouvent dans la source du brute-force.
Les messages ZRTP sont authentifiés à l'aide d'une chaîne inversée de hachages itérés comme clés. Si DHPart2 est modifié à la volée par Mallory, Alice détectera le DHPart2 modifié de Mallory comme non authentique, car le HMAC calculé ne correspondra pas au HMAC reçu. Pour réussir cette vérification, Mallory doit utiliser une chaîne complète de hachages itérés, et elle doit signer tous les messages envoyés avec cette chaîne.