Wednesday, December 5, 2018

Adventures in Video Conferencing Part 2: Fun with FaceTime

Posted by Natalie Silvanovich, Project Zero

FaceTime is Apple’s video conferencing application for iOS and Mac. It is closed source, and does not appear to use any third-party libraries for its core functionality. I wondered whecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r fuzzing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 contents of FaceTime’s audio and video streams would lead to similar results as WebRTC.

Fuzzing Set-up


Philipp Hancke performed an excellent analysis of FaceTime’s architecture in 2015. It is similar to WebRTC, in that it exchanges signalling information in SDP format and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n uses RTP for audio and video streams. Looking at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 FaceTime implementation on a Mac, it seemed cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bulk of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 calling functionality of FaceTime is in a daemon called avconferenced. Opening up cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 binary that supports its functionality, AVConference in IDA, it contains a function called SRTPEncryptData. This function cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n calls CCCryptorUpdate, which appeared to encrypt RTP packets below cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 header.

To do a quick test of whecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r fuzzing was likely to be effective, I hooked this function and altered cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 underlying encrypted data. Normally, this can be done by setting cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 DYLD_INSERT_LIBRARIES environment variable, but since avconferenced is a daemon that restarts automatically when it dies, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re wasn’t an easy way to set an environment variable. I eventually used insert_dylib to alter cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 AVConference binary to load a library on startup, and restarted cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process. The library loaded used DYLD_INTERPOSE to replace CCCryptorUpdate with a version that fuzzed every input buffer (using fuzzer q from Part 1) before it was processed. This implementation had a lot of problems: it fuzzed both encryption and decryption, it affected every call to CCCryptorUpdate from avconferenced, not just ones involved in SRTP and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re was no way to reproduce a crash. But using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 modified FaceTime to call an iPhone led to video output that looked corrupted, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 phone crashed in a few minutes. This confirmed that this function was indeed where FaceTime calls are encrypted, and that fuzzing was likely to find bugs.

I made a few changes to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 function that hooked CCCryptorUpdate to attempt to solve cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se problems. I limited fuzzing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 input buffer to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 two threads that write audio and video output to RTP, which also solved cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 problem of decrypted packets being fuzzed, as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se threads only ever encrypt. I cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n added functionality that wrote cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 encrypted, fuzzed contents of each packet to a series of log files, so that test cases could be replayed. This required altering cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 sandbox of avconferenced so that it could write files to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 log location, and adding spinlocks to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 hook, as calling CCCryptorUpdate is thread safe, but logging packets isn’t.

Call Replay


I cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n wrote a second library that hooks CCCryptorUpdate and replays packets logged by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first library by copying cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 logged packets in sequence into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 packet buffers passed into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 function. Unfortunately, this required a small modification to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 AVConference binary, as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 SRTPEncryptData function does not respect cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 length returned by CCCryptorUpdate; instead, it assumes that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 length of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 encrypted data is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 length as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 plaintext data, which is reasonable when CCCryptorUpdate isn’t being hooked. Since SRTPEncryptData always uses a large fixed-size buffer for encryption, and encryption is in-place, I changed cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 function to retrieve cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 length of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 encrypted buffer from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 very end of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 buffer, which was set in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 hooked CCCryptorUpdate call. This memory is unlikely to be used for ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r purposes due to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 typical shorter length of RTP packets. Unfortunately though, even though cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same encrypted data was being replayed to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 target, it wasn’t being processed correctly by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 receiving device.

To understand why requires an explanation of how RTP works. An RTP packet has cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 following format.


It contains several fields that impact how its payload is interpreted. The SSRC is a random identifier that identifies a stream. For example, in FaceTime cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 audio and video streams have different SSRCs. SSRCs can also help differentiate between streams in a situation where a user could potentially have an unlimited number of streams, for example, multiple participants in a video call. RTP packets also have a payload type (PT in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 diagram) which is used to differentiate different types of data in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 payload. The payload type for a certain data type is consistent across calls. In FaceTime, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 video stream has a single payload type for video data, but cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 audio stream has two payload types, likely one for audio data and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r for synchronization. The marker (M in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 diagram) field of RTP is also used by FaceTime to represent when a packet is fragmented, and needs to be reassembled.

From this it is clear that simply copying logged data into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 current encrypted packet won’t function correctly, because cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 data needs to have cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 correct SSRC, payload type and marker, or it won’t be interpreted correctly. This wasn’t necessary in WebRTC, because I had enough control over WebRTC that I could create a connection with a single SSRC and payload type for fuzzing purposes. But cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re is no way to do this in FaceTime, even muting a video call leads to silent audio packets being sent as opposed to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 audio stream shutting down. So cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se values needed to be manually corrected.

An RTP feature called extensions made correcting cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se fields difficult. An extension is an optional header that can be added to an RTP packet. Extensions are not supposed to depend on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 RTP payload to be interpreted, and extensions are often used to transmit network or display features. Some examples of supported extensions include cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 orientation extension, which tells cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 endpoint cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 orientation of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 receiving device and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mute extension, which tells cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 endpoint whecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 receiving device is muted.

