mcpField
A
apk-redteam-pipeline

apk-redteam-pipeline

github.com/uphiago安全1.3k42 次安装8 周前更新
代码仓库

关于 apk-redteam-pipeline

这项 Android 应用红队技能将 APK 获取、静态检查和运行时测试组织成分阶段流程,面向授权范围内的移动应用评估,覆盖应用清点、API 与组件分析。

主要功能

  1. 01组织名下应用清点
  2. 02APK 与拆分 XAPK 获取
  3. 03DEX 反编译与密钥搜索
  4. 04证书和导出组件检查
  5. 05Frida 插桩与流量捕获
  6. 06Firebase 配置审查

适用场景

  1. 01评估授权范围内的 Android 应用
  2. 02从 APK 中查找 API 主机与凭据
  3. 03检查导出组件和应用配置
  4. 04绕过证书固定后检查运行时请求

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/uphiago/recon-skills --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 --max-time 30 --connect-timeout 10 -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 --connect-timeout 10 \
  "https://d.apkpure.net/b/APK/<package_id>?version=latest" \
  -o "<package_id>.apk"

# Or via the legacy d-XX.app-mirror.example.com mirror chain (we saw this work)
次选:在 APKMirror 搜索
curl --max-time 30 --connect-timeout 10 -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 --max-time 30 --connect-timeout 10 -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 --max-time 30 --connect-timeout 10 -s "https://firestore.googleapis.com/v1/projects/<project_id>/databases/(default)/documents/users"

# Test if Realtime DB is publicly readable
curl --max-time 30 --connect-timeout 10 -s "https://<project_id>.firebaseio.com/.json"

# Test if Storage Bucket is publicly listable
curl --max-time 30 --connect-timeout 10 -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://)如果缺少证书固定,可能遭遇降级攻击中间人攻击
为内部主机固定的证书发现了新的资产——该主机确实存在
导出的 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 的模拟器或测试设备。
  • APKPure CDN 速率限制——下载内容被截断、缺少 EOCD 的情况很常见。更换 IP(切换 VPN 节点)后重试;对于部分下载的归档文件,7z x 比 unzip 更宽容。
  • 大型 APK 可能导致 jadx 内存溢出——对于大于 100 MB 的 APK,使用 -Xmx4g 增加 jadx 堆内存,或先改用仅运行 strings 的流程。
  • assets/ 中的 Keystore/SQLite 文件——由于不符合正则表达式机密模式而容易被忽略。请手动检查 assets/ 目录树中的 .db、.sqlite、.jks、.bks、.p12 文件。
  • ProGuard/R8 混淆——大多数 APK 都经过混淆;机密模式会保留,但类名不会。不要因为方法名是 a.b.c.d 就排除某个 APK。
  • Multi-dex APK——一些机密位于 classes2.dex 及后续文件中;不要只检查 classes.dex。
  • Play Store 开发者页面可能列出非活跃 / 测试版应用——请结合下载量和最后更新时间进行交叉核对;过时的应用可能已归档,但仍会泄露机密。

验证

运行此自测,以确认整个流程端到端正常:

  1. 获取测试——下载任意公开可用的 APK,并验证该文件是有效的 ZIP:

    download-apk() {
      local pkg="$1"
      curl -sk -L --max-time 60 --connect-timeout 10 "https://d.apkpure.net/b/APK/$pkg?version=latest" -o "/tmp/$pkg.apk"
      file "/tmp/$pkg.apk"  # should report: Zip archive data / Java archive data
    }
    download-apk org.example.testapp
    
  2. 反编译测试——apktool 能解码二进制清单:

    apktool d /tmp/org.example.testapp.apk -o /tmp/testapp_decoded/
    ls /tmp/testapp_decoded/AndroidManifest.xml 2>/dev/null && echo "PASS: manifest decoded" || echo "FAIL: apktool not installed or APK corrupted"
    
  3. 机密搜索测试——确认模式能匹配已知测试值:

    echo "AKIA1234567890ABCDEF" | grep -oE 'AKIA[A-Z0-9]{16}' && echo "PASS: AWS key pattern" || echo "FAIL"
    echo "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.dozjgNryP4J3jVmNHl0w5N_XgL0n3I9PlFUP0THsR8U" | grep -oE 'eyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]*' && echo "PASS: JWT pattern" || echo "FAIL"
    echo "AIzaSyD4iE2xVh2G7kLpQmN3jR8tUwXyZ1aBcDeF" | grep -oE 'AIza[A-Za-z0-9_-]{35}' && echo "PASS: Google API key pattern" || echo "FAIL"
    
  4. XAPK 处理测试——确认 7z 可用于处理分包 APK:

    7z --help >/dev/null 2>&1 && echo "PASS: 7z available" || echo "FAIL: install p7zip-full"
    
  5. Firebase 测试——确认 google-services.json 解析正常:

    echo '{"project_info":{"project_id":"test-project"}}' > /tmp/test-gs.json
    python3 -c "import json; d=json.load(open('/tmp/test-gs.json')); print(d['project_info']['project_id'])" && echo "PASS" || echo "FAIL"
    rm -f /tmp/test-gs.json
    

如果 5 项测试全部通过,说明整个流程已正常运行。测试 1(获取)可能因 APKPure CDN 屏蔽而失败——这不会影响工作流的其余部分;请改用 APKMirror 或直接 APK URL。


工具安装(一次性)

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 --connect-timeout 10 "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 — 获取算法和示例令牌后即可进行 JWT 操纵
  • evidence-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 字符串搜索生成 AWS Access Key ID + Secret → cloud-iam-deep aws sts get-caller-identity → 角色/策略枚举 → IAM 权限提升路径(24 种已记录的 AWS 提权模式之一)→ 接管云控制面。同样的流程也适用于从 APK 资源中提取的 GCP 服务账号 JSON 和 Azure shared-access-signature 令牌。
  • 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 注入接收点的导出组件也可能触发 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