Showing posts sorted by relevance for query facebook messenger. Sort by date Show all posts
Showing posts sorted by relevance for query facebook messenger. Sort by date Show all posts

Thursday, March 7, 2019

Android Messaging: A Few Bugs Short of a Chain

Posted by Natalie Silvanovich, Project Zero

About a year and a half ago, I did some research into Android messaging and mail clients. At the time, I didn’t blog about it, because though I found bugs, I wasn’t able to assemble them into a credible attack. However, in the spirit of writing about research that didn’t go as expected, I have decided to share it now. I think there is something interesting to learn about the impact of design choices on security from this research.

Applications Reviewed
I reviewed the following applications: Messages (the default Android SMS application), Gmail for Android, Microsoft Outlook, Facebook Messenger, WhatsApp, Signal and Telegram, which represent some of the most popular messaging and mail apps on Google Play.

Architecture, Attack Surface and Test Set-up
At a high level, messaging clients have a similar architecture. They communicate with a server that is responsible for locating the recipient that a user wants to communicate with and generally maintains the messaging session. Messages are also transmitted through the server, and clients that support end-to-end encryption can include some sort of encrypted envelope in these messages, that are passed directly to the recipient.

Though their protocols differ substantially, Facebook Messenger, WhatsApp and Telegram all use a layered approach, where messages can contain fields of different types with a hierarchy.  Telegram’s protocol is documented publicly. A single message can include pieces for both the server and the receiving client.

I started by looking at how unencrypted messages were handled by Facebook messenger, but this turned out to be a challenging attack surface. There were many protocols that could be used to send messages (such as mobile and web APIs), but then they were processed substantially before the message was received by the target device. This made it difficult to know whether any attack surface in the client was reachable. Therefore, I decided to focus on encrypted messages, as the server is not able to filter those.

I did not have the source for Facebook Messenger or WhatsApp, so I was only able to analyze the smali extracted from the APKs for these applications with apktool. The popularity of signal protocol simplified finding the encryption portion of these applications, as I was able to search for strings in libsignal. I then added a function that sent each message to a server I control and gave me the option to alter it before encrypting it. This gave me the ability to test malformed encrypted  messages.

Testing the mail and SMS clients were easier. For the Messaging app, I sent raw SMS messages using the sendDataMessage API from an app I wrote for an Android device. For the mail clients, I sent MIME messages directly using an SMTP server.  

Results Overview
Please note that these results are over a year old, and messaging clients have high code churn, so the clients may be different now. All the vulnerabilities discussed in this section have been fixed.

Messages


The default Android Messages app is largely written in Java, and uses the AOSP SMS and MMS processing to parse messages. It has a fairly low risk of memory corruption vulnerabilities due to this. Android processes some special SMS messages differently, which increases the risk of receiving these messages. Some messages are interpreted as OMTP for Visual Voicemail messages, but the processing of these messages, as well as the IMAP functionality used by Visual Voicemail are implemented in Java and contain the minimum necessary functionality. Android once supported SUPL (an SMS protocol for GPS ephemeris updates) parsing in the user space as well, and the intent handlers for it are still in the SMS stack. However, Qualcomm’s baseband handles these messages directly now, so they will not make it to the user space on newer devices. The main risk of vulnerabilities in the Messages app is the libraries used to process incoming media files. Many vulnerabilities have been discovered in these components in the past, though fewer have been reported recently, and media is processed by a low-privileged process. I did not find any vulnerabilities in Messages.

Gmail


The Gmail app processes MIME messages provided by an IMAP, POP or other server. The contents of the MIME message usually comes directly from another user, though mail servers sometimes do some filtering. Gmail uses some underlying mail APIs in AOSP, and both the application and the underlying APIs are implemented entirely in Java. I reported one directory traversal issue in Gmail due to attachment downloads.

Outlook


The Microsoft Outlook app is similar to the Gmail app in functionality. It also processes MIME provided by another server, however all of its protocol processing is done by code within the app. The application is written mostly in Java, and the existing native functionality is used for metrics and other features not related to mail. I reported a directory traversal issue similar to the one in Gmail in Outlook.

Facebook Messenger


Facebook Messenger is a large application compared to the other messaging applications I reviewed, and it was difficult to determine the functionality of a lot of the code. It contains a large number of native libraries, which are updated dynamically from the Facebook server on a nearly daily basis. Few of them seemed to be directly involved processing messages, though.

Facebook messenger communicates with the server using a protocol called Messaging Queue Telemetry Transport (MQTT). Underneath the MQTT is the thrift protocol, which is open source. The application contains both the Java and C++ version of the library, but only the Java one appears to be used. I reviewed these protocols, but did not find any vulnerabilities affecting Facebook Messenger.

WhatsApp


WhatsApp uses a layered protocol that is mostly implemented in Java. A small amount of message handling code used to process voice and video call requests is implemented in native code, which I discussed in this post. I did not find any vulnerabilities in WhatsApp messaging

Telegram


Telegram is open source and its APIs are publicly documented. It contains a fair amount of native code, but the code is mostly used to process device-to-server messages, as opposed to device-to-device messages. The attack surface available to a remote attacker is almost entirely in Java. I found one vulnerability in Telegram, which was also a directory traversal vulnerability related to attachments.

Signal


Signal is largely implemented in Java, and has a fairly small attack surface. Its protocols are well documented. I did not find any vulnerabilities in Signal.

Do These Bugs Matter?
Overall, I found three directory traversal vulnerabilities in these clients. They were surprisingly similar, all related to attachment names being allowed to contain special characters when they are downloaded. Directory traversal issues are fairly common in Android applications, likely in part due to how forgiving Java APIs are with regards to file names.

These bugs had some limitations though. To start, the bugs in the Gmail and Outlook mail clients only work when the client is being used with non-standard email addresses (i.e. Gmail is being used with a non-Gmail account or Outlook is being used with a non-Outlook email address). Both of these clients are widely used for this purpose, but this does mean these bugs will not impact every user. The bugs also require the user to download an attachment.

