不求甚解之考古某企业数字化平台
2024-6-27 17:12:13 Author: www.freebuf.com(查看原文) 阅读量:3 收藏

这是一篇拖更一年的文章。生活所迫 懒驴拉磨。去年实战遇到该系统,由于这套系统大多数据通信方式都是采用了Java的序列化数据传输,所以就导致了关于它的反序列化漏洞层出不穷,这次我们要考古的是一个另类的反序列化利用,一波三折,折了又折。

首先看一个熟悉的反序列化漏洞的利用接口:

/servlet/~aert/com.ufida.zior.console.ActionHandlerServlet

代码位置:

image-20240523154456835.png

代码处会将传入的数据流进行GZIP的解码然后调用readObject方法进行反序列化,经典的反序列化漏洞。但是这个位置很早就被披露出来并且当时目标已经修复该漏洞。

顺着这个接口往下看,会注意到一个关于ActionExecutor.exec()这个方法的调用

image-20240523154932484.png

跟进去大概看了一下关于exec方法的代码,有关于反射调用的动作。

image-20240523161723786.png

image-20240523155106232.png

上面invoke方法所需要的 类、方法、参数、都是我们传参可控的。

参数对应如下:

String 类型的msg 对应的就是actionName也就是类名

String 类型的methodName 对应的是 methodName 方法名

Object 类型的paramter 对应的是 paramter 参数对象

image-20240523161632712.png

我们本地构造的时候同样需要按照反序列化的顺序进行序列化,也就是:

oos.writeObject(msg);
        oos.writeObject(methodName);
        oos.writeObject(parameter);
        oos.writeObject(currentLanguage);
        oos.writeObject(logModule);

当我们传入的类名和方法名不为空的时候就会实例化我们传入的类对象。

image-20240523162542465.png

这里会判断我们传入的paramter是否为数组类型 ,最后会和类名 方法名 参数数量拼接存到map_method这个map中,然后通过这个key去map中取

image-20240523162712961.png

这里有个问题就是,如果ActionExecutor.exec从来没有调用过,那么map_method就是空的,这里可以看到他是一个静态属性

image-20240523163045989.png

那么这里m一定是null的

image-20240523163307247.png

如果方法没有在map中,进入if判断,如果pararmter是数组类型的就会动态赋值给paramClzs,获取方法对应参数类型数组,如果paramter不是数组类型的会直接获取到一个参数类型为Object.class的方法,由于Java特性,也就会导致乱调用,只要是参数数量为 1 的方法都有可能被调用然后存到method_map这个静态map中。恰巧这个map中的key存的是类名+方法名+方法参数数量.

这里假设 A类有两个方法exec(String string),另一个方法exec(int int),那么此时我们如果传入的paramter参数不是数组类型的,就有可能调用两个方法的任意一个,这就有点看运气了,由于反射调用之前会在method_map中查找对应的方法,所以一个类中同名方法且参数数量相同只能加载一个。

image-20240523163651615.png

如果获取不到我们传入的方法就会遍历我们传入类对象所有的方法,直到找到为止,否则抛出异常

image-20240523164946657.png

如果我们传入的方法可以被正确找到就会put 到上面提到的map_method这个静态的map中

image-20240523165105572.png

此时m方法不为null,就会来到后面的 if 判断,如果这个方法是有参的就会调用if里面的有参方法,反之就会调用无参的方法

image-20240523165316021.png

到这里调用链就分析结束了

结合上面的分析我们在构造payload的时候需要注意,我们需要一个类中存在可以RCE的方法,并且该方法不能有同名如果同名参数数量不能为1的情况

在这套系统的源码中找到freemarker.template.utility.Execute这个类的exec方法传入的参数是一个,正好满足我们前面的条件要求。

image-20240523170952009.png

POC测试效果如下:

image-20240523171140747.png

其实直到上一步可以调用到Runtime.exec执行命令就可以了,但是实战环境情况比较复杂。

一种是延续这种利用方式,命令执行写文件落地JSP到Web目录,这个漏洞会默认把文件落地到网站根目录可以直接解析JSP问题不大。但是如果不知道文件落地位置和Web的绝对路径,再或者目标机器不出网+杀毒软件&RASP拦截命令执行函数,这种利用方式就捉襟见肘了

恰巧作者在项目中就遇到一个杀软拦截命令执行函数,机器还不出网的环境,exec这个函数就满足不了了。

回头重新看代码发现问题所在点

image-20240523193547178.png

之所以出现一个类中同数量参数的方法乱调用的问题是来自于这里Class[] paramClzs = new Class[]{Object.class},如果我们可以控制paramter的数组类型,我们就可以控制方法的参数类型。介于上面杀毒软件&RASP会拦截命令执行函数的问题,这次选择代码执行的函数。

这套系统恰好存在bsh,直接调用bsh.Interpretereval方法执行JS代码。但是存在两个不同参数类型的eval,如果直接把paramter设置为String类型,最后可能会加载到参数为Reader的方法。

image-20240523203950144.png

先利用String数组将参数为String 的eval方法存到method_map中,然后第二个包正常将paramter设置String类型即可,如果不想这么麻烦的话,可以直接加载String类型的参数,万一调用到Reader参数的eval方法可以直接把paramter换成new StringReader("xxxxx")以下是测试加载回显。

image-20240523200646799.png

image-20240523200608627.png

作者:Ha1ey@深蓝攻防实验室


文章来源: https://www.freebuf.com/articles/web/404677.html
如有侵权请联系:admin#unsafe.sh