Một loạt các bài blog này có nhiệm vụ note và hệ thống lại kiến thức mình đã đọc + học từ những đàn anh, đàn em, ... Thật ra, phần lớn kiến thực được đạo lại + copy từ blog của anh tsug0d, Jang, ...
Về bản thân Java Reflection là một tính năng của ngôn ngữ Java, cho phép truy cập đối tượng bao gồm: tên class, field, method và có thể thao tác chỉnh sửa các field của đối tượng (kể cả private field) trong quá trình runtime.
Về hướng security thì Java Reflection thường được dùng để bypass filter hay dùng để get và set lại giá trị của các field của của đối tượng để theo đúng gadget chain trong bug Java Deserialization.
1. Bypass Filter
Ví dụ: Có bug Code injection, tuy nhiên string "Runtime", "exec" đã bị chặn, lúc này chúng ta có thể sử dụng Java Reflection để bypass
Đoạn code bypass sẽ như sau:
Note: class java.lang.Class là một entry point của mọi thao tác của reflection API. Hiểu cách cục súc hơn là nó là lớp cha của mọi class trong Java.
Trong Java chúng ta có 2 cách để lấy java.lang.Class object:
- Sử dụng Object.getClass() method ➜ method này sẽ trả về runtime Class object type
- Sử dụng .class ➜ ClassName.class ➜ trả về Class object static
Dễ hiểu hơn thì chúng ta sử dụng tính năng Evaluate Expression của IntelliJ
Ở dòng 18, String.class là một object của class java.lang.String, sau đó sử dụng method Object.getClass() để lấy Object của class java.lang.Class ➜ Có được entrypoint
Và như đã nói, Java reflection rất linh động, ví dụ: chúng ta không nhất thiết cứng nhắc theo kiểu String.class.getClass(), mà có thể gọi bằng cách "".getClass().getClass()
Okay, sau khi có được entrypoint java.lang.Class() rồi thì chúng ta gọi forName(<tên_class>) để lấy class chúng ta cần:
Khi đã có object của class rồi, chúng ta có thể lấy method của class đó bằng getMethod(), như hình bên dưới lấy method exec() nhận String làm argument
Vì sao phải có cái String.class phía sau? đơn giản là vì trong java có nhiều method bị trùng tên nhưng khác argument nên phải khai báo để máy biết cái nào mà lấy.
Kết quả là chúng ta lấy được method java.lang,Runtime.exec(java.lang.string) ➜ tiếp theo cần gọi nó lên ➜ sử dụng invoke()
Method.invoke(Object object, Object[] args) ➜ method invokes the underlying method represented by this Method object
Nếu bạn thấy khó hiểu thì nó sẽ như thế này, về cơ bản thì payload của chúng ta là Runtime.getRuntime().exec("whoami");
Bây giờ chúng ta đã có exec, và exec lại được gọi từ Runtime.getRuntime() nên: exec.invoke(Runtime.getRuntime(), "whoami")
2. Chỉnh sửa field
Phần này lên quan đến bug Deserialization, trong gadget chain chúng ta cần phải sửa một số giá trị của các field để đúng ý đồ ➜ dùng Reflection
Nhận xét
Đăng nhận xét
Toản Đăng ơi! Có nhật xét mới