But there are also some limitations that affect exploitability. To start, none of these issues can overwrite a file that exists, they can only write a new file. So there needs to be somewhere an attacker can place a file that is processed by the system, but does not already exist. Secondly, applications on Android have limited permissions, and typically cannot write outside of their application directory.

The Telegram issue probably is exploitable, as there happened to be a configuration file that did not exist by default, but Telegram would process it if it existed, and the processing code had a memory corruption vulnerability in it. I couldn’t find anything like this for the mail clients, though.

One idea I had was to look for a vulnerability in SQLite, as Gmail and Outlook use SQLite databases to store a variety of data. SQLite supports journaling, which means that when a SQLite database is changed, a journal file is written first, so that if the system crashes or loses power during the write, the database is not corrupted. If this occurs, the journal file will exist the next time the database is accessed, and SQLite knows to restore it. Otherwise, the journal file will be deleted when the write is completed successfully. This means that a SQLite database can be altered by writing a journal file with a specific name in the same directory, and this file does not generally already exist.

I tried this, and was able to alter databases, but none of them seemed to allow me to escalate privileges or perform unpermitted operations other than altering what mail a user sees in the app. Looking for something more generic, I considered the possibility of finding a bug in how SQLite parses journal files or database files.

I fuzzed both database loading and journal handling using AFL. I found four bugs, three of which I think are unexploitable, and one which is very borderline in terms of exploitability.

I could not find any more ways to exploit a directory traversal that cannot overwrite a file in an Android application, so I’m not convinced that these directory traversal attacks would be especially valuable to attackers.

Conclusion
I reviewed several Android messaging and mail applications. I found three directory traversal bugs, but these bugs had some limitations, and it is not clear if this type of bug is exploitable in the generic case.

These bugs were very similar, and point to challenges in correctly handling file paths in Android Java. The two bugs in the mail clients only occurred when the application was used with an email address which is not managed by the maker of the application, despite it being a common use case,  which suggests this could be an under-tested or under-reviewed feature of mail clients. For the most part, these clients were implemented in Java, which made it more difficult to find bugs in them, as memory corruption attacks were not available.

This research focused on the portions of mail and messages that are not processed by an intermediary server, and therefore allow an attacker to send any data to be processed without filtering. While the easiest to attack, these features are only a part of the attack surface of a messaging or mail client. I will likely investigate the server-mediated features of messaging clients in the future.

Tuesday, January 19, 2021

The State of State Machines

Posted by Natalie Silvanovich, Project Zero

On January 29, 2019, a serious vulnerability was discovered in Group FaceTime which allowed an attacker to call a target and force the call to connect without user interaction from the target, allowing the attacker to listen to the target’s surroundings without their knowledge or consent. The bug was remarkable in both its impact and mechanism. The ability to force a target device to transmit audio to an attacker device without gaining code execution was an unusual and possibly unprecedented impact of a vulnerability. Moreover, the vulnerability was a logic bug in the FaceTime calling state machine that could be exercised using only the user interface of the device. While this bug was soon fixed, the fact that such a serious and easy to reach vulnerability had occurred due to a logic bug in a calling state machine -- an attack scenario I had never seen considered on any platform -- made me wonder whether other state machines had similar vulnerabilities as well. This post describes my investigation into calling state machines of a number of messaging platforms, including Signal, JioChat, Mocha, Google Duo, and Facebook Messenger.

WebRTC and State Machines

The majority of video conferencing applications are implemented using WebRTC, which I’ve discussed in several past blog posts.  WebRTC connections are created by exchanging call set-up information in Session Description Protocol (SDP) between peers, a process which is called signalling. Signalling is not implemented by WebRTC, which allows peers to exchange SDP in whatever secure communication message is available to them, usually WebSockets for web applications, and secure messaging for messaging applications.

There are a few types of SDP that can be exchanged by WebRTC peers. In a typical connection, the caller starts off by sending an SDP offer, and then the callee responds with an SDP answer. These messages contain most information that is needed to transmit and receive media, including codec support, encryption keys and much more. After the offer/answer exchange, peers can send SDP candidates to other peers. Candidates are potential network paths that the two peers can use to connect to each other, and SDP candidates contain information such as IP addresses and TURN servers. Peers usually send more than one candidate to a peer, and candidates can be sent at any time during a connection.

WebRTC connections maintain an internal state related to whether an offer or answer has been received and processed, however, applications that use WebRTC usually have to maintain their own state machine to manage the user state of the application. How the user state maps to the WebRTC state is a design choice made by the WebRTC integrator, which has both security and performance consequences. For example, some applications do not exchange any SDP until the callee user has interacted with the application to answer the call, meanwhile others set up the peer-to-peer connection, and start sending audio and video from caller to callee before the callee is even notified of the call.

Regardless of design, transmitting audio or video from an input device must be directly enabled by application code using WebRTC. This is usually done using a feature called tracks. Every input device is considered a ‘track’, and each specific track must be added to a specific peer connection by calling addTrack (or language equivalent) before audio or video is transmitted. Tracks can also be disabled, which is useful for implementing mute and camera-off features. Each track also has an RTPSender property that can be used to fine-tune the properties of transmission, which can also be used to disable audio or video transmission.

Theoretically, ensuring callee consent before audio or video transmission should be a fairly simple matter of waiting until the user accepts the call before adding any tracks to the peer connection. However, when I looked at real applications they enabled transmission in many different ways. Most of these led to vulnerabilities that allowed calls to be connected without interaction from the callee.

Signal Messenger

I looked at Signal in September 2019, and at that time, the application had a calling setup that is very similar to what is recommended in WebRTC documentation.

A peer-to-peer connection is established, and then the callee's audio track is added to the connection when the callee accepts the call by interacting with the user interface. Then a message is sent to the caller via the peer-to-peer connection, telling it to also move to the connected state and add the track.

Unfortunately, the application didn’t check that the device receiving the connect message was the caller device, so it was possible to send a connect message from the caller device to the callee. This caused the audio call to connect, allowing the caller to hear the callee’s surroundings. I tested this bug by changing Signal’s open-source code to send the message and recompiling the attacking client.

