+17

Case study phân tích cách mã hóa traffic của một ứng dụng Android

Mở đầu

Khi thực hiện pentest một số ứng dụng Android, đôi khi ta sẽ gặp phải trường hợp các request từ thiết bị Android và response gửi từ server về sẽ được mã hóa. Để có thể chỉnh sửa request với mục đích pentest ứng dụng thì việc hiểu và tái hiện lại được cơ chế mã hóa và giải mã là cần thiết. Trong bài viết này, mình sẽ lấy ví dụ về một ứng dụng để xem thực tế chúng ta sẽ cần làm các bước như thế nào để có thể đạt được mục tiêu này nhé 😃

Cài đặt công cụ

Trước hết, chúng ta cần cài đặt các công cụ emulator (mình sử dụng WSA của windows), jadx và frida. Chi tiết cách cài đặt, các bạn có thể tham khảo series bài viết sau của bạn @tranminhnhat@minhtuan.nguy:

Ứng dụng mẫu

Ở đây mình có sử dụng một ứng dụng Android có chức năng login. Mình xin phép che tên ứng dụng để tránh bị ăn gậy 😂. Sau khi sử dụng Proxydroid để chuyển hướng traffic sang Burp, thực hiện login với email abc@example.com và password 123456 thì chúng ta thấy có traffic như sau:

image.png

Du22azpzkVjMk0l0Emtcv1S8xnawAf+zMFcnvJaNhnC7ejCWD3pdDPHJeP5N1dFhon/EFHIuZO3NpGNLn2tDmwvPElDD2BG+zGAPgwQ3Ct8=

Rõ ràng là dữ liệu của chúng ta đã được mã hóa hết vào biến param data rồi thực hiện base64.

Ngoài ra ở một số API, dữ liệu từ server trả về tuy là JSON nhưng content thì cũng không phải là plaintext:

{"code":0,"data":{"info":"rLrUWFNS+npD4GybX979A02j5M6nJI9wy0i3unlQ9MvGnq85XXwNWqOPvqVclKQUDYTeC2sOiV2w5DwqfzRMgjLNribJEFmiyxQPsgw+mGo="}}

Giờ chúng ta cùng xem thử cách ứng dụng này mã hóa dữ liệu như thế nào.

Phân tích ứng dụng Android

Trước hết thì có vài điểm cần lưu ý:

  • Để đảm bảo hiệu suất của ứng dụng thì việc mã hóa thường sẽ sử dụng mã hóa đối xứng, phổ biến nhất là AES, thay vì mã hóa bất đối xứng (như RSA)
  • Do đây là mã hóa giữa client và server (và server cũng trả về dữ liệu mã hóa) nên có thể chắc chắn 99% là phía client sẽ có key để giải mã

Chúng ta sẽ sử dụng jadx để decompiler ứng dụng:

image.png

Thử search với từ khóa aes, chúng ta thấy ngay nhiều kết quả trông rất khả quan:

image.png

Chú ý đến đoạn sau ở class getAESCipher

Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");

là đoạn code dùng để khởi tạo instance dùng cho mã hóa, giải mã AES được dùng khá phổ biến, khi vào hàm này chúng ta có thể thấy ngay các khai báo secret key và IV:

image.png

Tuy nhiên, khi kiểm tra nơi gọi đến hàm getAESCipher (trong jadx, chọn vào tên hàm và bấm phím x) thì chỉ có duy nhất một nơi sử dụng, và đọc nội dung hàm này và hàm ngay phía trên thì đây là các xử lý dùng để mã hóa và giải mã file chứ không phải traffic trên server. image.png

Như vậy là chúng ta đã tìm đúng, nhưng chưa trúng 😂 . Quay trở lại với khung tìm kiếm, ấn vào Load more để ra hết tất cả kết quả, chúng ta thấy có những hàm khác như sau:

image.png

Class DecodeUtils được sử dụng ở nhiều vị trí, nghe tên thôi đã thấy tiềm năng rồi. Vào trong class này, ta thấy sử dụng rất nhiều các hàm

  • NativeUtil.getInstance().aesDecryptWithKey
  • NativeUtil.getInstance().aesEncryptWithKey

image.png

