Skip to content

miticollo/poc-anfora

Repository files navigation

PoC AnForA

A tool for the Automated Forensic Analysis of iOS Applications. In particular, AnForA automates most of the activities that need to be carried out to forensically analyze iOS applications, and that has been designed in such a way to yield various important properties, namely fidelity, artifact coverage, artifact precision, effectiveness, repeatability, and generality.

Watch the demo

YouTube video demo

Features

  • Installing and uninstalling apps
  • Changing location
  • Dumping files and their metadata before and after each sub-experiment over SSH
  • Generating pcap files for each sub-experiment
  • Attaching to all user-spawned processes
  • Detecting all paths (Data and AppGroup containers)
  • Using Appium for UI automation
  • Partially reverting sub-experiment writings on the file system
  • Partially handling third-party writings (e.g., application permissions)

TODO

  • Advance Action File Generator (AAFG)
    An interactive GUI that mirrors the iPhone screen. During user interaction, it generates the action file with appropriate sleep times, if statements and functions.

  • Add an option (like --test) to test the generated (or written) action file without dumping, sniffing, or hooking, only performing FS revert.

  • Get paths dynamically

  • Remove all TODO

Supported devices

⚠️ This PoC is designed for iPhone X with iOS 16.3.1.

This means that IT DOESN'T WORK on other iDevices. Because Appium sometimes taps the screen using coordinates. They are hardcoded to adjust this PoC to your iPhone you can change these coordinates.

How to run

  1. Clone this project
    git clone --depth=1 -j8 https://github.com/miticollo/poc-anfora.git
    cd poc-anfora
  2. Download NodeJS dependencies
    npm -ddd install
  3. Install pip dependencies
    brew -v install cairo gobject-introspection
  4. Download Python dependencies
    pip -vvv install --upgrade -r requirements.txt
  5. Choose Xcode version if you want to build WDA app, otherwise skip this step
    export DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer # Adjust path if necessary
  6. Run Appium server
    npx appium server --session-override
  7. Open a new terminal window and choose appropriate options to properly run the PoC.
    • If you have already installed the WDA app you can run the Python script without any particular options on all supported OSs:

      python ./src/main.py UDID -o DUMP_PATH

      To find <UDID>, you can use idevice_id -l.

    • If you have not already installed the WDA app and

      • your OS is macOS
        python ./src/main.py UDID -o DUMP_PATH -b it.uniupo.dsdf.WebDriverAgentRunner --team-id <TEAM_ID>
        The procedure to retrieve your <TEAM_ID> depends on whether you are enrolled in the Apple Developer program or not. If you are enrolled in the program, you can follow this guide to find your <TEAM_ID>. However, if you have a free account, you must create a blank project with Xcode and then run utility/devteamid.sh with the Apple ID that you used to create the previous project. When you create a new project, Xcode downloads a provisioning file and generates an identity (certificate + private key). The Organizational Unit (OU) attribute in this X.509 certificate is set to <TEAM_ID> and it is assigned to you by Apple. Remember that <TEAM_ID> is unique and immutable, so save it for future uses. You can also find this certificate by exploring the Keychain app, in particular looking in login.keychain.
      • your OS is not macOS
        1. Follow below instructions to prepare a Docker container with macOS.
        2. Open Xcode
          open -a /Applications/Xcode.app # Adjust path if necessary
        3. Add your Apple ID to Xcode. Go to Settings > Accounts.
        4. Create a blank project using the Apple ID you have just added to Xcode.

          Note
          This step is FUNDAMENTALLY because without it, you can't use utility/devteamid.sh given that there is no identity in Keychain.

        5. Close Xcode.
        6. Pass through iPhone to container
        7. Unlock the login.keychain. Add the following command before Appium server start command.
          security -v unlock-keychain -p PASSWORD login.keychain && npx appium server --session-override

          Warning
          This permits the build over SSH without GUI.

        8. Finally run
           python ./src/main.py UDID -b it.uniupo.dsdf.WebDriverAgentRunner --team-id <TEAM_ID> --install-wda-only
          to (re)install the WDA app. Find your TEAM_ID using utility/devteamid.sh with the Apple ID that you used for Xcode.
        9. Shutdown the container. Now you can use Linux or Windows!

      Note
      If appium server fails with error: Failed to register bundle identifier: The app identifier "it.uniupo.dsdf.WebDriverAgentRunner.xctrunner" cannot be registered to your development team because it is not available. Change your bundle identifier to a unique string to try again. You can fix it with the option [-b BUNDLE_ID].