This vulnerability was fixed in the client in September 2019, and since then, Signal’s signalling code has been replaced by the ringrtc project, which uses a more conservative state machine.

This bug was purely in Signal’s code, and was not due to a misunderstanding of WebRTC functionality. The state machine design was largely effective requiring user consent to transmit audio, but a specific check was not implemented.

JioChat and Mocha

I accidentally found two very similar vulnerabilities in JioChat and Mocha messengers in July 2020 while testing whether a WebRTC exploit would work on them. They both had a similar signalling design, which was server-mediated.

The offer and answer are exchanged via the server, and then both the caller and the callee send their candidates to the server. The server then stores them until the callee interacts with their device and accepts the call. Then the peer-to-peer connection is created, and when WebRTC enters into its internal connected state, the track is added, causing audio and video to be transmitted.

This design has a fundamental problem, as candidates can be optionally included in an SDP offer or answer. In that case, the peer-to-peer connection will start immediately, as the only thing preventing the connection in this design is the lack of candidates, which will in turn lead to transmission from input devices. I tested this by using Frida to add candidates to the offers created by each of these applications. I was able to cause JioChat to send audio without user consent, and Mocha to send audio and video. Both of these vulnerabilities were fixed soon after they were filed by filtering SDP on the server.

These issues were caused by a misunderstanding of how WebRTC works coupled with an attempt to improve WebRTC performance with an unusual signalling design. Normally, WebRTC integrators have to decide whether to wait until the callee has answered the call to set up the peer-to-peer connection. Setting the connection up early improves performance and prevents the user from having to wait when they answer a call, but also greatly increases the remote attack surface of WebRTC. These applications tried to improve performance without the security cost with this design, but didn’t consider all the ways that WebRTC can start a peer-to-peer connection.

It is generally not a good idea for integrators to gate audio or video transmission on any WebRTC feature that is not adding or enabling tracks. To start, many WebRTC features are complex, so it is easy to make a mistake that allows audio or video to be transmitted. Also, if the feature that is gated on is not commonly-used or not a security feature, it could be poorly tested or changed in the future.

Duo

I looked at Google Duo in September 2020. Duo’s signalling methodology is somewhat different from a lot of messengers because it supports a feature that allows the callee to preview the caller’s video before answering. So a one-way video stream needs to be set up before the call is answered.

The image above shows the setup of the one-way video stream. Dotted lines represent asynchronous calls made using Java executors. The lack of transmission from callee to caller is enforced by two methods. First, the SDP offer contains the property a=sendonly for video, which causes video to only be transmitted in one direction. Also, when the callee receives the offer from the caller, it adds the video track to the peer connection, but then disables it using the RTPSender property of the track (the audio track is not added or enabled until the user accepts the call).

Neither of these methods effectively prevents video from being transmitted from callee to caller. The SDP property is easy to get around because the caller provides the SDP to the callee, so it can be easily altered. Disabling the video track as soon as the offer is processed should work, except for the asynchronous design. Normally, the setLocalDescription method (which processes the SDP offer) calls the callback onSetSuccess, and then sets up the peer-to-peer connection after the callback has finished. However, if the callback makes another asynchronous call, the guarantee that onSetSuccess finishes before the connection is set up no longer holds, because the setLocalDescription method only waits for the onSetSuccess thread to finish. This creates a race between disabling the video and setting up the connection, so in some situations, the callee could transmit a few video frames to the caller before transmission is disabled.

I tested this by using Frida to alter the SDP sent by the callee, and then I tried many methods to win the race. It turned out to be fairly hard to win, and I spent roughly two weeks trying to figure out how to slow down the video disable call enough to give the connection time to set up. I ended up sending multiple offers and adding candidates to the offers, which decreased the connection time, as the network connection was already established. Then I sent many messages that take a long time to process through the data channel of the peer-to-peer connection to slow down the disabling of the video track. Data messages are processed on the same thread queue as disabling the video track in Duo, so sending data messages filled up the queue that was needed to disable video with many other entries, delaying the track being disabled.

This bug was fixed in December 2020 by removing the asynchronous call from onSetSuccess. While Duo generally designed signalling in a way that is effective in preventing video transmission from callee to caller, implementing the design asynchronously introduced problems. Asynchronous signalling implementations are becoming more common on mobile applications, as there are many unpredictable situations in which WebRTC needs to wait on the network or a peer, and separating function calls into different threads means a delay in one call won’t affect unrelated functionality. However, asynchronous calls make it more difficult to model how a state machine will behave in all situations, so it is important to be cautious about adding asynchronous calls to WebRTC signalling. In this case, the asynchronous call to disable the video track added nothing in terms of performance, as there is no reason any of the calls made to disable the track could block, and onSetSuccess already runs in its own thread and can yield to higher priority threads. It’s important to balance the risk and benefit of asynchronous calls and not indiscriminately include them in an application.

Facebook Messenger

I looked at Facebook Messenger in October 2020. It was a fairly challenging target because of the amount of reverse engineering required. Stepping back a bit, WebRTC has bindings in several programming languages which allow it to be integrated into applications using that language. Most Android applications that integrate WebRTC use the Java bindings. This makes investigating signalling state machines fairly straightforward, as important Java functions, such as setLocalDescription (which processes offers and answers), addRemoteIceCandidate (which processes candidates) and addTrack (which adds tracks to connections) can be hooked in Frida and logged for analysis. It is also reasonably straightforward to change the behavior of the attacker device using these calls.

Facebook Messenger does not use Java bindings to integrate WebRTC, instead it uses C++ bindings. Moreover, it statically links WebRTC to a larger library (librtcR20.so, which is likely the rsys library mentioned in this article), so the symbols for calls to bindings get stripped, making them difficult to hook. In addition, Facebook Messenger serializes SDP into another format before it is transmitted, so it is difficult to determine how signalling works by monitoring traffic.

