Behind the Scenes of iPIN Lite – A Secure PIN & Password Safe
Note: Snoop-it is a tool to assist dynamic analysis and blackbox security assessments of iOS applications by retrofitting existing apps with debugging and runtime tracing capabilities. It was introduced during the DeepSec Security Conference and is publicly available at https://code.google.com/p/snoop-it/ (Cydia Repository: repo.nesolabs.de).
Previous studies have indicated, that many of the available secure password managers aren’t as secure by design, as intended. In a study on “Secure Password Managers”, Andrey Belenko and Dmitry Sklyarov have shown that many mobile password managers fail to provide the claimed level of data protection.
One quite popular app that was not included within their study is “iPIN Lite - Secure PIN & Password Safe” by IBILITIES, INC. This app spotted my attention, not least because it provides an “innovative sensor keyboard” and “state-of-the-art encryption” using the “Advanced Encryption Standard and a key length of 256 bit” – so what could possibly go wrong?
The typical approach which is chosen to analyze an iOS application dynamically, is to examine the app on a jailbroken device. This removes the limitations imposed by Apple, provides root access to the iOS operating system and enables access to the Objective-C Runtime.
Thus, after installing iPIN Lite (Version 2.27) from the Apple App Store on my testing device, I configured Snoop-it to get ready to run. During initialization of iPIN Lite, Snoop-it is transparently integrated using library injection techniques. At the same time, a webserver is started inside the app in order to make all debugging and runtime tracing capabilities of Snoop-it accessible via an easy-to-use graphical web interface.
After iPIN Lite has finished launching and the sensor keyboard (which is a special login view, more on this later) was displayed, I pointed my browser to the Snoop-it web interface.
One feature of Snoop-it is to monitor file system accesses of an app. During initialization of iPIN Lite several ViewControllers and resource files are loaded, obviously to present the login view. Less obvious, but even more interesting was one access to a file named iPinSecurityModel.dat which resides in the /Library/ipin_data/ folder of the application sandbox (see Figure 1).
|Figure 1: Files accessed by iPIN Lite at startup|
Although this file probably serves as a basis for the security model of iPIN Lite, it was not protected by Apple File Data Protection mechanisms (protection class NSFileProtectionNone). Consequently, one of the next steps was to look at the contents of this file (using Snoop-it it is as easy as double-clicking on the specific entry to download the file). Unfortunately, the contents of the security model file appeared to be in binary format, probably some kind of encoding or encryption. Worse luck! So what next?
Luckily, the characteristics of the Objective-C Runtime enable comprehensive dynamic analysis of running apps. One of the most important functions of the Objective-C Runtime is objc_MsgSend. This function serves as a central dispatcher and routes messages between existing objects. Accordingly, every method invocation in Objective-C results in one or more messages to that dispatcher. If we could intercept all messages to this dispatcher, we would get a very clear picture of the actual control flow and a clear vision of what is going on inside the app.
One solution for that could be to monitor all calls to objc_msgSend on a debugger level using gdb. This approach makes an awful lot of noise due to all the background activities of the runtime which are shown up as well. In consequence it’s really hard to figure out app specific calls.
A better approach would be to intercept messages to objc_msgSend within the runtime. On a runtime level, filters could be applied to focus on app specific classes and method invocations inside the actual app. Inspired by Aspective-C and Subjective-C we extended those existing solutions to consider penetration testing needs and integrated a powerful method tracing feature into Snoop-it.
Thus, in order to evaluate the encryption scheme, I switched over to the method tracing tab and examined the methods that were invoked during initialization of iPIN Lite. I was especially interested in the processing of the security model file, which has shown up in the file system access list earlier (see access to the file iPinSecurityModel.dat in Figure 1).
Indeed, as the tracing output reveals (see Listing 1), the security model file was accessed at the very beginning. In fact, the file was protected using a hard-coded cryptographic key that resides inside the application binary.
+ [iPinModel(0x90f68) initFromFile] + [iPinModel(0x90f68) securityModelFilePath] + [iPinModel(0x90f68) securityModelFilePath] + [PBKDF2(0x9124c) getKeyForPassphrase:], args: <__NSCFConstantString 0x92160: [initForWritingWithMutableData]> + [iPinModel(0x90f68) initSharedModelWithUnarchiver:withObjectKey:], args: <0x2002aef0>, <__NSCFConstantString 0x92150: iPINModel> + [iPinModel(0x90f68) sharedModel] - [iPinModel(0x200e2130) initWithCoder:], args: <0x2002aef0> - [iPinModel(0x200e2130) setSensorHash:], args: <__NSCFString 0x2002a630: 8CF37F50FB1A7943FBA8EAA20FFF1E56> - [iPinModel(0x200e2130) setEncryptedSensorCode:], args: <__NSCFData 0x2002a540, length 16 bytes> - [iPinModel(0x200e2130) setPasswordHash:], args: <__NSCFString 0x2002a470: 098F6BCD4621D373CADE4E832627B4F6> - [iPinModel(0x200e2130) setEncryptedPassword:], args: <__NSCFData 0x2002a2d0, length 16 bytes> - [iPinModel(0x200e2130) setFailedAttemptsCounter:], args: 0
|Listing 1: Method tracing output of iPIN Lite – Part 1|
According to the tracing output shown in Listing 1, the security model file contains hashes of a sensor-code (sensorHash) and a password (passwordHash) as well as an encrypted password string (encryptedPassword). These values are transferred into an instance of the “iPinModel” class. Presumably, these hashes will be used later on during authentication to verify the sensor-code or the password entered by the user. It’s quite questionable whether a key derivation function applied on a static string really makes sense :-)
Anyway, let’s take a quick look at this sensor-code: iPIN Lite provides an “innovative sensor keyboard” which consists of 9 touch-sensitive sensors (see Figure 2). This keyboard is supposed to provide “quick access to all your PINs - without any annoying and time-killing passwords.” The authentication is based on a geometrical shape or any individual sensor combination. Therefore, the “individual sensor code is calculated by the order in which (..) these sensors have been activated and deactivated”. By now, this looks like another showcase of the everlasting conflict between usability and security. Let’s see.
|Figure 2: Sensor Keyboard of iPin Lite|
As soon as one sensor is touched, its color is changed into blazing blue. In the background, the touch events are registered from the corresponding ViewControllers.
The following method trace (see Listing 2) shows, that the sensors are numbered consecutively from 10 to 90. A touch on the upper middle sensor corresponds to a value of 20. In the end, the values of all touched sensors are joined into one common sensor-code. On every touch, a MD5 hash is calculated from the current sensor-code and is compared to the sensorHash value (which was derived from the security model file). Consequently, the overall security of iPIN Lite solely depends on the strength of these sensor-codes, whose search space is in fact very limited. If we could guess the sensor-code, the security model of iPIN Lite would have been completely broken.
- [UISensorKeyboardImageView(0x200dc000) touched] - [UISensorKeyboardImageView(0x200dc000) touch] - [UISensorKeyboardImageView(0x200dc000) setTouched:], args: 1 - [UISensorKeyboardImageView(0x200dc000) numberOfTouches] - [UISensorKeyboardImageView(0x200dc000) setNumberOfTouches:], args: 1 - [SensorKeyboardViewController(0x200c9a40) tock] + [iPinModel(0x90f68) sharedModel] - [iPinModel(0x200e2130) sensorSoundTurnedOff] - [SensorKeyboardViewController(0x200c9a40) input] - [UISensorKeyboardImageView(0x200dc000) value] - [SensorKeyboardViewController(0x200c9a40) setInput:], args: <__NSCFString 0x200dec80: 20> - [LoginViewController(0x20093ce0) valueChanged:], args: <__NSCFString 0x200dec80: 20> + [CryptoUtils(0x90f54) md5:], args: <__NSCFString 0x200dec80: 20> + [iPinModel(0x90f68) sharedModel] - [iPinModel(0x200e2130) sensorHash]
|Listing 2: Method tracing output of iPIN Lite – Part 2|
Attacking the Encryption Scheme
Snoop-it provides a feature to invoke arbitrary methods at runtime. For this, Snoop-it queries the Objective-C Runtime for all available app classes and methods during startup. In addition, Snoop-it monitors initialization of each class and keeps track of all available instances in memory to invoke those instance methods later on. Thus, to determine the current sensorHash, I used that feature of Snoop-it and invoked the corresponding getter method of the iPinModel class. This returned me a hash value of 8CF37F50FB1A7943FBA8EAA20FFF1E56 (see Figure 3).
|Figure 3: Determine the actual sensorHash from an instance of the iPinModel class|
In order to attack the encryption scheme, I wrote a python script to brute force all possible sensor codes and to compare it against this sensorHash. After a few seconds, the script provided the correct sensor code sequence 10 20 30 60 90 (see Figure 4).
Output of the python script:
$ python sensor_bruteforce.py -s 8CF37F50FB1A7943FBA8EAA20FFF1E56 Sensor Hash: 8cf37f50fb1a7943fba8eaa20fff1e56 Sensor Code: 1020306090
|Figure 4: Sensor Code Accepted|
Finally, let’s see how the actual app data is decrypted. According to the output shown in Listing 3, the sensor-code is used to derive a key and to decrypt the encryptedPassword value which is stored in the security model file.
- [iPinModel(0x2007ee20) decryptPasswordWithKey:], args: <__NSCFString 0x2009d570: 1020306090> - [iPinModel(0x2007ee20) encryptedPassword] + [PBKDF2(0xf824c) getKeyForPassphrase:], args: <__NSCFString 0x2009d570: 1020306090> - [iPinModel(0x2007ee20) setPassword:], args: <__NSCFString 0x200f9d50: secretPassword> - [iPinModel(0x2007ee20) calculatePasswordHash] - [iPinModel(0x2007ee20) password]
|Listing 3: Method tracing output of iPIN Lite – Part 3|
Afterwards, the decrypted password (“secretPassword”) is used to derive another key, which is then used to decrypt the actual iPIN data (see Listing 4).
- [iPinModel(0x2007ee20) password] + [PBKDF2(0xf824c) getKeyForPassphrase:], args: <__NSCFString 0x200f9d50: secretPassword > - [Pin(0x2002a7c0) initWithCoder:], args: <0x1f5a4320> - [Pin(0x2002a7c0) setPinValue:], args: <__NSCFString 0x2002e3f0: 4711> - [Pin(0x2002a7c0) setNote:], args: <__NSCFString 0x2002a760: Sample PIN Note> - [Pin(0x1f5d1890) initWithCoder:], args: <0x1f5a4320> - [Pin(0x1f5d1890) setPinValue:], args: <__NSCFString 0x200a5830: 1337> - [Pin(0x1f5d1890) setNote:], args: <NULL> - [iPINDataModel(0x2002ce80) setPinList:], args: <__NSArrayM 0x1f5c5330, size: 2> [..] - [iPinNavigationController(0x200317f0) init]
|Listing 4: Method tracing output of iPIN Lite – Part 4|
Once again, this case has demonstrated, that the security of an app is only as strong as its weakest link. Even if an app claims to protect your data using acknowledged encryption standards, it’s always worth to look behind the scenes. While this was quite time-consuming in the past, our new tool Snoop-it allows thorough analyses and on-the-fly manipulations of arbitrary iOS apps with an easy-to-use graphical user interface. Thus, reverse engineering of apps, bypassing client-side restrictions or unlocking additional features and premium content of apps is going to be a child’s play. Using Snoop-it, the attack surface of any iOS app can be explored more efficiently and even time-consuming steps, like evaluating encryption schemes, suddenly become possible in the twinkling of an eye.
Note: IBILITIES INC. was informed about these findings a few months ago. In the meantime, an updated version of iPIN was released.
The following video outlines the steps described above:
This video is also available at the following URL: http://youtu.be/qpw96GywvZE.
Thanks to Markus Troßbach for his close collaboration on developing Snoop-it!