<style>body {text-align: justify}</style>
Bài blog sau cung cấp kiến thức và kĩ năng cần thiết để có thể dựng môi trường pentest một ứng dụng Android.
## 1. Cài đặt Android Emulator
### 1.1 Cài đặt công cụ Android Emulator `LDPlayer`
Trong bài blog này, mình sử dụng **LDPlayer9** làm công cụ Android Emulator. Truy cập trang chủ của LDPlayer tại https://vn.ldplayer.net/ để thực hiện download và cài đặt theo hướng dẫn.
### 1.2 Tạo một thiết bị Android ảo với phiên bản Android 7 trở lên (API level >= 24)
Mặc định LDPlayer9 sẽ sử dụng một máy Android 9.

Tuy nhiên nếu muốn cài phiên bản khác, chúng ta có thể sử dụng chức năng LDMultiPlayer để tạo một thiết bị Android khác.

## 2. Tìm hiểu tổng quan về `adb`

### 2.1. List các thiết bị Android đang kết nối đến.

### 2.2. Truy cập vào shell của thiết bị Android ảo cài đặt ở trên.
Truy cập shell qua adb:
```
adb -s <DEVICE_NAME> shell
```
Lấy thông tin phiên bản Android và API level:
```
getprop ro.build.version.release
getprop ro.build.version.sdk
```
Lấy thông tin kiến trúc CPU:
```
getprop ro.product.cpu.abi
```

Kết quả trả về đây là máy Android 9 với API level 28 với kiến trúc CPU `x86_64`.
### 2.3. Đẩy file từ máy Host vào thiết bị Android.
Demo đẩy file certificate của BurpSuite vào thư mục `/data/local/tmp` trên thiết bị Android.
*Bước 1:* Download file certificate của Burpsuite tại http://burp/

*Bước 2:* Upload file `cacert.der` vừa tải về lên thiết bị Android bằng câu lệnh:
```
adb push <PATH>/cacert.der /data/local/tmp/cacert.der
```

### 2.4. Cài đặt một ứng dụng vào thiết bị bằng `adb`
Trước khi cài đặt, cần làm các bước sau:
- Trên điện thoại ảo vừa tạo, chọn `Settings` -> `About Phone` -> bấm 6 đến 12 lần vào trường `Build Number` để bật chế độ `developer`.

- Về lại Settings, chọn `System` -> `Developer Settings`.

- Ở trong đó thì bật `USB Debugging` lên, chức này cho phép ta tương tác điện thoại ảo với máy thật

Chọn ứng dụng và tải file `.apk` tại link sau: https://github.com/httptoolkit/android-ssl-pinning-demo/releases/tag/v1.3.0.
Cài đặt ứng dụng bằng câu lệnh
```
adb install D:\LDPlayer\APK_files\pinning-demo.apk
```

Cài đặt thành công.

## 3. Decompile file `.apk`
### 3.1. Tìm hiểu công cụ decompile file `.apk`:
Một số công cụ decompile file `.apk` thông qua:
- Command line: apktool, jadx
Demo decompile file `pinning-demo.apk` bằng `apktool`

Kết quả ta thu được source code dạng smali của ứng dụng, trong đó có file `AndroidManifest.xml` chứa các thông tin thiết yếu về ứng dụng.

- GUI: apktook-gui, jadx-gui, bytecode-viewer
Sau đây mình sử dụng `jadx-gui` để decompile file `pinning-demo.apk` ở trên.

- Các XML tag `<uses-permission>` trong file `AndroidManifest.xml`

Dòng `<uses-permission android:name="android.permission.INTERNET"/>` là một phần trong tệp manifest của Android, dùng để khai báo quyền truy cập internet cho ứng dụng. Bằng cách bao gồm dòng này trong tệp manifest, mình cho phép ứng dụng truy cập và giao tiếp với internet.
- Tìm các exported service/activity
Ứng dụng không export service hay activity nào.
- Tìm xem entry activity của ứng dụng