Extensions mean that even if it is possible to determine cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 payload type, marker and SSRC of data, this is not sufficient to replay cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exact packet that was sent. Moreover, FaceTime creates extensions after cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 packet is encrypted, so it is not possible to create cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 complete RTP packet by hooking CCCryptorUpdate, because extensions could be added later.

At this point, it seemed necessary to hook sendmsg as well as CCCryptorUpdate. This would allow cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 outgoing RTP header to be modified once it is complete. There were a few challenges in doing this. To start, audio and video packets are sent by different threads in FaceTime, and can be reordered between cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 time cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y are encrypted and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 time cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y are sent by sendmsg. So I couldn’t assume that if sendmsg received an RTP packet that it was necessarily cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 last one that was encrypted. There was also cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 problem that SSRCs are dynamic, so replaying an RTP packet with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same SSRC it is recorded with won’t work, it needs to have cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 new SSRC for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 audio or video stream.

Note that in MacOS Mojave, FaceTime can call sendmsg via eicá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 AVConference binary or cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 IDSFoundation binary, depending on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 network configuration. So to capture and replay unencrypted RTP traffic on newer systems, it is necessary  to hook CCCryptorUpdate in AConference and sendmsg in IDSFoundation (AVConference calls into IDSFoundation when it calls sendmsg). Ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365rwise, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same as on older systems.

I ended up implementing a solution that recorded packets by recording cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 unencrypted payload, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n recorded its RTP header, and using a snippet of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 encrypted payload to pair headers with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 correct unencrypted payload. Then to replay packets, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 packets encrypted in CCCryptorUpdate were replaced with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 logged packets, and once cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 encrypted payload came through to sendmsg, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 header was replaced with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 logged one for that payload. Fortunately, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 two streams with unique SSRCs used by FaceTime do not share any payload types, so it was possible to determine cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 new SSRC for each stream by waiting for an incoming packet with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 correct payload type. Then in each subsequent packet, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 SSRC was replaced with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 correct one.

Unfortunately, this still did not replay a FaceTime call correctly, and calls often experienced decryption failures. I eventually determined that audio and video on FaceTime are encrypted with different keys, and updated cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 replay script to queue cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 CCCryptor used by CCCryptorUpdate function based on whecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r it was audio or video content. Then in sendmsg, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 entire logged RTP packet, including cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 unencrypted payload, was copied into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 outgoing packet, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 SSRC was fixed, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 payload encrypted with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 next CCCryptor out of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 appropriate queue. If a CCCryptor wasn’t available, outgoing packets were dropped until a new one was created. At this point, it was possible to stop using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 modified AVConference binary, as all cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 packet modification was now happening in sendmsg. This implementation still had reliability problems.

Digging more deeply into how FaceTime encryption works, packets are encrypted in CTS mode, which requires a counter. The counter is initialized to a unique value for each packet that is sent. During cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 initialization of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 RTP stream, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 peers exchange two 16-byte random tokens, one for audio and one for video. The counter value for each packet is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n calculated by exclusive or-ing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 token with several values found in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 packet, including cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 SSRC and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 sequence number. Only one value in this calculation, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 sequence number, changes between each packet. So it is possible to calculate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 counter value for each packet by knowing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 initial counter value and sequence number, which can be retrieved by hooking CCCryptorCreateWithMode. The sequence number is xor-ed with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 random token at index 0x12 when FaceTime constructs a counter, so by xor-ing this location with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 initial sequence number and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n a packet’s sequence number, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 counter value for that packet can be calculated. The key can also be retrieved by hooking CCCryptorCreateWithMode.This allowed me to dispense with queuing cryptors, as I now had all cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 information I needed to construct a cryptor for any packet. This allowed for packets to be encrypted faster and more accurately.

Sequence numbers still posed a problem though, as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 initial sequence number of an RTP stream is randomly generated at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 beginning of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 call, and is different between subsequent calls. Also, sequence numbers are used to reconstruct video streams in order, so cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y need to be correct. I altered cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 replay tool determine cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 starting sequence number of each stream, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n calculate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 difference between cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 starting sequence number of each logged stream and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 sequence number of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 logged packet and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n add it to this value. These two changes finally made cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 replay tool work, though replay gets slower and slower as a stream is replayed due to dropped packets.   

Results


Using this setup, I was able to fuzz FaceTime calls and reproduce cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 crashes. I reported three bugs in FaceTime based on this work. All cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se issues have been fixed in recent updates.

CVE-2018-4366 is an out-of-bounds read in video processing that occurs on Macs only.

CVE-2018-4367 is a stack corruption vulnerability that affects iOS and Mac. There are a fair number of variables on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stack of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 affected function before cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stack cookie, and several fuzz crashes due to this issue caused segmentation faults as opposed to stack_chk crashes, so it is likely exploitable.

CVE-2018-4384 is a kernel heap corruption issue in video processing that affects iOS. It is likely similar to this vulnerability found by Adam Donenfeld of Zimperium.

All of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se issues took less than 15 minutes of fuzzing to find on a live device. Unfortunately, this was cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 limit of fuzzing that could be performed on FaceTime, as it would be difficult to create a command line fuzzing tool with coverage like we did for WebRTC as it is closed source.

In Part 3, we will look at video calling in WhatsApp.

No comments:

Post a Comment