Skip to content

Latest commit

 

History

History
146 lines (131 loc) · 17.7 KB

README.md

File metadata and controls

146 lines (131 loc) · 17.7 KB

Module 3 - Static Analysis

So far you've learned how to configure your computer and device with the necessary tools to decrypt iOS apps and copy them to your computer. In this module you'll learn how to analyze an iOS application by inspecting all its files, frameworks (dependencies) and lastly the application binary. It's called static analysis because you're not going to execute the binary, you'll be reviewing all the files contained in the .ipa archive. This is intended to be an interactive module, meaning I'll point you in the hopefully right direction and you are going to find the issues yourself. But don't worry, if you feel lost or cannot find any issues, all the solutions are at the end of the module (along with explanations on why they are considered issues and some recommended solutions).

After you decrypt an iOS application you'll end up with a .ipa file. This is an application archive, basically a zip archive. It includes the application binary, 3rd-party frameworks, configuration files, media files (like images and videos), UI elements (like storyboards and nibs), custom fonts and any other file the developers embed within the application.

To illustrate the most common vulnerabilities in iOS applications I've created a very insecure application called CoinZa[^1], I wrote it in Objective-C (aka Objc) to make it simpler to explain some reversing steps. Applications written in Swift still prove a bit difficult for some tools, though I plan to add support to some modules for Swift applications in the future. For now you can download the Objc version form here.

Extracting the application files

  • Extracting the .ipa contents is as simple as changing its extension to .zip and unzipping it.
mv CoinZa.ipa CoinZa.zip
unzip CoinZa.zip
  • After unzipping the contents you'll have a folder named Payload and inside you'll find the application bundle named CoinZa.app. Note: On an application downloaded from the App Store you'll find 2 more files along with the Payload folder, a iTunesArtwork file which is the app icon and a iTunesMetadata.plist file that contains information like the developer's name and ID, the bundle identifier, copyrights, the name of the application, your email and the date you purchased it, among other information.
  • Right-click (or Control ⌃ + Left-click) the CoinZa.app and select Show Package Contents.
  • Finally, move all the files within the .app bundle to a new folder. This is to have an easier access to them, instead of right-clicking it and selecting Show Package Contents all the time.
