[Write up] EVABSv4 (Phần 2)
Bài đăng này đã không được cập nhật trong 4 năm
Trong phần 1 mình đã giới thiệu từ Level 1 - 8 của lab EVABSv4. Qua 8 levels đầu chúng ta được làm quen với ADB (logcat, shell, pull); SQLite DB Browser; sơ qua về cấu trúc tệp tin trong file apk và cấu trúc thư mục trong local storage của 1 ứng dụng cài đặt trên thiết bị android.
Trong phần 2 này mình sẽ nói thêm về các sử dụng framework Frida, Patch app, Intercept http request bằng Burp Suite. Mình sẽ không nói thêm về các nội dung đã đề cập kỹ trong các bài writeup trước đó. Còn với các kiến thức về Frida và Burp Suite mình sẽ hướng đẫn kỹ hơn.
Và giờ thì chúng ta sẽ tiếp tục với...
Level 9: Smali Injection
Xem source code bằng bytecode viewer:
- SmaliInject.class:
- SmaliInject$2.class:
Dễ thấy nếu biến SIGNAL = "LAB_ON" thì chương trình sẽ in ra flag. Nhưng biến SIGNAL đang được đặt mặc định là "LAB_OFF" và không có lệnh nào thay đổi giá trị của biến này cả.
Vì thế chúng ta cần sửa code smali và build lại app mới sau khi sửa thì chương mình sẽ in ra flag. Cách patch và build lại file apk mình đã đề cập đến trong bài viết về [dịch ngược và patch file apk] (https://viblo.asia/p/tim-hieu-dang-ctf-reverse-android-dich-nguoc-va-patch-file-apk-Eb85okv252G)
Chúng ta có thể sửa code và build lại ứng dụng mới mà vẫn dùng được các chức năng bình thường do Dev đã không có cơ chế kiểm tra độ toàn vẹn code.
Level 10: Intercept
Theo như hint thì cần phải intercept request bằng burpsuite. Để intercept được request trên các phiên bản Android từ Android N trở lên thì phải add root CA có thời hạn ngắn. Nếu muốn đơn giản hơn thì chỉ cần cài EVABSv4 lên thiết bị có phiên bản thấp hơn Android N là sử dụng được burp CA.
Cách cài đặt Burp Suite theo hướng dẫn của portswigger.
Cấu hình Proxy như sau để bắt được các request từ thiết bị android ra ngoài:
Sau khi config để intercept được request rồi thì chỉ cần Send to repeater và gửi request lên là được. Trong respond có chứa flag.
Đây là một nguy cơ mất an toàn ứng dụng android do Dev không thực hiện SSL Pinning. Nếu một ứng dụng sử dụng SSL Pinning một cách cẩn thận thì server sẽ không phản hồi lại các request chúng ta gửi qua Burp.
Level 11: Custom PERM
Ở Level này ta phải tìm đúng input mới được, xem source trên bytecode viewer dễ dàng thấy ngay input đúng là cust0m_p3rm.
Sau khi nhập đúng input thì flag sẽ được truyền vào intent com.revo.evabs.action.SENSOR_KEY bằng hàm putExtra().
Ban đầu mình tìm cách để tác động vào intent nhằm lấy được data truyền vào intend đó nhưng tốn khá nhiều thời gian mà không được. Có thể do kiến thức của mình chưa đủ. Vì thế mình chuyển sang dùng Frida luôn. Ý tưởng là hook và sửa hàm putExtra() cho nó in ra flag.
Mình cùng từng viết 1 bài writeup sử dung Frida để hook function tại đây. Lần này thì mình sẽ giải thích kỹ hơn về Frida.
Hiểu nôm na thì khi sử dụng Frida mình sẽ phải xác định rõ đối tượng (hàm) mà mình muốn thay đổi và process (ứng dụng) sẽ thực hiện hàm này. Frida sẽ thay nội dung hàm mình muốn thành nội dung mới. Bằng cách đó, khi ứng dụng chạy hàm này thì thực ra nó đang hoạt động theo đúng cách ta muốn.
Có 2 hàm mà mình thường xử dụng với Frida:
- Java.choose(): scan trên heap tìm instance của class to muốn. Khi tìm được thì Frida sẽ chạy đoạn code mới của ta.
- Java.use(): khi hệ thống tạo instance mới của class mình muốn thì phần code mới mình viết sẽ được ghi đè vào.
Mình thường dùng Java.use() nhiều hơn. Ở bài này, vì hàm putExtra() có nhiều bản tùy theo kiểu tham số, nên mình phải sử dụng overload() để chỉ ra đúng hàm putExtra() nhận tham số là 2 string.
import frida
import sys
def onMessage(message, data):
print(message)
package = "com.revo.evabs"
jscode = """
Java.perform(function () {
send("[-] Starting hooks android.content.Intent.putExtra");
var intent = Java.use("android.content.Intent");
intent.putExtra.overload("java.lang.String", "java.lang.String").implementation = function(var_1, var_2) {
send("[+] Flag: " + var_2);
};
});
"""
process = frida.get_usb_device().attach(package)
script = process.create_script(jscode)
script.on("message", onMessage)
print("[*] Hooking", package)
script.load()
sys.stdin.read()
Kết qủa:
Ở đây khi mình kiểm tra flag thì lại báo là sai flag, trong khi mình khá chắc là cách mình làm đúng. Vì thế mình đã gửi mail hỏi tác giả của EVABS và nhận được phản hồi rằng cách mình làm là chính xác. Do code random có lỗi nên flag sinh sai.
Qua đó khẳng định thêm rằng các anh Ấn Độ rất nhiệt tình ))
Level 12 - Instrument
Khi click "MAP AREA" thì sẽ xuất hiện 2 tọa độ x và y cùng với 1 giá trị bằng x * y. Bài này cũng cần sử dụng Frida để làm, theo cảm nhận của mình thì còn dễ hơn level 11. Source code của level 12 trong file frida1.class
Logic so sánh của bài này rất đơn giản, flag sẽ được in ra nếu (x = a * b) > var5 + 150 với var5 là 1 số int random trong khoảng 0 -> 70. Vì a b cố định khiến x luôn là 50, như thế thì var5 random kiểu gì thì x cũng không thỏa mãn được. Vậy thì chỉ cần hook và sửa lại hàm nextInt(int) cho return -150 là được, nhanh gọn chẳng phải nghĩ hay tính toán gì.
import frida
import sys
def onMessage(message, data):
print(message)
package = "com.revo.evabs"
jscode = """
Java.perform(function () {
send("[-] Starting hooks java.util.Random.nextInt");
var random = Java.use("java.util.Random");
random.nextInt.overload("int").implementation = function(var_1) {
return -150;
};
});
"""
process = frida.get_usb_device().attach(package)
script = process.create_script(jscode)
script.on("message", onMessage)
print("[*] Hooking", package)
script.load()
sys.stdin.read()
Flag sẽ được in ra log:
Kiểm tra flag vẫn sai, chắc vẫn lỗi như level 11 :V
All rights reserved