
Prueba de concepto del exploit para CVE-2016-6271 que demuestra un ataque de hombre en el medio en ZRTP mediante la omisión del compromiso hash en libbzrtp, con simulación basada en Docker y fuerza bruta de SAS.
CVE-2016-6271 afecta a libbzrtp, una librería ZRTP desarrollada por Belledonne Communications.
Esta librería está integrada en aplicaciones de usuario final, por ejemplo linphone, que está disponible como aplicación para Android en Play store. La versión actual 3.2.7 incluye una versión de libbzrtp que no debería ser vulnerable a 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 es una solución para asegurar llamadas de voz sobre IP.
Lo siguiente es un extracto del 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.
Para resumir:
Un agente ZRTP vulnerable se compila a partir de un único archivo 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);
}
Para disfrutarlo, construye la imagen Docker con cd vulnerable-bzrtp && docker build -t vulnerable-bzrtp .. Ten en cuenta que el Dockerfile define start.sh como entrypoint, que establece el enrutamiento a través de Mallory; más sobre esto más adelante.
Divulgada el 30 de marzo de 2016 a Belledone Communications, esta vulnerabilidad fue corregida rápidamente con este commit.
ZRTP realiza Diffie-Hellman en dos mensajes llamados DHPart1 y DHPart2. Bob compromete el mensaje DHPart2 que enviará después de recibir el DHPart1 de Alice.
| Commit (Bob's ZID, options, hash value) F5 |
|<--------------------------------------------------|
| F6 DHPart1 (pvr, shared secret hashes) |
|-------------------------------------------------->|
| DHPart2 (pvi, shared secret hashes) F7 |
|<--------------------------------------------------|
La vulnerabilidad descubierta en bzrtp es la ausencia de verificación del hash commitment, dejando espacio para que un atacante forje pvi con propiedades interesantes.
Esta prueba de concepto implementa la debilidad descrita en 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.
Con Mallory como atacante activo, el intercambio DH anterior se convierte en:
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. * |
Está construido con Python3 y asyncio. Los paquetes IP crudos se capturan usando un socket PF_PACKET, escuchando solo tramas IPv4. Scapy ayuda a diseccionar las tramas crudas.
Analiza los paquetes ZRTP y los reescribe; en particular, recalcula las etiquetas de autenticación HMAC.
El bruteforcer de SAS está basado en C y toma como entrada:
Hello of responder || Commit || DHPart1DHPart1Construye la imagen Docker con cd mitm-bzrtp && docker build -t mitm-bzrtp . && cd ...