L1: Android Mobile Pentest 101¤
Bài 1 – Thiết lập môi trường¤
Mục tiêu¤
Tạo được điện thoại Android giả lập phục vụ kiểm thử bảo mật.
Tại sao cần môi trường giả lập?¤
Khi pentest ứng dụng Android, việc dùng điện thoại thật tiềm ẩn nhiều rủi ro: mất dữ liệu cá nhân, brick máy, vi phạm bảo hành. Điện thoại giả lập (emulator) cho phép:
- Tạo và xóa thiết bị tùy ý mà không ảnh hưởng phần cứng thật
- Dễ dàng snapshot/restore trạng thái máy
- Kiểm soát hoàn toàn môi trường (API level, cấu hình phần cứng)
- Root máy ảo mà không cần unlock bootloader
Phần mềm cần cài¤
| Phần mềm | Mục đích | Link |
|---|---|---|
| VirtualBox | Nền tảng ảo hóa để chạy Genymotion | https://www.virtualbox.org/wiki/Downloads |
| Genymotion | Tạo và quản lý thiết bị Android ảo | https://www.genymotion.com/download/ |
Lưu ý: VirtualBox chỉ đóng vai trò backend. Sau khi cài xong, bạn không cần tương tác trực tiếp với VirtualBox — Genymotion sẽ tự dùng nó.
Các bước thiết lập¤
Bước 1: Cài VirtualBox trước, sau đó cài Genymotion.
Bước 2: Mở Genymotion, tạo thiết bị mới bằng nút Add. Trong khóa học này sử dụng:
Bước 3: Chọn thiết bị vừa tạo, bấm Start để khởi động.
Kiến thức mở rộng: Các lựa chọn emulator khác
Ngoài Genymotion, bạn có thể dùng:
- Android Studio AVD (Android Virtual Device): Miễn phí, tích hợp sẵn trong Android Studio. Phù hợp cho developer hơn là pentester vì chậm hơn Genymotion.
- Android-x86: Cài Android lên VM như một hệ điều hành thật, kiểm soát sâu hơn.
- Frida + thiết bị thật đã root: Phù hợp khi cần test các tính năng phần cứng thật (NFC, sensor).
Genymotion được ưa chuộng trong pentest vì tốc độ khởi động nhanh, hỗ trợ nhiều API level, và đặc biệt là thiết bị đã root sẵn — điều cực kỳ quan trọng khi cần truy cập /data/data/.
Bài 2 – Android Debug Bridge (ADB)¤
Mục tiêu¤
Sử dụng thành thạo adb để tương tác với thiết bị Android (thật hoặc ảo).
ADB là gì?¤
Android Debug Bridge (ADB) là công cụ dòng lệnh cho phép giao tiếp giữa máy tính và thiết bị Android qua USB hoặc mạng TCP/IP. Đây là công cụ không thể thiếu trong quá trình pentest Android.
graph LR
A[Máy tính - PC] -->|TCP 5555| B[Genymotion - 192.168.56.101]
A -->|USB| C[Thiết bị thật]
Bật USB Debugging trên thiết bị ảo¤
Đây là bước bắt buộc để ADB có thể kết nối.
Bước 1: Vào Settings → About Phone
Bước 2: Bấm liên tục 7 lần vào trường Build Number để mở khóa Developer Options
Bước 3: Quay lại Settings → Developer Options → bật USB Debugging
Tìm ADB của Genymotion¤
Genymotion đi kèm ADB riêng. Bạn cần dùng đúng phiên bản này để tránh xung đột.
Kết nối ADB đến thiết bị ảo¤
Genymotion sử dụng địa chỉ IP mặc định 192.168.56.101, cổng 5555.
# Kết nối đến thiết bị ảo qua mạng
./adb connect 192.168.56.101:5555
# Kiểm tra danh sách thiết bị đang kết nối
./adb devices
Kết quả mong đợi:
Các lệnh ADB thường dùng trong pentest¤
Cài APK lên thiết bị:
Truy cập shell của thiết bị:
Vì Genymotion đã root sẵn, bạn có quyền root ngay lập tức — điều này cho phép truy cập toàn bộ filesystem kể cả /data/data/.
Xem log hệ thống theo thời gian thực:
Đây là lệnh cực kỳ hữu ích để phát hiện thông tin nhạy cảm bị lộ qua log (sẽ nói chi tiết ở phần sau).
Đẩy file từ máy tính lên thiết bị:
adb push /path/on/pc /path/on/device
# Ví dụ:
adb push /tmp/exploit.sh /data/local/tmp/exploit.sh
Kéo file từ thiết bị về máy tính:
adb pull /path/on/device /path/on/pc
# Ví dụ: lấy database của app về máy để phân tích
adb pull /data/data/com.example.app/databases/app.db ./app.db
Cài APK trực tiếp qua đường dẫn:
# Ứng dụng thực hành trong khóa học:
# https://github.com/dineshshetty/Android-InsecureBankv2
adb install InsecureBankv2.apk
Kiến thức mở rộng: ADB over WiFi và một số lệnh nâng cao
# Forward cổng từ máy tính vào thiết bị (hữu ích khi proxy traffic)
adb forward tcp:8080 tcp:8080
# Chụp screenshot
adb shell screencap -p /sdcard/screen.png
adb pull /sdcard/screen.png
# Gỡ cài đặt app
adb uninstall com.example.app
# Xem log chỉ của một app cụ thể
adb logcat --pid=$(adb shell pidof -s com.example.app)
# Chạy lệnh trực tiếp không cần vào shell
adb shell "cat /data/data/com.example.app/shared_prefs/*.xml"
Bài 3 – Phân tích tĩnh (Static Analysis)¤
Mục tiêu¤
Hiểu và thực hiện được các bước phân tích tĩnh trên file APK.
Phân tích tĩnh là gì?¤
Phân tích tĩnh là quá trình kiểm tra file APK mà không cần chạy ứng dụng. Bạn kiểm tra source code (đã decompile), cấu hình, tài nguyên để tìm ra các lỗ hổng bảo mật.
Ngược lại, phân tích động (dynamic analysis) là kiểm tra ứng dụng trong lúc nó đang chạy.
graph TD
A[File APK] --> B[Phân tích tĩnh]
A --> C[Phân tích động]
B --> D[Decompile code]
B --> E[Kiểm tra Manifest]
B --> F[Kiểm tra permissions]
B --> G[Kiểm tra hardcoded secrets]
C --> H[Intercept traffic]
C --> I[Hook functions - Frida]
C --> J[Kiểm tra log runtime]
Phần 1: Phân tích tự động với MobSF¤
MobSF (Mobile Security Framework) là framework mã nguồn mở, tất-cả-trong-một để kiểm tra bảo mật ứng dụng Android, iOS, và Windows. Nó tự động hóa phần lớn công việc phân tích tĩnh.
Cài đặt MobSF¤
# Clone repository
git clone https://github.com/MobSF/Mobile-Security-Framework-MobSF.git
cd Mobile-Security-Framework-MobSF
# Tạo và kích hoạt môi trường ảo Python
pip3 install virtualenv
virtualenv -p python3 venv
source venv/bin/activate
# Cài dependencies
pip3 install -r requirements.txt
# Khởi tạo database SQLite
python3 manage.py makemigrations
python3 manage.py migrate
# Chạy server
python3 manage.py runserver
Sau khi chạy, truy cập http://localhost:8000/ bằng trình duyệt.
Yêu cầu hệ thống¤
- Python 3.6+
- Oracle JDK 1.7 trở lên
- macOS cần cài Command-line tools (
xcode-select --install)
Sử dụng MobSF¤
Kéo thả file .apk vào giao diện web. MobSF sẽ tự động phân tích và cung cấp báo cáo về:
1. Thông tin cơ bản của app:
Package Name: com.android.insecurebankv2
Main Activity: com.android.insecurebankv2.LoginActivity
Target SDK: 26
Min SDK: 15
MD5: 0bb3788ed48ab0960109c39a98923445
2. Phân tích quyền (Permissions):
MobSF phân loại từng permission thành dangerous hoặc normal. Ví dụ với InsecureBankv2:
| Permission | Mức độ | Ý nghĩa |
|---|---|---|
INTERNET |
dangerous | Kết nối mạng tùy ý |
WRITE_EXTERNAL_STORAGE |
dangerous | Ghi vào thẻ nhớ |
SEND_SMS |
dangerous | Gửi SMS (tốn tiền người dùng) |
READ_PHONE_STATE |
dangerous | Đọc IMEI, số điện thoại |
READ_CONTACTS |
dangerous | Đọc danh bạ |
Nguyên tắc đánh giá permission
Permission dangerous không tự nhiên là lỗ hổng. Bạn cần hỏi: "App này có thực sự cần quyền này không?" Ví dụ một app đèn pin mà yêu cầu READ_CONTACTS thì đó là dấu hiệu đáng ngờ.
3. Phân tích AndroidManifest.xml:
MobSF tự động phát hiện các cấu hình nguy hiểm trong Manifest. Với InsecureBankv2:
| Vấn đề | Mức độ | Giải thích |
|---|---|---|
android:debuggable=true |
HIGH | App có thể bị attach debugger dễ dàng |
android:allowBackup=true |
MEDIUM | Dữ liệu app có thể backup ra ngoài qua ADB |
Activity PostLogin exported |
HIGH | Activity này có thể bị gọi từ app khác |
| Content Provider exported | HIGH | Database có thể bị truy cập từ app khác |
Phần 2: Phân tích thủ công với Bytecode Viewer¤
Công cụ tự động không phát hiện được tất cả mọi thứ. Việc đọc code thủ công là kỹ năng bắt buộc.
Bytecode Viewer là tool miễn phí cho phép decompile APK và xem source Java ngay lập tức.
Tải tại: https://github.com/Konloch/bytecode-viewer/releases
Cách sử dụng¤
Kéo file .apk vào Bytecode Viewer. Tool sẽ tự động:
1. Giải nén APK
2. Chuyển đổi .dex → .jar (dùng dex2jar)
3. Decompile bytecode → Java source (dùng JD-Core, CFR, Procyon...)
Bạn có thể chọn các decompiler khác nhau để so sánh kết quả khi một decompiler cho ra code không đọc được.
Ví dụ: Phát hiện backdoor trong code¤
Khi đọc file DoLogin$RequestTask.class, phát hiện logic đăng nhập bất thường:
if (this.thiss0.username.equals("devadmin")) {
// Gửi request đến endpoint /devlogin — bỏ qua kiểm tra password
localHttpPost2.setEntity(new UrlEncodedFormEntity(localArrayList));
localHttpResponse = localDefaultHttpClient.execute(localHttpPost2);
} else {
// Đăng nhập bình thường
localHttpPost1.setEntity(new UrlEncodedFormEntity(localArrayList));
localHttpResponse = localDefaultHttpClient.execute(localHttpPost1);
}
Phát hiện backdoor
Nếu username là devadmin, app gửi request đến endpoint /devlogin thay vì /login thông thường. Endpoint này không kiểm tra password, cho phép đăng nhập với bất kỳ mật khẩu nào. Đây là một hardcoded backdoor điển hình.
Malicious Code Scanner¤
Bytecode Viewer có plugin Malicious Code Scanner để tự động tìm các pattern nguy hiểm như:
java/lang/reflect/Method.invoke— Reflection (có thể dùng để bypass security)java/lang/reflect/Field.setAccessible— Truy cập field privateRuntime.exec()— Thực thi lệnh hệ thống- Các API đọc thông tin thiết bị (IMEI, contacts...)
Phần 3: Các kiểm tra thủ công quan trọng¤
Kiểm tra 1: Thông tin đăng nhập lưu không mã hóa trong database¤
Sau khi đăng nhập vào InsecureBankv2, kiểm tra database SQLite của app:
# Vào shell thiết bị
adb shell
# Di chuyển đến thư mục database của app
cd /data/data/com.android.insecurebankv2/databases
# Xem danh sách file
ls
# Mở database bằng sqlite3
sqlite3 mydb
# Xem danh sách bảng
.tables
# Đọc dữ liệu
SELECT * FROM names;
Nếu kết quả trả về username/password dạng plaintext → lỗ hổng nghiêm trọng.
Kết quả an toàn
Nếu không thấy thông tin nhạy cảm trong database, hoặc dữ liệu được mã hóa đúng cách → Safe.
Kiểm tra 2: Thông tin nhạy cảm lưu dưới dạng plaintext¤
# Từ thư mục /data/data/com.android.insecurebankv2
# Tìm kiếm đệ quy các từ khóa nhạy cảm
grep -r 'deviceId' $(find .)
grep -r 'password' $(find .)
grep -r 'token' $(find .)
Các từ khóa cần kiểm tra: deviceId, uid, userId, imei, phone, password, token, secret, apiKey
Kiểm tra 3: File Backup không được mã hóa¤
Nếu android:allowBackup=true trong Manifest, dữ liệu app có thể bị backup ra ngoài:
# Backup toàn bộ dữ liệu app (trên thiết bị sẽ hiện popup xác nhận)
adb backup -apk -shared com.android.insecurebankv2
# File backup.ab sẽ được tạo ra
# Chuyển đổi sang định dạng có thể đọc
cat backup.ab | (dd bs=24 count=0 skip=1; cat) | zlib-flate -uncompress > backup_compressed.tar
# Giải nén
tar -xvf backup_compressed.tar
Kiểm tra các file trong thư mục vừa giải nén, đặc biệt là:
- apps/<package>/sp/*.xml — SharedPreferences
- apps/<package>/db/* — SQLite databases
Với InsecureBankv2, file mySharedPreferences.xml chứa:
<?xml version='1.0' encoding='utf-8' standalone='yes'?>
<map>
<string name="superSecurePassword">DTrWZVXjSoFdgOe6lfHxJg==</string>
<string name="EncryptedUsername">ZGluZXNo</string>
</map>
Mật khẩu tuy có vẻ mã hóa, nhưng key nằm ngay trong code — xem tiếp bên dưới.
Kiểm tra 4: Thông tin nhạy cảm lộ trong log¤
# Xem log theo thời gian thực
adb logcat
# Hoặc filter theo tag cụ thể
adb logcat -s "Successful Login"
Sau khi đăng nhập vào InsecureBankv2, log hiển thị:
Lỗ hổng nghiêm trọng
Thông tin đăng nhập bị ghi vào log hệ thống dưới dạng plaintext. Bất kỳ app nào có quyền READ_LOGS đều có thể đọc được. Trên thiết bị đã root hoặc qua ADB, ai cũng có thể xem.
Kiểm tra 5: Thuật toán mã hóa yếu¤
Trong CryptoClass.class:
public class CryptoClass {
// Key hardcoded ngay trong code!
String key = "This is the super secret key 123";
// IV toàn số 0 — cực kỳ nguy hiểm!
byte[] ivBytes = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
public static byte[] aes256encrypt(byte[] iv, byte[] key, byte[] plaintext) {
IvParameterSpec ivSpec = new IvParameterSpec(iv);
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
return cipher.doFinal(plaintext);
}
}
Vấn đề: 1. Key hardcoded trong source code — ai decompile cũng thấy 2. IV toàn số 0 — IV cố định phá vỡ tính bảo mật của CBC mode 3. Dùng AES-CBC nhưng IV không random → cùng plaintext luôn cho cùng ciphertext
Khai thác: Dùng key và IV đã biết để giải mã password:
from Crypto.Cipher import AES
import base64
def unpad(data):
return data[:-data[-1]]
def decrypt(key, ciphertext, iv):
cipher = AES.new(key.encode('utf-8'), AES.MODE_CBC, iv)
return cipher.decrypt(ciphertext)
key = "This is the super secret key 123"
iv = b'\x00' * 16
ciphertext = base64.b64decode("DTrWZVXjSoFdgOe6lfHxJg==")
plaintext = unpad(decrypt(key, ciphertext, iv)).decode('utf-8')
print(plaintext) # Kết quả: Dinesh@123$
Kiểm tra 6: Activity Hijacking¤
Nếu một Activity trong Manifest có android:exported=true, bất kỳ app nào (hoặc người dùng qua ADB) đều có thể gọi thẳng Activity đó mà không cần đi qua flow đăng nhập bình thường.
<!-- Trong AndroidManifest.xml -->
<activity
android:name="com.android.insecurebankv2.PostLogin"
android:exported="true" />
Khai thác:
# Vào shell thiết bị
adb shell
# Gọi thẳng Activity PostLogin bằng Activity Manager
am start -n com.android.insecurebankv2/.PostLogin
App sẽ nhảy thẳng vào màn hình sau đăng nhập mà không yêu cầu credentials.
Hậu quả
Attacker có thể bypass toàn bộ màn hình login, truy cập trực tiếp vào chức năng chuyển tiền, xem sao kê, đổi mật khẩu mà không cần biết username/password.
Kiến thức mở rộng: Android Security Checklist
Ngoài các kiểm tra trong tài liệu này, một pentest Android đầy đủ còn cần kiểm tra:
Phân tích tĩnh nâng cao:
- Certificate pinning có được implement không, và có thể bypass không
- Anti-root / Anti-tampering detection có tồn tại không
- Obfuscation (ProGuard/R8) có được áp dụng không
- Các API key, token, URL endpoint nhạy cảm trong code/resources
- WebView có bật JavaScript interface nguy hiểm không (addJavascriptInterface)
- Deep link / Intent handling có bị abuse không
Phân tích động: - Intercept HTTPS traffic bằng Burp Suite + certificate pinning bypass - Hook function bằng Frida để bypass root detection, certificate pinning - Kiểm tra traffic có bị mã hóa đúng cách không - Kiểm tra session management (token expiry, logout thực sự xóa token chưa)
Tài liệu tham khảo: - OWASP Mobile Security Testing Guide (MSTG) - OWASP Mobile Top 10 - Android Security Checklist của WithSecure - InsecureBankv2 — Lab thực hành