专栏名称: 看雪学苑
致力于移动与安全研究的开发者社区,看雪学院(kanxue.com)官方微信公众帐号。
目录
相关文章推荐
瑞恩资本RyanbenCapital  ·  佑驾创新(02431),三大暗盘至少升7.6 ... ·  昨天  
瑞恩资本RyanbenCapital  ·  佑驾创新(02431),三大暗盘至少升7.6 ... ·  昨天  
看雪学苑  ·  本周更新:Windbg高级调试命令补充讲解 ... ·  2 天前  
古北路烧烤哥  ·  这下知道什么是新基建新主线了吗? ·  2 天前  
古北路烧烤哥  ·  这下知道什么是新基建新主线了吗? ·  2 天前  
奇舞精选  ·  知名前端库 Vant 和 Rspack ... ·  3 天前  
奇舞精选  ·  知名前端库 Vant 和 Rspack ... ·  3 天前  
研讯社  ·  周末,新变化! ·  4 天前  
研讯社  ·  周末,新变化! ·  4 天前  
51好读  ›  专栏  ›  看雪学苑

攻击 Western Digital NAS 个人云存储设备

看雪学苑  · 公众号  · 互联网安全  · 2017-03-18 18:02

正文

在 Exploitee.rs,有时我们寻找有趣的设备进行攻击,而有时设备会找到我们。今天,我们将谈谈最近一段时间(我们发现自己处于后一种情况)我们在攻击一系列 Western Digital 的网络附加存储设备方面的经验。

去年年中,我开始寻找一个能借助 Plex(一款我最近很喜欢用的媒体播放器)提供硬件解码功能的网络附加存储设备。经过一番研究,我订购了一个 Western Digital“MyCloud”PR4100。这个设备满足了我的所有需求,并得到一个朋友强烈推荐。在将 NAS 添加到我的网络并首次访问设备的管理页面之后,我对在网络中不经适当审核而添加新设备感到厌烦。所以,我登录该设备,启用 SSH 访问,并查看该设备的 Web 服务器功能如何工作。

💎 登录绕过

我很快发现第一个令人震惊的 bug,这个 bug 来自于一段执行用户登录检查功能(使用 cookie 或 PHP 会话变量)的代码。使用 cookie 进行身份验证不一定是一件坏事,但问题是西部数据 MyCloud 的登录界面使用它们的方式。检查下面的代码。

/lib/login_checker.php

function login_check()

{

        $ret = 0;

        if (isset($_SESSION['username']))

        {

                if (isset($_SESSION['username']) && $_SESSION['username'] != "")

                $ret = 2; //login, normal user

 

                if ($_SESSION['isAdmin'] == 1)

                        $ret = 1; //login, admin

        }

        else if (isset($_COOKIE['username']))

        {

                if (isset($_COOKIE['username']) && $_COOKIE['username'] != "")

                $ret = 2; //login, normal user

 

                if ($_COOKIE['isAdmin'] == 1)

                        $ret = 1; //login, admin

        }

        return $ret;

}

上述代码包含一个名为“login_check”的函数,此函数由所有后端 PHP 脚本使用,用于验证预认证的用户。上面的代码可以通过两条途径完成检查,第一是通过检查“username”和“isAdmin”的会话值,第二是(如果先前失败)尝试使用 cookie 完成相同的过程。因为 cookie 是由用户提供的,所以脚本寻找的要求可以被攻击者满足。上述会话和 cookie 的检查过程总结如下。

  • “username”变量已设置,并且不为空 - 用户以普通权限用户身份登录。

  • “isAdmin”变量设置为1 - 用户以管理员身份登录。

这意味着在任何时候使用该 PHP 脚本进行登录检查时,攻击者能够通过提供 2个特制的 cookie 值绕过检查。

在写下我发现的过程中,一个新的固件被推出来修补上述 bug。然而,这个补丁引入了一个新的漏洞,它具有与上述 bug(更新前)相同的后果。下面是包括固定代码的当前版本。