Đi tiếp vào class NativeUtil này:

image.png

Chúng ta chỉ thấy signature của các hàm chứ không có source code, vì đơn giản là các hàm này là nằm trong các lib native của ứng dụng và không được code bằng Java.

In software design, the Java Native Interface (JNI) is a foreign function interface programming framework that enables Java code running in a Java virtual machine (JVM) to call and be called by[1] native applications (programs specific to a hardware and operating system platform) and libraries written in other languages such as C, C++ and assembly.

Như vậy, phần mã hóa này sẽ nằm trong thư viện lib + alg. Đổi đuôi file .apk thành .zip và giải nén, tìm đến thư mục lib > arm64-v8a:

image.png

chúng ta sẽ thấy có file libalg.so (và ngạc nhiên hơn là có cả file debug của thư viện này 😂 )

Sử dụng Frida

Để có thể hiểu chi tiết về các mã hóa thì bắt buộc chúng ta phải reverse engineering file .so ở trên. Tuy nhiên, nếu chỉ dừng lại ở bước xem (và có thể phần nào tạo request theo ý mình) thì đến đây, ta có thể dùng Frida hook.

Right-click ở tên hàm và chọn copy as frida snippet (f) như dưới đây:

image.png

Sau đó copy và paste vào file hook.js để tạo thành file như sau. Mục tiêu là log ra các tham số được truyền vào và kết quả trả về của các hàm mã hóa/giải mã này:

image.png

Chạy frida-server trong thiết bị rồi sử dụng câu lệnh sau để spawn và hook ứng dụng:

image.png

frida -U -l hook.js -f com.redacted

Thực hiện đăng nhập lại trên ứng dụng, trên console sẽ thấy output ra tham số và kết quả mã hóa:

image.png

BINGO! Chúng ta cũng có thể sửa lại code để ở bước gọi đến hàm aesEncryptWithKey, ta thêm một đoạn nữa để gọi hàm với tham số tùy ý.

image.png

và đây là kết quả:

image.png

Phân tích thư viện native

Nếu chỉ dừng lại ở trên thì vẫn khá khó để có thể thao tác trên Burp, chúng ta cần "go deeper". Bật IDA lên và load file libalg.so ở trên vào:

image.png

Do đã biết tên các hàm khi gọi từ phía Java, chúng ta thấy ngay các hàm tương ứng cần tìm. Việc còn lại là đọc code để tìm key.

image.png

Chú ý đến hàm getKey ở dưới đây có truyền một tham số vào có kiểu là unsigned int. Đây sẽ là index của key được sử dụng (do ứng dụng sử dụng nhiều key mã hóa khác nhau cho từng chức năng). Đây cũng chính là tham số int i được truyền vào ở phía Android.

image.png

Chi tiết phần reverse để lấy key này thì mình sẽ không đi chi tiết, chúng ta chỉ cần biết các bước cần làm là đã đủ rồi 😃. Nếu khó quá, hãy thử hỏi ChatGPT nhé mọi người:

image.png

Sau khi có được key và các thức mã hóa dữ liệu, chúng ta có thể tái hiện lại quá trình giải mã trên CyberChef như sau:

Với dữ liệu ở đầu bài viết: Du22azpzkVjMk0l0Emtcv1S8xnawAf+zMFcnvJaNhnC7ejCWD3pdDPHJeP5N1dFhon/EFHIuZO3NpGNLn2tDmwvPElDD2BG+zGAPgwQ3Ct8=

image.png

đã giải mã thành công. Đến đây thì ta có thể sử dụng Hackvertor, viết một custom tag để có thể tùy ý chỉnh sửa dữ liệu đẩy lên trong Burp. Chi tiết thì bạn có thể tham khảo thêm ở bài viết khác của mình: Biến đổi payload trong Burp Suite nhanh chóng và dễ dàng hơn cùng với extension Hackvertor

Kết

Giống như mã hóa trên ứng dụng web, chúng ta cần đọc code JS thì với Android, chúng ta cũng cần đọc hiểu code Java, và đôi khi là cả code assembly nữa 😂

P/S: HAPPY NEW YEAR mọi người! Chúc các anh em pentester có một năm đầy bug nhé 🐛


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí