Yeongjin Jang provides further insight into the Mactans attack by describing provisioning profile obtaining process and installing a hidden app onto iOS device.
Yeongjin Jang: Next is the description of provisioning profile. In the iOS Frameworks, there are some entities that require execution of their code on the device without Apple’s involvement. They are individual developers or some enterprises who have proprietary applications and want in-house distribution. To allow them to run the code on a device, Apple introduced the provisioning profiles. To get this provisioning profile, we need active developer’s license and the UDID of the device, and we need Internet connection. I will explain in more detail why we need those things.
To allow devices to run developer-signed code under the mandatory code signing policy of the iOS devices, Apple uses the provisioning profile. Basically, it binds a list of devices to a certain developer’s license, and then it will be digitally signed by Apple to follow up the certificate trust chain. Existence of the provisioning profile means that Apple has allowed a certain developer to run their signed code on specified devices. For example, on my iPhone which is used for iOS app development, it has a bunch of provisioning profiles and it is also signed by Apple, and only after installing those provisioning profiles I can run my application on the device.
In the provisioning profile, devices are registered with the UDID. That’s why we need to grab the UDID at the first stage. The registration of the device can be done through the developers’ portal, developer.apple.com website, so Mactans needs Internet connection to generate this file and get this signed by Apple.
However, we believe that it is not that hard to get Internet connection for a charger like Mactans. For example, if there’s free Wi-Fi connection, Mactans can use it; or if there’s a weak-keyed encrypted connection, then Mactans can hack it; or, with the advanced system-on-chip technology, we can ship Mactans with SIM card, then it can freely use the cellular network connection which is available anywhere these days. With the available Internet connection, getting this provisioning profile can easily be automated.
Let’s see what the common way to get a provisioning profile is. I found these questions & answers on the Stack Overflow, which is a well-known developers’ community. One guy says he has a device and the UDID but he doesn’t have physical access to the device, and he needs to get the provisioning profile. And the answer is: login to the provisioning portal, type some UDID and select something, and click Generate. So, it just requires the login credentials and typing the UDID, and a few clicks. And it can be easily automated by browser automation tools. We used Selenium, which is well known, and it’s really easy.
Once a provisioning profile is obtained, then it can be installed through the connection that we established at the prior pairing step. During the installation iDevices do not ask for user’s permission to install, nor is there any visual indication when it is installing on the device. Also, after installing the provisioning profile we can now inject arbitrary app that is signed by our own developer’s license. Also, on installing the application, it does not ask the user for install permission. However, unlike with the jailbreak attack, Mactans attack does not give the root privilege. So, if we install an application on the device it will be shown on the SpringBoard, the main screen of iOS devices, and it is still under the sandbox protection, so it has a runtime limitation. To make this Mactans attack meaningful and stealthy, we need to go to some further steps like hide the app to prevent unwanted deletion and we need to circumvent runtime restrictions.
Let’s start with hiding an app. Actually, there already exist some hidden apps on every stock iDevice. For example, the DemoApp.app and FieldTest.app already exist on iOS devices but the user might not see them. So we look into the common things of those apps and we look into some metadata which is called Info.plist, and there is the key ‘SBAppTags’ and the value ‘hidden’. By setting this property as ‘hidden’, it will make the app not be shown on the SpringBoard, nor will be it be shown on the Task Manager either. So, the user might not see our injected app if we set these flags.
To completely hide an app, we need to hide the execution too. Many people believe that in iOS devices there is no background service available. However, that’s not true - by default Apple allows 10-minute limits for the background service for any application. A 10-minute limit can be short, but after a short time of searching through the developers’ community I found two easy ways to circumvent this limitation. One way is, if we terminate background execution before reaching the 10-minute limit and spawn the background thread again, then iOS Frameworks will extend the limit to another 10 minutes. Or, if we set our app as a VoIP application, then we can set a callback function called ‘setKeepAliveTimeout’, and if we set it to 600 seconds, which is 10 minutes, and it will be called every 10 minutes – then we can spawn a new background thread again and again. With this method we can make our app run indefinitely on the device.
So, we can hide an app and the execution. What can the hidden app then do? Unlike with the jailbreak attack, we do not have the root privilege and we are still under the Sandbox, but there is one advantage we can get, that is, we can freely call a private API. Private API is an undocumented API on the iOS Frameworks, and calling it is prohibited by Apple’s review process. However, in the Mactans attack there is no such limitation because there is no review process. We are just injecting our app through the USB communication.
We found two interesting things on exploiting a private API, and one thing is taking a screenshot. By running this code on the screen, a background thread can take a screenshot of the current foreground window. And, as everybody knows, in the iOS Frameworks, whenever a user types a password on the password form it will show the last character the user typed in to verify their typing. So, if we take a screenshot, whenever a touch comes in, then our app can steal the password character by character.
Another interesting thing is that the screenshot is a passive attack. For an active attack, we can actually simulate the touch and the physical button press event. It is actually intended for the Xcode, for the developers, to do some automated user testing, and this is stored at UIAutomation.framework, which is on the developer’s disk that is shipped with the Xcode. But if we just grab that UIAutomation.framework file and ship it with our payload application, then we can simulate the touch without the Xcode. So, there’s a list of available APIs and there’s ‘sendTap’ at some point, so we can actually generate the touch event at the screen coordinate; or it has the ‘clickLock’, ‘clickMenu’, ‘clickVolumeUp’, so we can also collect the physical button press event. So, previously, from the screenshot we had the eye of the user, and with the touch event we have the hand of the user; therefore our hidden app can do everything the user can.