Other OSs

To support other operating systems, we will use Docker, specifically this project. Please note that I have only tested this project on Linux. However, the project also provides instructions for Windows.

Linux

I'll show what you must do on your host and on macOS separately.

On your host

Note
I used Manjaro as Linux Distro.

The information for the project that I linked before is extensive, so here are the main steps with some additions:

  1. Setup Linux to pass through iPhone to container. If you want to use an SSH session, you can install sshpass on your Linux machine using a package manager such as yum, apt-get, or pacman, depending on your distribution. For example, in my case, I used the following command:
    yay -S sshpass
    Then, run the following command to establish an SSH connection:
    # adjust the values to match your environment
    sshpass -p <password> ssh -v user@localhost -p 50922

    Warning
    You need to enable remote login in the virtual macOS first.

  2. Initial setup
  3. Choose a macOS release. I chose Ventura. To increase verbosity, you can pass the global option -l with the argument debug to docker. Pass the option --name 'anfora_appium' to correctly identify our container.
  4. In another terminal window start a TCP listener on port 3000 using socat, a more versatile and powerful networking tool than nc
    socat TCP-LISTEN:3000,reuseaddr,fork -
    In this way any incoming connections will be forked into a new process (fork option), so that multiple clients can connect simultaneously. The - at the end specifies that data from the connection should be written to the standard output. We will use it as shared clipboard between host and guest if necessary.
  5. If you have shut down the container, you can restart it by running:
    docker -l debug start -ai "$(docker ps -a -f 'name=anfora_appium' -q)"

    Note
    This command lists all containers (running and stopped) and filters the output based on the container name. It then prints only the short UUID identifier using the -q option, which is used as input for the docker start command.

On macOS side

