# 通达OA任意文件上传分析

**URL:** <https://forum.90sec.com/t/topic/883>\
**Category:** 代码审计\
**Created:** [2020 年3 月 17 日 14:19 UTC](https://forum.90sec.com/t/topic/883 "2020-03-17T14:19:57Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

作者： ![l1nk3r](https://forum.90sec.com/user_avatar/forum.90sec.com/l1nk3r/32/1212_2.png) [@l1nk3r](https://forum.90sec.com/u/l1nk3r)\
发布日期： [2020 年3 月 17 日 14:19 UTC](https://forum.90sec.com/t/topic/883/1 "2020-03-17T14:19:57Z")

</div>

## 0x01 概述

该漏洞被黑产利用，用于投放勒索病毒，根据厂商补丁，进行相关漏洞分析工作，原理很简单。

## 0x02 漏洞分析

### 任意文件上传

在厂商补丁的其他版本中出现了`ispirit/im/upload.php`这个路径，跟进来一看实际上是一个很明显的文件上传漏洞，而且是未授权的文件上传，分段来看一下代码。

先看未授权部分，P不为空的情况下，包含`inc/session.php`，并且通过 **session\_id** 注册 **session** ，P可通过 **POST['P']** ，因此不多赘述。

```php
$P = $_POST["P"];
if (isset($P) || ($P != "")) {
	ob_start();
	include_once "inc/session.php";
	session_id($P);
	session_start();
	session_write_close();
}

```

再看下面这一小段，假设 **DEST\_UID** 为空的情况下，会直接返回`接收方ID无效`相关信息，并且退出，因此这里的处理方式也很简单， **DEST\_UID** 可通过 **POST["DEST\_UID"]** 搞定，这里也不多赘述了。

```php
$DEST_UID = $_POST["DEST_UID"];
$dataBack = array();
if (($DEST_UID != "") && !td_verify_ids($ids)) {
	$dataBack = array("status" => 0, "content" => "-ERR " . _("接收方ID无效"));
	echo json_encode(data2utf8($dataBack));
	exit();
}

```

再往下走，当`$_FILES`全局变量大于等于1的时候，简单理解就是有文件上传的时候，会调用 **upload** 函数进行处理，这里的文件上传的 **name** 为`name="ATTACHMENT"`

```php
if (1 <= count($_FILES)) {
	if ($UPLOAD_MODE == "1") {
		if (strlen(urldecode($_FILES["ATTACHMENT"]["name"])) != strlen($_FILES["ATTACHMENT"]["name"])) {
			$_FILES["ATTACHMENT"]["name"] = urldecode($_FILES["ATTACHMENT"]["name"]);
		}
	}

	$ATTACHMENTS = upload("ATTACHMENT", $MODULE, false);

```

跟进 **upload** 方法，可以很明显看到 **is\_uploadable** 这个方法针对上传的文件名进行判断。

```php
function upload($PREFIX, $MODULE, $OUTPUT)
{
	if (strstr($MODULE, "/") || strstr($MODULE, "\\")) {
		if (!$OUTPUT) {
			return _("参数含有非法字符。");
		}

		Message(_("错误"), _("参数含有非法字符。"));
		exit();
	}
  ...
		if ($ATTACH_ERROR == UPLOAD_ERR_OK) {
			if (!is_uploadable($ATTACH_NAME)) {
				$ERROR_DESC = sprintf(_("禁止上传后缀名为[%s]的文件"), substr($ATTACH_NAME, strrpos($ATTACH_NAME, ".") + 1));
			}

```

很明显存在一个后缀名非法的判断，所以这点并不能直接上传PHP文件。

```php
function is_uploadable($FILE_NAME)
{
	$POS = strrpos($FILE_NAME, ".");

	if ($POS === false) {
		$EXT_NAME = $FILE_NAME;
	}
	else {
		if (strtolower(substr($FILE_NAME, $POS + 1, 3)) == "php") {
			return false;
		}

```

继续往下走，因为上传不回显的话，搞定了也没啥用，还得猜文件名麻烦，找到了一个回显的地方。

```php
if ($UPLOAD_MODE == "1") {
...
	if ($MSG_CATE == "file") {
		$CONTENT = "[fm]" . $ATTACHMENT_ID . "|" . $ATTACHMENT_NAME . "|" . $FILE_SIZE . "[/fm]";
	}
	else if ($MSG_CATE == "image") {
		$CONTENT = "[im]" . $ATTACHMENT_ID . "|" . $ATTACHMENT_NAME . "|" . $FILE_SIZE . "[/im]";
	}
	else {
		$DURATION = intval($DURATION);
		$CONTENT = "[vm]" . $ATTACHMENT_ID . "|" . $ATTACHMENT_NAME . "|" . $DURATION . "[/vm]";
	}
  ...
$dataBack = array("status" => 1, "content" => $CONTENT, "file_id" => $FILE_ID);
	echo json_encode(data2utf8($dataBack));

```

构造 **poc** 上传之后，这里可以看到`1436405170|shell.jpg`这个内容，那么它对应的文件名是`1436405170.shell.jpg`

 ![image](https://forum.90sec.com/uploads/default/original/2X/3/318829153ef112157952f689e41617195c6bc9aa.png)

然后尴尬的事情发生了，上传的文件即使不能是PHP也不在web目录下，它的路径是`/attach/im/2003/filename`。

 ![image](https://forum.90sec.com/uploads/default/original/2X/8/8dc5aab2d14e59ac7502cc90d2b1f5d4d65a0b16.jpeg)

### 文件包含

也就是说上面的漏洞要达到RCE的目的，还需要一个文件包含，包含点从补丁上找找，是这个`ispirit/interface/gateway.php`。

简单分析一下，解析一个循环解析`$json`，假设`$key`是 **url** 的情况下，它的值会丢给`$url`，之后会调用 **include\_once** 针对这个进行包含了。

```php
if ($json) {
	$json = stripcslashes($json);
	$json = (array) json_decode($json);

	foreach ($json as $key => $val ) {
		if ($key == "data") {
			$val = (array) $val;

			foreach ($val as $keys => $value ) {
				$keys = $value;
			}
		}

		if ($key == "url") {
			$url = $val;
		}
	}

	if ($url != "") {
		if (substr($url, 0, 1) == "/") {
			$url = substr($url, 1);
		}

		if ((strpos($url, "general/") !== false) || (strpos($url, "ispirit/") !== false) || (strpos($url, "module/") !== false)) {
			include_once $url;
		}
	}

```

所以从代码来看非常的简单，简单提一嘴，这套代码有 **disable\_function** 的限制，需要bypass一下，整个过程非常的简单。

 ![image](https://forum.90sec.com/uploads/default/original/2X/b/b8c3a55d0fb618a61e5e60c57e7e7cf353650efc.jpeg)

## 0x03 漏洞修复

修复的话，到[这里](http://www.tongda2000.com/news/673.php)下补丁就好了，这套系统漏洞贼多，有兴趣的可以看看，代码是PHP zend 5.4加密的，百度一下就能解开了。

---

<div class="post-metadata">

作者： ![1054397776](https://forum.90sec.com/letter_avatar_proxy/v4/letter/1/0ea827/32.png) [@1054397776](https://forum.90sec.com/u/1054397776)\
发布日期： [2020 年3 月 17 日 15:44 UTC](https://forum.90sec.com/t/topic/883/3 "2020-03-17T15:44:55Z")

</div>

大佬，有2015的源码下载地址不，小弟也想分析分析。

---

<div class="post-metadata">

作者： ![l1nk3r](https://forum.90sec.com/user_avatar/forum.90sec.com/l1nk3r/32/1212_2.png) [@l1nk3r](https://forum.90sec.com/u/l1nk3r)\
发布日期： [2020 年3 月 18 日 01:53 UTC](https://forum.90sec.com/t/topic/883/4 "2020-03-18T01:53:34Z")

</div>

[下载地址](https://www.tongda2000.com/download/2015.php)  
直接安装就好了，环境是集成的环境，安装之后，webroot就是源代码，使用的是zend 5.4加密的，解密就好了。

---

<div class="post-metadata">

作者： ![zhhyuu](https://forum.90sec.com/letter_avatar_proxy/v4/letter/z/c2a13f/32.png) [@zhhyuu](https://forum.90sec.com/u/zhhyuu)\
发布日期： [2020 年3 月 18 日 02:47 UTC](https://forum.90sec.com/t/topic/883/5 "2020-03-18T02:47:42Z")

</div>

~下载源码安装后没有ispirit/interface/gateway.php这个文件。。

---

<div class="post-metadata">

作者： ![guobaoyou](https://forum.90sec.com/letter_avatar_proxy/v4/letter/g/5daacb/32.png) [@guobaoyou](https://forum.90sec.com/u/guobaoyou)\
发布日期： [2020 年3 月 18 日 03:23 UTC](https://forum.90sec.com/t/topic/883/6 "2020-03-18T03:23:18Z")

</div>

看了通达的补丁，带文件包含ispirit/interface/gateway.php的只有11版本的，是只有一个版本由文件包含吗？

---

<div class="post-metadata">

作者： ![Mstir](https://forum.90sec.com/letter_avatar_proxy/v4/letter/m/41988e/32.png) [@Mstir](https://forum.90sec.com/u/Mstir)\
发布日期： [2020 年3 月 18 日 03:26 UTC](https://forum.90sec.com/t/topic/883/7 "2020-03-18T03:26:41Z")

</div>

2015版本能上传文件，但是没有 ispirit/interface/gateway.php 这个文件

---

<div class="post-metadata">

作者： ![l1nk3r](https://forum.90sec.com/user_avatar/forum.90sec.com/l1nk3r/32/1212_2.png) [@l1nk3r](https://forum.90sec.com/u/l1nk3r)\
发布日期： [2020 年3 月 18 日 03:45 UTC](https://forum.90sec.com/t/topic/883/8 "2020-03-18T03:45:36Z")

</div>

有些之前的文件包含没修复的可以一起用。

---

<div class="post-metadata">

作者： ![l1nk3r](https://forum.90sec.com/user_avatar/forum.90sec.com/l1nk3r/32/1212_2.png) [@l1nk3r](https://forum.90sec.com/u/l1nk3r)\
发布日期： [2020 年3 月 18 日 03:45 UTC](https://forum.90sec.com/t/topic/883/9 "2020-03-18T03:45:59Z")

</div>

上传是个插件，应该是全版本通杀，还需要找个包含

---

<div class="post-metadata">

作者： ![securitycn](https://forum.90sec.com/letter_avatar_proxy/v4/letter/s/f1d935/32.png) [@securitycn](https://forum.90sec.com/u/securitycn)\
发布日期： [2020 年3 月 18 日 07:50 UTC](https://forum.90sec.com/t/topic/883/10 "2020-03-18T07:50:12Z")

</div>

只有v11 才有gateway.php 文件

---

<div class="post-metadata">

作者： ![cdz](https://forum.90sec.com/user_avatar/forum.90sec.com/cdz/32/80_2.png) [@cdz](https://forum.90sec.com/u/cdz)\
发布日期： [2020 年3 月 18 日 08:25 UTC](https://forum.90sec.com/t/topic/883/12 "2020-03-18T08:25:52Z")

</div>

有些版本在mac目录下

---

<div class="post-metadata">

作者： ![jiushi](https://forum.90sec.com/letter_avatar_proxy/v4/letter/j/898d66/32.png) [@jiushi](https://forum.90sec.com/u/jiushi)\
发布日期： [2020 年3 月 20 日 09:39 UTC](https://forum.90sec.com/t/topic/883/13 "2020-03-20T09:39:24Z")

</div>

有些版本路径不同
