Tuesday, March 5, 2013 At 8:45AM
I am going to walk you through a testing technique that can be used at runtime to uncover security flaws in an iOS application when source code is not available, and without having to dive too deeply into assembly. I am going to use a recent example of an iOS application I reviewed, which performed its own encryption when storing data onto the device. These types of applications are a lot of fun to look at due to the variety of insecure ways people implement their own crypto. In this example the application required authentication, and then pulled down some data and stored it encrypted on the device for caching. The data was presented to the user where they could “act” upon it. Sounds pretty generic, but hopefully the scenario is familiar enough to those who assess mobile apps.
Upon analyzing the application traffic, it was obvious that no crypto keys were being returned from the server. After sweeping the iOS Keychain and the entire Application container, I could make the educated assumption that the key is either a hardcoded value or derived using device specific information.
Using the Hopper Disassembler (Available on the Mac App Store), I was able to see that the application was leveraging the Common Crypto library for its encryption. I checked the cross-references for calls to the CCCryptorCreate function in order find the code areas which perform encryption. The following screenshot shows getSymmetricKeyBytes being called right before the CCCryptorCreate function. I felt pretty confident that the purpose of the getSymmetricKeyBytes method was going to be to return the symmetric key used for encryption.
I decided to create a Mobile Substrate tweak in order to hook into getSymmetricKeyBytes and read the return value. I used the class-dump-z tool to get a listing of all the exposed Objective-C interfaces. From here it is easy to get more detailed information about the method, such as the class name, return type and any required parameters. The following is a short snippet retrieved from the class-dump-z results.
@interface SecKeyWrapper : XXUnknownSuperclass { NSData* publicTag; NSData* privateTag; NSData* symmetricTag; unsigned typeOfSymmetricOpts; SecKey* publicKeyRef; SecKey* privateKeyRef; NSData* symmetricKeyRef; } [..snip..] -(id)getSymmetricKeyBytes; -(id)doCipher:(id)cipher key:(id)key context:(unsigned)context padding:(unsigned*)padding; [..snip..]
We can quickly create a tweak by using the Theos framework. The tweak in this case looked as follows:
%hook SecKeyWrapper - (id)getSymmetricKeyBytes { NSLog(@”HOOKED getSymmetricKey”); id theKey = %orig; NSLog(@”KEY: %@”, theKey); return theKey; } %end %ctor { NSLog(@”SecKeyWrapper is created.”); %init; }
It doesn’t do much more then read the return value of the original method call and write it out to the console. It was possible to confirm that a static key was being used by running the tweak on another iPad, and observing that the same symmetric key was returned. The next step was to decrypt the files. We could hook into the doCipher:key:context:padding method and just print out the first parameter to get the plaintext data. That would work, but that wouldn’t be reproducible since the Tweak code would only execute when the doCipher:key:context:padding method is actually run by the application. A quick Google search on the SecWrapper class turned up the following sample code from Apple.
By leveraging the wrapper it was possible to create an offline script to decrypt the application contents.
While looking at sample code I noticed two things. The app developer chose to change Apple’s implementation of the getSymmetricKeyBytes method and return a static key. The other interesting discovery was bad practices in Apple’s sample code for the doCipher:key:context:padding method. The following code snippet shows that it will use a static IV of 16 bytes of 0x0’s.
// Initialization vector; dummy in this case 0’s. uint8_t iv[kChosenCipherBlockSize]; memset((void *) iv, 0x0, (size_t) sizeof(iv));
An alternative method to achieve the same result would be to use cycript, which provides a Javascript interpreter to hook run arbitrary objective-c code and also hook into iOS applications at runtime without having to go through the whole Mobile Substrate Tweak creation. The following example shows how cycript could be used to retrieve the symmetric crypto key.
rgutie01s-iPad:~ root# cycript -p 290 cy# var sharedwrapper = [SecKeyWrapper sharedWrapper]; @”<SecKeyWrapper: 0x183080>” cy# [sharedwrapper getSymmetricKeyBytes] @”<[Symmetric Key Value Omitted>”
To recap:
- Runtime analysis can be leveraged to easily break custom encryption when source code is not available and without having to dive into assembly.
- Developers need to beware of using sample code downloaded from the web, especially crypto code as it’s really hard to get right (as shown by the sample from Apple).
Author: Ron Gutierrez
©Aon plc 2023