Azimuth Security: Attacking Crypto Phones: Weaknesses in ZRTPCPP <body onload='MM_preloadImages(&apos;;,&apos;;,&apos;;,&apos;;)'><script type="text/javascript"> function setAttributeOnload(object, attribute, val) { if(window.addEventListener) { window.addEventListener('load', function(){ object[attribute] = val; }, false); } else { window.attachEvent('onload', function(){ object[attribute] = val; }); } } </script> <div id="navbar-iframe-container"></div> <script type="text/javascript" src=""></script> <script type="text/javascript"> gapi.load("", function() { if (gapi.iframes && gapi.iframes.getContext) { gapi.iframes.getContext().openChild({ url: '\075509652393303233687\46blogName\75Azimuth+Security\46publishMode\75PUBLISH_MODE_HOSTED\46navbarType\75BLUE\46layoutType\75CLASSIC\46searchRoot\75\46blogLocale\75en\46v\0752\46homepageUrl\75\46vt\0751038547295672672920', where: document.getElementById("navbar-iframe-container"), id: "navbar-iframe" }); } }); </script>
azimuth security services training resources about BLOG
project zeus
"You will not be informed of the meaning of Project Zeus until the time is right for you to know the meaning of Project Zeus."
Current Posts
April 2010
May 2010
August 2010
September 2012
February 2013
March 2013
April 2013
May 2013
June 2013
December 2013
March 2014
Attacking Crypto Phones: Weaknesses in ZRTPCPP
Attacking Crypto Phones: Weaknesses in ZRTPCPP
posted by Mark @ 6/27/2013 09:08:00 AM  

