# The Art of Deserialization Gadget Hunting


Bài viết này phần nào đó là chia sẻ lại những kiến thức riêng về Java Deserialization mình đã nghiên cứu trong thời gian qua cho mọi người, phần nữa là để giúp chính mình nhớ lại những gì đã làm, dạo này tự dưng bị bệnh hay quên <@_@>, (có hôm đọc lại chính blog của mình mà cứ như đọc bài của người ta =)) ).

Khái niệm cơ bản về Java Deserialization (Deser) mình không nhắc lại nữa mà sẽ nói về cách làm sao mà từ readObject() lead to RCE, hay còn được gọi là gadgetchain.

Có lẽ cũng giống mình hồi mới biết đến Java Deser, cách nhìn của những người chỉ sử dụng các payload đó ở mức khách quan, chưa thấy được cái hay trong cái gadgetchain mình đang sử dụng. Sau khi nghiên cứu một thời gian mới thấy thực sự nể phục công sức của những người đi trước, không cần dùng công cụ hỗ trợ mà vẫn tìm ra được nhiều gadgetchain hữu ích để góp vào bộ payload của ysoserial!

**Một số khái niệm mình cần nêu trước khi vào bài:**

* **Source**: là điểm bắt đầu của gadgetchain. Khi deser, java sẽ gọi method readObject() của source Object.

* **Sink**: sau khi ghép nối các chain thì sẽ dẫn tới sink, hay cách khác, sink chính là điểm cuối của gadgetchain. Thường sink sẽ có các metod hữu ích như **Reflection **method invoke, file write, …

* **Reflection in java**: đây là 1 API của java, cho phép truy xuất, sửa đổi hành vi của method, field, class, interfaces. Do vậy việc tìm hiểu và viết được gadgetchain phụ thuộc rất nhiều vào cái Java Reflection. (for more detail: [https://www.geeksforgeeks.org/reflection-in-java/](https://www.geeksforgeeks.org/reflection-in-java/?fbclid=IwAR101djrM59HEpJbVDddgTXPYmrCVQMQACFiRFUVsy8ANijS7DopIRqYfv8))

* **Method call**: method A gọi method B, method A -&gt; method B

IDE mình sử dụng chủ yếu là IntellIJ IDEA, lý do là vì nó free for student và tiện …

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1624241422420/EL52YzMqw.png)

Các công cụ mình cần dùng: git, svn, các framework, mvn, gradle … được tích hợp tất tần tật vào. Bạn sẽ không phải bận tâm đến chuyện setup thêm gì nhiều, mà chỉ cần focus vào công việc thôi. Một lựa chọn khác đó là Eclipse, nhưng điểm yếu của eclipse là khi debug sẽ không show ra các local variable nếu như không có source của class đó, cách eval của eclipse cũng hơi bất tiện nên mình khuyên dùng IntellIJ cho việc đọc và debug các loại code liên quan tới Java.

License của IntellIJ thì các bạn có thể sử dụng mail edu của trường hoặc dùng gmail cũng được, apply vào student program của họ là bạn sẽ có hẳn mấy năm sử dụng Ultimate version thoải mái. Nếu không có chương trình này thì ko biết giờ này mình đang chật vật dùng bản crack ở đâu đó nữa ¯\_(ツ)_/¯.

***Note**: OS mình đang dùng là windows nên tổ hợp phím tắt sử dụng trong bài sẽ khác so với những bạn sử dụng OS khác*

_______________________________

Về cơ bản, gadgetchain là kết quả của việc lắp ghép các method call, gán ghép các field làm sao cho nó đi theo luồng mà mình mong muốn: RCE, write file, …

Tưởng tượng các method call như các đoạn ống nước riêng lẻ thì công việc tìm gadgetchain chính là quá trình lắp ghép các đoạn ống** thích hợp **lại với nhau, và kết quả là có thể dẫn nước từ nguồn (source) tới đích (~sink).

Lý thuyết suông về một vấn đề nào đó thì có thể sẽ hơi khô khan và khó hiểu cho người mới tìm hiểu (nhất là với giọng văn nửa mùa của mình). Do vậy trong phần này mình sẽ đi vào phân tích luồng hoạt động của 1 số gadgetchain có trong bộ ysoserial, cũng như nói vềcác source, sink thường gặp trong các gadgetchain.

**#1. URLDNS**

Cách hoạt động của chain này khá đơn giản:

```
  HashMap.readObject()
    HashMap.hash()
      URL.hashCode()
        URLStreamHandler.hashCode()
          URLStreamHandler.getHostAddress()
            InetAddress.getByName()
```


Gadgetchain này tồn tại ngay bên trong **rt.jar** của java, mục đích cuối cùng của gadgetchain này là tạo 1 request dns lookup tới domain tùy ý. Từ đó có thể được sử dụng để kiểm tra xem target có thể deserialize object được hay không!

Bắt đầu phân tích từ source của chain này, đó là tại ***HashMap.readObject()*.**

**java.util.HashMap **là 1 class có sẵn trong runtime machine của java, để đi đến class này từ IntellIJ IDEA, ta sử dụng tổ hợp phím: `**Ctrl + N` **rồi gõ HashMap vào, được kết quả như sau:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1624241424180/SmYlBLxGO.png)

