关于 apk-redteam-pipeline
apk-redteam-pipeline 是面向授权 Android 应用安全评估的技能,涵盖 APK 清点、获取、静态与运行时分析,并强调验证发现结果。
主要功能
- 01清点 Android 应用并获取 APK
- 02DEX 反编译与密钥扫描
- 03检查证书和导出组件
- 04检查 Firebase 配置
- 05使用 Frida 分析并捕获流量
适用场景
- 01评估项目范围内的 Android 应用
- 02发现嵌入的端点与凭据
- 03检查导出组件的 Intent 风险
- 04跟踪运行时令牌和 API 请求
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ elementalsouls/ claude-bughunter --skill apk-redteam-pipeline安装后在 Claude Code 中输入/apk-redteam-pipeline确认已加载。
详细介绍
使用此技能的时机
在以下情况触发:
- Recon 发现目标开发者名下有 1 个或多个移动应用(Play Store 开发者页面)
- Web 应用直接托管
*.apk文件(例如某次测试期间在子域名上发现Recruitz.apk) - 信息窃取程序日志泄露了 APK 包 ID(例如窃取程序转储格式中出现
com.<brand>.app、com.<brand>.<sub-brand>模式) - 客户端应用、经销商/合作伙伴门户或员工移动端配套应用在测试范围内
- 漏洞赏金计划将 Android 列入测试范围
请勿用于:
- 仅限 iOS 的目标(使用不同流程——IPA 逆向、MobSF、frida-ios-dump)
- 已通过 JS bundle 分析覆盖的 React Native/Flutter Web 应用
- 仅限服务端的评估
阶段 0 — 清点所有组织自有应用
抓取 Play Store 开发者页面
# Find developer page from the target's brand name
curl -sk -A "Mozilla/5.0" "https://play.google.com/store/apps/developer?id=<Brand+Name>" -o /tmp/dev.html
# Extract package IDs
grep -oE 'id=[a-zA-Z0-9._]+' /tmp/dev.html | sort -u
示例输出(已匿名处理——多品牌企业通常有 7 个包):
com.events.<brand>build
com.<corp>.<sub-brand-1>
com.<corp>.<sub-brand-2>
com.<corp>.<flagship>
com.<corp>.<product-line-1>
com.<corp>.<product-line-2>
com.<corp>.<sub-brand-3>
与信息窃取程序日志交叉核对
信息窃取程序日志格式包含类似 *@com.<corp>.<app> 的包名——如果你有泄露的转储文件,可从 creds_userpass.txt 中提取这些信息。
品牌排列组合猜测(多品牌企业模式)
com.<brand>.app
com.<brand>.mobile
com.<brand>.android
com.<brand>connect.app
in.<brand>.dealer
in.co.<brand>.app
阶段 1 — 获取 APK
首选:直接从 APKPure 获取(无需身份验证)
# Follow 302 redirects to actual download
curl -sk -L --max-time 60 \
"https://d.apkpure.net/b/APK/<package_id>?version=latest" \
-o "<package_id>.apk"
# Or via the legacy d-XX.winudf.com mirror chain (we saw this work)
次选:在 APKMirror 搜索
curl -sk -A "Mozilla/5.0" "https://www.apkmirror.com/?post_type=app_release&searchtype=apk&s=<brand>" \
| grep -oE 'href="[^"]+\.apk[^"]*"' | sort -u
备选:在 APKPure 网页搜索
curl -sk "https://apkpure.com/search?q=<brand>" | grep -oE 'data-dt-app="[^"]+"'
XAPK 与 APK
.xapk= 包含多个拆分 APK 的 zip 文件(base + config.armeabi-v7a + config.en + 等)- 先解压外层文件,再解压内层的
base.apk或<package>.apk - 部分 apkpure 下载会返回缺少 EOCD 签名的截断 XAPK——这是 CDN 限流的表现;更换 IP 后重试,或使用
7z x,它比unzip更宽容
# Standard unzip (works for clean APK)
unzip -o <package>.apk -d extracted_<package>/
# For truncated/repaired XAPK
7z x -y <package>.apk -o"extracted_<package>"
# For nested XAPK
for inner in extracted_<package>/*.apk; do
mkdir -p "extracted_<package>/$(basename "$inner" .apk)"
unzip -o "$inner" -d "extracted_<package>/$(basename "$inner" .apk)"
done
阶段 2 — DEX 反编译(jadx)
# Install
brew install jadx # macOS
# or
wget https://github.com/skylot/jadx/releases/latest/download/jadx-1.5.x.zip
# Decompile
jadx -d decompiled_<package>/ <package>.apk
# For XAPK that contains multiple APKs
for inner in extracted_<package>/*.apk; do
jadx -d decompiled_<package>_$(basename "$inner" .apk)/ "$inner"
done
如需快速扫描“仅字符串”而不进行完整反编译:
find extracted_<package> -name "classes*.dex" -exec strings -8 {} \; > strings_<package>.txt
阶段 3 — 搜索密钥(60 种模式目录)
# URL grep — owned-domain references
grep -oE 'https?://[a-zA-Z0-9.-]+\.(target1|target2|target3)\.(com|io|net|in)[a-zA-Z0-9./_?=&%-]*' strings_<package>.txt | sort -u
# Internal IP / port URLs
grep -oE 'https?://(10\.|172\.(1[6-9]|2[0-9]|3[01])\.|192\.168\.|127\.)[0-9.]+(:[0-9]+)?[a-zA-Z0-9./_?=&-]*' strings_<package>.txt
# Cloud credentials
grep -oE 'AKIA[A-Z0-9]{16}' # AWS Access Key
grep -oE 'aws_secret_access_key[\s:=]+[A-Za-z0-9/+=]{40}' # AWS Secret
grep -oE 'AIza[A-Za-z0-9_-]{35}' # Google API key
grep -oE 'ya29\.[A-Za-z0-9_-]+' # Google OAuth refresh token
grep -oE 'gh[ps]_[A-Za-z0-9]{36}' # GitHub PAT
grep -oE 'glpat-[A-Za-z0-9_-]{20}' # GitLab PAT
grep -oE 'xox[pbar]-[A-Za-z0-9-]+' # Slack token
grep -oE 'sk-[A-Za-z0-9]{48}' # OpenAI API key
grep -oE 'sk-ant-[A-Za-z0-9_-]{90,}' # Anthropic API key
grep -oE 'AC[a-f0-9]{32}' # Twilio Account SID
grep -oE 'sk_live_[A-Za-z0-9]{24}' # Stripe live key
grep -oE 'pk_live_[A-Za-z0-9]{24}' # Stripe publishable
grep -oE 'mailgun-[A-Za-z0-9-]{40}' # Mailgun
grep -oE 'SG\.[A-Za-z0-9_-]{22}\.[A-Za-z0-9_-]{43}' # SendGrid
# JWT (any algorithm)
grep -oE 'eyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]*' strings_<package>.txt
# Firebase
grep -oE '"(api_key|project_id|database_url|storage_bucket|client_id|mobilesdk_app_id|google_app_id|gcm_defaultSenderId)"\s*:\s*"[^"]+"' \
extracted_<package>/res/values/strings.xml \
extracted_<package>/google-services.json \
decompiled_<package>/resources/AndroidManifest.xml 2>/dev/null
# OAuth client secrets
grep -oE 'client_secret["\s:=]+[A-Za-z0-9_-]{24,}' strings_<package>.txt
# Hardcoded passwords (heuristic — many false positives, manual review)
grep -oE '"password"\s*:\s*"[^"]+"|password\s*=\s*"[^"]+"' decompiled_<package>/sources/**/*.java 2>/dev/null
真实案例发现(已匿名处理——来自一次经授权的测试)
# Customer-facing APK shipped a hardcoded URL of this shape:
https://api.<client>.example/<path-token>/<resource-token>?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.<payload>.<sig>
# Decoded JWT payload: {"sid":<int>,"iat":<unix-ts>,"exp":<unix-ts>}
# Expired ~8 years earlier — but path tokens + 30 /v1/* endpoints still useful intel
阶段 4 — 提取固定证书
# Find .cer / .der / .pem files in assets/
find extracted_<package>/assets -iname "*.cer" -o -iname "*.der" -o -iname "*.pem" -o -iname "*.crt" 2>/dev/null
# Or in network_security_config.xml
find extracted_<package> -name "network_security_config.xml" -exec cat {} \;
# For each cert, extract subject + SAN (might reveal new internal API hosts)
for cert in $(find extracted_<package>/assets -iname "*.cer"); do
echo "=== $cert ==="
openssl x509 -in "$cert" -noout -subject -issuer -dates 2>/dev/null
openssl x509 -in "$cert" -noout -text 2>/dev/null | grep -E 'Subject:|DNS:|Issuer:|Validity'
done
真实案例
某次经授权测试中的一款面向客户的 APK 包含 assets/api_<service>_<domain>_com.cer,揭示了 api.<service>.<domain>.example 资产的存在,而被动侦察此前并未发现该资产。
阶段 5 — 枚举导出组件
AndroidManifest.xml 会列出组件。导出的组件(尤其是带有 android:exported="true" 或通过 intent-filter 隐式导出的组件)可由其他应用触发,可能构成 Intent 注入攻击面。
# Decode binary AndroidManifest if needed
apktool d <package>.apk -o decoded_<package>/ # apktool decodes binary manifest
# Or read directly from jadx output
cat decompiled_<package>/resources/AndroidManifest.xml | grep -E '<(activity|service|receiver|provider)' | head -50
# Filter exported
grep -E 'android:exported="true"' decompiled_<package>/resources/AndroidManifest.xml
针对每个导出的组件,检查:
- 它是否接受会流入 WebView 的 extras(intent → WebView → XSS / file://)
- 它是否接受 URI extras(可能通过深层链接造成 SSRF)
- 它是否将 extras 传递给其他 Activities(Intent 重定向)
阶段 6 — 检查 Firebase/云服务配置
# google-services.json — full Firebase config
find extracted_<package> -name "google-services.json" -exec cat {} \; | python3 -m json.tool
# Look for:
# project_id → can guess Firestore / RTDB URL: https://<project_id>.firebaseio.com/.json
# storage_bucket → can guess GCS bucket: gs://<bucket>
# web_api_key → can use to enumerate Firebase tenant config
# Test if Firestore is publicly readable
curl -s "https://firestore.googleapis.com/v1/projects/<project_id>/databases/(default)/documents/users"
# Test if Realtime DB is publicly readable
curl -s "https://<project_id>.firebaseio.com/.json"
# Test if Storage Bucket is publicly listable
curl -s "https://firebasestorage.googleapis.com/v0/b/<bucket>/o"
阶段 7 — 运行时插桩(Frida)
当静态分析不够时使用——你可能需要在运行时转储令牌、绕过证书固定,或跟踪 API 调用。
设置
pip install --break-system-packages frida-tools objection
adb devices # ensure device/emulator connected
# Push frida-server to device (root required, or use rooted emulator like Genymotion / x86_64 AVD)
绕过证书固定(通用方法)
// frida-script-pinning-bypass.js
Java.perform(function() {
// OkHttp
try {
var CertificatePinner = Java.use('okhttp3.CertificatePinner');
CertificatePinner.check.overload('java.lang.String', 'java.util.List').implementation = function() {
console.log('[+] OkHttp pinning bypassed for: ' + arguments[0]);
return;
};
} catch (e) {}
// HttpsURLConnection
try {
var TrustManagerImpl = Java.use('com.android.org.conscrypt.TrustManagerImpl');
TrustManagerImpl.verifyChain.implementation = function(chain) {
console.log('[+] TrustManagerImpl verifyChain bypassed');
return chain;
};
} catch (e) {}
});
frida -U -l frida-script-pinning-bypass.js -f <package_id> --no-pause
Hook HTTP 请求
Java.perform(function() {
var OkHttpClient = Java.use('okhttp3.OkHttpClient');
var Request = Java.use('okhttp3.Request');
var Call = Java.use('okhttp3.Call');
OkHttpClient.newCall.implementation = function(req) {
var url = req.url().toString();
var headers = req.headers().toString();
console.log('[REQ] ' + url);
console.log('[HDRS] ' + headers);
return this.newCall(req);
};
});
使用 objection 快速提取令牌
objection --gadget com.target.app explore
# Inside:
android hooking watch class_method <class>.<method> --dump-args --dump-return
阶段 8 — 捕获网络流量(通过 mitmproxy)
绕过证书固定后,可用于深入发现 API。
# Run mitmproxy on host
mitmproxy --listen-port 8080
# Configure Android device proxy to host:8080
# Install mitmproxy CA cert on device:
# - Pull from http://mitm.it on the device, or
# - Push to /system/etc/security/cacerts/ on rooted device
# Use the Frida pinning bypass script while traffic flows through mitmproxy
# All API calls visible in mitmproxy UI
决策树 — 如何处理发现的内容
| 发现 | 下一步 |
|---|---|
| 有效 JWT(未过期) | 针对 API 主机进行测试 — 它是否授予访问权限?尝试操纵 sid |
| 已过期的 JWT | 检查路径令牌 / API 端点结构 — 这些信息在 VPN 后仍有用 |
| AWS 访问密钥 | 使用 awscli 进行测试:aws sts get-caller-identity — 许多泄露的密钥仍有权限 |
| Firebase project_id + web_api_key | 测试 Firestore/RTDB/Storage 的公开读取权限 |
| Google API 密钥(AIza*) | 使用 https://www.googleapis.com/customsearch/v1 等进行测试 — 查看该密钥启用了哪些 API |
| 硬编码的 HTTP URL(http://) | 如果缺少证书固定,可能遭遇降级攻击 MITM |
| 内部主机的固定证书 | 发现新资产 — 该主机确实存在 |
| 导出的 Activity 包含 WebView | 测试 Intent 注入 → URL 加载滥用 |
| 堆栈跟踪痕迹(Stack Overflow URL) | 找出开发者提出的问题 → 推断架构 |
| 硬编码凭据 | 立即进行喷洒攻击(遵守相关技能中的任何限制) |
反模式
- 不要只搜索“password” — 大多数密钥都有特定的高信号模式(AKIA、AIza、eyJ 等)。搜索通用词会产生过多噪声。
- 不要跳过 XAPK 拆分 APK — config.armeabi 拆分包和 config. 拆分包有时包含不同的代码路径。
- 不要把过期的 JWT 当作“无用情报” — 路径结构、端点列表和签名算法仍然有用。上文 8 年前过期的 JWT 示例就说明了这一点。
- 不要只逆向最新版本 — 较旧的 APK 版本(可通过 APKMirror 版本历史获取)有时仍保留已从新版本移除、但在服务端仍有效的密钥。
- 即使应用看起来“简单”,也不要忽略 Firebase — Firebase 规则配置错误(Firestore 可公开读取)极为常见。
- 不要在生产设备上运行 Frida — 仅使用已 Root 的模拟器或测试设备。
工具安装(一次性)
brew install jadx p7zip
pip install --break-system-packages frida-tools objection
# Genymotion or AVD for rooted Android emulator
为了方便下载 APK,可以添加一个 download-apk shell 函数:
download-apk() {
local pkg="$1"
curl -sk -L --max-time 60 "https://d.apkpure.net/b/APK/$pkg?version=latest" -o "$pkg.apk"
echo "Downloaded $(wc -c < "$pkg.apk") bytes"
file "$pkg.apk"
}
与相邻技能的衔接
offensive-osint— Play Store / APKMirror 枚举是更广泛 OSINT 的一部分hunt-cloud-misconfig— 发现 Firebase 可公开读取后,后续处理正是此技能的专长hunt-api-misconfig— 获取算法和示例令牌后操纵 JWTevidence-hygiene— 将提取的密钥纳入报告前需要脱敏redteam-mindset— 在交战第 1 天逆向 APK,而不是事后才做
真实案例发现模板(已匿名化 — 授权交战)
发现:面向客户的 APK 中存在硬编码 JWT + 30 多个内部 API 端点
- 对象:旧版移动应用构建中的硬编码痕迹暴露了内部 API 面
- 观察:对
com.<client>.<app>进行反编译后,发现嵌入的 JWT(约 8 年前已过期)以及指向api2.<client>.example的 30 多个/v1/*端点路径(仅限内部访问,外部无法访问) - 描述:APK 随附了开发者构建痕迹。路径令牌属于通过隐蔽性实现安全;API 端点清单具有侦察级价值。
- 影响:获得 VPN 后的立足点(通过凭据泄露)后,攻击者无需逆向二进制文件即可获取完整的 API 面图谱。通过 SSRF/LFI 恢复 HS256 密钥后,即可任意伪造令牌。
- 建议:轮换 HS256 密钥,迁移至 RS256,从构建中移除硬编码 URL,并审计组织内所有 APK。
- 证据:提取的字符串、解码后的 JWT、端点清单
相关技能与链路
cloud-iam-deep— APK 秘密提取经常会获得有效的 AWS/GCP/Azure 凭据。链路原语:jadx 字符串 grep 得到 AWS Access Key ID + Secret →cloud-iam-deepaws sts get-caller-identity→ 枚举角色/策略 → IAM 权限提升路径(24 种有文档记录的 AWS 提权模式之一)→ 接管云控制面。同一流程也适用于从 APK 资源中提取的 GCP 服务账号 JSON 和 Azure 共享访问签名令牌。hunt-api-misconfig— APK 端点清单会直接提供 API 攻击面;批量赋值、JWT 和 CORS 漏洞很常见。链路原语:APK 揭示/v1/users/me和/v1/admin/users→ 使用hunt-api-misconfig对/v1/users/me进行批量赋值探测({is_admin:true})→ 提升为管理员角色 → 访问/v1/admin/users。hunt-rce— 从 APK 提取的硬编码 JWT 签名密钥(HS256)可用于伪造任意令牌。链路原语:APK 字符串中提取出 HS256 密钥 → 伪造管理员令牌 → 访问管理员 API → 如果 API 存在 eval/template/sink → 使用hunt-rce入侵服务器。此外,如果应用是本地安装的,带有 intent 注入 sink 的导出组件可以触达Runtime.exec。offensive-osint— APK 是更广泛的组织侦察图谱中的一个节点;可结合泄露语料库和证书透明度数据。链路原语:APK 揭示内部 API 主机名api2.example.com→ 使用offensive-osint查询证书透明度 → 发现关联的子域名 → 扩大攻击面。redteam-report-template— APK 发现需要清晰说明“二进制文件泄露了什么”,因为客户工程师常常会把移动端静态分析发现斥为“混淆问题”。链路原语:已验证的发现(提取出的令牌/URL/密钥)→triage-validation的 7-Question Gate(特别是:“此凭据目前仍能通过身份验证吗?”)→ 使用redteam-report-template打包,并明确注明二进制版本和提取复现步骤。
评论
支持 Markdown