I eventually realized that the only reasonable way to figure out how Facebook Messenger signalling works was to figure out its network protocol. Thankfully, Facebook has publicly stated that they use fbthrift, a branch of thrift. I loaded the librtcR20.so library into IDA to see if I could find where it called into the thrift library, but while there were a few calls, it looked like the code was mostly statically linked. I eventually figured out that this is because thrift generates serialization code for every protocol implemented, so most of the serialization and deserialization code ends up compiled with the protocol processing code. So I decided to compile fbthrift, make a sample serializer and look at it in IDA, so I could get an impression of what compiled fbthrift serializers look like. I noticed that during serialization, members of an object are serialized by calling a method called writeFieldBegin. I also noticed that when this method is called, the field name is required, even though it is usually not included in the serialized output. So I looked for a function in librtcR20 that was very frequently called with different string parameters that seemed reasonable for field names. Not very many functions fulfilled that criteria, so I was able to identify writeFieldBegin.

At this point, I could find many places where objects are serialized, and needed to identify which one was the message used to set up WebRTC calls.

Earlier, I’d noticed a method in the library called P2PCall::OnP2PMessageFromPeer (note that the symbol for this method is stripped, but the method name is logged when it is called). This seemed a likely place that a deserialized message would be processed. Searching for the string “P2PMessage”, I found the serialization code for a type called P2PMessageRequest. I assumed that this was where call setup messages were created.

Thrift serialization code is generated based on class definitions in a thrift definition file. Based on the field names and types passed to writeFieldBegin, I was able to slowly reverse engineer the complete thrift definition for this type. It was tedious work, because the definition was fairly long, and the code is obfuscated in a way that makes register use inconsistent, so I wasn’t confident that any automated approach would be accurate.

Below is a sample of the serialization code.

Notice that it writes two fields from an object of type Extmap. The first, named id, is a mandatory field. The function that writes the code is as follows.

The field identifier written is 1, and the field type is 8, which translates to i32 (32-bit integer). The second field is an optional field, and the registers to write it are set in the following code.

This sets the field name to uri, the field identifier to 2, and the field type to 8 (also i32). All together, this code can be represented by the following thrift definition.

```

struct Extmap{

        1: i32 id

        2: optional i32 uri

}

```

After similarly reverse engineering every field of the P2PMessageRequest type, I had a complete thrift definition, available here.

I did two things with this thrift definition.  First, I used it to determine the layout of the P2PMessageRequest type in C++. This was extremely valuable, as it allowed me to load the struct definition into IDA with every single field named correctly. This made it much easier to understand how incoming messages are handled in P2PCall::OnP2PMessageFromPeer. This ended up being a bit of a process. fbthrift can generate C++ header files directly from a thrift definition, but these are very long and contain a lot of unnecessary definitions, and can not be processed by IDA. So I ended up compiling the generated source and loading it into IDA, and then exporting the structure definitions and importing them into another IDA instance where librtcR20.so was already loaded. A few fields had different sizes in my compilation versus Facebook’s, but it was close enough that I could get it to work with a few modifications.

Below is an example of code decompiled in IDA with the thrift definition imported, to give an idea of how much easier it makes it to understand the processing of the message object.

I was also able to decode and generate messages sent over the network. To do this, I generated the serialization code from the thrift definition in Python, as thrift supports code generation in many languages. Then, I was able to import this code when using Frida Python to hook functions in Facebook Messenger.

Then I needed to find the code that handled incoming P2PMessageRequest messages. Since these messages are handled by native code, meanwhile most Facebook messages are handled by Java code, I looked for a native call with an appropriate name. I found com.facebook.webrtc.WebrtcEngine.onThriftMessageFromPeer. I hooked this method with Frida, and fed its byte array parameter in the generated deserializer, and it decoded incoming messages.

I found a similar method used to send thrift messages, sendThriftToPeer (this method’s class name is obfuscated and changes in every version of Facebook Messenger, but it can be found by grepping the application’s smali). I was also able to hook this method, and alter its byte array parameter, to change a P2PMessageRequest message sent by Facebook Messenger.

Now, I was able to understand Facebook Messenger’s signalling state machine. There are two different ways that signalling can occur, depending on where the user is signed into Facebook Messenger. If the user is signed in on multiple devices or browsers, very little happens before the callee interacts with their device. The offer, answer and candidates are exchanged, but they are stored by the callee device and not processed until the callee user answers the call. This makes sense, because Facebook Messenger doesn’t know what device to connect to otherwise.

If the callee is only signed in on a single device, the state machine is more interesting.

In this case, Facebook Messenger enables the track as soon as an offer is received, but alters the offer so that all outgoing streams are inactive. It then replaces the offer with one where they are active when the user interacts with the device.

I was concerned that there might be a way to bypass the alteration of the offer, but I looked at how this was done, and while I generally don’t recommend using anything other than adding or disabling tracks to disable input device transmission, it was fairly robust. The offer is altered after the SDP is decoded into an internal WebRTC object, and the changes are made directly to this object, which eliminates the possibility of parsing errors.

However, looking at how incoming messages are handled, I noticed that many message types other than offers, answers and candidates are processed before the call is answered. One type that stood out was called SdpUpdate. When an SdpUpdate message is received, the local offer or answer is updated by calling setLocalDescription.

This message type didn’t do anything when sent to the state machine above, as it is already storing SDP and waiting to call setLocalDescription. But in the situation where the user is logged into two devices, it caused setLocalDescription to be called and started the audio connection.

It is not clear what the SdpUpdate message type is used for in Facebook Messenger. I tried many scenarios on my test devices, including network switchover, and was not able to generate one in normal use. Regardless, it is clear that it was not intended for this message type to be received before the call is answered. It is similar to the Signal bug described above, in that it is not related to the application’s use of WebRTC, but due to a missing check when handling input that can cause state transitions.

This vulnerability was fixed in November 2020 with server changes that prevent this message type from being sent before a call is connected.

Other Applications

