mobile
user. Each app has a unique home directory and is sandboxed, so that they cannot access protected system resources or files stored by the system or by other apps. These restrictions are implemented via sandbox policies (aka. profiles), which are enforced by the Trusted BSD (MAC) Mandatory Access Control Framework via a kernel extension. iOS applies a generic sandbox profile to all third-party apps called container. Access to protected resources or data (some also known as app capabilities) is possible, but it's strictly controlled via special permissions known as entitlements.UIImagePickerController
(iOS 11+) and its modern replacement PHPickerViewController
(iOS 14+). These APIs run on a separate process from your app and by using them, the app gets read-only access exclusively to the images selected by the user instead of to the whole "Camera Roll". This is considered a best practice to avoid requesting unnecessary permissions.Info.plist
file of the app under the UIRequiredDeviceCapabilities
key.Typically you'll find thearmv7
capability, meaning that the app is compiled only for the armv7 instruction set, or if it’s a 32/64-bit universal app.
nfc
device capability.UIRequiredDeviceCapabilities
as a mere indication that the app is using some specific resources. Unlike the entitlements related to app capabilities, device capabilities do not confer any right or access to protected resources. Additional configuration steps might be required for that, which are very specific to each capability.bluetooth-le
device capability can be set in order to restrict non-BLE capable devices from downloading their app.bluetooth-peripheral
or bluetooth-central
(both UIBackgroundModes
) should be added if BLE background processing is required.NSBluetoothPeripheralUsageDescription
key has to be included in the Info.plist
file, meaning that the user has to actively give permission. See "Purpose Strings in the Info.plist File" below for more information.Entitlements are key value pairs that are signed in to an app and allow authentication beyond runtime factors, like UNIX user ID. Since entitlements are digitally signed, they can’t be changed. Entitlements are used extensively by system apps and daemons to perform specific privileged operations that would otherwise require the process to run as root. This greatly reduces the potential for privilege escalation by a compromised system app or daemon.
embedded.mobileprovision
).<appname>.entitlements
file as the com.apple.developer.default-data-protection
entitlement with default value NSFileProtectionComplete
. In the IPA we might find this in the embedded.mobileprovision
as:Info.plist
file of the app.Info.plist
file. Otherwise, if the app attempts to access protected data or resources without having provided the corresponding purpose string, the access will fail and the app might even crash.Info.plist
file:Info.plist
file in the default editor and search for the keys starting with "Privacy -"
."Privacy - Location When In Use Usage Description"
will turn into NSLocationWhenInUseUsageDescription
).Info.plist
is located in Payload/<appname>.app/Info.plist
.plutil -convert xml1 Info.plist
) as explained in the chapter "iOS Basic Security Testing", section "The Info.plist File".UsageDescription
:Info.plist
file to check if the permission makes sense.Info.plist
file used by a Solitaire game:NSPhotoLibraryUsageDescription
can be considered as a storage permission giving access to files that are outside of the app's sandbox and might also be accessible by other apps. In this case, it should be tested that no sensitive data is being stored there (photos in this case). For other purpose strings like NSLocationAlwaysUsageDescription
, it must be also considered if the app is storing this data securely. Refer to the "Testing Data Storage" chapter for more information and best practices on securely storing sensitive data.<appname>.entitlements
). It is automatically generated by Xcode but may be manually edited and/or extended by the developer as well.application-groups
):Payload/<appname>.app/
) under the name embedded.mobileprovision
..plist
, it is encoded using Cryptographic Message Syntax. On macOS you can inspect an embedded provisioning profile's entitlements using the following command:<key>Entitlements</key>
)..entitlements
files. This could be also the case for the embedded.mobileprovision
file. Still, you should be able to extract the entitlements property lists from the app binary yourself (which you've previously obtained as explained in the "iOS Basic Security Testing" chapter, section "Acquiring the App Binary").-e
) all XML files (-y=xml
):-qc
to quietly run one command and exit) to search all strings on the app binary (izz
) containing "PropertyList" (~PropertyList
):plist
files. If we inspect the first one (0x0015d2a4) we see that we were able to completely recover the original entitlements file from Telegram.Note: thestrings
command will not help here as it will not be able to find this information. Better use grep with the-a
flag directly on the binary or use radare2 (izz
)/rabin2 (-zz
).
-a, --text
flag (treats all files as ASCII text):-A num, --after-context=num
flag to display more or less lines. You may use tools like the ones we presented above as well, if you have them also installed on your jailbroken iOS device.This method should work even if the app binary is still encrypted (it was tested against several App Store apps).
<appname>.entitlements
file and the Info.plist
file, it is time to verify how the requested permissions and assigned capabilities are put to use. For this, a source code review should be enough. However, if you don't have the original source code, verifying the use of permissions might be specially challenging as you might need to reverse engineer the app, refer to the "Dynamic Analysis" for more details on how to proceed.Info.plist
file match the programmatic implementations.state
property of the CBCentralManager
class is used to check system-authorization status for using Bluetooth peripherals.NSLocationWhenInUseUsageDescription
).Core Location
). You may use the Apple Developer Documentation for this.CLLocationManager
), for example, using frida-trace
.CLLocationManager
implement this method):-U
connects to the USB device.-m
includes an Objective-C method to the traces. You can use a glob pattern (e.g. with the "*" wildcard,-m "*[* *authorizationStatus*]"
means "include any Objective-C method of any class containing 'authorizationStatus'"). Typefrida-trace -h
for more information.
+[CLLocationManager authorizationStatus]
returned 0x4
(CLAuthorizationStatus.authorizedWhenInUse) and was called by +[TGLocationUtils requestWhenInUserLocationAuthorizationWithLocationManager:]
. As we anticipated before, you might use this kind of information as an entry point when reverse engineering the app and from there get inputs (e.g. names of classes or methods) to keep feeding the dynamic analysis.tg://resolve?domain=fridadotre
is a custom URL scheme and uses the tg://
scheme.https://telegram.me/fridadotre
is a universal link and uses the https://
scheme..entitlements
file looking for com.apple.developer.associated-domains
. Each of the domains must be prefixed with applinks:
, such as applinks:www.mywebsite.com
..entitlements
file:apple-app-site-association
file from the server using the associated domains you got from the previous step. This file needs to be accessible via HTTPS, without any redirects, at https://<domain>/apple-app-site-association
or https://<domain>/.well-known/apple-app-site-association
."paths": ["*"]
) in order to allow all possible paths. Only if specific areas of the website should not be handled by some app, the developer can restrict access by excluding them by prepending a "NOT "
(note the whitespace after the T) to the corresponding path. Also remember that the system will look for matches by following the order of the dictionaries in the array (first match wins).applinks
) in its com.apple.developer.associated-domains
entitlement. iOS will refuse to open those links if the verification did not succeed. Some reasons to fail verification might include:appID
s do not match (this would be the case of a malicious app). iOS would successfully prevent any possible hijacking attacks.application:continueUserActivity:restorationHandler:
. If you have the original project try searching for this method.openURL:options:completionHandler:
to open a universal link to the app's website, the link won't open in the app. As the call originates from the app, it won't be handled as a universal link.From Apple Docs: When iOS launches your app after a user taps a universal link, you receive anNSUserActivity
object with anactivityType
value ofNSUserActivityTypeBrowsingWeb
. The activity object’swebpageURL
property contains the URL that the user is accessing. The webpage URL property always contains an HTTP or HTTPS URL, and you can useNSURLComponents
APIs to manipulate the components of the URL. [...] To protect users’ privacy and security, you should not use HTTP when you need to transport data; instead, use a secure transport protocol such as HTTPS.
NSUserActivity
object comes from the continueUserActivity
parameter, as seen in the method above.webpageURL
must be HTTP or HTTPS (any other scheme should throw an exception). The scheme
instance property of URLComponents
/ NSURLComponents
can be used to verify this.Universal links offer a potential attack vector into your app, so make sure to validate all URL parameters and discard any malformed URLs. In addition, limit the available actions to those that do not risk the user’s data. For example, do not allow universal links to directly delete content or access sensitive information about the user. When testing your URL-handling code, make sure your test cases include improperly formatted URLs.
NSUserActivity
object with an activityType
value of NSUserActivityTypeBrowsingWeb
. The activity object’s webpageURL
property contains the HTTP or HTTPS URL that the user accesses. The following example in Swift verifies exactly this before opening the URL:NSURLComponents
API can be used to parse and manipulate the components of the URL. This can be also part of the method application:continueUserActivity:restorationHandler:
itself or might occur on a separate method being called from it. The following example demonstrates this:openURL:options: completionHandler:
method and check the data being handled.Note that theopenURL:options:completionHandler:
method is not only used to open universal links but also to call custom URL schemes.
scheme
to "https" before opening it and how it uses the option UIApplicationOpenURLOptionUniversalLinksOnly: true
that opens the URL only if the URL is a valid universal link and there is an installed app capable of opening that URL.openURL:options:completionHandler:
is among the ones found (remember that it might be also present because the app opens custom URL schemes). Next, to ensure that no sensitive information is being leaked you'll have to perform dynamic analysis and inspect the data being transmitted. Please refer to "Identifying and Hooking the URL Handler Method" in the "Dynamic Analysis" of "Testing Custom URL Schemes" section for some examples on hooking and tracing this method.To do it from Safari you will have to find an existing link on a website that once clicked, it will be recognized as a Universal Link. This can be a bit time consuming.
apple-app-site-association
of apple.com we have seen above we chose the following paths:http://www.apple.com/shop/buy-iphone/iphone-xr
) it only offers the option to open it (in the browser).http://www.apple.com/today
) it shows options to open it in Safari and in "Apple Store":Note that there is a difference between a click and a long press. Once we long press a link and select an option, e.g. "Open in Safari", this will become the default option for all future clicks until we long press again and select another option.
application:continueUserActivity: restorationHandler:
by either hooking or tracing, we will see how it gets called as soon as we open the allowed universal link. For this you can use for example frida-trace
:apple-app-site-association
file:https://t.me/addstickers/radare
(found through a quick Internet research) and open it from the Notes app.__handlers__/
:__handlers__/
to obtain more details:NSUserActivity
. If we look in the Apple Developer Documentation we can see what else we can call from this object.-i
includes any method. You can also use a glob pattern here (e.g.-i "*open*Url*"
means "include any function containing 'open', then 'Url' and something else")
__handlers__/
:swift-demangle
via xcrun
:xcrun can be used invoke Xcode developer tools from the command-line, without having them in the path. In this case it will locate and run swift-demangle, an Xcode tool that demangles Swift symbols.
application:continueUserActivity:restorationHandler:
from the app delegate as expected.application:continueUserActivity:restorationHandler:
handles the URL but does not open it, it calls TelegramUI.openExternalUrl
for that.https://t.me/addstickers/radare
.userInfo
of the NSUserActivity
object. In the previous case there was no data being transferred but it might be the case for other scenarios. To see this, be sure to hook the userInfo
property or access it directly from the continueUserActivity
object in your hook (e.g. by adding a line like this log("userInfo:" + ObjC.Object(args[3]).userInfo().toString());
).com.apple.developer.associated-domains
entitlement and in the server's apple-app-site-association
file (in both cases via the keyword "activitycontinuation":
). See "Retrieving the Apple App Site Association File" above for an example.If the user is using a web browser on the originating device, and the receiving device is an iOS device with a native app that claims the domain portion of thewebpageURL
property, then iOS launches the native app and sends it anNSUserActivity
object with anactivityType
value ofNSUserActivityTypeBrowsingWeb
. ThewebpageURL
property contains the URL the user was visiting, while theuserInfo
dictionary is empty.
NSUserActivity
object we've received meets exactly the mentioned points:UIActivity
Sharing you should pay special attention to:UIActivity
works by creating a UIActivityViewController
and passing it the desired items (URLs, text, a picture) on init(activityItems: applicationActivities:)
.excludedActivityTypes
property. It is highly recommended to do the tests using the latest versions of iOS as the number of activity types that can be excluded can increase. The developers have to be aware of this and explicitly exclude the ones that are not appropriate for the app data. Some activity types might not be even documented like "Create Watch Face".UIActivityViewController
:init(activityItems:applicationActivities:)
method.excludedActivityTypes
, if any.application:openURL:options:
(or its deprecated version UIApplicationDelegate application:openURL:sourceApplication:annotation:
) in the app delegate.Info.plist
file and search for:UTExportedTypeDeclarations
/UTImportedTypeDeclarations
if the app declares exported/imported custom document types.CFBundleDocumentTypes
to see if the app specifies any document types that it can open.Info.plist
file.Note that this is the same as if we would retrieve the IPA from the phone or accessed via e.g. SSH and navigated to the corresponding folder in the IPA / app sandbox. However, with objection we are just one command away from our goal and this can be still considered static analysis.