Chọn class mà IntellIJ tìm được ở phía dưới, ta sẽ mở được đúng class đang cần đi tới **java.util.HashMap.**

* *Chức năng này áp dụng được kể cả với các class không có source nằm trong classpath của project.*

Di chuyển từ ô tìm kiếm class **HashMap **sẽ dẫn bạn tới phần đầu của class như thế này:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1624241425691/UcEN3W_zo.png)

Tiếp tục sử dụng tổ hợp phím: `**Ctrl + F12`** để list ra các method nằm trong class này:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1624241427312/3aeLsnYXE.png)

Method mình cần đi tới bây giờ là **readObject(), **gõ trực tiếp chữ “*readobject*” ngay sau khi `**Ctrl + F12`** để tìm method này (lưu ý là ko có ô để gõ chữ đâu), được kết quả:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1624241428818/V6-IRVxL9.png)

Click vào kết quả hoặc Enter để chuyển đến method này luôn:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1624241430554/FI4D5abbF.png)

***Fact**: Việc sử dụng quen và thành thạo các tổ hợp phím tắt của IntellIJ sẽ giúp cho quá trình phân tích gadget được thuận lợi và nhanh hơn rất nhiều!*

Khi đã navigate tới **HashMap.readObject(), **ta cần tìm tới đoạn mà method này sẽ gọi tới chain tiếp theo của nó (ở đây là gọi tới **HashMap.hash()** )

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1624241432217/3Q4U6tjQ6.png)

Như trong trường hợp của mình, tại dòng **#1413**, method này gọi tới **HashMap.hash(). **Set breakpoint tại điểm này để xem các giá trị biến local của method trước khi nhảy vào **hash(), **sử dụng tổ hợp phím `**Ctrl + F8` **để đặt breakpoint tại dòng này.

Bắt đầu debug mode bằng cách click vào hình con bọ hoặc dùng tổ hợp `**Shift + F9`**:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1624241433751/678s_IxmM.png)

Nếu bạn chưa chạy file test lần nào thì chuyển tab sang file cần chạy, chuột phải vào bất cứ đâu trong editor và chọn `**Debug ...`**

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1624241435317/rXIOxgX6q.png)

Debugger dừng tại breakpoint đã đặt trước trong **HashMap.readObject()**, khi đó màn hình debugger sẽ có dạng như thế này:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1624241437208/JLLVIqR3e.png)

* **Project File:** là cửa sổ show ra các source file java, khi chạy các file java trong IntellIJ sẽ lấy working directory tại đây luôn.

* **Project ‘s Library: **hiển thị các library có trong classpath của project

* **Stack Trace: **cửa sổ này hiển thị ra backtrace, hay còn được hiểu là show ra các method đã gọi tới method hiện tại.

* **Local Variable: **đây là một điểm mạnh mà mình rất thích ở IntellIJ. Khi debug, IntellIJ sẽ cố gắng lấy hết giá trị các biến để show ra cửa sổ này, giúp cho việc debug được dễ dàng hơn, nhưng đôi khi nó lại gây ra những sai sót và hiểu lầm cho người dùng (mình sẽ nói chi tiết ở phía dưới).

Ngoài ra, trong cửa sổ editor, ngay bên cạnh các dòng code cũng có show giá trị của các biến rất trực quan.

Tiếp tục với việc debug, bấm **F7 **để đi vào **HashMap.hash()**

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1624241439055/wQuOvejx9.png)

Lúc này IDE cho ta nhiều lựa chọn, là muốn đi vào **putVal() **hoặc đi vào **hash(). **Lựa chọn bằng cách đơn giản là click chuột vào 1 trong 2 method. Tại dòng **1413, **từ method **readObject()** gọi tới method **hash() **và có truyền vào biến *key, *giá trị của key chính là URL Object của target mình cần resolve DNS:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1624241440876/fpou7bkxa.png)

Đoạn code xử lý bên trong method **hash() **như sau:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1624241442421/bZ4lEYr4p.png)

Tại đây, method này gọi tới method **hashCode() **của object *key *vừa được truyền vào. Như trong trường hợp này, chính là gọi tới **URL.hashCode().**