There were a few other applications I looked at and did not find problems with their state machines. I looked at Telegram in August 2020, right after video conferencing was added to the application. I did not find any problems, largely because the application does not exchange the offer, answer or candidates until the callee has answered the call. I looked at Viber in November 2020, and did not find any problems with their state machine, though challenges reverse engineering the application made this analysis less rigorous than the other applications I looked at.

Discussion

The majority of calling state machines I investigated had logic vulnerabilities that allowed audio or video content to be transmitted from the callee to the caller without the callee’s consent. This is clearly an area that is often overlooked when securing WebRTC applications.

The majority of the bugs did not appear to be due to developer misunderstanding of WebRTC features. Instead, they were due to errors in how the state machines are implemented. That said, a lack of awareness of these types of issues was likely a factor. It is rare to find WebRTC documentation or tutorials that explicitly discuss the need for user consent when streaming audio or video from a user’s device.

Many of these state machines had needless complexity in how they handled call set-up, which was also a factor. Unnecessary threading, reliance on obscure features and large numbers of states and input types increase the likelihood of this type of vulnerability occurring in a signalling state machine.

It is also concerning to note that I did not look at any group calling features of these applications, and all the vulnerabilities reported were found in peer-to-peer calls. This is an area for future work that could reveal additional problems.

Conclusion

I investigated the signalling state machines of seven video conferencing applications and found five vulnerabilities that could allow a caller device to force a callee device to transmit audio or video data. All these vulnerabilities have since been fixed. It is not clear why this is such a common problem, but a lack of awareness of these types of bugs as well as unnecessary complexity in signalling state machines is likely a factor. Signalling state machines are a concerning and under-investigated attack surface of video conferencing applications, and it is likely that more problems will be found with further research.

Thursday, August 6, 2020

Exploiting Android Messengers with WebRTC: Part 3

Posted by Natalie Silvanovich, Project Zero


This is a three-part series on exploiting messenger applications using vulnerabilities in WebRTC. CVE-2020-6514 discussed in the blog post was fixed on July 14 with these CLs.This series highlights what can go wrong when applications don't apply WebRTC patches and when the communication and notification of security issues breaks down. 

Part 3: Which Messengers?

In Part 2, I described an exploit for WebRTC on Android. In this section, I explore which applications it works on.

The exploit

When writing the exploit, I originally altered the SCTP packets sent to the target device by altering the source of WebRTC and recompiling it. This wasn’t practical for attacking closed source applications, so I eventually switched to using Frida to hook the binary of the attacking device instead. Frida’s hooking functionality allows for code to be executed before and after a specific native function is called, which allowed my exploit to alter outgoing SCTP packets as well as inspect incoming ones. Functionally, it is equivalent to altering the source of the attacking client, but instead of the alterations being made in the source at compile time, they are made dynamically by Frida at run time. The source for the exploit is available here.

There are seven functions that the attacking device needs to hook, as follows.

usrsctp_conninput // receives incoming SCTP
DtlsTransport::SendPacket // sends outgoing SCTP
cricket::SctpTransport::SctpTransport // detects when SCTP transport is ready
calculate_crc32c // calculates checksum for SCTP packets
sctp_hmac // performs HMAC to guess secret key
sctp_hmac_m // signs SCTP packet
SrtpTransport::ProtectRtp // suppresses RTP to reduce heap noise

These functions can be hooked as symbols, or as offsets in the binary.

There are also three address offsets from the binary of the target device that are needed for the exploit to work.  The offset between the system function and the malloc function, as well as the offset between the gadget described in the previous post and the malloc function are two of these. These offsets are in libc, which is an Android system library, so they need to be determined based on the target device’s version of Android. The offset from the location of the cricket::SctpTransport vtable to the location of malloc in the global offset table is also needed. This must be determined from the binary that contains WebRTC in the application being attacked.

Note that the exploit scripts provided have a serious limitation: every time memory is read, it only works if bit 31 of the pointer is set. The reasons for this are explained in Part 2. The exploit script has an example of how to fix this and read any pointer using FWD_TSN chunks, but this is not implemented for every read. For testing purposes, I reset the device until the WebRTC library was mapped in a favorable location.

Android Applications

A list of popular Android applications that integrate WebRTC was determined by searching APK files on Google Play for a specific string in usrsctp. Roughly 200 applications with more than five million users appeared to use WebRTC. I evaluated these applications to determine whether they could plausibly be affected by the vulnerabilities in the exploit, and what the impact would be.

It turned out the ways applications use WebRTC are quite varied, but can be separated into four main categories.

  • Projection: the screen and controls of a mobile application is projected into a desktop browser with user consent for enhanced usability
  • Streaming: audio and video content is sent from one user to many users. Usually there is an intermediary server, so the sender does not need to manage possibly thousands of peers, and the content is recorded for later viewing
  • Browsers: all major browsers contain WebRTC to implement the JavaScript WebRTC API
  • Conferencing: two or more users communicate via audio or video in real time

The impact of the vulnerabilities used in the exploit is different for each of these categories. Projection is low risk, as a lot of user interaction is required to set up the WebRTC connection, and the user has access to both sides of the connection in the first place, so there is little to gain by compromising the other side. 

Streaming is also fairly low risk. While it’s possible that some applications use peer-to-peer connections when a stream has a low number of viewers, they usually use an intermediary server that terminates the WebRTC connection from the sending peer, and starts new connections with the receiving peers. This means that the attacker usually cannot send malformed packets directly to a peer. Even with a set-up where streaming is performed peer-to-peer, user interaction is required for the target to view the stream, and there’s often no way to limit who can access a stream. For this reason, streaming applications that use WebRTC are probably not useful for targeted attacks. Of course, it is possible that these vulnerabilities affect the servers used by streaming services, but this was not investigated in this research.

Browsers are almost certainly vulnerable to most bugs in WebRTC, because they allow a large amount of control over how it is configured. To exploit such a bug in a browser, an attacker would need to set up a host that acts like the other peer in the peer-to-peer connection, and convince the target to visit a webpage that starts a call to that host. In this case, the vulnerability would have a similar impact to other memory corruption vulnerabilities in JavaScript.