Trong ứng dụng này, `MainActivity` được định nghĩa là entry activity được xác định bởi:
```
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
```
## 4. Tìm hiểu và thiết lập ứng dụng qua proxy BurpSuite.
### 4.1. Cài đặt certificate của BurpSuite. Vấn đề của API level >= 24 và cách khắc phục?
Nếu ứng dụng mà chúng ta đang cố gắng MITM nhắm mục tiêu Android 6.0 hoặc thấp hơn, chúng ta có thể đơn giản là thêm certificate của chúng ta vào kho CA được thêm bởi người dùng. Khi ứng dụng xác minh chuỗi tin tưởng cho chứng chỉ tùy chỉnh của chúng ta, nó sẽ tìm thấy certificate vừa thêm trong kho CA và chứng chỉ của chúng ta sẽ được trust. Tuy nhiên, nếu ứng dụng nhắm mục tiêu Android phiên bản 7.0 trở lên (API level >= 24), nó sẽ không trust vào certificate được thêm bởi người dùng. Để vượt qua điều này, chúng ta cần thêm certificate vào `/system/etc/security/cacerts` theo các bước như sau:
- Bước 1: Chuyển đổi cert Burpsuite sang định dạng PEM và đổi tên thành `<subject_hash_old>.0`.

- Bước 2: Cần remount để có quyền read write vào file system
Chú ý cho phép quyền ghi lên ổ cứng tại đây (Đối với LDPlayer):

Thực thi các câu lệnh sau để upload cert Burpsuite:
```
adb root
adb remount
adb push .\9a5ba575.0 /system/etc/security/cacerts
```

Sau khi upload thành công, truy cập *Security & location* -> *Encryption & credentials* -> *Trusted credentials*, ta thấy đã có cert.

### 4.2. Thiết lập ứng dụng qua proxy bằng 2 cách: Cấu hình wifi và Iptables
Set up proxy Burpsuite tại `192.168.117.53:8080`.

**Cách 1:** Cấu hình proxy qua Wifi
Thêm IP và Port của Burpsuite proxy:

Kết quả bắt request bằng Burpsuite:

**Cách 2:** Cấu hình proxy qua Iptables
- Truy cập adb shell:
```
adb shell
```
- Xóa tất cả các quy tắc trong chuỗi NAT của iptables. Khi thực hiện lệnh này, các quy tắc trong chuỗi NAT sẽ được xóa và mặc định sẽ áp dụng các cấu hình NAT mặc định của hệ thống.:
```
iptables -t nat -F
```
- Redirect lưu lượng HTTP đến địa chỉ của proxy Burpsuite đang lắng nghe tại `192.168.117.53:8080`:
```
iptables -t nat -A OUTPUT -p tcp --dport 80 -j DNAT --to-destination 192.168.117.53:8080
```
- Redirect lưu lượng HTTPS đến địa chỉ của proxy Burpsuite đang lắng nghe tại `192.168.117.53:8080`:
```
iptables -t nat -A OUTPUT -p tcp --dport 443 -j DNAT --to-destination 192.168.117.53:8080
```
- Cấu hình sao cho các gói tin TCP có cổng đích là 80 và 443 sau khi đi qua các quá trình định tuyến (routing) sẽ thực hiện chức năng MASQUERADE, tức là thay đổi địa chỉ nguồn của gói tin thành địa chỉ IP của network interface ra ngoài.
```
iptables -t nat -A POSTROUTING -p tcp --dport 80 -j MASQUERADE
iptables -t nat -A POSTROUTING -p tcp --dport 443 -j MASQUERADE
```
- Cấu hình http_proxy trên global:
```
settings put global http_proxy 192.168.117.53:8080
```

- Tắt cấu hình proxy trên global:
```
settings put global http_proxy :0
```
Lúc này bắt request trên burpsuite thành công.

### 4.3. [Challenge :D]
Thiết lập điện thoại thật qua BurpSuite trên máy tính không có cùng kết nối wLAN với thiết bị. Một ví dụ thực tế áp dụng là khi cần proxy trên máy PC chỉ có kết nối cáp Ethernet với mạng nội bộ, và không có card wLAN để phát hotspot cho điện thoại.
Kết nối USB với máy Android vào PC.

