通达OA任意文件上传/文件包含RCE漏洞分析
通达OA任意文件上传/文件包含RCE漏洞分析
0x01 前提
关于这个漏洞的利用方式:
利用方式大致有两种:
- 包含日志文件。
- 绕过身份验证文件上传然后在文件包含。
下面主要分析第二种
0x01 漏洞介绍
_通达OA_系统代表了协同OA的先进理念,16年研发铸就成熟OA产品,协同OA软件行业唯一央企团队研发,多次摘取国内OA软件金奖,拥有2万多家正式用户,8万多家免费版用户,超过…
主要危害:
攻击者可以在为登陆或者说,无任何条件触发漏洞,上传图片木马文件,请求进行文件包含最终可达成远程命令执行
影响版本:
- V11版
- 2017版
- 2016版
- 2015版
- 2013版
- 2013增强版
0x02 漏洞分析
我用的官网下载的V11.3
利用方式大致有两种:
- 包含日志文件。
- 绕过身份验证文件上传然后在文件包含。
下面我主要分析饶过权限上传,然后文件包含的方式:
首先下载安装
打开源码一看,都加密了,使用zend进行了加密。
所以先要进行解密,百度即可。
绕过身份验证文件上传部分
存在漏洞的上传功能文件为 webroot\ispirit\im\upload.php
解密后的源码
1 |
|
看下开头这一块,就是绕过的核心部分
1 | set_time_limit(0); |
- 这里获取了一个P,如果P存在或者不为空,就要包含上面的auth.php,看名字就知道是一个主要实现身份认证功能,所以通过这里的参数”P”绕过登录认证,就可以去下面的上传了
- 在往后就是两个IF条件句,只要进去了都要exit退出,所以要绕过才能进入上传的逻辑里面
1 | $DEST_UID = $_POST['DEST_UID']; |
- 进入循环后使用PHP的 $_FILES 函数来获取我们上传的文件信息
1 | $_FILES['ATTACHMENT']['name'] |
- 第一个下标必须是我们的input name值,因此我们的POST包的Content-Disposition: form-data; name=“ATTACHMENT”; filename=”xxx.php.png”中的name必须是’ATTACHMENT’。
- 也就是有文件上传就会调用upload函数
- 后续对获取的文件名处理了一下,对获取的文件名行一次url解码,对比文件名长度是否有变化,如果有变化,则将url解码后的文件名作为最后的文件名
- 在45行有upload函数,要跟进看一下干了什么,inc/utility_file.php的1321行
1 | $ATTACHMENTS = upload('ATTACHMENT', $MODULE, false); |
函数具体代码如下:
1 | function upload($PREFIX = 'ATTACHMENT', $MODULE = '', $OUTPUT = true) |
- 看下is_uploadable()函数对文件名进行检查,跟进到该函数,同样位于inc/utility_file.php
- 这个仔细看一下,代码意思是查找 “.” 在文件名中最后一次出现的位置然后
1 | strtolower(substr($FILE_NAME, $POS + 1, 3)) == 'php' |
- 这是 substr( 文件名,最后一次点的位置+1,3个位置)
- 从存在 ”.“ 开始匹配3位,判断后缀是否为php,,如果为php则返回false,否则将”.”之前的作为EXT_NAME。
- 这么判断 .php肯定是不行了,只能是 shell.php. 或者 shell.php.png
- 那么只能是配合文件包含漏洞了
变量传递问题
由于在upload.php中UPLOAD_MODE值的是一个重要的流程走向的判断
但是并没有发现是从哪来的,所以一直很疑惑,
但根据payload中POST的UPLOAD_MODE值可以被正常带入且影响文件上传走向
预测 UPLOAD_MODE值的方法存在于被包含的文件中,
但是UPLOAD_MODE这个参数名仅存在于upload.php中
开始追溯,发现下面的路径
具体调用为upload.php -> session.php -> coon.php -> td_config.php -> common.inc.php
关键部分
1 | if (0 < count($_POST)) { |
- 首先一开始对 P O S T 长 度 进 行 了 判 断 , 这 里 _POST长度进行了判断,这里 POST长度进行了判断,这里_POST实际是一个数组,接着使用foreach函数对数组进行遍历,
- 在这里$_POST数组中key为”UPLOAD_MODE”,value为”2”,那么根据配会到
1 | if (substr($s_key, 0, 15) != 'TD_HTML_EDITOR_') { |
最终数组键名UPLOAD_MODE成了了变量名,而他的对应键值成为了变量值
所以 upload.php 未直接接收UPLOAD_MODE值,而我们仍可以传递到这里
upload函数的中 调用 add_attach函数,设置$ATTACHMENTS[‘ID’]
- 再往后 继续跟进函数add_attach,函数同样位于inc/utility_file.php文件下
- 找到了保存路径的方式
1 | function add_attach($SOURCE_FILE, $ATTACH_NAME, $MODULE, $YM, $ATTACH_SIGN, $ATTACH_ID) |
可以看到返回值 A T T A C H I D N E W 有 三 部 分 组 成 ATTACH_ID_NEW有三部分组成 ATTACHIDNEW有三部分组成AID, Y M , YM, YM,ATTACH_ID
其实UPLOAD_MODE值随便为1,2,3中的任意一个数字,都可以返回文件名字和部分路径,不看也行
文件包含部分
- 这个比较简单
- 文件包含功能的文件位于webroot\ispirit\interface\gateway.php
- 具体代码如下:
1 | <?php |
这里的参数也是,POST直接传入就可以了,分析在上面也有主要是有这两个个就可以
```
include_once ‘inc/session.php’;
include_once ‘inc/conn.php’;1
2
3
4
5
6
7
8
9
10
11
12- 逻辑较为简单,
- 如果这里不传递参数P为空,就以绕过前面一系列的检测直
- 随后从json中获取url参数的值
- 只有 general/、ispirit/、module/ 在url内,在直接包含 \$url,
- 文件包含结束
构造一个就好了/ispirit/interface/gateway.php?json={“url”:”/general/../../attach/im/2003/1153189608.jpg”}
```
0x03 修复方案
- 更新官方发布的补丁 http://www.tongda2000.com/news/673.php