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."

Archives Current Posts April 2010 May 2010 August 2010 September 2012 February 2013 March 2013 April 2013 May 2013 June 2013 December 2013 March 2014 January 2015 Posts Attacking Crypto Phones: Weaknesses in ZRTPCPP Attacking Crypto Phones: Weaknesses in ZRTPCPP



* 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:

ZRtp::findBestSASType()* ZRtp::findBestAuthLen() ZRtp::findBestCipher() ZRtp::findBestHash()

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()) continue; 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()) continue; if (*(int32_t*)(algosOffered[numAlgosOffered++]->getName()) == *(int32_t*)mandatorySasType) { mandatoryFound = true; } } 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 (https://github.com/wernerd/ZRTPCPP), 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.Thefunction 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) is shown.In the above code, the destination buffer where data is being copied to is- a statically-size 1024 byte buffer on the heap (part of theinstance). 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.ZRTPCPP contains multiple stack overflows that arise when preparing a response to a client's ZRTP Hello packet. Specifically, the ZRtp::prepareCommit() function () 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 fromis shown.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 thatis defined as 7 (as per the ZRTP specification dictates), meaning thathas 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: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.



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); parent->sendPacketZRTP(static_cast(ppktAck)); parent->synchLeave(); return; }



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) zrtpPingAck.setLocalEpHash(zid); zrtpPingAck.setRemoteEpHash(ppkt->getEpHash()); zrtpPingAck.setSSRC(peerSSRC); 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 :) Quite simply, the counter variable i is incremented twice in each iteration of the loop, which I believe to be a mistake.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: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 nois 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):The packet is immediately given to thefunction, which is returned to the client:Thefunction 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 :) 10 comments: Subscribe to Post Comments [Atom] << Home