Skip to content

Latest commit

 

History

History
991 lines (652 loc) · 20.9 KB

ios_pentesting_notes.md

File metadata and controls

991 lines (652 loc) · 20.9 KB

iOS Penetration Testing Guide

A comprehensive guide to managing iOS devices, installing and debugging apps, and performing penetration testing using various tools and commands.


Table of Contents

  1. Listing and Managing Devices
  2. Booting and Installing on Simulator
  3. SSH into iOS Device
  4. Obtaining Device UDID
  5. Dumping IPA from Jailbroken Device
  6. Installing and Debugging iPhone Apps from Command Line
  7. Bypassing Protections
  8. Frida Usage
  9. Objection Usage
  10. Miscellaneous Tools and Commands
  11. Tips and Security Best Practices
  12. Useful Websites and Tools
  13. Example: iOS Hooking and Runtime Manipulation with DVIA-v2

Listing and Managing Devices

List Connected iOS Devices

xcrun xctrace list devices

Open iOS Simulator

open -a simulator

Booting and Installing on Simulator

Boot Simulator Device

xcrun simctl boot <device_udid>

Install App on Booted Simulator

xcrun simctl install booted <path_to_app>

SSH into iOS Device

ssh [email protected] -o "StrictHostKeyChecking=no" \
-o "UserKnownHostsFile=/dev/null" \
-o "ProxyCommand=inetcat 44"

Password: alpine


Obtaining Device UDID

Get ID of Connected iPhone

idevice_id -l

Get UDID via Various Command Line Tools on macOS

Using I/O Registry Explorer (ioreg)

ioreg -p IOUSB -l | grep "USB Serial"

Example Output:

"USB Serial Number" = "9e8ada44246cee813e2f8c1407520bf2f84849ec"

Using ideviceinstaller (Available on Linux)

  1. Install ideviceinstaller:

    brew install ideviceinstaller
  2. List Device UDIDs:

    idevice_id -l

    Example Output:

    316f01bd160932d2bf2f95f1f142bc29b1c62dbc
    

Using system_profiler

system_profiler SPUSBDataType | \
sed -n -e '/iPad/,/Serial/p;/iPhone/,/Serial/p;/iPod/,/Serial/p' | \
grep "Serial Number:"

Example Output:

Serial Number: 64655621de6ef5e56a874d63f1e1bdd14f7103b1

Using instruments

instruments -s devices

Dumping IPA from Jailbroken Device

Getting the IPA File from an OTA Distribution Link

During development, apps are sometimes provided to testers via over-the-air (OTA) distribution. You'll receive an itms-services link, such as:

itms-services://?action=download-manifest&url=https://s3-ap-southeast-1.amazonaws.com/test-uat/manifest.plist

Using ITMS Services Asset Downloader

  1. Install the Tool:

    npm install -g itms-services
  2. Download the IPA File:

    itms-services -u "itms-services://?action=download-manifest&url=https://s3-ap-southeast-1.amazonaws.com/test-uat/manifest.plist" -o - > out.ipa

Getting the Installed IPA File Using Open Source Tools and Frida Directly from Device

Using frida-ios-dump

Note: Start port forwarding.

iproxy 2222 44

Way 1:

python3 dump.py -l
python3 dump.py <APPLICATION_NAME> -u mobile -P alpine

Way 2:

frida-ps -Uai
# OR
python3 dump.py -l
python3 dump.py <Identifier>

Installing and Debugging iPhone Apps from Command Line

Using ios-deploy

  1. Install ios-deploy:

    brew install ios-deploy
  2. Install App:

    Way 1:

    ios-deploy -b <APP.ipa>

    Way 2: Using TrollStore from Sileo

    • Install TrollHelper.
    • Install TrollStore after opening TrollHelper.
    • Import unsigned IPA using the + button.
    • Installed and working!

    Way 3: On a Rootful Jailbreak with Cydia

    • Ensure AppSync is installed.
    • Use Cydia directly to install the IPA or use tools like 3uTools for Mac.

Bypassing Protections

Bypass Jailbreak Detection

ios jailbreak disable --quiet

Using Objection:

objection -g com.someapp.dev explore --startup-command 'ios jailbreak disable --quiet'