Conferencing is the highest risk usage of WebRTC, but the actual impact of a vulnerability depends on a lot of how users of an application contact each other. The highest risk design is an application where any user can contact any other user based on an identifier. Some applications require the callee to have interacted in a specific way with the caller before a call can be made, which makes users harder to contact a target and generally reduces risk. Some applications require users to enter a code or visit a link to start a call, which has a similar effect. There is also a large group of applications where it is difficult or impossible to call a specific user, for example chat roulette applications, and applications which have features that allow a user to start a call to customer support. 

For this research, I focused on conferencing applications that allow users to contact specific other users. This reduced my list of 200 applications to 14 applications, as follows.

Name
Installs on Play Store
1B
1B
1B
500M
100M
OK and TamTam (similar apps by same vendor)
100M/10M
100M
50M
10M
10M
10M
10M

This list was compiled on June 18, 2020. Note that a few applications were removed because their server was not operational on that day, or they were very difficult to test (for example, required watching multiple ads to make a single call).

One application tested will not be identified in this blog post, as a serious additional vulnerability was discovered in the process of testing that has not yet been fixed or reached its disclosure deadline. This blog post will be updated when the disclosure deadline has passed. Update (2020-10-14): The affected application was Mocha. We discovered this vulnerability.

Testing the Exploit

The following section describes my attempts to test the exploit against the above applications. Please note that due to the number of applications, limited time was spent on each, so there is no guarantee that every attack against WebRTC was considered. While I am very confident that applications found to be exploitable are indeed exploitable, I am less confident about applications found to be not exploitable. If you need to know whether a specific application is vulnerable for the purposes of protecting users, please contact the vendor instead of relying on this post.

Signal

I started off by testing Signal because it is the only open-source application on this list. Signal integrates WebRTC as a part of a library called ringrtc. I built ringrtc and then Signal with symbols, and then hooked the needed symbols with the Frida script on the attacker device. I tried the exploit and it worked about 90% of the time!




This attack did not require any user interaction with the target device because Signal starts the WebRTC connection before an incoming call is answered, and this connection can accept incoming RTP and SCTP. The exploit is not 100% reliable on Signal and other targets because Bug 376 requires that a freed heap allocation is replaced with the next allocation of the same size performed by the thread, and occasionally another thread will do an allocation of the same size in the meantime. Failure results in a crash that is usually not evident to the user because the process respawns, but a missed call will appear.

This exploit was performed on Signal 4.53.6 which was released on January 13, 2020, as Bug 376 had already been patched in Signal by the time I finished the exploit. CVE-2020-6514 was also fixed in later versions, and ASCONF has also been disabled in usrsctp, so the code that caused Bug 376 is no longer reachable. Signal has also recently implemented a feature that requires user interaction for the WebRTC connection to be started when the caller is not in the callee’s contacts. Signal has also stopped using SCTP in their beta version, and plans to add this change to the release client once it is tested. The source for this exploit is available here.

Google Duo


Duo was also an interesting target, as it is preinstalled on so many Android devices. It dynamically links the Android WebRTC library, libjingle_peerconnection_so.so with no obvious modifications. I reverse engineered this library in IDA to find the location of all the functions that needed to be hooked, and then modified the Frida script to hook them based on their offsets from an exported symbol. I also modified the offset between the cricket::SctpTransport vtable and the global offset table, as it was different than in Signal. The exploit also worked on Duo. Source for the Duo exploit is available here.



This vulnerability did not require any user interaction, as like Signal, Duo starts the WebRTC connection before a call is answered.

The exploit was tested on version 68.0.284888502.DR68_RC09 which was released on December 15, 2019. The vulnerability has since been fixed. Also, at the time this application was released, it was possible for Duo to call any Android device with Google Play Services installed, regardless of whether Duo had been installed. This is no longer the case. A user now needs to set up Duo and have the caller in their contacts for an incoming call to be received.

Google Hangouts


While Google Hangouts uses WebRTC, it does not use data channels, and does not exchange SDP in order to set up calls, so there is no obvious way to enable them from a peer. For that reason, the exploit does not work on Hangouts.

Facebook Messenger


Facebook Messenger is another interesting target. It has a large number of users, and according to its documentation, any user can call any other user based on their mobile number. Facebook Messenger integrates WebRTC into a library called librtcR11.so, which dynamically links to usrsctp from another library, libxplat_third-party_usrsctp_usrsctpAndroid.so. Facebook Messenger downloads these libraries dynamically as opposed to including them in the APK, so it is difficult to identify the version I examined, but it was downloaded on June 22, 2020. 

The librtcR11.so library appears to use a version of WebRTC that is roughly six years old, so it was before the class cricket::SctpTransport existed. That said, the analogous class cricket::DataMediaChannel appeared to be vulnerable to CVE-2020-6514. The libxplat_third-party_usrsctp_usrsctpAndroid.so library appears to be more modern, but contains the vulnerable code for Bug 376. That said, it does not appear to be possible to reach this code from Facebook Messenger, as it is set to use RTP data channels as opposed to SCTP data channels, and does not accept attempts to change the channel type via Session Description Protocol (SDP). While it is not clear whether the motivation behind this design is security, this is a good example of how restricting attacker access to features can reduce an application’s vulnerability. Facebook also waits until a call is answered before starting the WebRTC connection, which further reduces the exploitability of any WebRTC vulnerabilities that affect it.

Interestingly, Facebook Messenger also contains a more modern version of WebRTC in a library called librtcR20.so, but it does not appear to be used by the application. It is possible to get Facebook Messenger to use the alternate library by setting a system property on Android, but I could not find a way an attacker could cause a device to switch libraries.

Viber


Like Facebook Messenger, while Viber version 13.3.0.5 appeared to contain the vulnerable code, but the application disables SCTP when the PeerConnectionFactory is created. This means an attacker cannot reach the vulnerable code.

VK