mkdir CoinZaFiles
mv Payload/CoinZa.app/* CoinZaFiles/

Analyzing embedded files

Your end goal is to understand as much as possible what the developers are shipping with every application. It's a good idea to start by looking for low-hanging fruit kind of issues. In iOS reversing these come as configuration files, example data files, database connection files or embedded private keys for SSH connections. Yes, as I've said before, I've seen all of these cases in real applications.

  • The two most common configuration files I've encountered in iOS applications are .plist and .json. Start your research by reading through all the files you can find with these extensions and see if you can find some information that should not be there.
  • A very important file is the Info.plist in the root directory of an iOS application. This file contains a lot of configuration data like if the application enables weak TLS settings on some domains (search for the NSAppTransportSecurity key), or if the application accepts custom Scheme URLs (search for the CFBundleURLTypes key).
  • Compiled CoreData models (.mom, .momd) can be decompiled into xcdatamodel files using tool called momdec. These files can later be inspected in Xcode.

Analyzing 3rd party frameworks

Almost every single iOS application uses at least one 3rd party framework. As a security researcher this is very important because this increases the attack surface and more often than not the developers forget to update their dependencies and the bigger the list of dependencies, the harder it is to keep track of updated versions. This means that as long as an application "still works" there's no incentive to update these 3rd party frameworks. This leaves users with outdated, and potentially vulnerable, code on their devices. All the 3rd party framework within an iOS bundle live in a folder called Frameworks.

  • Open the Frameworks folder, take a look at which frameworks CoinZa is using and pay attention to the frameworks' versions.
  • Tip 1: The framework's version is disclosed in its info.plist file.
  • Tip 2: Google those framework versions and search for known vulnerabilities.

Dumping the application classes

An essential part of the static analysis of any application is to gather information about what methods and classes are contained in the application. This step gives you very important information because, as many developers know, declaring very descriptive methods help the development of good products. Thus the names of some of the methods will give an insight of what the application features are. I'll show you how to use class-dump-z to dump the application's classes and methods. There's not going to be an exercise for this section, but you can then spend some time reading through the output and taking notes on interesting classes or methods.

  • Dumping the classes is extremely easy with class-dump-z, navigate to the folder where you extracted the CoinZa.app files and run class-dump-z with the binary name as its first parameter and save the ouput on a dump.txt file:
    cd ~/Downloads/CoinZaFiles
    class-dump-z CoinZa > dump.txt
  • If you open the dump.txt file, you have now all the classes, methods and some instance variable names of the application binary. As you can see there are some interesting classes like Wallet, KeyPair, AddFundsViewController, CreateWalletViewController. Even without installing the application we can see that this probably is a cryptocurrency application.
  • Finally, if you run class-dump-z with no parameters it will show you all the options it has for dumping classes.

Disassembling and decompiling the binary - Hopper

After the initial reconnaissance work, you've reached (IMO) the most exciting part of this module, understanding the actual behaviour of the application methods. After searching through the classes and methods in the class-dump-z output, you could see that this application is very small; but most of the applications are significantly bigger and have far more classes and methods. Because of this, it's important that you can prioritize your work and focus on the more interesting cases.

  • To disassemble and decompile the binary open Hopper and drag-n-drop the CoinZa binary in Hopper's active window. Note: You'll see that this binary is a FAT binary, which means that it contains code for more than one architecture. In this case it contains code for the ARMv7 and ARM64 architectures because this application targets a minimum version of iOS 10 and the minimum supported devices on iOS 10 are the iPhone 5, iPod Touch 6th Gen and iPad 4th Gen, which are ARMv7 devices.

Hopper

  • Hopper will ask you which architecture you want to disassemble. You can choose which ever you want though I'd recommend the ARMv7 since it has a smaller and simpler instruction set but Hopper has some trouble disassembling some parts of the application on ARMv7 and to explain better I'll be using the ARM64 disassembled code.
  • After selecting the architecture, it will ask you to set some options for the Mach-o file. The defaults should suffice.
  • Hopper will then begin to disassemble the binary. It shouldn't take too long since, again, this is a small app. But I've had some instances where it took about 45min to finish, and this was on a MacPro 6-core Xeon with 64GB RAM.
  • Once Hopper finishes disassembling, select the Procedures tab on the left panel and you'll be able to see the list of method names that hopper was able to find.

Hopper Procedures

  • If you select the Str tab (next to the Procedures one) as you probably guessed is the list of all the String-looking or printable characters within the binary. This is another favourite of mine since you can start searching for words like secret, private, test or debug and trace their usage. More often than not, developers leave test classes that provide a good insight. Sometimes there are even developer modes that we can enable to get extra functionality out of the application.

  • To trace the usage of a string:

    • Search for a string, for example search for isProVersion.
    • On the main window, select the string and right-click on it.
    • On the menu select References to aIsproversion.
    • Hopper will take you to a the cfstring section, which is where the c-string literals are listed.
    • Select the cfstring_isProVersion and right-click on it and select References to cfstring_isProVersion.
    • Hopper will now show you a window with a list of methods. As you probably guessed, this is the list of methods that use the isProVersion string.
    • Select the first instance of [AddFundsViewController viewDidAppear:] and click Go.
    • On the main window you'll now see the assembly code of the viewDidAppear method of the AddFundsViewController class. If this is a bit confusing for you, Hopper has also a decompiler function.
    • In the middle of the top options bar select the Pseudo-code Mode tab (the one with the if(b) text).

    Hopper Pseudo-code Mode

    • You'll be able to see that the string isProVersion is actually a key of an object stored in the NSUserDefaults shared settings. I'll explain more on this in a bit.
  • With the string search exercise you found evidence of features potentially guarded by a ProVersion state. You also saw in the previous exercise that you can load the pseudo-code of a method.

  • To analyze a method with its pseudo-code: Note: use the ARM64 disassembly for this exercise.

    • Click on the Procedures tab and search for WalletDetailViewController and select the didUpdateWalletBalance: method.
    • Uncheck the Remove potentially dead code checkbox. Sometimes Hopper tries to optimize the decompiled code or just gets it wrong and the pseudo-code has some missing information. I usually uncheck this checkbox in case that happened.
    • I want to bring your attention to this section of the pseudo-code:
    r2 = @"isProVersion";
    if (objc_msgSend(r0, @selector(boolForKey:)) != 0x0) {
            r8 = 0x1001f0000;
            r2 = @"isProVersion";
            r1 = @selector(stringWithFormat:);
            var_60 = d8 * 0x1001ad2e0;
            r2 = @"Since you are a pro user we added an extra 20%% and it's on us!\nYour balance will actually increase by US$%f.";
            r0 = objc_msgSend(@class(NSString), r1);
            r29 = r29;
    } else {
            r8 = 0x1001f0000;
            r2 = @"isProVersion";
            var_60 = d8;
            r2 = @"Funds purchased successfully, your balance will increase by US$ %f.";
            r0 = objc_msgSend(@class(NSString), @selector(stringWithFormat:));
            r29 = r29;
    }
    • What you can see is that enabling the ProVersion state will be beneficial to an attacker since it will grant them an extra 20% of something. You don't know what that something is yet, but looks like you should take a note about this finding. 😉 Specially since it looks like the check is done on the client side.
    • I'll leave it to you to keep digging around and take notes of interesting methods and classes. Analyze as many classes and methods as you can because they will help on the next module.
  • Tip 1: Ignore all classes with the FIR prefix, they are part of the Firebase framework and are outside of the scope of this analysis.

  • Tip 2: If you are using the trial version of Hopper take into account that it will self-close every 30min.

Disassembling and decompiling the binary - Ghidra

On March 5th, 2019 the NSA released a free and open source reversing tool called Ghidra. Ghidra supports Windows, Linux and macOS. Even though it's a very new tool and I haven't been using it as long as Hopper, I wanted to add it to the course so that we all could learn from it. Note: Like I said, I haven't used Ghidra much so please bear with me while I show you how to use it.

  • You can launch Ghidra by running the ghidraRun bash script at the root of the ghidra_9.0.1/ directory. Note: Ghidra requires the Java JDK, if you don't have it on your machine you can download it from here.
./ghidraRun
  • If this is the first time you're running Ghidra you'll have to create a project. Click on File and then New Project... (or ⌘ + N).
  • Choose if you want a Shared or Non-Shared project. Shared project can be accessed by other users.
  • Select a directory to save your project and give it a name.
  • Drag-n-drop the CoinZa binary into Ghidra.
  • Ghidra will display a dialog saying that the file contains nested files.This is the same as Hopper telling you that it was a FAT binary and you need to choose an architecture. Select the Batch option.
  • You'll be presented with a window showing you the two architectures in the binary. AARCH64:LE:64:v8A is ARM64 and ARM:LE:32:v8 is ARMv7. You can keep both selected, but since they are the same I'd suggest to just keep one selected.
  • Ghidra will show a toast saying the file was imported. Super fast eh? Not so fast, imported doesn't mean disassembled.
  • Expand your project folder and the CoinZa folder and you'll see a file called either ARM-32-cpu0x9 or AARCH64-64-cpu0x0 depending on the file you previously selected.
  • Drag-n-drop the ARM-32-cpu0x9/AARCH64-64-cpu0x0 file on top of the CodeBrowser button (the one with the dragon icon).
  • Ghidra will tell you that the file hasn't been analyzed and if you want to do it. Click Yes.
  • Leave the default selected Analyzers selected and click Analyze. Note: To be honest I haven't played around too much with Ghidra to know the different analyzers, that's why I suggested to leave the defaults.
  • In my computer Ghidra took significantly longer than Hopper.
  • On the Symbol Tree window (on the far left) select Classes and scroll down to Wallet and select the WalletDetailViewController class.
  • Within the WalletDetailViewController functions search, again, for didUpdateWalletBalance.
  • On the Decompiler window (on right side of the split windows) you'll see the decompiled code of the method. Note: If you don't see the Decompiler window press ⌘ + E.
_objc_msgSend(&OBJC_CLASS__NSUserDefaults,"standardUserDefaults");
uVar2 = objc_retainAutoreleasedReturnValue();
iVar1 = objc_msgSend(uVar2,"boolForKey:",&cf_isProVersion);
if (iVar1 == 0) {
  _objc_msgSend(&OBJC_CLASS__NSString,"stringWithFormat:",
                &cf_Fundspurchasedsuccessfully,yourbalancewillincreasebyUS$%f.);
} else {
  _objc_msgSend(&OBJC_CLASS__NSString,"stringWithFormat:",
                &
                cf_Sinceyouareaprouserweaddedanextra20%%andit'sonus!YourbalancewillactuallyincreasebyUS$%f.
               );
}
  • As you can see this looks very similar to what Hopper showed on its pseudo-code mode.
  • A huge advantage is that Ghidra is free!

Hopper Pseudo-code Mode

Conclusions

  • A static analysis on an iOS application can take you as little or as long as you want. You can go as deep as you can. Specially because the same techniques used to inspect the main application binary can be used to reverse engineer the 3rd party frameworks' binaries. I personally spend many days, and sometimes even many weeks, performing static analysis on iOS applications. Note: The first mobile bug I was ever rewarded for on HackerOne was a weak encryption vulnerability, specifically an insecure encryption key generation, basically I was able to predict past and future encryption keys. This was possible because I spent a lot of time understanding their key generation algorithm and was finally able to understand its behaviour without even running the application, all via static analysis.
  • Many developers don't realize that any file they embed in their application will be very easy to extract and analyze.
  • As researchers is very good idea to check the 3rd party frameworks bundled with the application.
  • Gather as much information as you can on this step because you'll use it in the dynamic analysis step.

Solutions

Find the solutions here.