Android Pentesting và các vấn đề liên quan

0. Overview

Các product hiện nay, hầu hết đều có mặt trên nền tảng mobile - Android và iOS, thậm chí có những product mà hầu hết business trên nền mobile ( VD các ví điện tử ). Việc pentesting và những lỗ hổng trên nền mobile có những đặc trưng và khác biệt so với web. Tuy nhiên trước khi bước vào được giai đoạn "pentesting", có một công việc quan trọng khác, đó là việc dựng được môi trường. Trong bài viết này mình sẽ đề cập đến các rào cản " tiền pentest " với Android.

1. SSL Pinning - SSL được pin sẵn vào trong Application

Đầu tiên phải nói về Secure Web Connections:

Khi Client bắt đầu 1 Secure session với Server, có 3 điều hai bên phải thống nhất:

  • How keys be exchange - Làm sao để trao đổi các key cho nhau?
  • How will data be encrypted - Dữ liệu được mã hóa theo cách nào ?
  • How will messages be marked as authentic - Như thế nào thì messages được đánh dấu là xác thực ?

Ví dụ Server có thể quyết định rằng sẽ sử dụng RSA để trao đổi keys, dùng AES 256 để encrypt data và SHA-1 để sign messages.

Nếu Client có support các loại trên, nó sẽ request một certificate chain từ Server, khi client đã xác nhận certificate chain, public key sẽ được trích xuất từ certificate.

Theo mặc định, việc triển khai SSL được sử dụng trong các App sẽ tin tưởng bất kỳ Server nào có certificate được tin cậy bởi OS ( như hình trên ). Đó là một danh sách các CA ( certificate authorities ) có sẵn trong OS.

Đây là lúc SSL Pinning phát huy tác dụng. Developers có thể compile (biên dịch) public key vào trong application code, điều này về cơ bản là pinned key vào ứng dụng. Khi máy client nhận được public key từ Server, nó sẽ so sánh key này với key được pinned trong ứng dụng. Nếu key đúng, sẽ khởi tạo sessions.

Hiện nay có 3 loại SSL Pinning:

  • Certificate Pinning
  • Public Key Pinning ( Là loại được đề cập ở phía trên )
  • SPKI Pinning

Certificate Pinning: Đây là phương pháp pinning toàn bộ certificate thay vì chỉ pinning public key và cũng là phương pháp dễ thực hiện nhất. Vậy sẽ ra sao khi certificate expires ( hết hạn ) ? Client sẽ phải update application với certificate mới trước khi certificate trên Server được update. Vì vậy đôi khi Public key pinning là phương thức được ưa chuộng hơn.

Public key pinning: Linh hoạt hơn nhưng phức tạp hơn một chút do cần các bước bổ sung để trích xuất public key từ certificate.

SPKI Pinning ( Subject Public Key Information ): là phương thức pinning mới nhất, hash của public key và meta-data được pin vào trong ứng dụng.

Nếu ứng dụng không sử dụng SSL Pinning, sẽ rất dễ bị tấn công Man-in-the-Middle.

Như vậy SSL Pinning giúp Developers có thêm một lớp bảo mật bổ sung trong ứng dụng của họ và rất dễ thực hiện với các thư viện như AF Networking ( với iOS ) hay OkHTTP ( với Android ).

Lý do phải bypass cái này vì chúng ta sẽ dựng proxy server để chặn bắt request từ App gửi lên Server, mà Server và App lại chỉ nói chuyện khi có đúng Cert mà thôi...

2. Anti VM - Không cho phép cài đặt / sử dụng trên thiết bị ảo hóa.

Đơn giản thì đây là cách thức để Application phát hiện thiết bị có phải là thiết bị ảo hóa ( emulator ) hay không, nếu có thì các tính năng sẽ hạn chế hoặc không cho phép cài đặt.

Tại sao việc pentest Application trên emulator vẫn được sử dụng ? Đơn giản vì nó tiện hơn, mọi thiết bị, mọi phiên bản android...chỉ cần chọn và install, sau 5 phút bạn đã có ngay 1 thiết bị android emulator với đầy đủ chức năng. Ứng dụng tạo emulator device được biết đến và sử dụng phổ biến hàng đầu là Genymotion.

Thực tế với Pentester thì đây không phải vấn đề gì nghiêm trọng lắm, vì đa số thường dùng ... thiết bị thật luôn 😂 Nếu bạn không có đủ trang thiết bị cần thiết thì việc reverse app để loại bỏ phần detect này có lẽ cũng không quá khó khăn.

Cách Application detect ra thiết bị là emulator cũng muôn hình vạn trạng. Đây là một ví dụ:

Code tường minh như thế này thì chẳng có lý do gì không bypass được cả, có thể modify string như sau:

Như vậy là function trên đã "vô hại" và application có thể cài đặt được trên emulator.

3. Root Detection Techniques

Nếu việc Anti VM không có vẻ gì là đau đớn lắm vì có thể dễ dàng dùng thiết bị thật thay thế 😆, thì việc "anti rooted device" lại là một câu chuyện khác. Vì dù là thiết bị thật hay emulator, tất cả đều phải rooted, do có liên quan tới rất nhiều vấn đề khi pentest.

Đây là ví dụ về một đoạn script để detect Root theo 3 cách khác nhau. Đương nhiên vẫn còn có những cách khác và những binary khác hỗ trợ cho việc này.

/** @author Kevin Kowalewski */
public class RootUtil {
    public static boolean isDeviceRooted() {
        return checkRootMethod1() || checkRootMethod2() || checkRootMethod3();
    }

    private static boolean checkRootMethod1() {
        String buildTags = android.os.Build.TAGS;
        return buildTags != null && buildTags.contains("test-keys");
    }

    private static boolean checkRootMethod2() {
        String[] paths = { "/system/app/Superuser.apk", "/sbin/su", "/system/bin/su", "/system/xbin/su", "/data/local/xbin/su", "/data/local/bin/su", "/system/sd/xbin/su",
                "/system/bin/failsafe/su", "/data/local/su", "/su/bin/su"};
        for (String path : paths) {
            if (new File(path).exists()) return true;
        }
        return false;
    }

    private static boolean checkRootMethod3() {
        Process process = null;
        try {
            process = Runtime.getRuntime().exec(new String[] { "/system/xbin/which", "su" });
            BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
            if (in.readLine() != null) return true;
            return false;
        } catch (Throwable t) {
            return false;
        } finally {
            if (process != null) process.destroy();
        }
    }
}

Khi tìm hiểu Mobile Device Management (MDM), có rất nhiều cách để detecting thiết bị Android đã root. Những phương thức khá giống nhau và thường liên quan tới việc tìm kiếm package hoặc file cụ thể nào đó, hoặc quyền thư mục và chạy các lệnh nhất định.

Thông qua việc review source code, pentester có thể modify lại như ví dụ ở trên và nhiều hướng dẫn khác để bypass việc detect root, kể cả khi Safetynet - API chính chủ Google, chuyên để chống người dùng đã root, mở khoá bootloader hoặc cài bản custom ROM sử dụng Android Pay được sử dụng.

4. Code Obfuscation

Nếu coi đây là 1 phần của "tiền pentest" ( thực tế nó không phải ở bước dựng được môi trường ), thì nó sẽ là phần khoai nhất. Đây là kỹ thuật được thêm vào khi sản phẩm chuẩn bị được publish. Nhằm giữ cho source code không thể đọc hiểu được bởi bên thứ ba. Một ví dụ cơ bản về việc Code Obfuscation của một ứng dụng liên quan tới TIỀN ( mình đã đổi tên ứng dụng ):

Và một Application khác trông rất thân thiện khi không có Code Obfuscation:

Đây là một kỹ thuật cần thiết và quan trọng. Tuy nhiên việc Obfuscation Code có ảnh hưởng đến performance của App và 1 số vấn đề liên quan. Thành ra ở ví dụ thứ 2 kia, dù đây là application in-house của một công ty chuyên về Software nhưng việc Obfuscation Code không được áp dụng.

5. Kết luận

Bài viết giới thiệu về "những cái khó" trước khi bắt đầu bắt tay vào pentest ứng dụng Android nói riêng và Mobile Application nói chung. Đương nhiên khi pentest thì cũng không thiếu những cái khó khác và những thứ đặc trưng của từng App.

Hi vọng sau khi dựng xong được "môi trường", các bạn có thể happy với nó và tìm được thật nhiều bugs 💪💪

6. Tài liệu tham khảo

https://owasp.org/www-community/controls/Certificate_and_Public_Key_Pinning

https://www.youtube.com/watch?v=is8lHjEkk7U

https://www.cloudflare.com/learning/ssl/what-happens-in-a-tls-handshake/

https://mobile-security.gitbook.io/mobile-security-testing-guide/android-testing-guide/0x05j-testing-resiliency-against-reverse-engineering#common-root-detection-methods

https://www.juanurs.com/Bypassing-Android-Anti-Emulation-Part-III/

https://medium.com/@angelhiadefiesta/how-to-obfuscate-in-android-with-proguard-acab47701577