---
# System prepended metadata

title: ysoserial - CommonsCollections5
tags: [ysoserial]

---

**Về cái gadget chain CommonsCollections5 này sẽ hơi khó hiểu ban đầu (với những người mới học về java insecure deserialization như mình)**

**Mình có đọc [bài viết của anh @Jang](https://sec.vnpt.vn/2020/02/the-art-of-deserialization-gadget-hunting-part-2/) trước khi viết nên mình có thể sẽ theo flow của anh ấy, và mình sẽ viết chi tiết thêm những ý mình chưa biết trước đó.**

**Bắt đầu thôi !!!**

# 1. Requirement

Đọc bài này trước để hiểu về gadget chain và các thuộc tính của java https://hackmd.io/UP6a19qUT9OwEGBhm0Fuhw

# 2. Setup to debug

- Ở bài này, mình sẽ phân tích gadget chain `CommonsCollections5` thuộc bộ `ysoserial`

```bash
$  java -jar ysoserial.jar
Y SO SERIAL?
Usage: java -jar ysoserial.jar [payload] '[command]'
  Available payload types:
     Payload             Authors                     Dependencies
     -------             -------                     ------------
     AspectJWeaver       @Jang                       aspectjweaver:1.9.2, commons-collections:3.2.2
     BeanShell1          @pwntester, @cschneider4711 bsh:2.0b5
     C3P0                @mbechler                   c3p0:0.9.5.2, mchange-commons-java:0.2.11
     Click1              @artsploit                  click-nodeps:2.3.0, javax.servlet-api:3.1.0
     Clojure             @JackOfMostTrades           clojure:1.8.0
     CommonsBeanutils1   @frohoff                    commons-beanutils:1.9.2, commons-collections:3.1, commons-logging:1.2
     CommonsCollections1 @frohoff                    commons-collections:3.1
     CommonsCollections2 @frohoff                    commons-collections4:4.0
     CommonsCollections3 @frohoff                    commons-collections:3.1
     CommonsCollections4 @frohoff                    commons-collections4:4.0
     CommonsCollections5 @matthias_kaiser, @jasinner commons-collections:3.1
     CommonsCollections6 @matthias_kaiser            commons-collections:3.1
     CommonsCollections7 @scristalli, @hanyrax, @EdoardoVignati commons-collections:3.1
     FileUpload1         @mbechler                   commons-fileupload:1.3.1, commons-io:2.4
     Groovy1             @frohoff                    groovy:2.3.9
     Hibernate1          @mbechler
     Hibernate2          @mbechler
     JBossInterceptors1  @matthias_kaiser            javassist:3.12.1.GA, jboss-interceptor-core:2.0.0.Final, cdi-api:1.0-SP1, javax.interceptor-api:3.1, jboss-interceptor-spi:2.0.0.Final, slf4j-api:1.7.21
     JRMPClient          @mbechler
     JRMPListener        @mbechler
     JSON1               @mbechler                   json-lib:jar:jdk15:2.4, spring-aop:4.1.4.RELEASE, aopalliance:1.0, commons-logging:1.2, commons-lang:2.6, ezmorph:1.0.6, commons-beanutils:1.9.2, spring-core:4.1.4.RELEASE, commons-collections:3.1
     JavassistWeld1      @matthias_kaiser            javassist:3.12.1.GA, weld-core:1.1.33.Final, cdi-api:1.0-SP1, javax.interceptor-api:3.1, jboss-interceptor-spi:2.0.0.Final, slf4j-api:1.7.21
     Jdk7u21             @frohoff
     Jython1             @pwntester, @cschneider4711 jython-standalone:2.5.2
     MozillaRhino1       @matthias_kaiser            js:1.7R2
     MozillaRhino2       @_tint0                     js:1.7R2
     Myfaces1            @mbechler
     Myfaces2            @mbechler
     ROME                @mbechler                   rome:1.0
     Spring1             @frohoff                    spring-core:4.1.4.RELEASE, spring-beans:4.1.4.RELEASE
     Spring2             @mbechler                   spring-core:4.1.4.RELEASE, spring-aop:4.1.4.RELEASE, aopalliance:1.0, commons-logging:1.2
     URLDNS              @gebl
     Vaadin1             @kai_ullrich                vaadin-server:7.7.14, vaadin-shared:7.7.14
     Wicket1             @jacob-baines               wicket-util:6.23.0, slf4j-api:1.6.4
```

- Đối với gadget chain CC5, ta cần sử dụng các phiên bản `3.* < 3.2.2`  và `4.* < 4.4`

- Dùng maven để add lib mà ta cần dùng https://mvnrepository.com/artifact/commons-collections/commons-collections/3.1

- Mình sẽ sử dụng trực tiếp payload tại ysoserial để tiến hành debug
![image](https://hackmd.io/_uploads/B1BwM7wtC.png)

# 3. Gadget chain Analysis

- Gadget chain của `CommonsCollections5` có dạng như sau:

```java=
BadAttributeValueExpException.readObject()
    TiedMapEntry.toString()
        TiedMapEntry.getValue()
            LazyMap.get()
                ChainedTransformer.transform()
                    ConstantTransformer.transform()
                    InvokerTransformer.transform()
                        Method.invoke()
                            Class.getMethod()
                    InvokerTransformer.transform()
                        Method.invoke()
                            Runtime.getRuntime()
                    InvokerTransformer.transform()
                        Method.invoke()
```

- Ta sẽ đi luôn vào phân tích flow của chain này thì ta sẽ hiểu được cách họ build payload cũng như việc áp các tham số vào

## Intellij Debugger

- Entry point Đầu tiên sẽ là `BadAttributeValueExpException.readObject()`, đặt breakpoint tại đây
![image](https://hackmd.io/_uploads/HJPOimDtR.png)

- `valObj.toString()` được gọi và `valObj` = `TiedMapEntry`chính là gadget tiếp theo của chain này - `TiedMapEntry.toString()`
![image](https://hackmd.io/_uploads/HyEmnmDYR.png)

- Nhưng sau khi đi qua đoạn `valObj.toString()` thì calc đã bị pop up kèm theo một alert
![image](https://hackmd.io/_uploads/r1miZEDY0.png)

- Nội dung ở đây sẽ được hiểu là `TiedMapEntry` đã được kích hoạt trong quá trình debugger chạy - Tại sao lại như vậy?

- Sau khi tham khảo bài viết của anh Jang cũng như [tại đây](https://stackoverflow.com/questions/47866398/skipped-breakpoint-because-it-happened-inside-debugger-evaluation-intellij-ide), ta sẽ rút ra được:
    -  Debugger tự động đưa ra giá trị của `Object, fields,...` dưới dạng human-readable cho ta xem khi tới một breakpoint nào đó - có nghĩa là nó sẽ tự động gọi dến method `toString()` đối với các object class có `toString()`
    ![image](https://hackmd.io/_uploads/Sk4AGwDKC.png)
    - Chính vì lẽ đó mà object `valObj` đã được debugger tự động gọi đến `toString()` để hiển thị giá trị biến khi debug, điều này dẫn đến trigger gadget chain
    ![image](https://hackmd.io/_uploads/S18JLwwt0.png)


- Vậy ta sẽ đặt break point tại điểm sau đó là `org.apache.commons.collections.keyvalue.TiedMapEntry#toString`
![image](https://hackmd.io/_uploads/HkRi3QwFA.png)

- Calc vẫn bị pop up do `this` chính là object và vẫn tiếp tục tự động gọi đến `org.apache.commons.collections.keyvalue.TiedMapEntry#toString`
![image](https://hackmd.io/_uploads/SJiYwPPY0.png)

- Bỏ qua đặt break point tại `TiedMapEntry` do debugger sẽ trigger `toString()`, ta sẽ đặt breakpoint tại `org.apache.commons.collections.map.LazyMap#get` và có thể bắt đầu phân tích
![image](https://hackmd.io/_uploads/rJv4dvPFA.png)

## Gadget chain Analysis

### org.apache.commons.collections.map.LazyMap#get
![image](https://hackmd.io/_uploads/rJt2dODYC.png)

- Tại đây, chương trình sẽ check xem có tồn tại key hay không, nếu tồn tại sẽ gọi đến `this.factory.transform(key)` = `ChaindTransformer.transform(key)`

### org.apache.commons.collections.functors.ChainedTransformer#transform
![image](https://hackmd.io/_uploads/HyTm5uwY0.png)

- Tại hàm này, chương trình thực hiện loop qua 5 lần với tham số object để gọi các phương thức khác nhau rồi gán lại giá trị cho object đó
    - **object = ConstantTransformer.transform(object)**
    - **object = InvokerTransformer.transform(object)**
    - **object = InvokerTransformer.transform(object)**
    - **object = InvokerTransformer.transform(object)**
    - **object = ConstantTransformer.transform(object)**
    - Số lần loop tương ứng với số object đã được build tại payload
    ![image](https://hackmd.io/_uploads/B1Sav_OKR.png)

#### 0. ConstantTransformer.transform()
![image](https://hackmd.io/_uploads/rkgEmtPF0.png)

- Object được trả về chính là `class java.lang.Runtime()`

#### 1. InvokerTransformer.transform()
![image](https://hackmd.io/_uploads/SkPMHYvFA.png)

- Đối với hàm `getClass()`, hàm này thông thường sẽ lấy input là một object rồi trả về class của object đó (nói dễ hiểu sẽ là trả về class mà object đó thuộc về)

- Nhưng do input ở đây là object `class java.lang.Runtime()` (nói cách khác nó chính là một class). Mà class của các phương thức class thuộc về sẽ luôn là `java.lang.Class()`
![image](https://hackmd.io/_uploads/SJR86FvYR.png)

- Bước tiếp theo sẽ gọi đến `cls.getMethod(iMethodName, iParamTypes)`, hàm này thuộc [java reflection](https://gpcoder.com/2883-huong-dan-su-dung-java-reflection/), hàm này trả về method `getMethod()` đã được set trong payload

![image](https://hackmd.io/_uploads/H1qACKPY0.png)

![image](https://hackmd.io/_uploads/Bk-DGoPt0.png)
- Cuối cùng, `method.invoke()` được gọi để call method `getMethod` của `class java.lang.Runtime()` với tham số là `getRuntime` - tức là nó sẽ get Method `getRuntime` của `class java.lang.Runtime()`
![image](https://hackmd.io/_uploads/SkchEowFC.png)

#### 2. InvokerTransformer.transform()
![image](https://hackmd.io/_uploads/SJcU_v_FR.png)

- Chính vì tại bước trước, `method.invoke()` được trả về 
mà [đây chính là method của java reflection](https://gpcoder.com/2883-huong-dan-su-dung-java-reflection/) nên class được trả về là class method của java reflection

- Method param của bước này chính là invoke nên khi trả về giá trị getMethod sẽ là object `java.lang.reflect.Method.invoke()`
![image](https://hackmd.io/_uploads/BJKeqPdYA.png)
![image](https://hackmd.io/_uploads/rk5tFD_tA.png)

- Bước này khi return sẽ thực thi method `reflect.Method.invoke` của method `Runtime.getRuntime()` với tham số null
![image](https://hackmd.io/_uploads/HysiWOdY0.png)
-> Giá trị trả về vẫn sẽ là `Runtime.getRuntime()` = object `Runtime`

#### 3. InvokerTransformer.transform()
![image](https://hackmd.io/_uploads/Hy_irdOK0.png)

- Do input lần này sẽ là `Object Runtime` nên cls trả về sẽ là `class java.lang.Runtime`

- Method tại đây được trả về sẽ là `java.lang.Runtime.exec(java.lang.String)`
![image](https://hackmd.io/_uploads/H1GlLudFA.png)

- Bước cuối cùng, java reflect sẽ thực thi `method exec` của `object Runtime` với arg tương ứng là `calc.exe` và đây chính là **điểm sink** trigger calc cuối cùng
![image](https://hackmd.io/_uploads/BJd_LO_K0.png)
![image](https://hackmd.io/_uploads/HkD0LOutR.png)

### Đối với bài này, ta cần tự debug cũng như xem tài liệu về các phương thức như invoke, java reflection,.. để hiểu hơn về cách hoạt động ở đây

# References

- https://sec.vnpt.vn/2020/02/the-art-of-deserialization-gadget-hunting-part-2/

- https://nhienit.wordpress.com/2021/11/25/commonscollection-gadget-chain-for-learning-purposes/
