在 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 的检查过程总结如下。
这意味着在任何时候使用该 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