Search code examples
iossecuritysandboxjailbreak

How to check for rooted iOS/iPadOS in our apps, like the recent checkra1n exploit?


I was going through the checkra1n exploit which jailbreaks the iOS and looked at a few open-source libraries that alert's the user that your device is compromised.

Is there a security certificate that can recognize that the device is jailbroken or a direct link/API to Apple's servers that our app verifies before it goes through a critical transaction?

Basically, the problem statement here is that a malicious user should not be able to access the critical transactional data from the rooted device or the app's sandboxed environment.


Solution

  • There is no API for checking jailbreak device, all checks are made local, but there are quite a few checks that you can implement to make the attacker's job harder:

    1. You can make your app "ask" the OS not to be run on debugger and if it is, it just crashes. You can read more here.

    2. You can check the file system for presence of specific files, that exist only on jailbroken phones with FileManager (NSFileManager):

      • /Applications/Cydia.app
      • /Library/MobileSubstrate/MobileSubstrate.dylib
      • /bin/bash
      • /usr/sbin/sshd
      • /etc/apt
      • /private/var/lib/apt/

        1. You can check if your app can open/handle a deeplink to Cydia: "cydia://package/com.example.package"
        2. You can check if your app is running with root permissions by trying to make a file out of the sandbox for your app (lets say in the root of the file system) and then deleting it.
        3. You can check what dynamic libraries are currently loaded. When a phone is jailbroken, there are some specific frameworks loaded like:
      • MobileSubstrate (used for hooking into the app's process)
      • SubstrateLoader (used for hooking into the app's process)
      • CydiaSubstrate (used for hooking into the app's process)
      • libcycript (lib from tool for decrypting binaries)
      • cynject (lib from tool for decrypting binaries)

    If you decide to implement these checks, be careful for several things like how you store your strings in the binary. If your executable Mach-O file is looked in dissasembler like Hopper and you have stored lets say the string "MobileSubstrate" the attacker can easily see it there in the __TEXT area of the executable look where this address is used and guess that you are trying to perform a jailbreak check, and NOP out your whole jailbreak test function. Keep Strings like that encoded in some way, lets say Base64.

    Other dead giveaways that you do a jailbreak test, is function names, do not name your func like isJailbroken() because these symbols can be seen again, use meaningless names (the opposite of good programming practise). Also add the tag __attribute__((always_inline)) to the declarations of your c functions that are related to jailbreak checks and @inline(__always) to the ones in Swift. If you are not familiar with function inlining you can read more about it here.

    I have build a framework containing all these checks, obfuscated but with a lot of comments, if you would like you can check it out here 🙂

    The jailbreak scene is a constant cat and mouse chase, who is going to win the chase really depends on who is willing to spend more efforts into it.

    Hope this helps!