OWASP for iOS: M1 — Improper Platform usage, Part 2

This story describes how iOS developers can fight M1 category vulnerabilities from OWASP Mobile Top Ten 2016. The category covers misuse of a platform features or failure to use platform security controls. In Part 2 we’ll cover miscellaneous iOS features that can by mistake spoil app’s security.

Anatoly Rosencrantz
4 min readJun 15, 2017

Cached Application Snapshots

Telegram chat and Photos leaked to snapshots

Starting from iOS 7 the system takes and caches a screenshot of user interface at the time your application goes background.

Screenshots are stored in .ktx (iOS9) or .png (iOS10) format at Library/Caches directory (which is not backed up via iTunes or iCloud):

(App Folder)/Library/Caches/Snapshots/com.bundle.id.of.your.app/

The interface snapshot image can contain sensitive data. To avoid leakage, cover it with an image view, clear textfields, hide labels, etc. Use applicationWillResignActive(_:) to hide information and applicationDidBecomeActive(_:) to restore original view.

Today Extension Cache (researched for iOS10 only)

If your app has Today extension it will have UUID-named directory in /private/var/mobile/Containers/Data/PluginKitPlugin/<UUID>

Not alike application’s snapshots, Today extensions preserve their state by caching last relevant data in /Library/Caches/com.bundle.id.of.your.app.with.widget.suffix/Cache.db

Autocorrection and Secure UITextField

UITextField conforms to UITextInputTraits protocol, which among others have properties:

  1. var autocorrectionType: UITextAutocorrectionType whether the text object tracks unknown words and suggests a more suitable replacement candidate to the user. In order to learn new words, all text from text objects with autocorrection are cached at path /User/Library/Keyboard/dynamic-text.dat
  2. var isSecureTextEntry: Bool whether the text object should disable text copying, hide the text being entered and prevents text to be cached.
Ayaka Nonaka is cool, follow her

To prevent sensitive information like username and password to be stored in dynamic-text.dat, put UITextFields to isSecureTextEntry state if text should not be visible, or switch off autocorrectionType if text should be visible. As a side effect, your users will not be confused by iOS attempts to autocorrect their names. That really hurts, believe me.

Pasteboard

In some cases user does not want text copied to pasteboard to be accessible outside the app. iOS10 and macOS Sierra allows even to share contents of pasteboard to each other via Universal Clipboard of Handoff feature, which can leak user data to (possibly compromised) devices.

UIPasteboard class allows to create in-app pasteboard. To exclude a pasteboard from Handoff, call the setItems(_:options:) method with the localOnly option.

Networking Cache Policies

Any HTTP and HTTPS request loaded through URLSession will be handled by URLCache, who provides a in-memory and on-disk caching mechanism. Cache database is stored at Library/Caches directory (which is not backed up via iTunes or iCloud):

(App Folder)/Library/Caches/com.bundle.id.of.your.app/Cache.db

Some tables in Cache.db

URLRequest instance specifies how the local cache is used by setting the cache policy to one of the NSURLRequest.CachePolicy values:

  1. useProtocolCachePolicy — default
  2. reloadIgnoringLocalCacheData — don’t use the cache
  3. returnCacheDataElseLoad — use the cache (no matter how out of date), or if no cached response exists, load from the network
  4. returnCacheDataDontLoad — offline mode: use the cache (no matter how out of date), but don’t load from the network

By default, shared for all applications URLCache.shared is used, but applications can instantiate their own cache storages.

If you’re using URLSessionDataDelegate easiest way will be to call completion handler with nil in the end of urlSession(dataTask:willCacheResponse:completionHandler:)

App Groups

Apps and extensions owned by a developer account can share content when configured to be part of an App Group. Once configured to be part of an App Group, apps have access to the following:

  • Shared on-disk container for storage, which will stay on the device as long as at least one app from the group is installed
  • Shared preferences
  • Shared keychain items

The Apple Developer Portal guarantees that App Group IDs are unique across the app ecosystem.

Logging

No sensitive information should be printed to logs, whether you use system commands or third-party frameworks. Both NSLog and print output can be read by everyone who have access to device at least thru Console.app and Xcode tools even without full access to filesystem.

Apple System Log (pre-iOS10 SDK): a low-level C API which presents on OSX and iOS and has a man page. It turns out you can query the log for messages related to specific apps or just log the entire thing. Since iOS7 apps can query only their own logs, tho.

Unified Logging (iOS10 SDK): all legacy APIs (NSLog, asl_log_message, syslog, etc) are redirected to new system. Log data is stored in binary .tracev3 files in /var/db/diagnostics or /var/db/uuidtext and can be opened by Apple’s tools.

Dynamic strings, collections, arrays are assumed to be private, and if developer didn’t override this behavior, parameter’s description will be replaced with <private> word. Usage of Unified Logging and Activity Tracing is described in another story.

Because of unobvious way of extruding Apple’s logs out of device, third party libraries are often used (Crashlytics, Cocoalumberjack). Their output file is placed inside app’s directory, so can be easily accessible with forensics tools.

This text was written in January 2016, in respect of Swift3, Xcode8.1, iOS9 and iOS10.

--

--