VK is a social networking app released by Mail.ru in which users have to explicitly allow specific other users to contact them before each user is allowed to call them. I tested my exploit against VK, and it required some modifications to work. To start, VK doesn’t use data channels as a part of its WebRTC connection, so I had to enable it. To do this, I wrote a Frida script that hooks nativeCreateOffer in Java, and makes a call to createDataChannel before the offer is created. This was sufficient to enable SCTP on both devices, as the target device determines whether to enable SCTP based on the SDP provided by the attacker. The version of WebRTC was also older than the one I wrote the exploit for. WebRTC doesn’t contain any version information, so it is difficult to tell for sure, but the library appeared to be at least one year old based on log entries. This meant that some of the offsets in the ‘fake object’ used by the exploit were different. With a few changes, I was able to exploit VK.

VK sends an SDP offer to a target device to start a call, but the target does not return the SDP answer until the user has accepted the call, which means this exploit requires the target to answer the call before the WebRTC connection is started. This means the exploit will not work unless the target manually answers the call. In the video below, the exploit takes a fair amount of time to run after the user has answered. This is due to how I designed the exploit, and not due to fundamental limitations of the vulnerabilities it uses. In particular, the exploit waits for usrsctp to generate specific packets even though they could be generated more quickly by the exploit script, and also uses delays to avoid packet reordering when responses could be checked instead. It is likely that with enough effort, this exploit could run in less than five seconds. Also note that I altered the exploit to work with a single incoming call, as opposed to two incoming calls in the exploits above, as it is not realistic to expect a target to answer a call twice in quick succession. This didn’t require substantial changes to how the exploit works, though it does make the exploit code more complex and difficult to debug.



Regardless, the requirement that a user must choose to accept calls from an attacker before they can call, alongside the requirement that the user answer the call and stay on the line for a few seconds makes this exploit substantially less useful against VK compared to applications without these features.

Testing was performed against VK 6.7 (5631). Like Facebook, VK dynamically downloads its version of WebRTC, so it is difficult to specify its version, however testing was performed on July 13, 2020. VK has since updated their servers so that a user cannot start a call with SDP that contains data channels, so the exploit no longer works. Note that VK does not use WebRTC for two-party calls, only group calls, so I tested this exploit using a group call. The source for the exploit is available here.

OK and TamTam


OK and Tamtam are similar messaging applications released by the same vendor, also Mail.ru. They use a dynamically downloaded version of WebRTC that is identical to the one used by VK. Since the library is exactly the same, my exploit also worked on OK, and I didn’t bother also testing TamTam because it is so similar.



Like VK, OK and TamTam do not return the SDP answer until the target has answered the call by interacting with the phone, so this is not a fully remote exploit on OK and TamTam. OK also requires users to choose to accept messages from another user before the user can call them. TamTam is a bit more liberal, for example, if a user verifies a phone number, any user who has their phone number can contact them.

Testing was performed on version 20.7.7 of OK on Monday, July 13. SDP-only testing was performed on TamTam version 2.14.0. Since then, the servers for these applications have been updated so that SDP containing data channels cannot be used to start a call, so the exploit no longer works.

Discord
Discord has documented its use of WebRTC thoroughly. The application uses an intermediary server for WebRTC connections, which means that it is not possible for a peer to send raw SCTP to another peer, which is required for the exploit to work. Discord also requires several clicks to enter a call. For these reasons, Discord is not affected by the vulnerabilities discussed in this post.

JioChat


JioChat  is a messaging application that allows for any user to call any other user based on phone number. Analyzing version 3.2.7.4.0211, it appeared that its WebRTC integration contained both vulnerabilities, and the app exchanges the SDP offer and answer before the callee accepts the incoming call, so I expected the exploit to work without user interaction. However, this was not the case when I tested it, and it turns out that JioChat uses a different strategy to prevent the WebRTC connection from starting until the callee has accepted the call. I was able to easily bypass this strategy, and get the exploit to work on JioChat.



Unfortunately, JioChat’s connection delay strategy introduced another vulnerability, which has been fixed, but the disclosure period has not expired for. For this reason, details of how to bypass it will not be shared in this blog post. The source for the exploit without this functionality is available here. JioChat has recently updated their servers so that SDP containing data channels cannot be used to start a call, meaning that the exploit no longer works on JioChat.

Slack and ICQ


Slack and ICQ are similar in that they both integrate WebRTC, but do not use the transport features of the library (note that Slack doesn’t integrate WebRTC directly for audio calls, it integrates Amazon Chime, which integrates WebRTC). They both use WebRTC for audio processing only, but implement their own transport layer and do not use WebRTC’s RTP and SCTP implementations. For this reason, they are not vulnerable to the bugs discussed in this blog post, and many other WebRTC bugs.

BOTIM


BOTIM has an unusual design that prevents the exploit from working. Instead of calling createOffer and exchanging SDP, each peer generates its own SDP based on a small amount of information from the peer. SCTP is not used by this application by default, and it was not possible to use SDP to turn it on. Therefore, it was not possible to use this exploit. BOTIM does appear to have a mode where it exchanges SDP with a peer, but I could not figure out how to enable it.

Other Application


The exploit worked in a fully remote fashion on one other application, but setting up the exploit revealed an obvious additional serious vulnerability in the application. Details of the exploit’s behavior on the application will be released after the disclosure period has expired for the vulnerability.

Discussion

The Risk of WebRTC

Out of the 14 applications analyzed, WebRTC enabled a fully remote exploit on four applications, and a one-click exploit on two more. This highlights the risk of including WebRTC in a mobile application. WebRTC does not pose a substantially different risk than other video conferencing solutions, but the decision to include video conferencing in an application introduces a large remote attack surface that wouldn’t be there otherwise. WebRTC is one of the few fully remote attack surfaces of a mobile application, and of Android in general. It is likely the highest risk component in almost every application that uses it for video conferencing.

Video conferencing is vital to the functionality of some applications, but in others it is an ‘extra’ that is rarely used. Low usage does not make video conferencing any less of a risk to users. It is important for software makers to consider whether video conferencing is a truly necessary part of their application, with a full understanding of the risk it presents to users.

WebRTC Patching

