iOS Crackme: an efficient way to learn by doing

TL;DR

As part of the practical exercise we give during esCoaching sessions, we recently developed a practical crackme challenge for our iOS mobile security trainees. This post explains what this crackme is like and why we developed it this way.
Beware, this post includes some spoilers for the future trainees (sorry fam, we won’t release it, and no code either).

The thing is, space tourism is coming fast and we don’t really know what’s in there. Maybe we’ll encounter friendly aliens but… maybe not. At eShard, we’re committed to defend our clients the best way we can. For our iOS training, we decided to create a fun crackme that would help people learn how to defend themselves in space along with how to defend and attack iOS applications.

Screenshot menu

Screenshot menu

This crackme is in the form of a little “space invader”-like game with a little twist: you can win a level only by cheating.

A journey in space

When we created this iOS crackme, we decided to make something different, something more fun but still relevant to real world situations. We thought about a few applications like a password manager, a banking application, etc. but were not very convinced about the “fun” potential. After speaking with a few friends, we decided that a little game like a Space Invader could work for us.

The “level design” was pretty obvious: you need to be sure the player cannot survive a wave of enemies. For that, you have multiple choices: number of enemies, their placement, the number of “lives” of the user, etc. Then, if the user is dead, they’re prompted with the “game over” screen, otherwise, they are rewarded with a flag.

Game over screen

Game over screen

At each new level, the difficulty increases by applying new concepts or adding runtime protections. The aim is to finish every level to obtain their flags. If the trainee is curious enough, they can even find other flags that were placed here and there in various usual “developer mistakes”.

Solving a level

As we wanted this to be fun and “realistic”, we did not want the trainee to be forced to use any technique to solve a level. As such, to evaluate one’s work (and because we give most of our trainings remotely), trainees need to send us a report of how they solved every level. This requires more work for us but, at the same time, it is always rewarding to see how they performed and what techniques they used that we have not thought of.

A level in the game

A level in the game

To give you an idea, they could, for example, hook the creation of a scene to ensure the player has more lives than they would ever need, make sure enemies are not loaded, void collisions, etc. It could also be possible to repackage the application and change the configuration of the enemies, or patch the code or… Really, any method is good. We only ask them three things:

  • use at least three different techniques that were taught during classes (including hooking, static reverse, repackaging, etc.)
  • do not call directly any “flag” function they could find
  • have fun!

The first levels are quite easy to solve but each time, a new technique is introduced. Some levels introduce protections, others cryptography, etc. If your player is still alive when there’s no more enemy, then, it means you won and you’re rewarded by a flag!

Real-world protections

Software protection controls are widely used in the mobile application world, so it is very important for us to show the ways to deal with these protections. Therefore, we implemented the most common anti-tampering and anti-reverse engineering protection techniques in the application.

Any of those protection techniques is not effective enough if taken independently. However, based on a layered defense approach, scattering checks throughout the code can improve the effectiveness of the overall defense strategy.

Many of those techniques have already been described here and the most common ones are:

  • Jailbreak detection,
  • debugger detection,
  • code instrumentation detection, including framework/tools detection, code hooking and code injection detection.

Developer mistakes

For the sake of realism, we also intentionally introduced bad coding practices, that hopefully, will further help in cheating and thus finding the flags.

It is important for developers to pay attention to security as it is a crucial aspect of application development. It is equally important for security testers to be able to identify those mistakes to be able to find so-called “low-hanging fruits”, namely, a set of common bad habits that leave the code of the application with holes that are easy to recognize.

Examples of common mistakes are for instance:

  • leaving hardcoded secrets in the code
  • use of insecure data storage to store valuable information
  • leaving debug logs that provide too much information that can be leveraged to quickly guess the purpose of the code
  • bad crypto usage that actually defeat the primary usage of the cryptographic function
  • etc.

Distribution puzzle

While working on this project was very fun and interesting, we had unforeseen challenges for the testing phase. One of the main problems was the distribution of the application. As we target iOS, we have to comply with Apple’s policy. As a consequence, we used a developer account in order to be able to sign our application for installation on trainee’s devices. What we did not know at the time was that, with a simple developer account, it is not possible to distribute the application without a bit of a struggle.

The first solution we came with was to add every trainee’s phone ID on our developer account. This did not please us as that could be a bit of a privacy concern for some. We checked how our clients and OWASP were dealing with distribution problems and saw that a key was present in their embedded.mobileprovision file that we did not have:

<key>ProvisionsAllDevices</key>
<true/>

After a little digging, we understood that it was possible to use this only with an Enterprise Account which requires at least 100 employees…

The second solution we found was to use TestFlight to distribute the crackme to alleged “beta testers”. To use TestFlight, one has to submit their application to Apple’s validation process. To our big surprise, it was accepted in under 24-hours. That might be because it is a game. At first we thought “yay, we can finally distribute the application” but then, we saw that 2 compilation of the same code did not give the same output, which would defeat some of our portections. As we did not have time to investigate anymore, we decided to abandon TestFlight and find a new solution.

Finally, after asking on OWASP’s Slack we decided to use AppSync. This application totally disables code signing checks at installation-time. As this could lead to security problems, we ask our trainees to uninstall it right after having installed the crackme. That way, the code signing is still enforced but our application can run without any problem!

Acknowledgements

We would like to use this occasion to thank the whole jailbreak (and particularly the checkra1n team) community for their tremendous work. Most of our work could not be possible without them taking countless hours of their time to create reliable jailbreaks.