通达OA前台任意用户登录分析

2020-05-09 约 229 字 预计阅读 2 分钟

声明:本文 【通达OA前台任意用户登录分析】 由作者 这是一个睿智 于 2020-05-09 09:04:11 首发 先知社区 曾经 浏览数 125 次

感谢 这是一个睿智 的辛苦付出!

最近爆了个通达 OA 任意用户登录漏洞,正好分析分析,顺便师傅一起学习。

漏洞分析

第一处

首先我们找到文件根目录的文件 logincheck_code.php,这个文件是没有权限验证的。

我们会发现在 180 行附近有两行代码:

$LOGIN_UID = $UID;
$LOGIN_USER_ID = $USER_ID;
...
$_SESSION["LOGIN_UID"] = $LOGIN_UID;
$_SESSION["LOGIN_USER_ID"] = $LOGIN_USER_ID;

验证登录时就是判断的这两个 SESSION

往上翻翻 $UID 哪来的:

可以发现是直接从 $_POST 中获取的,也就是任意控制即可。

但是 15 行附近有个判断,如果缓存里没有 CODE_LOGIN.$CODEUID$CODEUID 也是可以任意控制的) 就退出程序了,我们可以全局搜索一下这个缓存在哪里设置了。

很快找到一处: ispirit\login_code.php

<?php

include_once "inc/utility_all.php";
include_once "inc/utility_cache.php";
include_once "inc/phpqrcode.php";
$codeuid = $_GET["codeuid"];
$login_codeuid = TD::get_cache("CODE_LOGIN_PC" . $codeuid);

if (empty($login_codeuid)) {
    // 给 codeuid 设置个随机值
    $login_codeuid = getUniqid();
}

$databack = array("codeuid" => $login_codeuid, "source" => "pc", "codetime" => time());
$dataStr = td_authcode(json_encode($databack), "ENCODE");
$dataStr = "LOGIN_CODE" . $dataStr;
$databacks = array("codeuid" => $login_codeuid, "authcode" => $dataStr);

//将 codeuid 存入缓存
TD::set_cache("CODE_LOGIN_PC" . $login_codeuid, $login_codeuid, 120);

//输出 codeuid
echo json_encode(td_iconv($databacks, MYOA_CHARSET, "utf-8"));
echo "\r\n\r\n\r\n";

?>

这里给重要的三句话写了注释。我们只要直接访问一次这个文件就可以伪造了。

复现测试

首先访问一次 /ispirit/login_code.php

存下这个 codeuid。然后访问 /logincheck_code.php

UID 设置成 1,这个 ID 默认是管理员。然后 CODEUID 设置成: _PC+codeuid

随便访问个需要验证的 url/pda/main.php

第二处任意登录

一样的思路,我们全局搜索会找到在文件 \ispirit\login_code_check.php 处有类似的代码:

我们往上翻:

会发现 $UID 来自 $code_info$code_info 又来自缓存 CODE_INFO_PC+$login_codeuid

这里的 $code_info[type] 需要等于 confirm.

再上面一点有这样的代码:

//$codeuid 可控
$login_codeuid = TD::get_cache("CODE_LOGIN_PC" . $codeuid);

这里和之前一样得。

然后我找找哪里有设置 CODE_INFO_PC 的代码,在文件 general\login_code_scan.php

可以发现这里的 codeuidtype 都是可控的。现在就可以利用了。

漏洞复现

  1. 首先访问 /ispirit/login_code.php 获取 codeuid
  2. 访问 /general/login_code_scan.php 提交 post 参数:

source=pc&type=confirm&codeuid={5D9B864F-07AD-519C-13D1-E573E226302A}&uid=1&

  1. 最后访问 /ispirit/login_code_check.php?codeuid=xxx

这样 $_SESSION 里就有了登录的信息了。

补丁分析

第一处修复 logincheck_code.php

这里从 redis 中获取了数据,判断了 $UID 不等于 0 的话才能下一步,相当于做了个权限验证吧。

如果我们能找到一处设置 OA:authcode:token:XXX 的地方,或者找到一处可以控制键值的缓存,即可绕过。

第二处修复 \general\login_code_scan.php

在设置 CODE_INFO_PC前进行了权限验证,这里根据传入的 session 查询此 session 是否登陆过,如果没登陆过就退出程序

思考及总结

这个漏洞其实挺简单的,但是到现在才发现,看来挖掘这样的洞更需要一些耐心和细心。由于这个程序用了全局覆盖,我们可以直接覆盖 _SESSION 里的数据,但是 _SESSION 是存在 redis 中的。所以如果有一处先开启 session_start 然后引入了 session.php 文件,即可直接覆盖 _SESSION 里的数据。

关键词:[‘安全技术’, ‘漏洞分析’]


author

旭达网络

旭达网络技术博客,曾记录各种技术问题,一贴搞定.
本文采用知识共享署名 4.0 国际许可协议进行许可。

We notice you're using an adblocker. If you like our webite please keep us running by whitelisting this site in your ad blocker. We’re serving quality, related ads only. Thank you!

I've whitelisted your website.

Not now