IP thiết bị Android: `192.168.137.9` ở dải mạng khác PC.

Trong khi PC có IP `192.168.117.53`.

Trên Burpsuite, proxy lắng nghe tại port 8080.

Thực thi câu lệnh sau:
```
adb reverse tcp:8081 tcp:8080
```
Điều này có nghĩa rằng: khi có request đi qua port 8081 của thiết bị Android, các request này sẽ được route đến port 8080 của máy PC, chính là port proxy đang lắng nghe.

Bây giờ chỉ việc set proxy mạng của thiết bị Android `127.0.0.1:8081` để các request đi qua port 8081.

Thử mở app Momo, thực hiện chức năng thì thấy BurpSuite thông báo `fail to negotiate a TLS connection` → proxy thành công.

## 5. Bypass SSL Pinning để đọc requests.
### 5.1. Tìm hiểu SSL Pinning
SSL pinning là một kỹ thuật bảo mật trong ứng dụng di động và các ứng dụng web để tăng cường đáng tin cậy và ngăn chặn các cuộc tấn công trung gian (man-in-the-middle attacks).
Khi một ứng dụng thực hiện kết nối bảo mật (như HTTPS) với một máy chủ, thông thường nó sẽ xác thực chứng chỉ SSL/TLS của máy chủ bằng cách so sánh với danh sách chứng chỉ tin cậy. Tuy nhiên, SSL pinning làm cho quá trình này nghiêm ngặt hơn bằng cách ràng buộc ứng dụng chỉ tin tưởng vào một số chứng chỉ cụ thể hoặc khóa công khai được chỉ định trước.
Các lựa chọn dùng để pinning:
- **Certificate Pinning**: Khi chương trình chạy lên và bắt đầu truy vấn, một certificate từ website hoặc server được gửi đến để so sánh với certificate được pin vào app. Nếu trùng thì app sẽ đồng ý tương tác với web/server.

