西部数码MyCloud NAS命令执行漏洞

匿名者  2021天前

在这篇文章中,我将要解释我是如何发现西部数据NAS设备的一些漏洞的,组合在一起后最终可以实现root权限的远程代码执行的效果。

要想控制NAS设备,需要保证攻击者与NAS设备处于同一网络,并且知道其真实IP。

POC在这里

前奏

这一切均源于,我决定斥资购买西部数据(WD)My Cloud EX2 Ultra。与其他型号不同,这款产品为消费者提供了切换硬盘驱动器的功能,可以让你无需额外安装应用程序即可使用它,甚至还可以在没有互联网的情况下使用。

在安装这个设备时,我决定先打开浏览器测试一下,幸不辱命,发现一个绕过身份验证的方法(通过设置cookie中的“isAdmin”为1)。奈何,在更新NAS以后,我发现这个漏洞已经在新版本中修复了。

此时我觉得肯定还会有其他漏洞,于是我决定继续测试下去。当我下载了WD网站的源代码以后,便开始搜索刚才这处校验用户身份的代码,终于成功找到我想要的代码片段。我发现更新后的代码中已经不再是依赖用户的Cookie信息,而是改为校验Session。

/* fixed code in 
      firmware/module/crfs/web/pages/lib/login_checker.php 
*/

function login_check()
{
    $ret = 0;

    if (!csrf_token_check()) /* this check can be bypassed easily as well */
        return $ret;

    if (isset($_SESSION['username']))
    {
        if (isset($_SESSION['username']) && $_SESSION['username'] != "")
            $ret = 2; //login, normal user

        if ($_SESSION['isAdmin'] == 1)
            $ret = 1; //login, admin
    }

    return $ret;
}