Bypass SSL Pinning

ios sslpinning disable --quiet

Using Objection:

objection -g com.someapp.dev explore --startup-command 'ios sslpinning disable --quiet'

Bypass Biometrics

ios ui biometrics_bypass --quiet

Using Objection:

objection -g com.someapp.dev explore --startup-command 'ios ui biometrics_bypass --quiet'

Frida Usage

Useful Resources

List Processes

frida-ps -Uai

Filter by Keyword:

frida-ps -Uai | grep -i 'keyword'

Get PID for a Specified Keyword

frida-ps -Uai | grep -i 'keyword' | cut -d ' ' -f 1

Discover Internal Methods/Calls

frida-discover -U -f com.someapp.dev | tee frida_discover.txt

Trace Internal Methods/Calls

frida-trace -U -p 1337

With Specific Functions:

frida-trace -U -p 1337 -i 'recv*' -i 'send*'

Frida Scripts

Bypass Biometrics Using ios-touch-id-bypass Script

frida -U -no-pause -l ios-touch-id-bypass.js -f com.someapp.dev

Using Codeshare:

frida -U -no-pause --codeshare ivan-sincek/ios-touch-id-bypass -f com.someapp.dev

On Touch ID Prompt: Press Cancel.

Recommendation: Use the built-in method in Objection.

Hook All Classes and Methods Using ios-hook-classes-methods Script

frida -U -no-pause -l ios-hook-classes-methods.js -f com.someapp.dev

Using Codeshare:

frida -U -no-pause --codeshare ivan-sincek/ios-hook-classes-methods -f com.someapp.dev

Objection Usage

Useful Resources

Basic Commands

  • Explore the App:

    objection -g com.someapp.dev explore
  • Run a Frida Script in Objection:

    import somescript.js

    Using Startup Script:

    objection -g com.someapp.dev explore --startup-script somescript.js

Get Information

  • Binary Information:

    ios info binary
  • Plist Information:

    ios plist cat Info.plist
  • Environment Variables:

    env
  • HTTP Cookies:

    ios cookies get
  • Dump Keychain, NSURLCredentialStorage, and NSUserDefaults:

    ios keychain dump
    ios nsurlcredentialstorage dump
    ios nsuserdefaults get

Memory Management

  • Dump App's Memory to a File:

    memory dump all mem.dmp
  • Search App's Memory Directly:

    memory search 'somestring' --string

Hooking

  • List Classes and Methods:

    ios hooking list classes
    ios hooking search classes 'keyword'
    ios hooking list class_methods 'someclass'
    ios hooking search methods 'keyword'
  • Hook a Class or Method:

    ios hooking watch class 'someclass'

    With Arguments and Return Values:

    ios hooking watch method '-[someclass somemethod]' --dump-args --dump-return
  • Change Method's Return Value:

    ios hooking set return_value '-[someclass somemethod]' false
  • Monitor Crypto Libraries:

    ios monitor crypto
  • Monitor the Pasteboard:

    ios pasteboard monitor

    Alternatively, dump the pasteboard using Cycript.


Miscellaneous Tools and Commands

Monitor the System Log

On Kali Linux:

idevicesyslog -p 1337

Get PID from a Keyword:

keyword="keyword"
idevicesyslog -p $(frida-ps -Uai | grep -i "${keyword}" | tr -s '[:blank:]' ' ' | cut -d ' ' -f 1)

Monitor File Changes

  1. SSH to Your iOS Device:

  2. Download and Run Filemon:

    wget http://www.newosxbook.com/tools/filemon.tgz && tar zxvf filemon.tgz && chmod +x filemon
    ./filemon -c -f com.someapp.dev

Notes:

  • Always look for created or cached files, images/screenshots, etc.
  • Use nano to edit files directly on your iOS device.
  • Sensitive files should not persist in app-specific directories or system-wide directories like /tmp/.

Images and Screenshots Path

cd /var/mobile/Containers/Data/Application/YYY...YYY/Library/SplashBoard/Snapshots/

Dump the Pasteboard

  1. SSH to Your iOS Device:

  2. Run Cycript:

    cycript -p 1337
  3. Access Pasteboard Items:

    [UIPasteboard generalPasteboard].items
  4. Exit Cycript: Press CTRL + D.

