In the first part of the article, we have discussed the iPhone application traffic analysis. The second part of the article covered privacy issues and property list data storage. The third part covered in-depth analysis of the iOS keychain data storage. In this part, we will look at different types of files stored/created in the application’s home directory and other insecure data storage locations.
Local data storage
SQLite is a cross-platform C library that implements a self-contained, embeddable, zero-configuration SQL database engine. The SQLite database does not need a separate server process and the complete database with multiple tables, triggers, and views is contained in a single disk file. The SQLite database offers all the standard SQL constructs, including Select, Insert, Update and Delete. As SQLite is portable, reliable and small, it is an excellent solution for persistent data storage on iOS devices.
SQLite library that comes with iOS is a lightweight and powerful relational database engine that can be easily embedded into an application. The library provides fast access to the database records. As the complete database is operated as a single flat file, applications can create local database files, and manage the tables and records very easily. In general, iOS applications use the SQLite database to store large and complex data as it offers good memory usage and speed. The SQLite database that comes with iOS does not have a built-in support for encryption. Most of the iOS applications store lots of sensitive data in plain text format in SQLite files. For example, to provide offline email access, Gmail iOS application stores all the emails in a SQLite database file in plain text format.
Unencrypted sensitive information stored in a SQLite file can be stolen easily by gaining physical access to the device or from the device backup. In addition, if an entry is deleted, SQLite tags the records as deleted but not purge them. Therefore, in case an application temporarily stores and removes the sensitive data from a SQLite file, deleted data can be recovered easily by reading the SQLite Write Ahead Log.
The SQLite files can be created with or without any file extension. Most common extensions are .sqlitedb and .db. The below article explains how to view SQLite files and how to recover the deleted data from SQLite files on the iPhone. For this exercise, I have created a demo application called CardInfoDemo. CardInfoDemo is a self-signed application, so it can only be installed on a jailbroken iPhone. The CardInfo demo application accepts any username and password, then collects the credit card details from the user and stores it in a SQLite database. Database entries are deleted upon logout from the app.
Steps to install the CardInfo application:
- Jailbreak the iPhone.
- Download the CardInfoDemo.ipa file – Download link.
- On Windows, download the iPhone configuration utility – Download link.
Open the iPhone configuration utility and drag the CardInfoDemo.ipa file on to it.
Connect the iPhone to the Windows machine using a USB cable. Notice that the connected device is listed in the iPhone configuration utility. Select the device and navigate to Applications tab. It lists the already-installed applications on the iPhone along with our CardInfo demo app.
- Click the Install button corresponding to the CardInfo application and it installs the CardInfo application on to the iPhone.
Steps to view CardInfo SQLite files:
- On the Jailbroken iPhone, install OpenSSH and Sqlite3 from Cydia.
- On Windows workstation, download Putty.
Connect the iPhone and the workstation to the same Wi-Fi network.
Note: Wi-Fi is required to connect the iPhone over SSH. If the Wi-Fi connection is not available SSH into the iPhone over USB.
- Run Putty and SSH into the iPhone by typing the iPhone IP address, root as username and alpine as password.
- Navigate to /var/mobile/Applications/ folder and identify the CardInfo application directory using ‘find . –name CardInfo’ command. On my iPhone CardInfo application is installed on the – /var/mobile/Application/B02A125C-B97E-4207-911B-C136B1A08687/ directory.
- Navigate to the /var/mobile/Application/B02A125C-B97E-4207-911B-C136B1A08687/CardInfo.app directory and notice CARDDATABASE.sqlite3 database file.
- Using the sqlite3 command, view the CARDDATABASE.sqlite3 and notice that CARDINFO table is empty.
Note: SQLite files can also be copied from the iPhone to a workstation over SSH and viewed using SQLite data browser and SQLite spy tools.
- On the iPhone, open CardInfo application and login (works for any username and password).
Enter credit card details and click on the Save button. In the background, it saves the card details in a SQLite database.
- View CARDDATABASE.sqlite3 and notice that CARDINFO table contains the data (credit card details).
- Logout from the application on the iPhone. In the background, it deletes the data from the SQLite database.
- Now view CARDDATABASE.sqlite3 and notice that the CARDINFO table is empty.
Steps to recover the deleted data from CardInfo SQLite file:
The SQLite database engine writes the data into Write Ahead Log before storing it in the actual database file, to recover from system failures. Upon every checkpoint or commit, the data in the WAL is written into the database file. So, if an entry is deleted from the SQLite database and there is no immediate commit query, we can easily recover the deleted data by reading the WAL. In case of iOS, the strings command can be used to print the deleted data from a SQLite file. In our case, running ‘strings CARDDATABASE.sqlite3’ command prints the deleted card details.
In iOS, if an application uses the SQLite database for temporary storage, there is always a possibility to recover the deleted temporary data from the database file.
For better security, use custom encryption while storing sensitive data in the SQLite database. Also, before deleting a SQLite record, overwrite that entry with junk data. Even if someone tries to recover the deleted data from the SQLite file, they will not get the actual data. Use iOS data protection constants while creating the SQLite files.
Most of the iOS applications do not want to prompt the user for login every time. So, they create persistent cookies and store them in cookies.binarycookies file on the application’s home directory. During the penetration test, investigate the cookies.binarycookies file for sensitive information, and to find session management issues. Cookies.binarycookies is a binary file and the content is not in readable format. Therefore, I wrote a python script BinaryCookieReader.py that can read the cookie file and display the content on the screen.
Steps to read the Cookies.binarycookies:
- On Windows, download WinScp, Python and BinaryCookieReader.py.
- Connect the iPhone and the workstation to the same Wi-Fi network.
- Run WinScp and SSH into the iPhone by typing the iPhone IP address, root as username and alpine as password.
- Navigate to the Library/Cookies folder in the application’s home directory.
- Copy the Cookies.binarycookies file to the Windows machine by dragging it.
- On Windows, open command prompt and run the following command to list the contents of cookies.binarycookies file:
Python BinaryCookieReader.py [Cookies.binarycookies file path]
Below is the screenshot of cookies created by Facebook iOS Application.
In an effort to learn how users type, iOS devices utilize a feature called Auto Correction to populate a local keyboard cache on the device. The keyboard cache is designed to autocomplete the predictive common words. The problem with this feature is, it records everything that a user types in text fields. The cache keeps a list of approximately 600 words. The keyboard cache is located at Library/Keyboard/en_GB-dynamic-text.dat file. To view the Keyboard cache, copy the en_GB-dynamic-text.dat file to a computer over SSH and open the file using a Hex Editor. Below is the screenshot of a keyboard cache Hex view.
The keyboard cache does not store the information typed in the fields that are marked as secure. By default, passwords and strings with all digits (pins and credit cards) are marked as secure. Hence, the data typed in those fields does not store in the keyboard cache. However, data typed in other text fields like username, security questions and answers might get stored in the keyboard cache. During a pentest clear the existing keyboard cache by navigating to iPhone Settings -> General -> Reset -> Reset Keyboard Dictionary (shown in the below image), then browse the application and enter data in text fields and analyze whether the data is getting stored in the keyboard cache or not.
During the application development, to disable auto complete for a text field, either mark it as secure (ex: mytextField.secureTextEntry = YES) or disable the autocomplete (mytextField.autocorrectionType = UITextAutocorrectionTypeNo;).
Along with the keyboard cache, when a user copies data from a text field, iOS stores the data into a pasteboard (clipboard in other operating systems). The pasteboard is shared among all the applications, so the information copied in one application can be accessed from other applications by reading the pasteboard. If the application is dealing with sensitive data, it is recommended to use a private or an application-specific pasteboard.
Pressing the iPhone home button shrinks the iOS application and moves it to the background with a nice effect. To create that shrinking effect, iOS takes a screenshot of the application and stores it in the Library/Caches/Snapshots folder in the respective application’s home directory. This might result in storing the user’s sensitive information on the device without user’s knowledge. Snapshots stored on the iPhone will automatically clear after the device is rebooted.
Ex: In case of Gmail iOS application, when a user press the iPhone home button after viewing the email, a snapshot of users’ email gets stored on the device without user’s knowledge. Below snapshot is captured after viewing a mail from the Citibank.
During development, the application snapshot problem can be fixed in two ways.
1. Remove sensitive data or change the screen to blank before the applicationDidEnterBackground()
2. Instead of hiding or removing sensitive data, application’s backgrounding can be disabled altogether by setting the “Application does not run in background” property in the application’s Info.plist file.
Along with plist files, SQLite files, binary cookies and snapshots, iOS applications can store other format files like pdf, xls, txt, etc. when viewed from the application. For example, in the Yandex.Mail iPhone application, when a user views an attachment, it gets stored on the device and remains on the device even after user logged out from the mail application. Applications that are storing temp files on the device should clear those files upon logout/close for better security. Below is the screenshot of Yandex.Mail attachment directory.
In general, iOS applications write data into logs for diagnostic and troubleshooting purpose. In addition, during development, applications developers commonly use NSLog for debugging purposes. These logs might include requests, responses, cookies, authentication tokens and other sensitive data. On the iPhone, data passed to the NSLog function is logged by Apple System Log (ASL) and the data remains on the log until the device is rebooted. Also, Error logs are not bounded by the application sandbox. Which means error logs generated by one application can be read by other applications. Therefore, if an application logs sensitive data, a malicious application can actively query for this data and send it to a remote server.
Error logs on the iPhone can be viewed directly using Console app. The Console app is available in the AppStore. Error logs can also be viewed using iPhone configuration utility or by syncing the device with iTunes and looking at CrashReporter folder.
For this exercise, I have created a demo application called CardInfoDemo. CardInfoDemo is a self-signed application, so it can only be installed on a Jailbroken iPhone. The CardInfo demo application accepts any username and password, then collects the credit card details from the user and writes it into the error log.
Steps to view the error logs:
Install CardInfoDemo application on the iPhone.
On Windows, install and open the iPhone Configuration Utility.
Connect the iPhone to the Windows machine using USB cable. Notice that the connected device is listed in the iPhone configuration utility. Select the device and navigate to Console tab.
On the iPhone, open CardInfo application and login (works for any username and password).
Enter credit card details and click on Save button. In the background, it logs the card details.
On the iPhone configuration utility console tab, you can notice the card details logged by the CardInfoDemo application.
For better security, do not log sensitive data. Also, remove debugging and troubleshooting logs from the application before publishing it.
Penetration Testing For iPhone Applications is going to be covered in a series of articles. In the Part 5, we will take a look at runtime analysis of iOS Applications.
Debunking NSLog Misconceptions
What’s in your iOS Image Cache ?
Hacking and Securing iOS Applications by Jonathan Zdziarski