/var/www/web/lib/login_checker.php

 20 function login_check()

 21 {

 22         $ret = 0;

 23 

 24         if (isset($_SESSION['username']))

 25         {

 26                 if (isset($_SESSION['username']) && $_SESSION['username'] != "")

 27                 $ret = 2; //login, normal user

 28 

 29                 if ($_SESSION['isAdmin'] == 1)

 30                         $ret = 1; //login, admin

 31         }

 32         else if (isset($_COOKIE['username']))

 33         {

 34                 if (isset($_COOKIE['username']) && $_COOKIE['username'] != "")

 35                 $ret = 2; //login, normal user

 36 

 37                 if ($_COOKIE['isAdmin'] == 1)

 38                         $ret = 1; //login, admin

 39 

 40                 if (wto_check($_COOKIE['username']) === 0) //wto check fail

 41                         $ret = 0;

 42         }

 43 

 44         return $ret;

 45 }

 46 ?>

在代码的更新版本中,调用了新函数“wto_check()”(40行)。此函数使用客户端提供的用户名以及用户的 IP 地址作为二进制参数在设备上运行。如果用户当前已经登录并且没有超时,则返回值 1,否则返回 0(指示用户未登录)。“wto_check()”方法的代码如下。

/var/www/web/lib/login_checker.php

  3 /*

  4   return value: 1: Login, 0: No login

  5 */

  6 function wto_check($username)

  7 {

  8         if (empty($username))

  9                 return 0;

 10 

 11         exec(sprintf("wto -n \"%s\" -i '%s' -c", escapeshellcmd($username), $_SERVER["REMOTE_ADDR"]), $login_status);

 12         if ($login_status[0] === "WTO CHECK OK")

 13                 return 1;

 14         else

 15                 return 0;

 16 }

 17 

 18 /* ret: 0: no login, 1: login, admin, 2: login, normal user */

 19

在上面的代码中你可以看到,为了将用户名和 IP 地址引入作为“wto”二进制的参数,在第 11 行进行了转义处理。上面代码的问题是 PHP 方法“escapeshellcmd()”的不正确使用,“escapeshellcmd()”的正确用途是处理整个命令字符串,而不仅仅是一个参数。这是因为“escapeshellcmd()”函数不转义引号,因此攻击者可以突破引号的封装(在我们的案例中为“-n”参数),允许引入新的参数执行。因此,我们可以添加新的参数实现自我登录,而绕过对用户是否已经登录的检查。尽管我们认为仅仅通过检查IP地址和是否登录超时来验证用户是否已经登录是远远不够的。编写这段代码的程序员应该使用“escapeshellarg()”,它用于过滤独立的二进制参数,并过滤掉引号。使用“escapeshellarg()”而不是目前使用的“escapeshellcmd()”至少可阻止上述提到的攻击。

💎 命令注入错误

WDCloud Web 界面的大多数功能实际上由设备上的 CGI 脚本处理。大多数二进制文件使用相同的模式,它们从请求中获取 post / get / cookie 值,然后使用 PHP 调用中的值来执行shell命令。在大多数情况下,这些命令将使用用户提供的数据(几乎不进行清理)。例如,考虑一下以下代码(来自于该设备)。

php/users.php

 15 $username = $_COOKIE['username'];

 16 exec("wto -n \"$username\" -g", $ret);

上面的代码从 COOKIE 的超全局变量(包含从请求提交来的 cookie 数组索引)分配一个值给本地变量“$ username”。然后,该值作为本地方法“wto”的二进制参数立即在 PHP 的“ exec() ”调用中被使用。因为没有数据清理,使用用户名值

username=$(touch /tmp/1)

将现有的 exec 命令转换为

wto -n "$(touch /tmp/1)" -g

并在其中执行用户提供的命令。

因为参数用双引号封装且我们使用“$(COMMANDHERE)”这样的语法,命令“touch / tmp / 1”先于“wto”方法被执行,其返回值被用作“wto”方法的“-n”参数。这种导致命令注入漏洞的基本模式在Web界面使用的许多脚本中被多次使用。虽然上述的一些漏洞可能被常规的身份认证所阻止,但是通过上面提到的绕过登陆可以克服该限制。另外,值得注意的是,所有通过 Web 界面执行的命令都是完成的,因此本案例中 Web 服务器是以 root 用户的身份在运行。

💎 其他错误

可能你认为上述错误已经很严重了,但在 Web 界面中仍然存在了大量的错误(像被注释掉的正常验证一样简单的):

addons/ftp_download.php

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

  7 //

  8 ///* login_check() return 0: no login, 1: login, admin, 2: login, normal user */

  9 //if (login_check() == 0)

 10 //{

 11 //      echo json_encode($r);

 12 //      exit;

 13 //}

