Gửi lúc: 04/10/2019 14:44:05
Bookmark and Share

Tấn công lược đồ mã hóa ổ lưu trữ dữ liệu trên hệ điều hành Android

Mã hóa toàn bộ ổ đĩa (Full Disk Encryption - FDE) [2] là quá trình mã hóa tất cả dữ liệu của người dùng được lưu trữ trên thiết bị để ngăn chặn các truy cập trái phép. Bài báo này mô tả quá trình tấn công lược đồ mã hóa toàn bộ ổ đĩa trên các bộ vi xử lý của Qualcomm, chạy hệ điều hành Android phiên bản từ 5.0 (Lollipop) trở lên, nhằm giải mã hệ thống tệp đã được mã hóa.

GIỚI THIỆU

Năm 2015, vụ việc giữa Apple và FBI được công bố rộng rãi đã thu hút được sự quan tâm của công chúng vì nó có liên quan đến chủ đề về bảo mật tính riêng tư - đặc biệt là trong bối cảnh các thiết bị di động. Sau vụ tấn công khủng bố San Bernardino năm 2015, FBI đã thu giữ chiếc điện thoại di động của kẻ khủng bố, Syed Farook, với mục đích tìm kiếm bằng chứng phục vụ cho cuộc điều tra đang diễn ra. Mặc dù sở hữu thiết bị, nhưng FBI không thể mở khóa và truy cập vào nội dung của nó. Thiết bị đang được nhắc đến ở đây là một chiếc iPhone 5C chạy trên hệ điều hành iOS 9.

Như ta đã biết, bắt đầu với iOS 8, Apple đã tự động kích hoạt hệ thống mã hóa toàn bộ ổ đĩa (FDE) bằng cách sử dụng khóa mã hóa được dẫn xuất từ mật khẩu của người dùng. Hình 1 dưới đây mô tả chức năng dẫn xuất khóa (KDF) trong lược đồ FDE của Apple.

Việc gắn kết khóa mã hóa với phần cứng của thiết bị gây ra nhiều khó khăn hơn cho những kẻ tấn công. Nó buộc kẻ tấn công phải sử dụng thiết bị trong mỗi lần bẻ khóa.

Chức năng dẫn xuất khóa được trình bày như trong Hình 1, được thiết kế theo cách sao cho việc tính toán trên thiết bị có thể phải mất một lượng thời gian đáng kể. Cụ thể, Apple đã chọn các tham số của hàm để một dẫn xuất khóa sẽ mất khoảng 80 mili giây. Độ trễ này sẽ làm chậm việc bẻ.

Hình 1. KDF trong lược đồ FDE của Apple

Để tiếp tục hạn chế các tấn công vét cạn trên thiết bị, Apple cũng đã cung cấp một sự gia tăng dần dần độ trễ giữa các lần dự đoán mật khẩu tiếp theo. Trên iPhone 5C, độ trễ này được tạo thực hiện hoàn toàn bằng phần mềm.

Cuối cùng, Apple cho phép tính năng xóa hoàn toàn tất cả thông tin được lưu trữ trên thiết bị sau 10 lần thử mật khẩu không thành công. Cấu hình này, cùng với độ trễ do phần mềm gây ra, làm cho việc bẻ khóa mật khẩu trên thiết bị trở nên không khả thi.

Ở đây, có thể thấy rằng Apple đã rất khéo léo trong khi thiết kế lược đồ FDE làm cho nó rất khó có thể bị phá vỡ, Android cũng tương tự như vậy. Trên thực tế, Android cũng đã cung cấp mã hóa toàn bộ ổ đĩa được kích hoạt mặc định kể từ phiên bản Android 5.0.

LƯỢC ĐỒ MÃ HÓA Ổ VÀ PHÂN VÙNG DỮ LIỆU TRÊN HỆ ĐIỀU HÀNH ANDROID

Bắt đầu từ phiên bản 5.0, các thiết bị Android tự động bảo vệ tất cả thông tin của người dùng bằng cách cho phép mã hóa toàn bộ ổ đĩa. FDE của Android dựa trên một hệ thống con trong nhân Linux được gọi là dm-crypt. Mật khẩu người dùng được sử dụng làm đầu vào cho hàm dẫn xuất khóa là cực kỳ quan trọng trong mô hình FDE của Android.

Quá trình này được mô tả chi tiết trong tài liệu chính thức về FDE của Android [1]. Về cơ bản, thiết bị sẽ tạo khóa chủ 128 bit được lựa chọn ngẫu nhiên (còn gọi là Khóa mã hóa thiết bị - DEK) và một giá trị salt 128 bit cũng được lựa chọn ngẫu nhiên. Sau đó, DEK được bảo vệ bằng cách sử dụng lược đồ dẫn xuất khóa phức tạp, sử dụng thông tin đăng nhập của người dùng (PIN/Mật khẩu/Mẫu) để dẫn xuất ra khóa mã hóa DEK. DEK đã được mã hóa sau đó được lưu trữ trên thiết bị, bên trong một cấu trúc đặc biệt không được mã hóa gọi là “crypto footer”. Hình 2 thể hiện vị trí và các thành phần của “crypto footer” trong thiết bị.

