某OA业务逻辑缺陷导致RCE的利用链解析

一、前言 随着网络安全攻防演练活动的推进,国内许多厂商产品的安全性越来越高,传统的漏洞挖掘思路已经不太容易能挖到漏洞了,许多时候需要分析代码的业务逻辑,将多个业务逻辑组合起来形成一个完整的漏洞利用。本篇文章将以抛砖引玉的方式,用笔者之前挖到的一个漏洞(已修复)为例,分享在漏洞挖掘方面的一些思路以及Trick。 该漏洞由三部分组成:特别的任意文件上传、身份认证绕过、RASP绕过及jsp访问拦截绕过。通过该漏洞可以在目标服务器达成远程代码执行的目的。 二、特别的任意文件上传 该漏洞就是由于系统中对上传文件格式以及跨目录做了严格的限制,直接找不到任意文件上传漏洞,但是通过两部分业务逻辑组合可以达成任意文件上传的目的。分为如下两个步骤: 2.1 上传文件并在数据库中记录 某认证后jersey类型的web接口会执行到如下代码,从this.params中获取两个值后调用loadFileForImage方法,此处的this.params中存储的是http请求包中的参数,所以用户完全可控。 loadFileForImage方法调用ImageConvertUtil#downloadUrl方法获取输入流后赋值给var8的data属性,var2赋值给ImagFileName属性,分别表示文件输入流和文件名,然后调用saveImageFile方法。 download方法根据用户提供的url直接获取输入流并返回,此处其实也存在一个ssrf漏洞。 saveImageFile方法关键代码主要有2部分逻辑,第一部分是调用ZipOutputStream.write方法将this.data(前边获取的文件输入流)写入zip文件。由于默认var6为 1,所以文件名是.zip结尾的,因此文件写入时文件名不可控。 第二部分逻辑是在zip文件写入完成后执行一段insert sql语句将这次文件写入操作记录在数据中。数据库中imageFileId字段表示当前操作的数字编号,imageFileName字段是前面设置的imagFileName属性用户可控,fileRealPath是zip文件绝对路径。 2.2 查数据库写文件 另一个认证后的jersey类型的web接口会调用到如下代码,该方法中new 一个ImageFileManager 对象var8,先调用getImageFileInfoById方法,再调用ImageFileManager#getInputStream获取其输入流后用FileOutputStream#write方法写入目标文件中,目标文件名是通过和var8.getImageFileName()拼接而成的。所以要是能控制var8的输入流和imageFileName属性就可以写入任意文件。而ImageFileManager 构造方法中所有并未给其属性赋值,所以赋值的过程一定在getImageFileInfoById方法中,方法参数var34是用户可控的。 getImageFileInfoById中根据imagefileid查数据库将值赋值给对应的属性,因为插入数据库的时候realname字段没写入值所以还是会获取imageFileName。 再看 getInputStream方法,获取fileRealPath路径的文件输入流并返回,关键代码如下: 2.3 小结 上传文件并在数据库中记录这一步骤可根据用户指定url获取输入流以zip形式保存在服务器上,并在数据库中保存文件相关信息包括用户指定的ImageFileName、zip文件的绝对路径等,最后返回imagefileid值。 查数据库写文件这一步骤根据用户输入的imagefileid值,将对应zip文件内容写入新文件中,新文件名是和ImageFileName值拼接而成。 以上两步结合就可以实现任意文件上传。 系统给所有jersey类型的web接口配置了filter去做身份认证,那么如何绕过身份认证呢?以下提供一种绕过的思路。 三、身份认证绕过 该身份认证绕过是利用invoker servlet的特性完成的。 3.1 invoker servlet简介及特性 invoker servlet是resin、tomcat等提供的功能,可以通过 URL 动态调用classpath中的任意servlet,甚至系统中没配置的servlet在都可以被调用。以下是resin官方文档中的描述。 invoker servlet一般是在resin如下xml配置文件配置 WEB-INF/resin-web.xml $RESIN_HOME/conf/app-default.xml $RESIN_HOME/conf/resin.xml ...... 以下是WEB-INF/resin-web.xml配置invoker servlet的例子 <web-app xmlns="http://caucho.com/ns/resin"> <!-- used with urls like http://localhost:8080/servlets/test.HelloServlet --> <servlet-mapping url-pattern="/servlet/*" servlet-name="invoker"/> </web-app> 以下是 $RESIN_HOME/conf/app-default.xml配置invoker servlet的例子 <cluster> <web-app-default> <servlet-mapping url-pattern="*.jsp" servlet-name="jsp"/> <servlet-mapping url-pattern="*.xtp" servlet-name="xtp"/> <servlet-mapping url-pattern="/servlet/*" servlet-name="invoker"/> <servlet-mapping url-pattern="/" servlet-name="file"/> </web-app-default> </cluster> tomcat7开始默认是不开启invoker servlet的。一般是在$TOMCAT_HOME/conf/web....

2024年06月05日 · 4 分钟 · mmuz