Alternatively: Monitor the pasteboard in Objection.

Get the Provisioning Profile

scp [email protected]:/private/var/containers/Bundle/Application/XXX...XXX/*.app/embedded.mobileprovision ./

Verify the Profile:

openssl smime -inform der -verify -noverify -in embedded.mobileprovision

Tips and Security Best Practices

  • Keyboard Restrictions:

    • Bypass by copying and pasting data into an input field.
  • Access Tokens:

    • Should be short-lived and invalidated on logout.
  • Testing:

    • Test widgets, push notifications, app extensions, and Firebase.
    • Deeplinks and widgets can bypass authentication, including biometrics.
  • API Security:

    • Flooding 3rd party APIs can cause monetary damage or DoS by exhausting quotas/limits. Only perform such actions if explicitly allowed.
  • Data Disclosure:

    • Apps should not disclose sensitive data in predictive text, app switcher, or push notifications.
    • Warn users when taking screenshots of sensitive data.
    • Inform users that biometrics authentication can be bypassed if the device is jailbroken.
  • Production Apps:

    • Should not be debuggable.

Useful Websites and Tools


Commands to Inspect Files from an IPA Binary

Inspect Memory Dumps, Binaries, and Files

  • After testing and logging out, download app-specific directories and inspect all files.
  • Extract Base64 strings from property list files to find sensitive data.
  • Use rabin2 over strings to read Unicode characters.

Single File

Search for Hardcoded Sensitive Data

rabin2 -zzzqq somefile | grep -Pi '[^\w\d\n]+(?:basic|bearer)\ .+'

rabin2 -zzzqq somefile | grep -Pi '(?:access|account|admin|basic|bearer|card|conf|cred|customer|email|history|id|info|jwt|key|kyc|log|otp|pass|pin|priv|refresh|salt|secret|seed|setting|sign|token|transaction|transfer|user)[\w\d]*(?:\"\ *\:|\ *\=).+'

rabin2 -zzzqq somefile | grep -Pi '[^\w\d\n]+(?:bug|comment|fix|issue|note|problem|to(?:\_|\ |)do|work)[^\w\d\n]+.+'

Extract URLs, Deeplinks, IPs, etc

rabin2 -zzzqq somefile | grep -Po '\w+\:\/\/[\w\-\.\@\:\/\?\=\%\&\#]+' | sort -uf | tee urls.txt

rabin2 -zzzqq somefile | grep -Po '(?:\b25[0-5]|\b2[0-4][0-9]|\b[01]?[0-9][0-9]?)(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}' | sort -uf | tee ips.txt

Extract All Strings and Decode Base64 Strings

rabin2 -zzzqq somefile | sort -uf > strings.txt

grep -Po '(?:[a-zA-Z0-9\+\/]{4})*(?:[a-zA-Z0-9\+\/]{4}|[a-zA-Z0-9\+\/]{3}\=|[a-zA-Z0-9\+\/]{2}\=\=)' strings.txt | sort -uf > base64.txt

for string in $(cat base64.txt); do
    res=$(echo "${string}" | base64 -d 2>/dev/null | grep -PI '[\s\S]+')
    if [[ ! -z $res ]]; then
        echo -n "${string}\n${res}\n\n"
    fi
done | tee base64_decoded.txt

Multiple Files

Search for Hardcoded Sensitive Data

IFS=$'\n'; for file in $(find . -type f); do
    echo -n "\nFILE: \"${file}\"\n"
    rabin2 -zzzqq "${file}" 2>/dev/null | grep -Pi '[^\w\d\n]+(?:basic|bearer)\ .+'
done

IFS=$'\n'; for file in $(find . -type f); do
    echo -n "\nFILE: \"${file}\"\n"
    rabin2 -zzzqq "${file}" 2>/dev/null | grep -Pi '(?:access|account|admin|basic|bearer|card|conf|cred|customer|email|history|id|info|jwt|key|kyc|log|otp|pass|pin|priv|refresh|salt|secret|seed|setting|sign|token|transaction|transfer|user)[\w\d]*(?:\"\ *\:|\ *\=).+'
done

IFS=$'\n'; for file in $(find . -type f); do
    echo -n "\nFILE: \"${file}\"\n"
    rabin2 -zzzqq "${file}" 2>/dev/null | grep -Pi '[^\w\d\n]+(?:bug|comment|fix|issue|note|problem|to(?:\_|\ |)do|work)[^\w\d\n]+.+'
done

Extract URLs, Deeplinks, IPs, etc

IFS=$'\n'; for file in $(find . -type f); do
    rabin2 -zzzqq "${file}" 2>/dev/null
done | grep -Po '\w+\:\/\/[\w\-\.\@\:\/\?\=\%\&\#]+' | grep -Piv '\.(css|gif|jpeg|jpg|ogg|otf|png|svg|ttf|woff|woff2)' | sort -uf | tee urls.txt

IFS=$'\n'; for file in $(find . -type f); do
    rabin2 -zzzqq "${file}" 2>/dev/null
done | grep -Po '(?:\b25[0-5]|\b2[0-4][0-9]|\b[01]?[0-9][0-9]?)(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}' | sort -uf | tee ips.txt

Extract All Strings and Decode Base64 Strings

IFS=$'\n'; for file in $(find . -type f); do
    rabin2 -zzzqq "${file}" 2>/dev/null
done | sort -uf > strings.txt

grep -Po '(?:[a-zA-Z0-9\+\/]{4})*(?:[a-zA-Z0-9\+\/]{4}|[a-zA-Z0-9\+\/]{3}\=|[a-zA-Z0-9\+\/]{2}\=\=)' strings.txt | sort -uf > base64.txt

for string in $(cat base64.txt); do
    res=$(echo "${string}" | base64 -d 2>/dev/null | grep -PI '[\s\S]+')
    if [[ ! -z $res ]]; then
        echo -n "${string}\n${res}\n\n"
    fi
done | tee base64_decoded.txt

Deeplinks

Test .well-known/apple-app-site-association

Use Branch.io AASA Validator.

Note: Deeplinks can bypass authentication, including biometrics.

Create an HTML Template to Manually Test Deeplinks

  1. Create Directory:

    mkdir ios_deeplinks
  2. Multiple URL Schemes:

    for scheme in $(cat url_schemes.txt); do
        for url in $(cat urls.txt | grep -Poi "${scheme}\:\/\/.+"); do
            if [[ ! -z $url ]]; then
                echo -n "<a href='${url}'>${url}</a>\n<br><br>\n" | \
                tee -a "ios_deeplinks/${scheme}_deeplinks.html"
            fi
        done
    done
  3. Single URL Scheme:

    scheme="somescheme"
    for string in $(cat urls.txt | grep -Poi "${scheme}\:\/\/.+"); do
        echo -n "<a href='${string}'>${string}</a>\n<br><br>\n"
    done | tee -a "ios_deeplinks/${scheme}_deeplinks.html"
  4. Serve the HTML Files:

    python3 -m http.server 9000 --directory ios_deeplinks

Notes:

Fuzz Deeplinks Using ios-deeplink-fuzzing Script with Frida

frida -U -no-pause -l ios-deeplink-fuzzing.js -f com.someapp.dev

Using Codeshare:

frida -U -no-pause --codeshare ivan-sincek/ios-deeplink-fuzzing -f com.someapp.dev

Additional Instructions:

  • Check the source code for more details.
  • You can paste the entire source code directly into Frida and call methods as needed.

Example: iOS Hooking and Runtime Manipulation with DVIA-v2

Overview

Demonstrates how to use Frida and Objection to reverse engineer and manipulate an iOS app (DVIA-v2).

Steps

  1. Start Frida Trace:

    frida-trace -U -i "*login*" DVIA-v2
  2. Interact with the App:

    • Enter values in login boxes.

    • Press the "Login Method 1" button.

    • Observe Swift function calls in the console:

      18737 ms  _T07DVIA_v240RuntimeManipulationDetailsViewControllerC18loginMethod1TappedyypF()
      22787 ms  _T07DVIA_v240RuntimeManipulationDetailsViewControllerC18loginMethod2TappedyypF()
      
  3. Load Objection into DVIA-v2:

    objection --gadget DVIA-v2 explore
  4. Search for Relevant Classes:

    ios hooking search classes login
    • Example Output: 30 classes found.
  5. Watch Specific Class:

    ios hooking watch class LoginValidate
    • Methods Observed:
      • +[LoginValidate isLoginValidated]
      • +[LoginValidate validateCode:viewController:]
  6. Trigger Method Call:

    • Press "Login Method 1" again.

    • Console Output:

      (agent) [442ynywbod3] Called: [LoginValidate isLoginValidated] (Kind: class) (Super: NSObject)
      
  7. Watch Method with Arguments and Return Values:

    ios hooking watch method "+[LoginValidate isLoginValidated]" --dump-args --dump-return
    • Console Output:

      (agent) [p2itp5paimj] Called: +[LoginValidate isLoginValidated] 0 arguments(Kind: class) (Super: NSObject)
      (agent) [p2itp5paimj] Return Value: 0x0
      
  8. Override Method Return Value:

    ios hooking set return_value "+[LoginValidate isLoginValidated]" true
    • Result: Bypass the login screen.

    • Console Output:

      (agent) [3so3hzb0hbz] +[LoginValidate isLoginValidated] Return value was: 0x0, overriding to 0x1
      

Using LLDB for Dynamic Analysis

  1. Create a Target Using App's Path:

    (lldb) target create /private/var/containers/Bundle/Application/6561F7CA-CC6B-44EE-80FA-497BF19C57BA/DVIA-v2.app/DVIA-v2
    

    Or Using Bundle Identifier:

    (lldb) target create --ios com.highaltitudehacks.DVIAswiftv2
    
  2. Launch the App:

    (lldb) process launch
    
    • Note: May take longer than expected. If stuck, press Ctrl+C.
  3. Calculate ASLR Offset:

    • Dump Image Sections:

      image dump sections DVIA-v2
      

      Or Run the Target:

      (lldb) target run
      
  4. Attach to Running Process by PID (Optional):

    (lldb) process attach --pid <PID>
    
  5. Set Breakpoints and Inspect Variables:

    • Example:

      (lldb) breakpoint set --name <method_name>
      
  6. Calculate Offset:

    0x000000010260c000 - 0x0000000100000000 = 0xfc6adf00
    
  7. Disassemble Function with Offset:

    dis -s 0x2f4000+0x00000001001bd300
    
  8. Set Breakpoint on Specific Address:

    br set -a 0x1004b1314
    
  9. Modify Register Value to Bypass Logic:

    register write x0 0x1
    
  10. Resume Execution:

    (lldb) c
    
    • Result: Success message on the application.

Searching for Custom Files and Databases

  • Search for Custom Files:

    find . \( -name '*.txt' -o -name '*.json' -o -name '*.pdf' -o -name '*.doc' -o -name '*.docx' -o -name '*.ppt' -o -name '*.xls' -o -name '*.xlsx' \) 2>/dev/null
  • Search for Custom Databases:

    find . \( -name '*.sqlite' -o -name '*.sqlite3' -o -name '*.db' -o \) 2>/dev/null

Check iOS Logs

idevice_id --list
idevicesyslog -u <ID> | grep <APP_BUNDLE_ID>

Additional Resources

  • Property Listener: ivan-sincek/property-lister

    • Usage After Downloading Cache.db:

      property-lister -db Cache.db -o plists
  • Convert Plist to Readable XML:

    plistutil -f xml -i com.someapp.dev.plist
  • Inspect Files:

    • Extract Base64 Strings:

      grep -Po '(?:[a-zA-Z0-9\+\/]{4})*(?:[a-zA-Z0-9\+\/]{4}|[a-zA-Z0-9\+\/]{3}\=|[a-zA-Z0-9\+\/]{2}\=\=)' strings.txt | sort -uf > base64.txt
    • Decode Base64 Strings:

      for string in $(cat base64.txt); do
          res=$(echo "${string}" | base64 -d 2>/dev/null | grep -PI '[\s\S]+')
          if [[ ! -z $res ]]; then
              echo -n "${string}\n${res}\n\n"
          fi
      done | tee base64_decoded.txt