cyberaudit-skill 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +77 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +241 -0
- package/dist/mcp-server.d.ts +2 -0
- package/dist/mcp-server.js +126 -0
- package/package.json +58 -0
- package/skills/cyberaudit/AGENT-BOOT.md +122 -0
- package/skills/cyberaudit/COMMANDS.md +1125 -0
- package/skills/cyberaudit/INSTALL.md +311 -0
- package/skills/cyberaudit/MASTER.md +194 -0
- package/skills/cyberaudit/README.md +154 -0
- package/skills/cyberaudit/USAGE-GUIDE.md +107 -0
- package/skills/cyberaudit/mobile/MOBILE-CHECKLIST.md +245 -0
- package/skills/cyberaudit/mobile/MOBILE-PHILOSOPHY.md +352 -0
- package/skills/cyberaudit/mobile/MOBILE-REMEDIATION-LIBRARY.md +468 -0
- package/skills/cyberaudit/mobile/MOBILE-THREAT-MODELS.md +279 -0
- package/skills/cyberaudit/mobile/frameworks/EXPO.md +247 -0
- package/skills/cyberaudit/mobile/frameworks/FLUTTER.md +338 -0
- package/skills/cyberaudit/mobile/frameworks/IONIC.md +248 -0
- package/skills/cyberaudit/mobile/frameworks/REACT-NATIVE.md +479 -0
- package/skills/cyberaudit/mobile/vulnerabilities/AUTH-MOBILE.md +160 -0
- package/skills/cyberaudit/mobile/vulnerabilities/BINARY-ANALYSIS.md +193 -0
- package/skills/cyberaudit/mobile/vulnerabilities/CRYPTO-MOBILE.md +192 -0
- package/skills/cyberaudit/mobile/vulnerabilities/IPC-DEEPLINKS.md +231 -0
- package/skills/cyberaudit/mobile/vulnerabilities/NETWORK-MOBILE.md +165 -0
- package/skills/cyberaudit/mobile/vulnerabilities/PERMISSIONS.md +180 -0
- package/skills/cyberaudit/mobile/vulnerabilities/RUNTIME-MOBILE.md +214 -0
- package/skills/cyberaudit/mobile/vulnerabilities/STORAGE.md +197 -0
- package/skills/cyberaudit/reports/EXECUTIVE-SUMMARY-TEMPLATE.md +188 -0
- package/skills/cyberaudit/reports/REPORT-TEMPLATE-MOBILE.md +410 -0
- package/skills/cyberaudit/reports/REPORT-TEMPLATE-WEB.md +222 -0
- package/skills/cyberaudit/shared/COMPLIANCE.md +307 -0
- package/skills/cyberaudit/shared/CVSS-GUIDE.md +175 -0
- package/skills/cyberaudit/shared/OWASP-MAPPER.md +130 -0
- package/skills/cyberaudit/shared/SEVERITY-SCORING.md +102 -0
- package/skills/cyberaudit/shared/THREAT-MODELING.md +112 -0
- package/skills/cyberaudit/web/WEB-CHECKLIST.md +222 -0
- package/skills/cyberaudit/web/WEB-PHILOSOPHY.md +308 -0
- package/skills/cyberaudit/web/WEB-REMEDIATION-LIBRARY.md +665 -0
- package/skills/cyberaudit/web/WEB-THREAT-MODELS.md +460 -0
- package/skills/cyberaudit/web/frameworks/ANGULAR.md +169 -0
- package/skills/cyberaudit/web/frameworks/EXPRESS.md +185 -0
- package/skills/cyberaudit/web/frameworks/LARAVEL.md +371 -0
- package/skills/cyberaudit/web/frameworks/NESTJS.md +337 -0
- package/skills/cyberaudit/web/frameworks/NEXTJS.md +352 -0
- package/skills/cyberaudit/web/frameworks/REACT.md +346 -0
- package/skills/cyberaudit/web/frameworks/VUE.md +205 -0
- package/skills/cyberaudit/web/vulnerabilities/AUTH-AUTHZ.md +117 -0
- package/skills/cyberaudit/web/vulnerabilities/BUSINESS-LOGIC.md +603 -0
- package/skills/cyberaudit/web/vulnerabilities/CORS.md +117 -0
- package/skills/cyberaudit/web/vulnerabilities/CSRF.md +131 -0
- package/skills/cyberaudit/web/vulnerabilities/DESERIALIZATION.md +96 -0
- package/skills/cyberaudit/web/vulnerabilities/HEADERS.md +105 -0
- package/skills/cyberaudit/web/vulnerabilities/IDOR-BOLA.md +153 -0
- package/skills/cyberaudit/web/vulnerabilities/INJECTION.md +165 -0
- package/skills/cyberaudit/web/vulnerabilities/SECRETS.md +119 -0
- package/skills/cyberaudit/web/vulnerabilities/SSRF.md +124 -0
- package/skills/cyberaudit/web/vulnerabilities/SUPPLY-CHAIN.md +142 -0
- package/skills/cyberaudit/web/vulnerabilities/XSS.md +133 -0
- package/skills/cyberaudit/web/vulnerabilities/XXE.md +94 -0
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
# 🔬 BINARY ANALYSIS — MOBILE VULNERABILITY GUIDE
|
|
2
|
+
# Binary security and reverse engineering protection
|
|
3
|
+
|
|
4
|
+
═══════════════════════════════════════════════════════════════
|
|
5
|
+
WHAT IS BINARY ANALYSIS?
|
|
6
|
+
═══════════════════════════════════════════════════════════════
|
|
7
|
+
|
|
8
|
+
YOUR APK/IPA IS PUBLIC
|
|
9
|
+
─────────────────────────
|
|
10
|
+
Any user can:
|
|
11
|
+
→ Download the APK from the Play Store
|
|
12
|
+
→ Extract the IPA from a jailbroken device
|
|
13
|
+
→ Download from third-party stores
|
|
14
|
+
|
|
15
|
+
With the APK/IPA, an attacker can:
|
|
16
|
+
→ Extract all strings from the binary
|
|
17
|
+
→ Reconstruct code logic
|
|
18
|
+
→ Find hidden API endpoints
|
|
19
|
+
→ Find hardcoded secrets
|
|
20
|
+
→ Modify the code and repackage the app
|
|
21
|
+
→ Bypass client-side security controls
|
|
22
|
+
|
|
23
|
+
COMMON BINARY ANALYSIS TOOLS
|
|
24
|
+
────────────────────────────────────
|
|
25
|
+
apktool → Decompiles APK (resources + smali)
|
|
26
|
+
jadx → Decompiles to readable Java/Kotlin
|
|
27
|
+
ghidra → Analyses native code (NDK)
|
|
28
|
+
frida → Runtime hooking (modify behavior)
|
|
29
|
+
objection → Mobile pentest framework based on Frida
|
|
30
|
+
radare2 → Advanced static analysis
|
|
31
|
+
strings → Extract strings from binary
|
|
32
|
+
class-dump → Extract iOS interfaces
|
|
33
|
+
Hopper → iOS/macOS disassembler
|
|
34
|
+
|
|
35
|
+
REACT NATIVE — THE SPECIAL CASE
|
|
36
|
+
────────────────────────────────────
|
|
37
|
+
React Native JavaScript code is in:
|
|
38
|
+
Android: assets/index.android.bundle
|
|
39
|
+
iOS : main.jsbundle
|
|
40
|
+
|
|
41
|
+
It is directly readable:
|
|
42
|
+
strings index.android.bundle | grep -i "api\|key\|secret"
|
|
43
|
+
|
|
44
|
+
Even "minified", the code remains readable JavaScript
|
|
45
|
+
and can be reformatted with tools.
|
|
46
|
+
|
|
47
|
+
═══════════════════════════════════════════════════════════════
|
|
48
|
+
BINARY VULNERABILITIES
|
|
49
|
+
═══════════════════════════════════════════════════════════════
|
|
50
|
+
|
|
51
|
+
VULN-BIN-001 — Hardcoded Secrets in Binary
|
|
52
|
+
Severity: CRITICAL (CVSS 9.1)
|
|
53
|
+
MASVS : MASVS-CRYPTO-5
|
|
54
|
+
|
|
55
|
+
What is found in binaries in practice:
|
|
56
|
+
→ Third-party API keys (Stripe, Twilio, AWS)
|
|
57
|
+
→ Internal environment URLs (staging, admin)
|
|
58
|
+
→ Encryption keys
|
|
59
|
+
→ Test tokens left in production
|
|
60
|
+
→ Undocumented API endpoints
|
|
61
|
+
→ Database credentials (rare but documented error)
|
|
62
|
+
|
|
63
|
+
Detection commands:
|
|
64
|
+
# Extract strings from a React Native APK
|
|
65
|
+
unzip app.apk
|
|
66
|
+
strings assets/index.android.bundle | \
|
|
67
|
+
grep -iE "(api_key|secret|password|token|bearer|sk-|pk_live)"
|
|
68
|
+
|
|
69
|
+
# With jadx (Kotlin/Java code)
|
|
70
|
+
jadx app.apk -d output/
|
|
71
|
+
grep -r "apiKey\|secret\|password" output/sources/
|
|
72
|
+
|
|
73
|
+
# iOS
|
|
74
|
+
strings App.app/App | grep -iE "(key|secret|token)"
|
|
75
|
+
|
|
76
|
+
Fix:
|
|
77
|
+
→ No secrets in source code (frontend or mobile)
|
|
78
|
+
→ Use environment variables injected at build time
|
|
79
|
+
→ Real secret keys remain server-side
|
|
80
|
+
→ The mobile app authenticates and receives
|
|
81
|
+
temporary tokens from the server which has the real secrets
|
|
82
|
+
|
|
83
|
+
VULN-BIN-002 — No Obfuscation (Android)
|
|
84
|
+
Severity: MEDIUM (CVSS 4.0)
|
|
85
|
+
MASVS : MASVS-CODE-4
|
|
86
|
+
|
|
87
|
+
Explanation:
|
|
88
|
+
Without obfuscation, code decompiled with jadx
|
|
89
|
+
is nearly identical to the original source code.
|
|
90
|
+
→ Business logic exposed
|
|
91
|
+
→ Proprietary algorithms copiable
|
|
92
|
+
→ Logical vulnerabilities easier to find
|
|
93
|
+
|
|
94
|
+
Fix for Android (build.gradle):
|
|
95
|
+
android {
|
|
96
|
+
buildTypes {
|
|
97
|
+
release {
|
|
98
|
+
minifyEnabled true
|
|
99
|
+
shrinkResources true
|
|
100
|
+
proguardFiles getDefaultProguardFile(
|
|
101
|
+
'proguard-android-optimize.txt'
|
|
102
|
+
), 'proguard-rules.pro'
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// proguard-rules.pro — Protect sensitive logic
|
|
108
|
+
-keep class com.yourapp.models.** { *; }
|
|
109
|
+
-keepclassmembers class * {
|
|
110
|
+
@com.google.gson.annotations.SerializedName <fields>;
|
|
111
|
+
}
|
|
112
|
+
// Obfuscate the rest
|
|
113
|
+
|
|
114
|
+
VULN-BIN-003 — Debug Code in Production
|
|
115
|
+
Severity: HIGH (CVSS 7.5)
|
|
116
|
+
MASVS : MASVS-CODE-2
|
|
117
|
+
|
|
118
|
+
Detection:
|
|
119
|
+
BuildConfig.DEBUG = true in release
|
|
120
|
+
android:debuggable="true" in manifest
|
|
121
|
+
/debug, /test, /dev endpoints accessible
|
|
122
|
+
Verbose logs enabled in prod
|
|
123
|
+
Expo developer mode active
|
|
124
|
+
|
|
125
|
+
Fix:
|
|
126
|
+
// Android — automatically false in release build
|
|
127
|
+
// Verify in build.gradle:
|
|
128
|
+
buildTypes {
|
|
129
|
+
release {
|
|
130
|
+
debuggable false // Explicit
|
|
131
|
+
minifyEnabled true
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// React Native — use __DEV__
|
|
136
|
+
if (__DEV__) {
|
|
137
|
+
// Debug code only
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Verify app is in release mode:
|
|
141
|
+
// npx react-native run-android --mode=release
|
|
142
|
+
// npx react-native run-ios --configuration Release
|
|
143
|
+
|
|
144
|
+
VULN-BIN-004 — Source Maps in Production
|
|
145
|
+
Severity: HIGH (CVSS 6.5)
|
|
146
|
+
MASVS : MASVS-CODE-4
|
|
147
|
+
|
|
148
|
+
Explanation:
|
|
149
|
+
Source maps allow reconstructing the exact
|
|
150
|
+
source code from the minified bundle.
|
|
151
|
+
If included in production build:
|
|
152
|
+
→ 100% readable source code
|
|
153
|
+
→ Original variable/function names
|
|
154
|
+
→ Project structure exposed
|
|
155
|
+
|
|
156
|
+
Fix:
|
|
157
|
+
// React Native — metro.config.js
|
|
158
|
+
module.exports = {
|
|
159
|
+
transformer: {
|
|
160
|
+
// In production: no source maps
|
|
161
|
+
enableBabelRCLookup: false,
|
|
162
|
+
},
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// EAS Build — eas.json
|
|
166
|
+
// Source maps can be uploaded to Sentry
|
|
167
|
+
// WITHOUT being included in the app
|
|
168
|
+
{
|
|
169
|
+
"build": {
|
|
170
|
+
"production": {
|
|
171
|
+
"env": {
|
|
172
|
+
"SENTRY_ORG": "...",
|
|
173
|
+
"SENTRY_PROJECT": "..."
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// sentry.properties — Separate upload
|
|
180
|
+
// Source maps go to Sentry, not in the APK
|
|
181
|
+
|
|
182
|
+
═══════════════════════════════════════════════════════════════
|
|
183
|
+
BINARY ANALYSIS CHECKLIST
|
|
184
|
+
═══════════════════════════════════════════════════════════════
|
|
185
|
+
|
|
186
|
+
□ No secrets in index.android.bundle / main.jsbundle ?
|
|
187
|
+
□ No secrets in compiled Kotlin/Swift files ?
|
|
188
|
+
□ No internal URLs in the binary ?
|
|
189
|
+
□ ProGuard/R8 enabled for Android release ?
|
|
190
|
+
□ android:debuggable="false" in release manifest ?
|
|
191
|
+
□ Source maps not included in production build ?
|
|
192
|
+
□ Binary strings analysed before each release ?
|
|
193
|
+
□ Release build tested different from dev build ?
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
# 🔒 CRYPTO MOBILE — VULNERABILITY GUIDE
|
|
2
|
+
# Cryptography in mobile applications
|
|
3
|
+
|
|
4
|
+
═══════════════════════════════════════════════════════════════
|
|
5
|
+
MOBILE CRYPTOGRAPHY — PRINCIPLES
|
|
6
|
+
═══════════════════════════════════════════════════════════════
|
|
7
|
+
|
|
8
|
+
GOLDEN RULES OF MOBILE CRYPTOGRAPHY
|
|
9
|
+
────────────────────────────────────────
|
|
10
|
+
1. Use platform cryptographic APIs
|
|
11
|
+
→ iOS: CryptoKit, CommonCrypto, Security Framework
|
|
12
|
+
→ Android: Keystore System, javax.crypto
|
|
13
|
+
→ Never implement your own crypto
|
|
14
|
+
|
|
15
|
+
2. Store keys in cryptographic hardware
|
|
16
|
+
→ iOS: Secure Enclave (A7+)
|
|
17
|
+
→ Android: StrongBox Keymaster (if available)
|
|
18
|
+
→ Otherwise: Software Keystore
|
|
19
|
+
|
|
20
|
+
3. Approved algorithms only
|
|
21
|
+
→ Symmetric: AES-256-GCM (authenticated)
|
|
22
|
+
→ Asymmetric: RSA-2048+, ECDSA P-256+
|
|
23
|
+
→ Hashing: SHA-256+
|
|
24
|
+
→ KDF: PBKDF2, bcrypt, argon2
|
|
25
|
+
→ NEVER: DES, 3DES, RC4, MD5, SHA1
|
|
26
|
+
|
|
27
|
+
4. Secure random generation
|
|
28
|
+
→ iOS: SecRandomCopyBytes
|
|
29
|
+
→ Android: SecureRandom (via Keystore)
|
|
30
|
+
→ Never Math.random() for crypto
|
|
31
|
+
|
|
32
|
+
═══════════════════════════════════════════════════════════════
|
|
33
|
+
MOBILE CRYPTO VULNERABILITIES
|
|
34
|
+
═══════════════════════════════════════════════════════════════
|
|
35
|
+
|
|
36
|
+
VULN-CRYPTO-001 — Weak Cryptographic Algorithms
|
|
37
|
+
Severity: CRITICAL (CVSS 9.1)
|
|
38
|
+
MASVS : MASVS-CRYPTO-1
|
|
39
|
+
|
|
40
|
+
Detection:
|
|
41
|
+
// React Native / JS
|
|
42
|
+
const hash = CryptoJS.MD5(password) // CRITICAL
|
|
43
|
+
const hash = CryptoJS.SHA1(data) // CRITICAL
|
|
44
|
+
const cipher = CryptoJS.DES.encrypt() // CRITICAL
|
|
45
|
+
const cipher = CryptoJS.RC4.encrypt() // CRITICAL
|
|
46
|
+
|
|
47
|
+
// Dart / Flutter
|
|
48
|
+
import 'package:crypto/crypto.dart';
|
|
49
|
+
final hash = md5.convert(bytes) // CRITICAL
|
|
50
|
+
final hash = sha1.convert(bytes) // Weak
|
|
51
|
+
|
|
52
|
+
// Java / Kotlin (Android)
|
|
53
|
+
MessageDigest.getInstance("MD5") // CRITICAL
|
|
54
|
+
Cipher.getInstance("DES") // CRITICAL
|
|
55
|
+
Cipher.getInstance("AES/ECB/PKCS5Padding") // ECB = vulnerable
|
|
56
|
+
|
|
57
|
+
Fix:
|
|
58
|
+
// React Native — Use expo-crypto or react-native-quick-crypto
|
|
59
|
+
import * as Crypto from 'expo-crypto'
|
|
60
|
+
|
|
61
|
+
const hash = await Crypto.digestStringAsync(
|
|
62
|
+
Crypto.CryptoDigestAlgorithm.SHA256, // SHA-256 minimum
|
|
63
|
+
data
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
// For encryption: AES-GCM via react-native-quick-crypto
|
|
67
|
+
import { createCipheriv, randomBytes } from
|
|
68
|
+
'react-native-quick-crypto'
|
|
69
|
+
|
|
70
|
+
const encrypt = (plaintext: string, key: Buffer): Buffer => {
|
|
71
|
+
const iv = randomBytes(12) // 96 bits for GCM
|
|
72
|
+
const cipher = createCipheriv('aes-256-gcm', key, iv)
|
|
73
|
+
|
|
74
|
+
const encrypted = Buffer.concat([
|
|
75
|
+
cipher.update(plaintext, 'utf8'),
|
|
76
|
+
cipher.final(),
|
|
77
|
+
])
|
|
78
|
+
|
|
79
|
+
const tag = cipher.getAuthTag() // GCM authentication tag
|
|
80
|
+
|
|
81
|
+
// Store: iv (12) + tag (16) + encrypted
|
|
82
|
+
return Buffer.concat([iv, tag, encrypted])
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
VULN-CRYPTO-002 — Hardcoded Cryptographic Key
|
|
86
|
+
Severity: CRITICAL (CVSS 9.1)
|
|
87
|
+
MASVS : MASVS-CRYPTO-5
|
|
88
|
+
|
|
89
|
+
Detection:
|
|
90
|
+
const ENCRYPTION_KEY = 'MySecretKey12345' // CRITICAL
|
|
91
|
+
const KEY = Buffer.from('aabbccdd...', 'hex') // CRITICAL
|
|
92
|
+
static final byte[] KEY = {0x41, 0x42, ...} // CRITICAL
|
|
93
|
+
|
|
94
|
+
// Flutter
|
|
95
|
+
const encryptionKey = 'hardcoded-secret-key' // CRITICAL
|
|
96
|
+
|
|
97
|
+
Fix:
|
|
98
|
+
// The key must be:
|
|
99
|
+
// 1. Randomly generated (not hardcoded)
|
|
100
|
+
// 2. Stored in Keychain/Keystore
|
|
101
|
+
// 3. Never in source code
|
|
102
|
+
|
|
103
|
+
// React Native — Secure generation and storage
|
|
104
|
+
import * as Keychain from 'react-native-keychain'
|
|
105
|
+
import { randomBytes } from 'react-native-quick-crypto'
|
|
106
|
+
|
|
107
|
+
const getOrCreateEncryptionKey = async (): Promise<Buffer> => {
|
|
108
|
+
const KEY_SERVICE = 'com.yourapp.encryption-key'
|
|
109
|
+
|
|
110
|
+
// Try to retrieve existing key
|
|
111
|
+
const existing = await Keychain.getGenericPassword({
|
|
112
|
+
service: KEY_SERVICE,
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
if (existing) {
|
|
116
|
+
return Buffer.from(existing.password, 'hex')
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Generate new key (first use)
|
|
120
|
+
const newKey = randomBytes(32) // 256 bits for AES-256
|
|
121
|
+
|
|
122
|
+
await Keychain.setGenericPassword(
|
|
123
|
+
'encryption-key',
|
|
124
|
+
newKey.toString('hex'),
|
|
125
|
+
{
|
|
126
|
+
service: KEY_SERVICE,
|
|
127
|
+
accessible: Keychain.ACCESSIBLE.WHEN_UNLOCKED_THIS_DEVICE_ONLY,
|
|
128
|
+
}
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
return newKey
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
VULN-CRYPTO-003 — Static or Predictable IV/Nonce
|
|
135
|
+
Severity: HIGH (CVSS 7.5)
|
|
136
|
+
MASVS : MASVS-CRYPTO-3
|
|
137
|
+
|
|
138
|
+
Explanation:
|
|
139
|
+
The IV (Initialization Vector) or Nonce must be:
|
|
140
|
+
→ Random and unique for EACH encryption operation
|
|
141
|
+
→ Never reused with the same key (especially in GCM)
|
|
142
|
+
|
|
143
|
+
A static IV allows:
|
|
144
|
+
→ Pattern analysis in encrypted data
|
|
145
|
+
→ Birthday attacks
|
|
146
|
+
→ In GCM: key recovery if IV reused!
|
|
147
|
+
|
|
148
|
+
Detection:
|
|
149
|
+
const iv = Buffer.from('1234567890123456') // CRITICAL: static
|
|
150
|
+
const iv = Buffer.alloc(16, 0) // CRITICAL: zeros
|
|
151
|
+
const iv = Buffer.from(userId, 'hex') // HIGH: predictable
|
|
152
|
+
|
|
153
|
+
Fix:
|
|
154
|
+
// ALWAYS generate a random IV
|
|
155
|
+
const iv = randomBytes(12) // 12 bytes for AES-GCM
|
|
156
|
+
|
|
157
|
+
// Store IV with encrypted data
|
|
158
|
+
// IV is NOT secret but must be unique
|
|
159
|
+
const stored = Buffer.concat([iv, encrypted, authTag])
|
|
160
|
+
|
|
161
|
+
VULN-CRYPTO-004 — Insecure Random Generation
|
|
162
|
+
Severity: HIGH (CVSS 7.5)
|
|
163
|
+
MASVS : MASVS-CRYPTO-3
|
|
164
|
+
|
|
165
|
+
Detection:
|
|
166
|
+
Math.random() // NEVER for crypto
|
|
167
|
+
Math.floor(Math.random() * ...) // NEVER
|
|
168
|
+
new Date().getTime() // NEVER as seed
|
|
169
|
+
|
|
170
|
+
// Java
|
|
171
|
+
new Random() // NEVER
|
|
172
|
+
new Random(System.currentTimeMillis()) // NEVER
|
|
173
|
+
|
|
174
|
+
Fix:
|
|
175
|
+
// JavaScript / React Native
|
|
176
|
+
import { randomBytes } from 'react-native-quick-crypto'
|
|
177
|
+
// OR
|
|
178
|
+
import * as Crypto from 'expo-crypto'
|
|
179
|
+
const randomValue = Crypto.getRandomBytes(32)
|
|
180
|
+
|
|
181
|
+
// Dart / Flutter
|
|
182
|
+
import 'dart:math';
|
|
183
|
+
final random = Random.secure() // .secure() = CSPRNG
|
|
184
|
+
final bytes = List<int>.generate(
|
|
185
|
+
32, (_) => random.nextInt(256)
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
// Java / Kotlin (Android)
|
|
189
|
+
import java.security.SecureRandom
|
|
190
|
+
val random = SecureRandom()
|
|
191
|
+
val bytes = ByteArray(32)
|
|
192
|
+
random.nextBytes(bytes)
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
# 🔗 IPC & DEEP LINKS — MOBILE VULNERABILITY GUIDE
|
|
2
|
+
# Inter-process communication and mobile deep links
|
|
3
|
+
|
|
4
|
+
═══════════════════════════════════════════════════════════════
|
|
5
|
+
IPC MOBILE — UNDERSTANDING THE RISKS
|
|
6
|
+
═══════════════════════════════════════════════════════════════
|
|
7
|
+
|
|
8
|
+
IPC (Inter-Process Communication) on mobile:
|
|
9
|
+
|
|
10
|
+
ANDROID iOS
|
|
11
|
+
────────── ───
|
|
12
|
+
Intents (explicit/implicit) URL Schemes
|
|
13
|
+
Content Providers Universal Links
|
|
14
|
+
Broadcast Receivers App Extensions
|
|
15
|
+
Bound Services XPC (system apps)
|
|
16
|
+
Deep Links / App Links Pasteboard
|
|
17
|
+
|
|
18
|
+
EACH IPC MECHANISM = EXTERNAL ENTRY SURFACE
|
|
19
|
+
→ Data coming from OUTSIDE the app
|
|
20
|
+
→ Potentially controlled by an attacker
|
|
21
|
+
→ Must be treated as HOSTILE
|
|
22
|
+
|
|
23
|
+
═══════════════════════════════════════════════════════════════
|
|
24
|
+
IPC AND DEEP LINK VULNERABILITIES
|
|
25
|
+
═══════════════════════════════════════════════════════════════
|
|
26
|
+
|
|
27
|
+
VULN-IPC-001 — Exported Android Activity Unprotected
|
|
28
|
+
Severity: HIGH (CVSS 7.5)
|
|
29
|
+
MASVS : MASVS-PLATFORM-1
|
|
30
|
+
|
|
31
|
+
Explanation:
|
|
32
|
+
An Activity with android:exported="true"
|
|
33
|
+
without permission protection can be launched
|
|
34
|
+
by any other application.
|
|
35
|
+
|
|
36
|
+
A malicious app can thus:
|
|
37
|
+
→ Launch sensitive Activities directly
|
|
38
|
+
→ Bypass the login screen
|
|
39
|
+
→ Access restricted features
|
|
40
|
+
|
|
41
|
+
Detection:
|
|
42
|
+
<activity
|
|
43
|
+
android:name=".AdminActivity"
|
|
44
|
+
android:exported="true"> <!-- Accessible to all apps! -->
|
|
45
|
+
<intent-filter>...</intent-filter>
|
|
46
|
+
</activity>
|
|
47
|
+
|
|
48
|
+
Exploitation:
|
|
49
|
+
// From a malicious app:
|
|
50
|
+
Intent intent = new Intent()
|
|
51
|
+
intent.setComponent(new ComponentName(
|
|
52
|
+
"com.targetapp",
|
|
53
|
+
"com.targetapp.AdminActivity"
|
|
54
|
+
))
|
|
55
|
+
startActivity(intent)
|
|
56
|
+
|
|
57
|
+
Fix:
|
|
58
|
+
<!-- Option A: Don't export if unnecessary -->
|
|
59
|
+
<activity
|
|
60
|
+
android:name=".InternalActivity"
|
|
61
|
+
android:exported="false" />
|
|
62
|
+
|
|
63
|
+
<!-- Option B: Protect with a permission -->
|
|
64
|
+
<activity
|
|
65
|
+
android:name=".SensitiveActivity"
|
|
66
|
+
android:exported="true"
|
|
67
|
+
android:permission="com.yourapp.INTERNAL">
|
|
68
|
+
</activity>
|
|
69
|
+
|
|
70
|
+
<!-- Declare signature-level permission -->
|
|
71
|
+
<permission
|
|
72
|
+
android:name="com.yourapp.INTERNAL"
|
|
73
|
+
android:protectionLevel="signature" />
|
|
74
|
+
<!-- protectionLevel="signature" = only apps signed
|
|
75
|
+
with the same key can send the intent -->
|
|
76
|
+
|
|
77
|
+
VULN-IPC-002 — Implicit Intent for Sensitive Data
|
|
78
|
+
Severity: HIGH (CVSS 6.8)
|
|
79
|
+
MASVS : MASVS-PLATFORM-1
|
|
80
|
+
|
|
81
|
+
Explanation:
|
|
82
|
+
Implicit intents (without a specific target component)
|
|
83
|
+
can be intercepted by other applications.
|
|
84
|
+
|
|
85
|
+
If an implicit intent contains sensitive data
|
|
86
|
+
(token, user data), a malicious app
|
|
87
|
+
with the same intent-filter can intercept it.
|
|
88
|
+
|
|
89
|
+
Detection:
|
|
90
|
+
Intent intent = new Intent("com.yourapp.ACTION_SHARE_TOKEN")
|
|
91
|
+
intent.putExtra("token", authToken) // Interceptable!
|
|
92
|
+
sendBroadcast(intent)
|
|
93
|
+
|
|
94
|
+
Fix:
|
|
95
|
+
// Use EXPLICIT intents for sensitive data
|
|
96
|
+
Intent intent = new Intent(context, TargetService.class)
|
|
97
|
+
intent.putExtra("action", "doSomething")
|
|
98
|
+
// No sensitive data in extras if broadcast
|
|
99
|
+
startService(intent)
|
|
100
|
+
|
|
101
|
+
// For broadcasts: use LocalBroadcastManager
|
|
102
|
+
// or signature permissions
|
|
103
|
+
LocalBroadcastManager.getInstance(context)
|
|
104
|
+
.sendBroadcast(intent)
|
|
105
|
+
|
|
106
|
+
VULN-IPC-003 — Deep Link Without Parameter Validation
|
|
107
|
+
Severity: HIGH (CVSS 7.1)
|
|
108
|
+
MASVS : MASVS-PLATFORM-2
|
|
109
|
+
|
|
110
|
+
Explanation:
|
|
111
|
+
Deep links can be triggered by:
|
|
112
|
+
→ An SMS or email received by the user
|
|
113
|
+
→ A web page (if autoVerify not configured)
|
|
114
|
+
→ Another application
|
|
115
|
+
→ A scanned QR code
|
|
116
|
+
|
|
117
|
+
If parameters are not validated:
|
|
118
|
+
→ Route injection (navigation to any screen)
|
|
119
|
+
→ Parameter injection (IDOR, manipulated amounts)
|
|
120
|
+
→ Open redirect (redirection to malicious sites)
|
|
121
|
+
→ Execution of unwanted actions
|
|
122
|
+
|
|
123
|
+
Exploitation:
|
|
124
|
+
// Forged link sent via SMS:
|
|
125
|
+
yourapp://transfer?to=attacker_account&amount=9999
|
|
126
|
+
|
|
127
|
+
// If the app doesn't validate:
|
|
128
|
+
→ Transfer executed without additional confirmation
|
|
129
|
+
|
|
130
|
+
Complete fix:
|
|
131
|
+
// See REM-MOB-005 in MOBILE-REMEDIATION-LIBRARY.md
|
|
132
|
+
|
|
133
|
+
VULN-IPC-004 — URL Scheme Hijacking (iOS)
|
|
134
|
+
Severity: HIGH (CVSS 6.5)
|
|
135
|
+
MASVS : MASVS-PLATFORM-2
|
|
136
|
+
|
|
137
|
+
Explanation:
|
|
138
|
+
On iOS, multiple apps can declare the same URL Scheme.
|
|
139
|
+
Depending on installation order, a malicious app can
|
|
140
|
+
intercept deep links intended for your app.
|
|
141
|
+
|
|
142
|
+
Example: A fake app declares myapp://
|
|
143
|
+
It receives deep links with reset tokens,
|
|
144
|
+
OAuth auth codes, etc.
|
|
145
|
+
|
|
146
|
+
Solution:
|
|
147
|
+
→ Universal Links (HTTPS) cannot be hijacked
|
|
148
|
+
→ They are linked to a domain that only your server
|
|
149
|
+
can claim (AASA file)
|
|
150
|
+
|
|
151
|
+
// iOS — Prefer Universal Links
|
|
152
|
+
// 1. Host https://yourapp.com/.well-known/apple-app-site-association
|
|
153
|
+
{
|
|
154
|
+
"applinks": {
|
|
155
|
+
"details": [{
|
|
156
|
+
"appIDs": ["TEAMID.com.yourapp"],
|
|
157
|
+
"components": [
|
|
158
|
+
{ "/": "/product/*" },
|
|
159
|
+
{ "/": "/order/*" },
|
|
160
|
+
{ "/": "/reset-password/*" }
|
|
161
|
+
]
|
|
162
|
+
}]
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// 2. Info.plist — Associated Domains
|
|
167
|
+
com.apple.developer.associated-domains :
|
|
168
|
+
applinks:yourapp.com
|
|
169
|
+
|
|
170
|
+
VULN-IPC-005 — Unsecured WebView JavaScript Bridge
|
|
171
|
+
Severity: CRITICAL (CVSS 8.8)
|
|
172
|
+
MASVS : MASVS-PLATFORM-4
|
|
173
|
+
|
|
174
|
+
Explanation:
|
|
175
|
+
A JavaScript Bridge exposes native functions
|
|
176
|
+
to the WebView's JavaScript code.
|
|
177
|
+
|
|
178
|
+
If the WebView loads untrusted content AND
|
|
179
|
+
the bridge is too permissive:
|
|
180
|
+
XSS in web content = access to native functions
|
|
181
|
+
|
|
182
|
+
Detection:
|
|
183
|
+
// React Native WebView with exposed bridge
|
|
184
|
+
<WebView
|
|
185
|
+
source={{ uri: dynamicUrl }} // Uncontrolled URL
|
|
186
|
+
onMessage={handleAllMessages} // Accepts everything
|
|
187
|
+
/>
|
|
188
|
+
|
|
189
|
+
// Handler doesn't validate origin
|
|
190
|
+
const handleAllMessages = (event) => {
|
|
191
|
+
const { action, data } = JSON.parse(event.nativeEvent.data)
|
|
192
|
+
if (action === 'readFile') readFile(data.path) // Dangerous
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
Fix:
|
|
196
|
+
<WebView
|
|
197
|
+
// Strictly controlled URLs
|
|
198
|
+
source={{ uri: 'https://trusted.yourapp.com' }}
|
|
199
|
+
|
|
200
|
+
onShouldStartLoadWithRequest={(request) => {
|
|
201
|
+
// Strict whitelist
|
|
202
|
+
return request.url.startsWith(
|
|
203
|
+
'https://trusted.yourapp.com'
|
|
204
|
+
)
|
|
205
|
+
}}
|
|
206
|
+
|
|
207
|
+
onMessage={(event) => {
|
|
208
|
+
let message
|
|
209
|
+
try {
|
|
210
|
+
message = JSON.parse(event.nativeEvent.data)
|
|
211
|
+
} catch {
|
|
212
|
+
return // Ignore invalid messages
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Whitelist of allowed actions
|
|
216
|
+
const allowedActions = ['shareContent', 'goBack']
|
|
217
|
+
if (!allowedActions.includes(message.action)) return
|
|
218
|
+
|
|
219
|
+
// Validate data by action
|
|
220
|
+
switch (message.action) {
|
|
221
|
+
case 'shareContent':
|
|
222
|
+
// Validate and sanitize content
|
|
223
|
+
if (typeof message.text !== 'string') return
|
|
224
|
+
shareContent(message.text.substring(0, 500))
|
|
225
|
+
break
|
|
226
|
+
case 'goBack':
|
|
227
|
+
navigation.goBack()
|
|
228
|
+
break
|
|
229
|
+
}
|
|
230
|
+
}}
|
|
231
|
+
/>
|