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.
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.
Hệ quả thực tế
Khi app có SSL Pinning, bạn không thể intercept traffic bằng các tool proxy như Burp Suite hay mitmproxy, vì self-signed certificate do các tool này tạo ra sẽ không được app chấp nhận.
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:
- 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. - Khi app kết nối đến server, server gửi certificate của mình trong quá trình TLS Handshake.
- App so sánh certificate nhận được với certificate đã được nhúng sẵn.
- 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.
Ví dụ thực tế – HTTP Public Key Pinning (HPKP)
Trên web, tiêu chuẩn HPKP (RFC 7469) cho phép server gửi header Public-Key-Pins chứa hash của public key. Trình duyệt sẽ lưu lại và kiểm tra ở các request sau. Tuy nhiên HPKP đã bị deprecated trên Chrome vì rủi ro "bricking" website nếu implement sai.
3. Vị trí Pin trong Certificate Chain¤
Một certificate chain thường có 3 tầng:
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.
Thực tiễn tốt nhất
Nên kết hợp pin vào cả Leaf lẫn một Intermediate/Root làm backup. Nếu Leaf bị revoke, app vẫn fallback được về pin backup, tránh tình trạng app bị "chết".
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ư:
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:
Bước 3: Đổi định dạng từ .der sang .cer (Android không hỗ trợ .der):
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:
Sửa trong AndroidManifest.xml:
Rồi recompile và re-sign lại:
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:
- Decompile APK bằng
apktool. - Tìm file certificate (
.cer,.crt) trong thư mụcassets/: - Thay thế
CustomCA.cerbằng certificate của Burp (đã đổi tên tương ứng). - 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:
- Decompile APK bằng
apktoolđể lấy smali code, hoặc dùngjadxđể đọc Java/Kotlin code dạng decompiled. - 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,...). - Patch đoạn logic check pinning (ví dụ: NOP hóa điều kiện so sánh, hoặc luôn return
true). - 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.
Tham khảo case study thực tế
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
};
});
Note
Nội dung chi tiết về Frida sẽ được trình bày ở Bài 8.
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:
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 |
|---|---|
apktool |
Decompile/recompile APK, đọc smali code |
jadx / jadx-gui |
Decompile APK sang Java, dễ đọc hơn smali |
Frida |
Dynamic hook, bypass pinning tại runtime |
Objection |
Wrapper của Frida, có sẵn lệnh bypass pinning |
Burp Suite |
Intercept và phân tích HTTP/S traffic |
MobSF |
Static 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