***Fact:** Do nó nằm ngay trong runtime library của java và rất dễ control cho nên đây là 1 trong những source chain bị lợi dụng rất nhiều để viết các gadgetchain có call tới **&lt;Object&gt;.hashCode()***

Tiếp tục **F7 **để đi vào **URL.hashCode():**

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1624241444100/h8Dc-cnvh.png)

Method **hashCode() **của class **URL **thực hiện kiểm tra xem có hashCode nào được cache không, nếu có bị cache rồi thì sẽ không đi tiếp nữa, mà trả về giá trị luôn. Do vậy, để chain hoạt động được thì giá trị **hashCode **này phải = -1.

*! Có lẽ hơi phi logic theo luồng văn hiện tại, nhưng là cần thiết nên mình sẽ nói qua về cách sử dụng Reflection API một chút. Chi tiết hơn nữa sẽ nằm trong loạt bài viết về cách xây dựng gadgetchain.*

*********

Ở trường hợp này, **hashCode **được khai báo là 1 private field của class **URL.**

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1624241445706/qnl7Q_bSu.png)

Để set được giá trị của 1 private field trong java, ta cần sử dụng tới Reflection API. Dưới đây là đoạn code nhỏ mình dựng lại cái URLDNS chain này:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1624241447411/ZQUXiMwdM.png)

Trong đó object ***u ***là URL object, ***ht ***là **HashMap **object.

Sau khi **put **URL object vào **ht**, **HashMap **sẽ thay đổi field **hashCode **của URL object thành giá trị mới “*!= -1*”. Nếu cứ tiếp tục và không sửa giá trị này, khi deserialize, chương trình sẽ trả về giá trị *hashCode *luôn, không đi theo nhánh mà ta mong muốn ban đầu.

Ngay sau dòng **ht.put() **là

```
Field f1 = URL.class.getDeclaredField("hashCode");
```


Đoạn này được sử dụng để lấy field **hashCode **từ class URL, cách sử dụng Reflection Field này rất đơn giản:

```
Field f1 = <Some Class>.getDeclaredField(<Field Name>);
```


Với &lt;Some Class&gt; có thể là **URL.class **hoặc gián tiếp **Class.forName(“java.net.URL”) **(cần lưu ý nếu sử dụng chính tên class đó thì phải có **.class **nữa).

Field **hashCode **được khai báo với dạng private, ta không thể thao tác trực tiếp ngay với nó được, mà phải **setAccessible() **trước:

```
f1.setAccessible(true);
```


Như vậy là field này đã có thể được set giá trị dù nó được khai báo là private.

Cú pháp sử dụng để set giá trị:

```
f1.set(u, -1);
```


* **f1 **là field **hashCode **của class **URL**

* **u **là **OBJECT **của class **URL**

* **-1** là giá trị cần set

Vậy là xong, private field **hashCode **của object **u **đã được set = -1.

***********

Quay trở lại với việc debug, ta đang dừng lại tại việc set **hashCode **= -1.

Chương trình chạy tiếp tục, **URL.hashCode() **gọi tới **handler.hashCode()**

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1624241448988/shoh-xlNH.png)

Field **handler **này là object của 1 class nào đó, ta cần kiểm tra nơi nào khai báo nó bằng cách dùng tổ hợp `**Ctrl + B`** để nhảy tới:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1624241450545/8IS38AEfO.png)

**handler **là 1 transient field, là object của **URLStreamHandler.**

*! Đặc điểm của transient field này là khi serialize, nó không được serialize cùng object!*

Tiếp tục **F7 **để nhảy vào **handler.hashCode() **hay cách khác chính là nhảy vào **URLStreamHandler.hashCode():**

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1624241452142/6_UMtRtUk.png)

Method này gọi tới **URLStreamHandler.getHostAddress() **với **URL **object ban đầu.

Nội dung của method này như sau:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1624241453840/lTyccmNKW.png)

Với **InetAddress.getByName() **chính là method thực hiện resolve dns với domain ta truyền vào.

Đây cũng được chính là sink của gadgetchain này.

____________

Vậy là mình đã giới thiệu sơ qua về 1 số khái niệm cơ bản về gadgetchain, cách sử dụng IntellIJ cũng như debug gadgetchain **URLDNS **từng bước.

Phần 1 của loạt bài sẽ dừng lại tại đây, trong phần 2 mình sẽ tiếp tục phân tích về 1 số gadgetchain khác trong bộ ysoserial.

Sau khi đã đầy đủ kiến thức mình sẽ chia sẻ tiếp về 1 số 0day gần đây mình có tìm được liên quan tới các loại gadgetchain này.

Cảm ơn các bạn đã đọc đến đây.

__Jang__