Now some instruction to set up macOS. These commands will be run inside container, so they are independently of host OS (Windows or Linux).

  1. After boot, you are in recovery mode. If necessary change the language otherwise the OS will be installed with the current language: English(US). To do this: File > Choose Language...

  2. Erase disk

  3. After installation - when desktop appears - you can run some commands to optimize macOS:

    1. Disable heavy login screen wallpaper
    2. Reduce Motion & Transparency
    3. Disable screen locking
    4. Show a lighter username/password prompt instead of a list of all the users

    If you want you can also choose others optimizations.

  4. To connect to the previously started listener, open a terminal and run the command nc 172.17.0.1 3000.

  5. In another terminal window and run git to install Command Line Tools for Xcode. This doesn't install Xcode.

  6. Install HomeBrew.

  7. To install Xcode, we will use a CLI tool called xcodes for two reasons:

    • this app automatically manages two or more different versions of Xcode and
    • another advantage is that xcodes can use aria2, a CLI tool to speed up the download of Xcode.

    Every version of Xcode comes with its own SDK version, which means that you need to install an old version of Xcode to use an old SDK version. For example, if you want to install the latest version of Xcode from the App Store and also need version 11.7 to compile your app for iOS 12+ and arm64e, you can download Xcode 11.7 from here. The file you download is a .XIP archive that you can extract using Archive Utility. Before moving it to /Applications, make sure to rename the .app folder to avoid conflicts with Xcode.app, which is the latest version. xcodes does all of this for you automatically. Furthermore, aria2 uses up to 16 connections to download files, making it 3-5x faster than URLSession.

    brew -v install robotsandpencils/made/xcodes aria2
    # Adjust XCODES_USERNAME and XCODES_PASSWORD to use your Apple ID
    XCODES_USERNAME="20024182@studenti.uniupo.it" XCODES_PASSWORD="..." xcodes install --latest --experimental-unxip --empty-trash

    This step takes a long time, so in the meantime, you can continue with the next step.

    Note
    It is not possible to pass XCODES_USERNAME and XCODES_PASSWORD to the container with docker run options -e and --env-file, because Docker-OSX creates a Docker container based on ArchLinux, then installs in it QEMU. This is necessary because Docker-OSX uses another project called OSX-KVM under the hood.
    To prove that an ArchLinux Docker container is used under macOS, we can use the following Bash command inside the container:

    docker exec -it 'anfora_appium' bash -c 'grep -e vmx -e svm /proc/cpuinfo'

    This command checks if a requirement is met.

  8. To install Python we will use pyenv a version manager with two important feature:

    • it automatically retrieves, compiles and installs a specific Python version and

    • you can choose a specific version per project.

      1. Install pyenv and set up the build environment
        brew -v update
        brew -v install pyenv openssl readline sqlite3 xz zlib tcl-tk
      2. Show hidden files
        defaults write com.apple.Finder AppleShowAllFiles true
        killall Finder
      3. Add autocompletion and shims to your shell environment
        pyenv init
        and follow instructions.
      4. Install the current latest Python 3 version, in my case 3.11.4
        pyenv install -v 3.11.4
        pyenv global 3.11.4
        To list all supported Python version you can run: pyenv install -l. This list can be updated every time that a pyenv update is available.
  9. We have almost done! We haven't yet install npm used by frida and Appium indeed appium server and its drivers are NodeJS programs. To install and manage it we will use a CLI tool called nvm which is a manager like pyenv.

    1. Install it with this bash command.
    2. Verify installation
      command -v nvm
    3. Install the latest NodeJS and npm version:
       nvm install --latest-npm
    4. To set the latest version of NodeJS as the default one:
      nvm alias default node
  10. Install usbfluxd to replace usbmuxd socket file to connect iPhone from host to container over network.

  11. Enable parallel building

    echo '' >> ~/.zprofile
    echo PATH=\"$(brew --prefix make)/libexec/gnubin:\$PATH\" >> ~/.zprofile

    then restart shell.

  12. Done! Go to previously section.

Capability: wdaLaunchTimeout

I had to add this capability, which was introduced in 2016; otherwise PoC would have failed inside the container during WDA installation. This is because macOS has fewer resources, which causes xcodebuild to take longer to finish. During compilation, the appium server continuously pings WDA, but it only sends a response when it is installed and running on iOS. If the wdaLaunchTimeout (which has a default value of 60000 ms or 1 minute) expires before the app starts up on iOS, the appium server tries to start a session anyway, even if it's unsuccessful. To avoid this, WebDriverAgent has a capability to change this timeout. I increased this value to 3 minutes, but if this is not sufficient, you can increase it using the short option -t of src/main.py.

In particular, when using the iOS driver, Appium tries to connect once every 0.5 seconds (500 ms), until wdaLaunchTimeout is up. More precisely, when wdaLaunchTimeout is 3 minutes (180000 ms), there will be 360 pings because 180000 / 500. However, every ping times out after 1 second (1000 ms), so there will be at most 180 effective pings.

How to Integrate Docker Container into AnForA Workflow?

A possible solution is to plan two different ways to integrate the Docker container:

  1. Manual mode: The user pulls the Docker container and installs the WDA app using the long option --install-wda-only.
  2. Automatic mode: The tool pulls the Docker container for the user and installs the WDA app using SSH. This option requires the AnForA team to create a customized container of the Docker-OSX project. The user will need to provide their Apple ID and password for Xcode installation.

The main difference between these two approaches is that the first one can be done at any time, unlike the second one.