未经校验的文件上传漏洞(CVE–2019-9951

通过审计这些“可爱的”PHP代码,我发现有一处没有正确使用login_check函数,从而导致未经校验的文件上传漏洞。

/* found in:
    firmware/module/crfs/web/pages/jquery/uploader/uploadify.php 
*/

include ("../../lib/login_checker.php");

if (login_check() != 1) /* i.e not-authenticated / admin */
{
    /* user-controlled */
    if ($_SERVER['HTTP_USER_AGENT'] == 'Shockwave Flash') 
    {
        $headers =  getallheaders();

        /* also user-controlled */
        if ($_GET['WD-CSRF-TOKEN'] !== $_POST['X-CSRF-Token'] || 
            strrpos($headers['Content-Type'], 'multipart/form-data;'))
        {
            echo json_encode($r);
            exit;
        }
        /* >> by reaching this line, you bypassed the authentication for this page*/
    }
    else
    {
        echo json_encode($r);
        exit;
    }
}
/* upload logic here */

不过,这还无法直接利用。因为uploadify.php文件将会校验目的路径并且限制仅允许写入到特定目录。

/* found in:
      firmware/module/crfs/web/pages/lib/login_checker.php 
*/

function check_path($path)
{
    $file_path = realpath($path);
    if (!$file_path) return false;

    if (strncmp($file_path, "/mnt/HD", 7) != 0 &&
        strncmp($file_path, "/mnt/USB", 8) != 0 &&
        strncmp($file_path, "/mnt/isoMount", 13) != 0)
        return false;

    return true;
}

身份认证绕过(CVE-2019-9950

证书在cgiMain导出的函数firmware/module/crfs/cgi/login_mgr.cgi中被管理。

事实证明,控制面板利用内置的操作系统凭证管理。这允许控制面板对照/etc/shadow中存储的用户名和密码检查提供的用户名和密码:

1.png

在如上文件中查找 nobody账户的密码,这个密码使用了旧的CRYPT算法加密:

nobody:pACwI1fCXYNw6:0:0:99999:7:::

我们可以使用John the Ripper 或者 hashcat来尝试破解这个hash,但是我觉得下面这种表示方式或许更加直观。

2.png

更搞笑的是,NAS中的用户名默认密码为空,因此任何人都可以轻而易举的获取一个session token。

POST http://WD/cgi-bin/login_mgr.cgi
{
    "cmd": "wd_login",
    "username": "nobody",
    "pwd": "",
    "port": "",
}

使用低权限获取root权限的RCE(CVE-2019-9949

当我们拥有了一个标准的权限token时,我们将有权获取并访问更多的攻击面。里面有一个文件管理功能(主要由webfile_mgr.cgi文件控制),但是有些功能被限制了,不支持打开zip/tar格式的文档。

3.png

当点击上图中的按钮时,将会发送如下带有cgi_unzip命令的HTTP请求到webfile_mgr.cgi文件。

Request URL:    "http://wd/cgi-bin/webfile_mgr.cgi"
Request method: "POST"

cmd:    "cgi_unzip"
path:   "/mnt/HD/HD_a2/Public/test"
name:   "myfile.zip"

之后,在firmware/module/crfs/web/pages/cgi_api.php文件中通过必要的路由和权限的校验后,cgi模块会通过转义路径来强制校验输入,然后再执行带有-t选项的unzip命令。

/* ... in  webfile_mgr.cgi */
fix_path_special_char_inline(archive_name);  // user controlled
// target_dir is checked to exist in the PHP code 
sprintf(cmdline, "cd %s;/usr/bin/unzip -t %s", target_dir, archive_name); 
ret = popen(cmdline, "r");
/* ... */

跟进fix_path_special_char_inline函数,可以看到校验很松散:

def fix_path_special_char_inline(input_str):
    out_str = ''
    for c in input_str:
        if c in '`$#%^&()+{};[]\=': # much secure
            out_str += '\\'
        out_str += c

    return out_str

可以看到使用了黑名单校验,在这个黑名单中,并没有校验管道符(|)。在bash或batch的世界中,当双管道符(||)处于两个命令之间时,前面的命令执行失败了,那么便会继续执行后面的命令。

在这种情境下,通过使前面unzip命令执行失败,攻击者可以注入一个root权限运行的shell命令。例如:

cd %s;/usr/bin/unzip -t 1||%MY_EVIL_COMMAND%

再来一个

事实证明,这里的文件管理功能很容易受到其他攻击。具体来说,使用符号链接提取存档将不需要进一步验证就可以创建它们,从而允许将来的文件系统操作滥用它们而不做任何限制。

例如:如果两个连续的cgi_untar命令在两份精心构造的存档上被执行时,可以导致任意文件写入漏洞(root权限)。同样,这个漏洞也仅需要一个普通用户权限。

发生这种情况的原因是,在提取压缩文件的代码中将使用cig_untar命令进行简单的解压缩操作,即使目标包含符号链接。然后,在提取第二个压缩文件时,攻击者可以使用事先构造好的符号链接写入到任意路径。

因为NAS使用的是squashfs,因此不是所有的路径都是可写的,例如,/bin/目录便不可以。为了娱乐最大化,我决定覆盖tar自己本身,因此可以通过如下操作来实现RCE:

  1. 上传第一个压缩文档,其中包含符号链接

  2. 发送cgi_untar命令:创建指向/bin/目录的符号链接

  3. 上传第二个压缩文档,其中包含Payload

  4. 发送cig_untar命令:覆盖/bin/tar文件

  5. 发送cig_untar命令:执行我的Payload

我觉得第二个漏洞尽管很严重,但是却不值得拥有一个属于自己的CVE编号。

漏洞时间轴

2019-01-20 向psirt@wdc.com发送报告并遵守30天的披露期限

2019-01-22 WD发送了自动回复

2019-02-05 被要求确认问题

2019-02-06 WD要求90天内解决问题

2019-03-05 请求的状态更新

2019-03-15 WD要求额外延长90天

2019-03-16 同意延长30天

2019-03-27 WD发布第一个补丁(CVE-2019-9950,CVE-2019-9951)

2019-05-20 WD 发布第二个补丁(CVE-2019-9949)

2019-05-22 公开漏洞


1. My Cloud EX2 Ultra测试所有版本号:2.31.149_20181015

2. 不过我当时并不知道在exploiteers已经被公布过

3. https://community.wd.com/t/new-release-my-cloud-firmware-versions-2-31-174-3-26-19/235932

    4. https://community.wd.com/t/new-release-my-cloud-firmware-versions-2-31-183-05-20-2019/237717

    本文由白帽汇整理并翻译,不代表白帽汇任何观点和立场
    来源:https://bnbdr.github.io/posts/wd/

    最新评论

    昵称
    邮箱
    提交评论