还有其他更具特定功能性的错误,如下面的例子,允许未经验证的用户能够将文件上传到 myCloud 设备。

addons/upload.php

  2 //if(!isset($_REQUEST['name'])) throw new Exception('Name required');

  3 //if(!preg_match('/^[-a-z0-9_][-a-z0-9_.]*$/i', $_REQUEST['name'])) throw new Exception('Name error');

  4 //

  5 //if(!isset($_REQUEST['index'])) throw new Exception('Index required');

  6 //if(!preg_match('/^[0-9]+$/', $_REQUEST['index'])) throw new Exception('Index error');

  7 //

  8 //if(!isset($_FILES['file'])) throw new Exception('Upload required');

  9 //if($_FILES['file']['error'] != 0) throw new Exception('Upload error');

 10 

 11 $path = str_replace('//','/',$_REQUEST['folder']);

 12 $filename = str_replace('\\','',$_REQUEST['name']);

 13 $target =  $path . $filename . '-' . $_REQUEST['index'];

 14 

 15 //$target =  $_REQUEST['folder'] . $_REQUEST['name'] . '-' . $_REQUEST['index'];

 16 

 17 move_uploaded_file($_FILES['file']['tmp_name'], $target);

 18 

 19 

 20 //$handle = fopen("/tmp/debug.txt", "w+");

 21 //fwrite($handle, $_FILES['file']['tmp_name']);

 22 //fwrite($handle, "\n");

 23 //fwrite($handle, $target);

 24 //fclose($handle);

 25 

 26 // Might execute too quickly.

 27 sleep(1);

上面的代码由未经检查的身份验证组成,该段代码被调用时将简单地检索上传的文件内容,并根据用户提供的路径来决定在哪里放置新文件。

除了本博客中列出的错误,我们将在 MyCloud Web 界面中发现的大量错误放在我们的 wiki 中。尽快修复错误是我们 Exploitee.rs 的普遍追求。然而,大量的严重错误的发现意味着,我们可能需要在供应商正确修复已发布的漏洞后重新评估产品。

💎 责任披露

Exploitee.rs 通常致力于同供应商合作,确保漏洞被正确地发布。然而,上一次在维加斯的 BlackHat 大会上取得了Pwnie奖后,我们了解了供应商在圈子里的声誉。特别地,某供应商在忽略了向他们所提交的一组错误的严重性后,仍然赢得了“Lamest Vendor Response” Pwnie奖。厂商的忽略使得易受攻击的设备更长时间地在线(尽管已经做过了责任披露)。因此,我们转而尝试向圈内人士做出有关这些缺陷的预警,并希望用户将其设备从接入公网的网络中转移走,或是尽可能限制访问。通过这个过程,我们完全公开了我们的所有研究,并希望这会加快给用户设备打补丁的速度。

 找到的 Bug 统计信息

  • 1 x绕过登录

  • 1 x任意文件写入

  • 13 x未经身份验证的远程命令执行Bug

  • 70 x需要验证命令执行Bug*

*绕过登录Bug 可以取得和“需要验证”Bug一样的效果。

💎 范围

即便不是全部也可以说是大多数,本项研究可以应用于西部数据的整个 MyCloud 系列产品。包括以下设备:

  • My Cloud

  • My Cloud Gen 2

  • My Cloud Mirror

  • My Cloud PR2100

  • My Cloud PR4100

  • My Cloud EX2 Ultra

  • My Cloud EX2

  • My Cloud EX4

  • My Cloud EX2100

  • My Cloud EX4100

  • My Cloud DL2100

  • My Cloud DL4100


原文链接:https://blog.exploitee.rs/2017/hacking_wd_mycloud/

本文由 看雪翻译小组 jasonk龙莲 编译

原文作者:zenofex of exploitee.rs

声明:转载请保留文章的完整性,注明作者、译者及出处, 并附上本文链接。


 热 门 阅 读:



《走进企业看安全.易宝支付》第9站 开始报名!

对 Samsung S6 的 SBOOT 逆向工程(一)

MySQL Out-of-Band 注入攻击

安卓勒索软件的发展趋势(一)

在 Linux 上使用 AFL 对 Stagefright 进行模糊测试

......

更多优秀文章点击左下角“关注原文”查看!


看雪论坛:http://bbs.pediy.com/

微信公众号 ID:ikanxue

微博:看雪安全

投稿、合作:www.kanxue.com