Định dạng ổ lưu trữ dữ liệu được mã hóa

Ổ đĩa sau khi đã được mã hóa có thể được giải mã đơn giản bằng cách lấy thông tin đăng nhập của người dùng truyền vào hàm dẫn xuất khóa và sử dụng khóa thu được để giải mã DEK đang được lưu trữ. Khi DEK được giải mã, nó có thể được sử dụng để giải mã dữ liệu của người dùng. Hình 3 mô tả quá trình giải mã ổ dữ liệu.

Hình 3. Quá trình mã hóa/giải mã ổ dữ liệu

Giống như của Apple, lược đồ FDE của Android cũng tìm cách ngăn chặn các tấn công vét cạn khóa bảo vệ trên thiết bị đối với cả tấn công online và offline. Để ngăn chặn các tấn công bẻ khóa trên thiết bị (tấn công online), Android đã sử dụng độ trễ giữa các lần thử giải mã và tính năng xóa thông tin của người dùng sau một vài lần thử giải mã không thành công (giống như iOS). Còn đối với tấn công vét cạn từ ngoài thiết bị (tấn công offline) được thực hiện bằng cách thêm một bước vào trong lược đồ dẫn xuất khóa trên, đó là bước gắn kết khóa với phần cứng của thiết bị. Sự gắn kết này được thực hiện bằng cách sử dụng Keystore (cơ sở dữ liệu lưu trữ khóa và chứng thư) trên nền tảng phần cứng - KeyMaster. Hình 4 mô tả quá trình mã hóa/giải mã ổ dữ liệu đã có bổ sung mô-đun KeyMaster.

Hình 4. Quá trình mã hóa/giải mã ổ dữ liệu khi có mô-đun KeyMaster

TẤN CÔNG TRÍCH XUẤT KHÓA CỦA KEYMASTER

Qualcomm đã cài đặt môi trường thực thi an toàn (QSEE) trong phần cứng thông qua TrustZone cho phép các ứng dụng nhất định, được gọi là các “trustlet”, ví dụ mô-đun KeyMaster, thực thi trên vi xử lý an toàn và chuyên dụng.

Hình 5. Kiến trúc của KeyMaster trên các thiết bị của Quanlcomm

KeyMaster

Mô-đun KeyMaster được sử dụng nhằm mục đích bảo vệ các khóa mật mã được các ứng dụng tạo ra. Để đảm bảo sự bảo vệ này không thể bị giả mạo, mô-đun KeyMaster được cài đặt chạy trong một môi trường hoàn toàn tách biệt với hệ điều hành Android, đó là môi trường thực thi tin cậy (TEE) như trong Hình 6. Trong bài báo này, hệ điều hành Android được gọi là “Thế giới không an toàn” và TEE được gọi là “Thế giới an toàn”.

Hình 6. KeyMaster được cài đặt trong môi trường thực thi tin cậy (TEE)

Hình 7 dưới đây mô tả lược đồ KDF [2] của Android sử dụng hàm dẫn xuất khóa được gắn kết với phần cứng. Để gắn kết KDF với phần cứng của thiết bị, một trường đã được lưu thêm vào “crypto footer”, đó là KeyBlob do KeyMaster tạo ra. Keyblob này chứa một khóa riêng RSA-2048 được mã hóa bởi KeyMaster, được sử dụng để ký khóa mã hóa trong một bước trung gian trong lược đồ KDF, do đó, trong mỗi lần giải mã DEK đều cần sử dụng mô-đun KeyMaster để cung cấp khóa trung gian.

Hình 7. Lược đồ KDF trong FDE của Android

Ngoài ra, “crypto footer” còn chứa một trường bổ sung nữa không phục vụ bất kỳ mục đích trực tiếp nào trong quá trình giải mã, đó là giá trị được trả về từ việc thực thi scrypt trên khóa trung gian cuối cùng (IK3). Giá trị này được gọi là “scrypted_intermediate_key” (Scrypted IK trong lược đồ trên). Nó được sử dụng để xác minh tính hợp lệ của mật khẩu FDE được cung cấp trong trường hợp có lỗi xảy ra trong quá trình giải mã.

Như vậy, KDF trong Android FDE được “gắn kết” với phần cứng của thiết bị bằng chữ ký của KeyMaster ở một bước trung gian. Tài liệu chính thức do Android cung cấp có nói rằng mô-đun KeyMaster “cung cấp cho các thiết bị Android dịch vụ bảo mật mạnh mẽ được hỗ trợ bởi phần cứng”. Nhưng chắc chắn như vậy là chưa đủ rõ ràng và thuyết phục.

Kỹ thuật dịch ngược KeyMaster của Qualcomm

Các kỹ thuật dịch ngược có thể được sử dụng đối với mô-đun KeyMaster để tìm hiểu rõ hơn về các hoạt động bên trong của nó.

Trước tiên, hãy xem xét mã nguồn của Android được sử dụng để tương tác với ứng dụng KeyMaster. Có thể thấy, trustlet chỉ hỗ trợ bốn lệnh khác nhau sau đây.

/**

* Commands supported

*/

enum  keymaster_cmd_t {

/*

* List the commands supported in by the hardware.

*/

KEYMASTER_GENERATE_KEYPAIR = 0x00000001,

KEYMASTER_IMPORT_KEYPAIR = 0x00000002,

KEYMASTER_SIGN_DATA = 0x00000003,

KEYMASTER_VERIFY_DATA = 0x00000004,

};

Vì vấn đề cần quan tâm là việc bảo vệ các key blob đã tạo, do đó, lệnh cần xem xét là KEYMASTER_SIGN_DATA. Lệnh này nhận được một key blob được mã hóa trước đó và bằng cách nào đó thực thi một thuật toán có sử dụng khóa mật mã được đóng gói. Bằng cách dịch ngược chức năng này, có thể thấy các key blob đã mã hóa được giải mã bởi mô-đun KeyMaster.

Kết quả của quá trình phân tích ngược đã chỉ ra rằng, bước sau cùng của quá trình ký là lời gọi hàm do_something_with_keyblob() chỉ đơn giản giải mã số mũ bí mật với khóa là buffer_0. Cuối cùng, hãy xem xét hàm được sử dụng để thu được giá trị HMAC và các khóa mã hóa, hàm get_enc_key_or_hmac_key():

int _fastcall get_enc_key_or_hmac_key(int request_type)

{

            int global_buffer; //r9@0

            int res; //r4@1

            int _strlen1; //r5@4

            int _strlen2; //r0@4

            int strlen1; //r5@6

            int strlen2; //r0@6

            res = 0;

            if(request_type)

            {

                        if(request)type == 1) //HMAC key

                        {

                                    strlen1 = strlen(global_buffer + 103); //KM HMAC HM Crypto key derived from SHK

                                    strlen2 = strlen(global_buffer + 73); //KM HMAC HM Crypto Dervived key

                                    if(!some_kind_of_kdf(0, 16, global_buffer + 73, strlen2, global_buffer + 103, strlen1, global_buffer + 224, 32))

                                                res = global_buffer + 224;

                        }

            }

            else //Encyption Key

            {

                        _strlen1 = strlen(global_buffer + 34); //KM CPHR HM Crypto Derived key

                        _strlen2 = strlen(global_buffer + 4); //KM CPHR HM Crypto key derived from SHK

                        if(!some_kind_of_kdf(0, 16, global_buffer + 4, _strlen2, global_buffer + 34, _strlen1, global_buffer + 208, 16))

                                    res = global_buffer + 208;

            }

            return res;

}

Đoạn mã trên cho thấy, khóa HMAC và khóa mã hóa đều được tạo ra bằng cách sử dụng một hàm dẫn xuất khóa nào đó. Mỗi khóa được tạo ra bằng cách gọi hàm KDF sử dụng một cặp chuỗi cố định làm đầu vào. Khóa dẫn xuất kết quả sau đó được lưu trữ trong bộ đệm toàn cục của ứng dụng KeyMaster và con trỏ đến khóa được trả về hàm gọi. Ngoài ra, hàm dẫn xuất khóa bên trong sử dụng một khóa phần cứng thực sự, được gọi là SHK (Secure Hardware Key), mà chắc chắn sẽ khó có thể được trích xuất bằng phần mềm.

Tuy nhiên, mã sau khi được dịch ngược đã cho thấy một thực tế rất quan trọng. Thay vì tạo một lược đồ trực tiếp sử dụng khóa phần cứng, các mã trên thực thi mã hóa và xác thực các key blob bằng cách sử dụng các khóa khả dụng một cách trực tiếp cho phần mềm TrustZone! Lưu ý rằng các khóa này cũng không thay đổi – chúng được dẫn xuất trực tiếp từ SHK và từ hai chuỗi cố định.

Tấn công trích khóa bảo vệ của KeyMaster

Quá trình phân tích ngược mô-đun KeyMaster của Qualcomm đã chỉ ra rằng hàm dẫn xuất khóa được sử dụng để sinh ra khóa KEK không gắn với phần cứng thực sự như đã mô tả. Điểm yếu này có thể được khai thác để trích xuất khóa mã hóa/giải mã của KeyMaster.

