L4: Android Mobile Pentest 101

Bài 6: SSL Pinning


1. Giới thiệu SSL Pinning

SSL Pinning (hay Certificate Pinning) là kỹ thuật bảo mật trong đó ứng dụng “ghim” (pin) một chứng chỉ X.509 hoặc public key cụ thể vào host mà nó giao tiếp. Thay vì tin tưởng bất kỳ chứng chỉ nào được ký bởi một CA (Certificate Authority) trong hệ thống, ứng dụng chỉ chấp nhận đúng chứng chỉ hoặc key mà nó đã biết trước.

Tại sao cần SSL Pinning?

Trong một kết nối HTTPS thông thường, thiết bị sẽ tin tưởng bất kỳ chứng chỉ nào được ký bởi một CA hợp lệ trong danh sách hệ thống. Điều này tạo ra lỗ hổng: nếu kẻ tấn công có thể cài CA của mình vào thiết bị (hoặc CA gốc bị xâm phạm), họ có thể thực hiện Man-In-The-Middle (MitM) attack – chặn và đọc toàn bộ traffic giữa app và server dưới dạng cleartext.

Client <-----> [Kẻ tấn công / Proxy] <-----> Server
               (giả mạo chứng chỉ)

Khi có SSL Pinning, dù kẻ tấn công có CA hợp lệ, ứng dụng vẫn từ chối kết nối vì chứng chỉ không khớp với cái đã được pin sẵn bên trong app.


2. Các phương thức Pin

2.1 Certificate Pinning

Đây là phương thức đơn giản và phổ biến nhất.

Cơ chế hoạt động:

  1. Khi app được build, developer lấy file certificate (.cer, .crt, .pem,…) của server và nhúng trực tiếp vào trong app.
  2. Khi app kết nối đến server, server gửi certificate của mình trong quá trình TLS Handshake.
  3. App so sánh certificate nhận được với certificate đã được nhúng sẵn.
  4. Nếu khớp → tiếp tục kết nối. Nếu không khớp → từ chối kết nối.

Ưu điểm: Dễ implement.

Nhược điểm: Certificate có ngày hết hạn. Khi certificate hết hạn, app phải được cập nhật để cập nhật certificate mới, nếu không app sẽ ngừng hoạt động.


2.2 Public Key Pinning

Cơ chế hoạt động:

Thay vì pin toàn bộ certificate, chỉ pin public key được trích xuất từ certificate đó.

Ưu điểm so với Certificate Pinning:

  • Khi certificate hết hạn và được renew, nếu giữ nguyên key pair (public/private key), public key không thay đổi → app không cần cập nhật.
  • Linh hoạt hơn trong việc quản lý vòng đời certificate.

Nhược điểm: Phức tạp hơn trong lúc implement vì phải tách public key ra khỏi certificate.


2.3 Hash Pinning (SPKI Pinning)

Cơ chế hoạt động:

Pin giá trị hash (thường là SHA-256) của certificate hoặc public key thay vì pin trực tiếp.

Ưu điểm:

  • Cho phép ẩn thông tin certificate/public key trong code.
  • Thường được cung cấp dưới dạng native API, tiện dùng.
  • Có thể dùng để xác thực danh tính tổ chức trong trường hợp bị giả mạo.

3. Vị trí Pin trong Certificate Chain

Một certificate chain thường có 3 tầng:

Root CA Certificate
    └── Intermediate CA Certificate
            └── Leaf Certificate (End-entity)

3.1 Pin vào Leaf Certificate

  • Bảo mật cao nhất: Xác nhận chính xác certificate của server bạn, kể cả khi Root CA bị xâm phạm.
  • Rủi ro: Nếu certificate hết hạn hoặc bị thu hồi, app ngừng hoạt động cho đến khi có bản update mới.
  • Cho phép sử dụng self-signed certificate.

3.2 Pin vào Root Certificate

  • Bạn tin tưởng hoàn toàn vào Root CA.
  • Rủi ro lớn: Nếu Root CA bị xâm phạm → toàn bộ chain bị tấn công, không còn ý nghĩa bảo vệ.

3.3 Pin vào Intermediate Certificate

  • Tin tưởng Intermediate CA không cấp sai certificate cho server của bạn.
  • Linh hoạt hơn: Miễn là bạn dùng cùng một nhà cung cấp certificate, mọi thay đổi ở Leaf Certificate đều hoạt động mà không cần update app.

4. Phát hiện SSL Pinning trong App

Có một số dấu hiệu và cách phát hiện:

  • Chỉ bắt được request đầu tiên rồi không bắt được nữa.
  • Hoặc không bắt được request nào dù đã cài CA của Burp vào máy.
  • App hiển thị lỗi kết nối hoặc crash khi bật proxy.

Tìm các chuỗi như:

"Trusted"
"Pinning"
"CertificatePinner"
"TrustManager"
"checkServerTrusted"

Vào Security Analysis → File Analysis, tìm các thông báo:

"Certificate/Key Files Hard-coded inside the App"
"This App uses an SSL Pinning secure Library"

Ví dụ thực tế MobSF có thể phát hiện thư viện như org.thoughtcrime.ssl-pinning.


5. Bypass SSL Pinning

Method 1: Thêm Custom CA vào User Certificate Store

Điều kiện: App chạy trên Android 6.0 (API level 23) trở xuống, hoặc app không có cấu hình Network Security Config.

Lý do hoạt động: Trên Android ≤ 6.0, app mặc định tin tưởng cả System CA lẫn User-added CA. Vì vậy nếu cài Burp CA vào User Certificate Store, app sẽ tin tưởng certificate giả của Burp.

