Post

Terramaster Tos Information Leakage Vulnerability Cve 2022 24990

Terramaster Tos Information Leakage Vulnerability Cve 2022 24990

TerraMaster TOS Information Leakage Vulnerability CVE-2022-24990

Vulnerability Description

TerraMaster TOS has an information leakage vulnerability. The attacker can obtain sensitive information on the server through the vulnerability, and cooperate with the CVE-2022-24989 vulnerability to obtain server permissions.

Vulnerability Impact

TerraMaster TOS < 4.2.31

Network surveying and mapping

“TerraMaster” && header=”TOS”

Vulnerability reappears

Login page

img

According to POC we see the api.php file

img

1
2
# 例如下列的Url调用那么$class将是 class,并且$function  func。
/module/api.php?class/func

Let’s pay attention to these positions. Here we first define a method array, and then define the value of the REQUEST_MODE parameter by judging whether the called method exists in this array.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
$GLOBALS['NO_LOGIN_CHECK'] = array("webNasIPS", "getDiskList", "createRaid", "getInstallStat", "getIsConfigAdmin", "setAdminConfig", "isConnected");

if (!in_array($function, $GLOBALS['NO_LOGIN_CHECK'])) {
    define('REQUEST_MODE', 1);
    //加载原始session
    if (isset($in['PHPSESSID']) && !empty($in['PHPSESSID'])) {
        session_id($in['PHPSESSID']);
        $GLOBALS['sessionid'] = $in['PHPSESSID'];
    }
    @session_start();
    @session_write_close();
    //初始化阵列
    $raid = new raid();
    $base_md = $raid->_main_disk();
    if (!empty($base_md)) {
        define('DATA_BASE', "$base_md/");
    } else {
        define('DATA_BASE', null);
    }
    define('USER_PATH', DATA_BASE . "User/"); //用户目录
    define('PUBLIC_PATH', DATA_BASE . "public/"); //公共目录
    define('DATA_THUMB', DATA_BASE . '@system/thumb/');//缩略图生成存放
} else {
    define('REQUEST_MODE', 0);
}

img

After completing the judgment code, the declared class $class will be instantiated and the declared method $function will be called.

1
2
3
4
5
6
7
8
$instance = new $class();
if (!in_array($function, $class::$notHeader)) {
    #防止请求重放验证...
    if (tos_encrypt_str($_SERVER['HTTP_TIMESTAMP']) != $_SERVER['HTTP_SIGNATURE'] || $_SERVER['REQUEST_TIME'] - $_SERVER['HTTP_TIMESTAMP'] > 300) {
        $instance->output("Illegal request, timeout!", 0);
    }
}
$instance->$function();

Let’s go to the file where the vulnerability appears include/class/mobile.class.php

img

There are several key judgments in the constructor

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
function __construct()
    {
        parent::__construct();
        $this->start = $this->mtime();

        if ($_SERVER['HTTP_USER_DEVICE'] == "TNAS"){
            $_SERVER['HTTP_USER_AGENT'] = "TNAS";
        }
        if (!in_array(Action, self::$notHeader)) {
            if (!strstr($_SERVER['HTTP_USER_AGENT'], "TNAS") || !isset($_SERVER['HTTP_AUTHORIZATION'])) {
                if($this->REQUESTCODE != $_SERVER['HTTP_AUTHORIZATION'] && hash("sha256", $this->REQUESTCODE) != $_SERVER['HTTP_AUTHORIZATION']) {
                    $this->output("Illegal request, please use genuine software!", false);
                }
            }
        }
        if (REQUEST_MODE) {
            if (DATA_BASE == null) {
                $this->output("main raid not exists", false);
            }
            //避免session不可写导致循环跳转
            if (!isset($_SESSION)) {
                $this->output("session write error!", false);
            } else {
                $this->user = &$_SESSION['kod_user'];
            }
            if (isset($this->in['PHPSESSID'])) {
                $this->sessionid = $this->in['PHPSESSID'];
            }
            #管理员接口
            if (in_array(Action, $this->noPermission)) {
                if ($this->user['role'] != "root") {
                    $this->output("User [{$this->user['name']}] does not have permission!", false);
                }
            }
        }
        if (!in_array(Action, self::$notCheck)) {
            if (!$this->loginCheck()) {
                $this->output("login is timeout", 0);
            }
        }
        //初始化
        if (self::$U == null) self::$U = new person();
        if (self::$U->deamon()) {
            $this->output("user hasn't permission!", true, 0);
        }
    }

The first one determines whether the called method name is in the $notHeader array, it tests whether the user agent http header is ‘TNAS’ and whether the AUTHORIZATION header is equal to $this->REQUESTCODE.

img

The second one determines whether the called method exists in a method that does not require login.

1
2
3
4
5
if (!in_array(Action, self::$notCheck)) {
            if (!$this->loginCheck()) {
                $this->output("login is timeout", 0);
            }
        }

Next, look at the definition of webNasIPS call

img

img

It can be found that this method exists in these judgment arrays, and we tracked this method

img

You can find that the call to this method only requires adding User-Agent: TNAS, to get sensitive information in the server.

1
/module/api.php?mobile/webNasIPS

img

This post is licensed under CC BY 4.0 by the author.