Khi đã có khóa KeyMaster, kẻ tấn công có thể vét cạn các số PIN, mật khẩu hoặc các mẫu khóa để thu được thành phần còn thiếu nhằm giải mã khóa DEK, và sau đó là hệ thống tệp được mã hóa. Để thuận tiện, đa số người dùng thường thiết lập khóa PIN có 4-5 chữ số hoặc một mẫu khóa đơn giản mà không chọn một mật khẩu đủ mạnh. Do vậy quá trình xử lý vét cạn là đơn giản.

Demo tấn công vét cạn khóa trên hệ thống mã hóa ổ và phân vùng dữ liệu trên hệ điều hành Android

Để tấn công vào lược đồ KDF của FDE mà có tham số gắn với phần cứng của thiết bị sử dụng KeyMaster, thì đòi hỏi phải lấy được khóa bảo vệ KeyMaster. Việc trích xuất khóa bảo vệ KeyMaster được trình bày trong mục C yêu cầu phải có một số kỹ thuật sâu để có thể chèn được shellcode vào trong mã kernel của Trustzone. Trong phần này, chúng tôi thực hiện demo một phần về tấn công đối với lược đồ sinh khóa trong FDE, với giả định là ta không thể tin tưởng vào khóa MasterKey này bởi vì: khóa này có thể trích xuất được theo như mô tả ở mục C hoặc các nhà sản xuất thiết bị phần cứng hoàn toàn có thể lấy được. Do vậy, trong demo tấn công vét cạn mật khẩu là các số PIN dưới đây ta bỏ qua mô-đun thực hiện gắn kết KDF với khóa phần cứng. Cụ thể, lược đồ khóa sử dụng cho tấn công này như hình dưới đây.

Chúng tôi đã tùy biến một hệ điều hành Android 7.1 và loại bỏ mô-đun gắn kết KDF với khóa phần cứng của KeyMaster trong FDE, mục đích để chứng minh rằng việc bảo vệ khóa DEK sử dụng số PIN là rất yếu và ta không tin tưởng vào khóa cứng trong KeyMaster.

Các thiết bị và công cụ được sử dụng trong tấn công demo bao gồm:

• Máy tính bảng Samsung Galaxy Tab S2, được cài đặt hệ điều hành Android 7.1đã được tùy biến

• Máy tính PC Dell Optiplex 3020, CPU: Intel(R) Core(TM) i5-4570 CPU  3.20GHz; RAM: 16GHz cài đặt hệ điều hành Debian 9.

• Công cụ TWRP [3] phiên bản 3.2 và công cụ dd của Linux (tiện ích dòng lệnh cho các hệ điều hành họ Unix, được sử dụng để chuyển đổi và sao chép các tệp tin).

Các bước thực hiện tấn công demo:

Hình 8. Tấn công vét cạn số PIN đối với KDF không gắn với phần mềm

Bên phía người dùng: Bật chức năng mã hóa ổ dữ liệu trên thiết bị máy tính bảng, giả sử máy tính bảng bị mất cắp.

Bên phía kẻ tấn công:

• Đọc dữ liệu bộ nhớ trên thiết bị dùng công cụ TRWP và dd.

• Phân tích phân vùng dữ liệu được mã hóa, thực hiện copy 16KB phần dữ liệu “Crypto Footer” ở cuối của phân vùng và 512Byte của phần dữ liệu header của phân vùng.

• Sử dụng chương trình vét cạn có tên là fde_attack.py, để tìm số PIN của người sử dụng, khi tìm ra số PIN thì ta hoàn toàn có thể tìm ra khóa DEK, từ đó có thể giải mã được toàn bộ dữ liệu của người dùng sử dụng công cụ TWRP.

KẾT LUẬN

Ta không thể tin tưởng vào khóa bảo vệ của MasterKey bởi vì khóa này có thể trích xuất được theo như mô tả ở trên, hoặc các nhà sản xuất thiết bị phần cứng hoàn toàn có thể lấy được. Tương tự như vậy ta không thể tin tưởng vào hệ TrustZone có sẵn trong các thiết bị phần cứng thương mại.

Để thuận tiện, đa phần mọi người dùng để thiết lập khóa màn hình trên các thiết bị di động chạy Android bằng một số PIN có 4-5 chữ số hoặc một mẫu khóa đơn giản mà không chọn một mật khẩu đủ mạnh. Do vậy quá trình xử lý vét cạn là đơn giản đối với lược đồ mã hóa FDE của Android.

Tài liệu tham khảo

[1]. https://source.android.com/security/encryption/full-disk

[2]. https://nelenkov.blogspot.com/2014/10/revisiting-android-disk-encryption.html

[3]. https://twrp.me/

Phạm Văn Lực, Trần Đức Long, Hoàng Thu Phương