In the wake of the recent NSA / Prism debacle, there has been a large push for secure, encrypted communications for the average user. This essentially means employing cryptography solutions in order to protect private communications from eavesdroppers (government or otherwise). Whilst this is a very positive course of action that user's can undertake, it makes sense to perform some evaluation of the security products upon which your communications are entrusted - does the attack surface change? Are there new avenues of exposure that didn't previously exist? With this in mind, I decided to take a brief look at the GNU ZRTPCPP library (, which is a core security component of various secure phone solutions (perhaps most notably, the impressive SilentCircle suite of applications). This blog post discusses several vulnerabilities that were uncovered in this initial audit. Note that these vulnerabilities can be triggered by un-authenticated, untrusted, remote parties, and affects the following software:

* SilentCircle (SilentPhone)
* CSipSimple
* Some of the Ostel clients (they use CSipSimple)
* LinPhone
* Twinkle
* Anything using the GNU ccRTP with ZRTP enabled

.. and possibly others. These vulnerabilities were recently reported by Azimuth to ZRTPCPP author/maintainer Werner Dittman who turned around fixes in a very short space of time, and also co-ordinated with some of the other vendors mentioned above. The remainder of this blog outlines some of the most major issues that were uncovered.

(UPDATE: The github now contains the fixes for these bugs, and SilentCircle has made their updates available via Google/Apple's app-stores).

The ZRTP protocol, which was originally designed by PGP creator Phil Zimmermann, is an addition to the Real-time Transport Protocol (RTP), and is intended to provide the ability for establishing Secure RTP (SRTP) sessions between users. ZRTP seeks to negotiate and establish a cryptographically secure, authenticated channel over the pre-established RTP connection, rather than using out-of-band channels such as SIP. The ZRTPCPP library, now part of GNU's secure telephony stack, implements the ZRTP protocol and is utilized by several securephone solutions, as previously mentioned. Here, we briefly discuss the issues uncovered in this library, which can be combined to attack the aforementioned software and potentially allow remote, arbitrary code execution by attackers on vulnerable installations. Each of the vulnerabilities described will be considered seperately.

Vulnerability 1. Remote Heap Overflow

The ZRtp::storeMsgTemp() function is used to temporarily hold a packet in memory so that it may later be hashed/verified. A buffer overflow exists in this function due to a lack of bounds checking of the size of the source buffer. The vulnerable function (from src/ZRtp.cpp) is shown.

void ZRtp::storeMsgTemp(ZrtpPacketBase* pkt) {
  int32_t length = pkt->getLength() * ZRTP_WORD_SIZE;
  memset(tempMsgBuffer, 0, sizeof(tempMsgBuffer));
  memcpy(tempMsgBuffer, (uint8_t*)pkt->getHeaderBase(), length);
  lengthOfMsgData = length;

In the above code, the destination buffer where data is being copied to is tempMsgBuffer - a statically-size 1024 byte buffer on the heap (part of the ZRtp instance). If an attacker sends a packet larger than 1024 bytes that gets stored temporarily (which occurs many times - such as when sending a ZRTP Hello packet), a heap overflow will occur, leading to potential arbitrary code execution on the vulnerable host.

Vulnerability 2. Multiple Stack Overflows

ZRTPCPP contains multiple stack overflows that arise when preparing a response to a client's ZRTP Hello packet. Specifically, the ZRtp::prepareCommit() function (src/ZRtp.cpp) calls the following functions, each of which contains the same flaw:


Each of these functions attempts to match a proposed algorithm/cipher/hash with those that have been pre-configured and supported by the responder's side. Some example code from ZRtp::findBestPubKey() is shown.

AlgorithmEnum* ZRtp::findBestPubkey(ZrtpPacketHello *hello) {
    int i;
    int ii;
    int numAlgosOffered;
    AlgorithmEnum* algosOffered[ZrtpConfigure::maxNoOfAlgos+1];
    int numAlgosConf;
    AlgorithmEnum* algosConf[ZrtpConfigure::maxNoOfAlgos+1];
    bool mandatoryFound = false;
    int num = hello->getNumPubKeys();

    if (num == 0) {
        return &zrtpPubKeys.getByName(mandatoryPubKey);

    ... fill out algosConf according to configuration ...

    // Build list of offered known algos in Hello, append mandatory algos if necessary
    mandatoryFound = false;
    for (numAlgosOffered = 0, i = 0; i < num; i++) {
        algosOffered[numAlgosOffered] = &zrtpPubKeys.getByName((const char*)hello->getPubKeyType(i));
        if (!algosOffered[numAlgosOffered]->isValid())
        if (*(int32_t*)(algosOffered[numAlgosOffered++]->getName()) == *(int32_t*)mandatoryPubKey) {
            mandatoryFound = true;

    if (!mandatoryFound) {
        algosOffered[numAlgosOffered++] = &zrtpPubKeys.getByName(mandatoryPubKey);

In the above code, it can be seen that each valid algorithm offered in the sender's ZRTP Hello packet is added to the algosOffered array. The flaw here is that ZrtpConfigure::maxNoOfAlgos is defined as 7 (as per the ZRTP specification dictates), meaning that algosOffered has 8 array slots in total. However, the count of public keys specified in the Hello packet is 4 bits, allowing the client to specify a maximum of 15 keys rather than 7. By taking advantage of this, a stack overflow may be triggered. Due to the technical constraints of this vulnerability, it is unlikely that these are exploitable beyond a crash, but further investigation would be required to confirm this.

* Note: ZRtp::findBestSASType() doesn't exactly have this flaw, due to what I believe is a functionality bug in the loop where it writes out the offered algorithms. This code is as follows.

    // Build list of offered known algos in Hello, append mandatory algos if necessary
    for (numAlgosOffered = 0, i = 0; i < num; i++) {
        algosOffered[numAlgosOffered] = &zrtpSasTypes.getByName((const char*)hello->getSasType(i++));
        if (!algosOffered[numAlgosOffered]->isValid())
        if (*(int32_t*)(algosOffered[numAlgosOffered++]->getName()) == *(int32_t*)mandatorySasType) {
            mandatoryFound = true;

Quite simply, the counter variable i is incremented twice in each iteration of the loop, which I believe to be a mistake.

Vulnerability 3. Information Leaking / Out of Bounds Reads

The ZRTPCPP library performs very little validation regarding the expected size of a packet versus the actual amount of data received. This can lead to both information leaking and out of bounds data reads (usually resulting in a crash).

Information leaking can be performed for example by sending a malformed ZRTP Ping packet. Ping packets usually have the following format:

 * Ping message.
 * The Ping message has a fixed size.

typedef struct Ping {
    uint8_t version[ZRTP_WORD_SIZE];    ///< The ZRTP protocol version
    uint8_t epHash[PING_HASH_SIZE];     ///< End point hash, see chap 5.16
} Ping_t;

 * The complete ZRTP Ping message.

typedef struct PingPacket {
    zrtpPacketHeader_t hdr;         ///< ZRTP Header
    Ping_t ping;                    ///< Ping message part
    uint8_t crc[ZRTP_WORD_SIZE];    ///< CRC of ZRTP message
} PingPacket_t

However, consider the case where we send one that consists of just a header and a checksum (i.e. the checksum immediately follows the ZRTP header where the version should be, and no epHash is present). No length check is performed to ensure a Ping packet is the required size, so sending such a packet will not raise an error. The following response is then created in ZrtpStateClass::processEvent() (src/ZrtpStateClass.cpp):

        else if (first == 'p' && middle == ' ' && last == ' ') {
            ZrtpPacketPing ppkt(pkt);
            ZrtpPacketPingAck* ppktAck = parent->preparePingAck(&ppkt);

The packet is immediately given to the ZRtp::preparePingAck() function, which is returned to the client:

ZrtpPacketPingAck* ZRtp::preparePingAck(ZrtpPacketPing* ppkt) {
    // Because we do not support ZRTP proxy mode use the truncated ZID.
    // If this code shall be used in ZRTP proxy implementation the computation
    // of the endpoint hash must be enhanced (see chaps 5.15ff and 5.16)

    return &zrtpPingAck;

The getEpHash() function retrieves the 8-byte hash from the Ping packet, which in this case is pointing to uninitialized heap memory after the end of the shortened Ping packet. It will transmit this data back to the sender. Using this vulnerability allows the attacker to discover useful pointers and heap state, and could be used in conjunction with the aforementioned heap overflow to gain reliable code execution. In addition, it could possibly be used to leak sensitive crypto-related data, although the extent of how useful this is has not been investigated.

In addition to the flaw mentioned above, you will note that most ZRTP packets perform little or no validation on the length of data they have received, but rather access fields in much the same way the Ping packet processing does. In most cases, this doesn't seem to be overly useful except to cause a crash, but further investigation might yield alternative information leaking/attack scenarios.

In conclusion, this is only an initial analysis of a minor component of these solutions. It would be beneficial for the security community to undertake further study of some of these products. I know I will be spending some more time here :)


At June 27, 2013 at 9:29 AM , Anonymous botnetzprovider said...

Any alternatives to use on Android phone which is secure?

At June 27, 2013 at 9:52 AM , Blogger Essobi said...

Nothing is secure. Trust no one.

At June 27, 2013 at 7:50 PM , Anonymous Anonymous said...

Interesting decision - let me ask you a couple of questions. Did you notice any repetition or base similarities in any of the "bugs?" Just curious, or were they all different? Would these "bugs" cause the possibility of external access from other then the end user? You do not have to identify the vendors in any way, of course, which would not be a cross-odds with your decision. Please publish your answer here.

At June 27, 2013 at 10:46 PM , Blogger Mark said...


The bugs were fairly standard memory corruption-style vulnerabilities. These have occurred in most major products at various stages of their existence. Successful exploitation of such bugs typically result in getting code execution access on the host running the vulnerable software. The extent of that access in this case would be determined by what sandboxes are in place within the target app - phone apps would be more restricted that PC-based ones in most cases, but you would still be able to have access to the decrypted conversations and so forth (as well as having a launching pad for escalating privileges on the system using a kernel vulnerability or similar).

At June 28, 2013 at 1:48 AM , Anonymous Anonymous said...

Thank you

At June 29, 2013 at 12:13 PM , Anonymous Anonymous said...

On Android you can use RedPhone by Open Whisper Systems

At June 30, 2013 at 8:59 AM , Anonymous Anonymous said...

Hi, Csipsimple also updated the zrtpcpp library to the last version containing the fix, it's on the csipsimple nightly version now, and I guess a new version should reach Google Play soon.

At September 7, 2013 at 3:06 AM , Blogger albina N muro said...

In the wake of the recent NSA / Prism debacle, there has been a large push for secure, encrypted communications for the average user. This essentially means employing cryptography solutions in order to protect private communications from eavesdroppers (government or otherwise). server safe

At March 9, 2014 at 9:43 PM , Anonymous Anonymous said...

I am using server on my own server and works ok. Better use your own server, instead of third party ones

Post a Comment

Subscribe to Post Comments [Atom]

<< Home

© Copyright 2013 Azimuth Security Pty Ltd