- **Public Key**
- Cần thực hiện nhiều bước hơn, vì phải tách key nằm trong certificate ra
- Cũng giống pin certificate, chương trình kiểm tra public key lấy ra từ certificate với key pin sẵn trong chương trình
- **Hashing**
- Cho phép bạn giấu certificate hoặc public key
- Rất tiện để sử dụng, vì kiểu pin này thường cung cấp dưới dạng native api
- Còn có thể dùng để chứng thực danh tính tổ chức trong trường hợp bị giả mạo
Việc sử dụng SSL pinning giúp ngăn chặn các cuộc tấn công giả mạo chứng chỉ SSL/TLS từ các bên tấn công. Điều này bảo vệ dữ liệu của người dùng khỏi việc bị đánh cắp hoặc giả mạo trong quá trình truyền đi. Tuy nhiên, việc triển khai SSL pinning đòi hỏi sự cẩn thận và quản lý cập nhật định kỳ của chứng chỉ, do các chứng chỉ có thể hết hạn hoặc thay đổi theo thời gian.
### 5.2. Tìm hiểu và cài đặt tool Objection. Sử dụng Objection để bypass SSL Pinning của ứng dụng.
\*Tham khảo về Objection tại [đây](https://github.com/sensepost/objection).
Ứng dụng cần bypass SSL pinning, ban đầu không thể thực thi các chức năng cho có SSL pinning.

Bây giờ ta sẽ đi download frida tại https://github.com/frida/frida/releases. Cần kiểm tra kiến trúc CPU của thiết bị android hiện tại.

Download frida-server bản phù hợp.

Sau khi giải nén, đẩy file frida-server vào thiết bị Android và thực thi nó bằng chuỗi lệnh sau:
```
$ adb root # might be required
$ adb push frida-server /data/local/tmp/
$ adb shell "chmod 755 /data/local/tmp/frida-server"
$ adb shell "/data/local/tmp/frida-server &"
```
Sau đó, install `objection` bằng câu lệnh:
```
pip install objection
```
Thực thi câu lệnh sau với `--gadget` là package của app cần bypass.
```
objection --gadget "tech.httptoolkit.pinning_demo" explore
```
Thực thi lệnh `android sslpinning disable`.

Lúc này các chức năng có thể bắt bởi Burpsuite và thực thi thành công.

Bypass thành công SSL Pinning.

### 5.3. Tìm hiểu và cài đặt tool Frida. Sử dụng Frida để bypass SSL Pinning của ứng dụng.
\*Tham khảo về Frida tại [đây](https://frida.re/).
Ứng dụng cần bypass SSL pinning, ban đầu không thể thực thi các chức năng cho có SSL pinning.

Bây giờ ta sẽ đi download frida tại https://github.com/frida/frida/releases. Cần kiểm tra kiến trúc CPU của thiết bị android hiện tại.

Download frida-server bản phù hợp.

Sau khi giải nén, đẩy file frida-server vào thiết bị Android và thực thi nó bằng chuỗi lệnh sau:
```
$ adb root # might be required
$ adb push frida-server /data/local/tmp/
$ adb shell "chmod 755 /data/local/tmp/frida-server"
$ adb shell "/data/local/tmp/frida-server &"
```
Ở máy PC, cần install frida bằng:
```
pip install frida-tools
```

Sử dụng lệnh `frida-ps -U` để kiểm tra các tiến trình đang chạy trên thiết bị Android.

Bây giờ thực hiện chuẩn bị hook script js để bypass ssl pinning. Mình sử dụng đoạn script sau: https://raw.githubusercontent.com/httptoolkit/frida-android-unpinning/main/frida-script.js
Cần một bước đẩy cert của Burpsuite lên trước tại `/data/local/tmp/cert-der.crt`.

Thực thi câu lệnh sau để thực hiện bypass ssl_pinning:
```
frida -U -f tech.httptoolkit.pinning_demo -l script.js
```

Lúc này app tự động được mở và ta có thể bắt request qua Burpsuite và bypass ssl pinning thành công.

Thực thi được các chức năng.

**Bypass Manually Pinned Request**
Chức năng `Manually Pinned Request` vẫn bị SSL Pinning và báo lỗi `Unrecognized cert hash`.

Ta sẽ đi xây dựng script để hook bằng Frida để bypass.
Đầu tiên, đi decompile file apk của ứng dụng, ta tìm thấy hàm đảm nhiệm chức năng trên là `sendManuallyCustomPinned` tại class `MainActivity`. Hàm này có sử dụng 1 object `MainActivity$sendManuallyCustomPinned$1$`.

Khi object đó được launch, nó gọi đến hàm `invokeSuspend()` để SSL Pinning. Tại đây, mình tìm thấy lỗi `Unrecognized cert hash` được trigger khi giá trị của `z==false` (Ban đầu chương trình khởi tạo `z=true`).
→ không để luồng chương trình đi vào `if (i >= length)...` (Ban đầu i=0 nên điều kiện này chưa thỏa)
→ Cần break ngay từ đầu ở điều kiện `doesCertMatchPin==true`
→ Hàm `doesCertMatchPin()` của `MainActivity` phải trả về true.

Đây chính là hàm `doesCertMatchPin()` của `MainActivity`.

Bây giờ mình chỉ cần hook cho hàm này trả về true bằng script sau:
```javascript
Java.perform(() => {
console.log("[-] Starting hook tech.httptoolkit.pinning_demo");
const mainActivityClass = Java.use("tech.httptoolkit.pinning_demo.MainActivity");
mainActivityClass.doesCertMatchPin.implementation = function() {
console.log("Bypassed Manually SSL Pinning");
return true;
}
});
```
Thực thi lệnh sau để thực hiện hook.
```
frida -U -f tech.httptoolkit.pinning_demo -l .\hook_manual.js
```
Lúc này khi click `Manually Pinned Request` đã không còn lỗi và ta bypass ssl pinning thành công.