This research showed that many applications fall behind with regard to applying security updates to WebRTC. Bug 376 was fixed in September of 2019, yet only two of the 14 applications analyzed had patched it. There were several factors that led to this.

To start, usrsctp does not have a formal process for identifying and communicating vulnerabilities. Instead, bug 376 was fixed like any other bug, so the code was not pulled into WebRTC until March 10, 2020.  Even after it was patched, the bug was not noted on the Security Notes for the Chrome Stable channel, which is where WebRTC tells developers to look for security updates. This means that developers of applications that use an older version of WebRTC and cherry-pick fixes, or applications that include usrsctp separately from WebRTC would not be aware of the need to apply this patch.

This is not the full story though, as many applications include WebRTC as an unmodified library, and there have been other WebRTC vulnerabilities included in the Chrome Security Notes since March 2020. Another contributing factor is that until 2019, WebRTC did not provide any security patching guidance to integrators, in fact, their website inaccurately said that no vulnerabilities had ever been reported in the library, which occurred because WebRTC security bugs are generally filed in the Chromium bug tracker, and there was no process for considering these bug’s impact on non-browser integrators at the time. Many of the applications I analyzed had versions of WebRTC that predated this, so it is likely that the legacy of this incorrect guidance still causes applications to not update WebRTC. While WebRTC has done a lot to make it easier for integrators to patch WebRTC, for example allowing large integrators to apply for advance notice of vulnerabilities, there is still likely a long tail of integrators who have only seen the old guidance. Of course, there is no guarantee that integrators would have followed better guidance if it was available, but considering that for a long time it was very difficult for an integrator to know when and how to update WebRTC even if they wanted to, it is likely it would have had an impact.

Integrators also have a responsibility to keep WebRTC up to date with security fixes, and many of them have failed in this area. It was surprising to see so many versions of WebRTC that are well over a year old. Developers should monitor every library they integrate for security updates, and apply them promptly.

Application Design


Application design affects the risk posed by WebRTC, and many applications researched were designed well. The easiest, and most important way to limit the security impact of WebRTC is to avoid starting the WebRTC connection until the callee has accepted the call by interacting with the device. This turns an exploit that can compromise any user quickly into an exploit that requires user interaction, and won’t be successful on every target. It also makes lower quality vulnerabilities not practically exploitable, because while a fully remote exploit can be attempted many times without the user noticing, an exploit that requires a user to answer a call needs to work in a small number of tries.

Starting the WebRTC connection late has a performance impact, and precludes certain features, like giving the callee a preview of the call. Of the applications that the exploit worked on, two started the connection without user interaction, and two required user interaction. JioChat and the application we are not yet identifying tried to use unique tricks to delay the connection until the user accepted the call without performance impact, but introduced vulnerabilities as a result. Developers should be aware that the best way to delay a WebRTC connection is to avoid calling setRemoteDescription until the user has accepted the call.  Other methods might not actually delay the connection and can cause other security problems.

Another way to reduce the security risk of WebRTC is to limit who an attacker can call, for example by requiring that the callee have the user in their contact list, or only allowing calls between users that have agreed to be able to message each other in the application. Like delaying the connection, this greatly reduces the targets an attacker can reach without a lot of effort.

Finally, integrators should limit the features of WebRTC an attacker can use to the features the application needs. Many applications were not vulnerable to this specific exploit because they had effectively disabled SCTP. Others did not use SCTP, but did not disable it in a way that prevented attackers from using it, and I was able to enable it. The best way to disable a feature in WebRTC is to remove it at compile time, which is supported for certain codecs. It is also possible to disable certain features through the PeerConnection and PeerConnectionFactory, and this is also very effective. Features can also be disabled by filtering SDP, but it is important to make sure that the filter is robust and tested thoroughly.

Conclusion

I wrote an exploit for WebRTC for Android involving two vulnerabilities in usrsctp. This exploit was fully remote on Signal, Google Duo, JioChat and one other application, and required user interaction on VK, OK and TamTam. Seven other messengers were not affected because they effectively disabled SCTP. Several applications used versions of WebRTC that did not include patches for either of the vulnerabilities used in the exploit. One remains unpatched. Low patch uptake is partially a result of WebRTC historically providing poor patching guidance. Integrators can reduce the risk of WebRTC by requiring user interaction to start a WebRTC connection, limiting who users can call easily and disabling unused features. They should also consider whether video conferencing is an important and necessary feature of their application.

Vendor Response

The software vendors mentioned in this blog post were given a chance to review this post before it was posted publicly, and some provided responses, as follows.

WebRTC

The WebRTC bug that was used both to bypass ASLR and move the instruction pointer has been fixed. WebRTC no longer passes the SctpTransport pointer directly into usrsctp, using an opaque identifier that is mapped to a SctpTransport instead, with invalid values being ignored. We have identified and patched every affected Google product and reached out to 50 applications and integrators using WebRTC, including all applications analyzed in this post. For all applications and integrators who have not yet patched the vulnerability, we recommend updating to the WebRTC M85 branch, or patching the following two commits: 1, 2.

Mail.ru

User security is of the highest priority for all Mail.ru Group products, which include VK, OK, TamTam and others. Acting on the information we received regarding the vulnerability, we immediately started the process of updating our mobile apps to the latest version of WebRTC. This update is currently underway. We have also implemented algorithms on our servers that no longer allow this vulnerability to be exploited in our products. This action allowed us to fix the issue for all of our users within 3 hours of receiving the information with an exploit demonstration.

Signal

We appreciate the effort that went into finding these bugs and improving the security of the WebRTC ecosystem. Signal had already shipped a defensive patch that protected users from this exploit prior to its discovery. In addition to routine updates of our calling libraries, we continue to take proactive steps to mitigate the impact of future WebRTC bugs.

Slack

We're pleased to see that this report concludes that Slack is not impacted by the referenced WebRTC vulnerabilities and exploits. Upon learning about this risk, we undertook additional diligence and confirmed that the entirety of our Calls service is not impacted by the vulnerabilities and findings described here.