iOS persistence is presumed to be the hardest bug to find. The attack surface is somewhat limited and constantly analyzed by Apple’s security teams.
Creativity is a key element of the hacker’s mindset. Persistence can be hard if the attackers play by the rules. As you may have guessed it already — attackers are not playing by the rules and everything is possible.
In this blog we’ll go over the ultimate persistence bug: a bug that cannot be patched because it’s not exploiting any persistence bugs at all — only playing tricks with the human mind.
Meet “NoReboot”: The ultimate persistence bug
We’ll dissect the iOS system and show how it’s possible to alter a shutdown event, tricking a user that got infected into thinking that the phone has been powered off, but in fact, it’s still running. The “NoReboot” approach simulates a real shutdown. The user cannot feel a difference between a real shutdown and a “fake shutdown”. There is no user-interface or any button feedback until the user turns the phone back “on”.
To demonstrate this technique, we’ll show a remote microphone & camera accessed after “turning off” the phone, and “persisting” when the phone will get back to a “powered on” state.
This blog can also be an excellent tutorial for anyone who may be interested in learning how to reverse engineer iOS.
Nowadays, many of us have tons of applications installed on our phones, and it is difficult to determine which among them is abusing our data and privacy. Constantly, our information is being collected, uploaded.
This story by Dan Goodin, speaks about an iOS malware discovered in-the-wild. One of the sentences in the article says: “The installed malware…can’t persist after a device reboot, … phones are disinfected as soon as they’re restarted.”
The reality is actually a bit more complicated than that. As we will be able to demonstrate in this blog, we cannot, and should not, trust a “normal reboot”.
How are we supposed to reboot iPhones?
According to Apple, a phone is rebooted by clicking on the Volume Down + Power button and dragging the slider.
Given that the iPhone has no internal fan and oftentimes it keeps its temperature cool, it’s not trivial to tell if our phones are running or not. For end users, the most intuitive indicator that the phone is the feedback from the screen. We tap on the screen or click on the side button to wake up the screen.
Here is a list of physical feedback that constantly reminds us that the phone is powered on:
- Ring/sound from incoming calls and notifications
- Touch feedback (3D touch)
- Vibration (silent mode switch triggers a burst of vibration)
- Screen
- Camera indicator
“NoReboot”: Hijacking the shutdown event
Let’s see if we can disable all of the indicators above while keeping the phone with the trojan still running. Let’s start by hijacking the shutdown event, which involves injecting code into three daemons.
When you slide to power off, it is actually a system application /Applications/InCallService.app
sending a shutdown signal to SpringBoard, which is a daemon that is responsible for the majority of the UI interaction.
We managed to hijack the signal by hooking the Objective-C method -[FBSSystemService shutdownWithOptions:]
. Now instead of sending a shutdown signal to SpringBoard, it will notify both SpringBoard and backboardd to trigger the code we injected into them.
In backboardd, we will hide the spinning wheel animation, which automatically appears when SpringBoard stops running, the magic spell which does that is [[BKSDefaults localDefaults]setHideAppleLogoOnLaunch:1]
. Then we make SpringBoard exit and block it from launching again. Because SpringBoard is responsible for responding to user behavior and interaction, without it, the device looks and feels as if it is not powered on. which is the perfect disguise for the purpose of mimicking a fake poweroff.
Shown above: Example of SpringBoard response to user’s interaction: Detects the long press action and evokes Siri
Despite that we disabled all physical feedback, the phone still remains fully functional and is capable of maintaining an active internet connection. The malicious actor could remotely manipulate the phone in a blatant way without worrying about being caught because the user is tricked into thinking that the phone is off, either being turned off by the victim or by malicious actors using “low battery” as an excuse.
Later we will demonstrate eavesdropping through the camera and microphone while the phone is “off”. In reality, malicious actors can do anything the end user can do and more.
System boot in disguise
Now the user wants to turn the phone back on. The system boot animation with Apple’s logo can convince the end user to believe that the phone has been turned off.
When SpringBoard is not on duty, backboardd is in charge of the screen. According to the description we found on theiphonewiki regarding backboardd.
“All touch events are first processed by this daemon, then translated and relayed to the iOS application in the foreground”. We found this statement to be accurate. Moreover, backboardd not only relay touch events, also physical button click events.
backboardd logs the exact time when a button is pressed down, and when it’s been released.
With the help from cycript, we noticed a way that allows us to intercept that event with Objective-C Method Hooking.
A _BKButtonEventRecord
instance will be created and inserted into a global dictionary object BKEventSenderUsagePairDictionary
. We hook the insertion method when the user attempts to “turn on” the phone.
The file will unleash the SpringBoard and trigger a special code block in our injected dylib. What it does is to leverage local SSH access to gain root privilege, then we execute /bin/launchctl reboot userspace
. This will exit all processes and restart the system without touching the kernel. The kernel remains patched. Hence malicious code won’t have any problem continuing to run after this kind of reboot.
The user will see the Apple logo effect upon restarting. This is handled by backboardd as well. Upon launching the SpringBoard, the backboardd lets SpringBoard take over the screen.
From that point, the interactive UI will be presented to the user. Everything feels right as all processes have indeed been restarted. Non-persistent threats achieved “persistency” without persistence exploits.
Hijacking the force restart event?
A user can perform a “force restart” by clicking rapidly on “Volume Up”, then “Volume Down”, then long press on the power button until the Apple logo appears.
We have not found an easy way to hijack the force restart event. This event is implemented at a much lower level. According to the post below, it is done at a hardware level. Following a brief search in the iOS kernel, we can confirm that we didn’t see what triggers the force-restart event. The good news is that it’s harder for malicious actors to disable force restart events, but at the same time end users face a risk of data loss as the system does not have enough time to securely write data to disk in case of force-restart events.
Misleading force restart
Nevertheless, It is entirely possible for malicious actors to observe the user’s attempt to perform a force-restart (via backboardd) and deliberately make the Apple logo appear a few seconds earlier, deceiving the user into releasing the button earlier than they were supposed to. Meaning that in this case, the end-user did not successfully trigger a force-restart.
NoReboot proof of concept
You can find the source code of NoReboot POC here.
Never trust a device to be off
Since iOS 15, Apple introduced a new feature allowing users to track their phone even when it’s been turned off. Malware researcher @naehrdine wrote a technical analysis on this feature and shared her opinion on “Security and privacy impact”. We agree with her on “Never trust a device to be off, until you removed its battery or even better put it into a blender.”
Subscribe to the Jamf Blog
Have market trends, Apple updates and Jamf news delivered directly to your inbox.
To learn more about how we collect, use, disclose, transfer, and store your information, please visit our Privacy Policy.