Các bước thực hiện:

Bước 1: Download Burp CA Certificate bằng cách truy cập http://burp trên trình duyệt đã cấu hình proxy qua Burp.

Bước 2: Push certificate lên máy ảo Android:

adb push cacert.der /sdcard/Download/cacert.der

Bước 3: Đổi định dạng từ .der sang .cer (Android không hỗ trợ .der):

adb shell
cd /sdcard/Download/
mv cacert.der cacert.cer

Bước 4: Vào Settings → Security → Install from SD card, chọn file cacert.cer, đặt tên (ví dụ “Burp”), chọn VPN and apps, bấm OK.

Bước 5: Kiểm tra tại Settings → Security → Trusted credentials → USER tab, bạn sẽ thấy “PortSwigger CA” xuất hiện.


Trường hợp app yêu cầu Android 7.0+:

Từ Android 7.0 (API 24), Google thay đổi chính sách: app mặc định chỉ tin tưởng System CA, không tin tưởng User CA nữa. Developer có thể enforce điều này trong AndroidManifest.xml:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.pinning_app.app"
    platformBuildVersionCode="25"
    platformBuildVersionName="7.0">

Cách bypass: Decompile APK bằng apktool, sửa version code xuống API 23:

apktool d app.apk -o app_decompiled

Sửa trong AndroidManifest.xml:

platformBuildVersionCode="23"
platformBuildVersionName="6.0"

Rồi recompile và re-sign lại:

apktool b app_decompiled -o app_patched.apk
# Sign lại bằng apksigner hoặc jarsigner

Method 2: Ghi đè Certificate trong APK

Điều kiện: App bundle sẵn một custom certificate file bên trong APK (thường nằm trong thư mục assets/).

Cách thực hiện:

  1. Decompile APK bằng apktool.
  2. Tìm file certificate (.cer, .crt) trong thư mục assets/:
    assets/
    ├── CustomCA.cer
    ├── fonts/
    └── views/
  3. Thay thế CustomCA.cer bằng certificate của Burp (đã đổi tên tương ứng).
  4. Recompile và re-sign APK.

App sẽ “nghĩ” rằng certificate của Burp là certificate hợp lệ của server.


Method 3: Patch trực tiếp code của App

Đây là phương pháp kỹ thuật cao nhất và hiệu quả với mọi trường hợp.

Cách thực hiện tổng quát:

  1. Decompile APK bằng apktool để lấy smali code, hoặc dùng jadx để đọc Java/Kotlin code dạng decompiled.
  2. Tìm đoạn code thực hiện SSL Pinning (thường nằm trong các class liên quan đến TrustManager, OkHttpClient, CertificatePinner,…).
  3. Patch đoạn logic check pinning (ví dụ: NOP hóa điều kiện so sánh, hoặc luôn return true).
  4. Recompile và re-sign.

Ví dụ – OkHTTP3 CertificatePinner:

Trong smali, tìm đoạn gọi CertificatePinner.check() và thay bằng lệnh return-void để bỏ qua bước kiểm tra.


Method 4: Hook bằng Frida

Đây là phương pháp phổ biến và linh hoạt nhất trong thực tế.

Frida là một dynamic instrumentation toolkit cho phép bạn inject script vào process đang chạy và hook các hàm bất kỳ tại runtime – không cần decompile hay recompile APK.

Ý tưởng: Hook vào hàm checkServerTrusted() của TrustManager hoặc hàm check() của CertificatePinner, override chúng để không làm gì (bỏ qua pinning).

// Frida script mẫu – bypass TrustManager
Java.perform(function() {
    var TrustManager = Java.use('javax.net.ssl.X509TrustManager');
    TrustManager.checkServerTrusted.implementation = function(chain, authType) {
        // Không làm gì – bỏ qua việc kiểm tra certificate
    };
});

6. Kiến thức mở rộng

Network Security Configuration (Android 7+)

Từ Android 7.0, Google giới thiệu Network Security Configuration – một file XML cho phép developer kiểm soát chính sách TLS của app một cách rõ ràng, thay vì phụ thuộc vào code.

<!-- res/xml/network_security_config.xml -->
<network-security-config>
    <domain-config>
        <domain includeSubdomains="true">example.com</domain>
        <pin-set expiration="2024-01-01">
            <pin digest="SHA-256">AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</pin>
            <!-- Backup pin -->
            <pin digest="SHA-256">BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=</pin>
        </pin-set>
    </domain-config>
</network-security-config>

Cấu hình này được khai báo trong AndroidManifest.xml:

<application android:networkSecurityConfig="@xml/network_security_config">

Khi pentest, đây là nơi đầu tiên cần tìm và chỉnh sửa nếu muốn bypass pinning bằng cách decompile.


Các công cụ thường dùng trong thực tế

Công cụMục đích
apktoolDecompile/recompile APK, đọc smali code
jadx / jadx-guiDecompile APK sang Java, dễ đọc hơn smali
FridaDynamic hook, bypass pinning tại runtime
ObjectionWrapper của Frida, có sẵn lệnh bypass pinning
Burp SuiteIntercept và phân tích HTTP/S traffic
MobSFStatic analysis tự động, phát hiện pinning

Bypass nhanh bằng Objection

Objection là tool xây dựng trên nền Frida, cung cấp sẵn lệnh bypass SSL Pinning mà không cần viết script:

objection --gadget "com.example.app" explore
# Sau đó trong Objection shell:
android sslpinning disable

Tham khảo thêm