在家用路由器上练习黑客技术
虽然我确实倾向于主要关注系统管理中的 Linux(毕竟,那是我的日常工作),但我一直对安全有着次要的兴趣,无论是加固系统、对被黑系统进行取证、获取 pico 投影仪的 root 权限,甚至是尝试寻找和利用漏洞。即使设置自己的 Web 服务并尝试利用它们很有趣,但在别人的代码中发现漏洞更令人满足。当然,缺点是大多数网站管理员不喜欢你侵入他们的网站。然而,至少对我来说,黑客行为再有趣,也不值得冒牢狱之灾的风险,所以我需要在更合法的方式中获得乐趣。这就是我的无线路由器发挥作用的地方。
无线路由器长期以来一直容易被黑客入侵。如果你随便找一群 Linux 极客,你肯定会发现他们中的许多人拥有或曾经拥有经典的 Linksys WRT 系列产品。如果你在网上搜索,你会发现各种各样的自定义固件可以安装来扩展其功能。虽然在某些版本的路由器上,你必须经历一些疯狂的步骤才能安装自定义固件,但这仍然与发现和利用服务器上的漏洞不是同一种挑战。虽然我有一堆 WRT54G 路由器,但本文不是关于它们的;相反,它是关于 D-Link DIR-685 的。
D-Link DIR-685我第一次注意到 D-Link DIR-685 是在 woot.com 上的 Woot-Off 活动期间。如果你熟悉 Woot-Offs,你就会明白,当一个新产品出现在网站上时,你只有有限的时间来决定是否购买它,然后它就会消失,一个新产品就会出现。当我读到规格时,我就知道这款路由器看起来很有前景。首先,它是一款 802.11n 路由器,而我正想从我的 802.11g 网络升级。其次,它背面有五个不同的千兆端口以及两个 USB 端口。最后,锦上添花的是,它不仅在前面有一个有趣的彩色 LCD,可以显示统计数据、照片或其他数据,而且你还可以插入一个高达 1Tb 的 2.5 英寸 SATA 硬盘,并将这东西变成一个小型 NAS。基于它在 2.5 英寸硬盘上需要 ext3 文件系统的事实,我可以合理地假设它甚至已经运行了 Linux。我没有太多时间来查看是否有人已经入侵了路由器或创建了自定义固件,所以我下定决心并点击了订购按钮。
当我在等待路由器运到我家时,我做了一些额外的研究。虽然不幸的是,看起来我找不到任何自定义固件(这款路由器最初非常昂贵,所以我估计它没有很大的安装基础),但我确实找到了一个网站,有人记录了如何打开路由器并连接串行端口,这样你就可以访问本地串行控制台。我决定,在最坏的情况下,如果我找不到更简单的方法,我总是可以走这条路。
当我拿到路由器时,我通过 Web 界面在我的网络上进行了初始设置,然后最后一次查找是否有任何自定义固件或其他方法,除了串行控制台之外,可以在路由器上获得 root 权限。我没能找到任何东西,但在我费力拆开它之前,我决定在 Web 界面上四处看看,看看我是否看到了任何明显的东西。第一个死胡同是在我通过 Web 界面启用 FTP 服务时出现的,但我无法找到任何已知的 FTP 服务器漏洞可以利用。与我在 pico 投影仪上获得 root 权限时不同,当我针对该机器运行 nmap 时,我没有幸运到有 telnet 在等待我
PORT STATE SERVICE
21/tcp open ftp
80/tcp open http
139/tcp open netbios-ssn
445/tcp open microsoft-ds
仅限一次 Ping
当我继续搜索时,我得到了我的第一个线索:ping 测试。Web 界面提供了一整套诊断工具,其中包括允许你 ping 远程机器以测试连接的工具,网址为 http://<router ip>/tools_vct.php(图 1)。我认为 PHP 脚本很可能只是将你输入的 hostname 或 IP 地址转发到运行 ping 的系统调用,所以我首先在我的输入中添加了一个分号和一个 ls
命令。不幸的是,有一个 JavaScript 例程对输入进行了清理,但我注意到的是,在我提交有效输入后,变量也出现在 URL 中:http://<router ip>/tools_vct.php?uptime=175036&pingIP=127.0.0.1。

图 1. Ping 测试
我发现,虽然页面使用 JavaScript 来清理输入,但它没有清理 POST 数据。事实上,我可以将我想要的任何东西作为 pingIP 的值,它不仅会接受它,而且由于 PHP 页面在输出中显示了 pingIP 的值,我也会在结果网页中看到我的变量输出,这为 JavaScript 注入和 XSS 攻击打开了各种可能性。当然,这些都无助于我在机器上获得 root 权限,所以我开始尝试弄清楚我可以发送哪种有效负载来执行系统调用。
无法逃脱正是在这个时候,我在网上搜索了一个完整的 URL 转义代码表。你可能已经注意到,例如,每当你在 URL 中键入空格时,现在的浏览器都倾向于将其转换为 %20。这只是在 URL 中以转义形式有效的符号的众多不同转义代码之一。表 1 显示了一些对于我试图实现的目标更有用的代码。
表 1. URL 转义代码转义代码 | 字符 |
%3B | ; |
%3F | ? |
%26 | & |
%22 | " |
%3C | < |
%3E | > |
%7C | | |
%60 | ` |
因此,例如,为了执行简单的命令注入测试,你可能会尝试添加 sleep 命令。如果页面在重新加载之前似乎暂停了那么长时间,那么你的命令注入就成功了。因此,为了尝试在该页面上使用 sleep 命令,我将 pingIP 设置为“127.0.0.1; sleep 30”的编码 URL 如下所示:http://<router ip>/tools_vct.php?uptime=175036&pingIP=127.0.0.1%3B%20sleep%2030。
“如果是 PHP,肯定会有漏洞。”我迭代了各种不同的符号和选项来传递 pingIP,但我尝试的任何方法似乎都没有任何效果。我正在和我的一个朋友谈论我正在尝试的事情以及我还没有发现任何可用的漏洞,我得到了令人鼓舞的回复:“如果是 PHP,肯定会有漏洞。”我认为,如果我已经设法找到了 JavaScript 注入 XSS 漏洞,如果我继续寻找,我肯定能找到某种进入方式。我决定暂时忘记 ping 页面,尝试寻找其他漏洞。
我的下一个线索是在我查看 http://<router ip>/tools_system.php 上的系统工具页面时出现的(图 2)。该页面上一个显眼的项目是重启按钮。我认为它至少有可能进行某种系统调用,所以我查看了我的浏览器中该网页的源代码,并注意到当你单击重启按钮时,JavaScript 调用了这个 URL:http://<router ip>/sys_config_valid.xgi?exeshell=submit%20REBOOT。没有什么比名为 exeshell 的 CGI 变量更令人放心的了。因为我从我的 ping 测试中获得了各种编码 URL 示例,所以我决定尝试将 sleep 命令括在反引号中,看看它是否会退出到 shell——结果,它奏效了!

图 2. 系统工具页面
有效负载好的,现在我有一种可行的方法可以在系统上执行 shell 命令。下一个问题是我将如何利用它来远程登录。我的第一个方法是尝试执行 netcat,让它监听一个高端口,并使用 -e 参数,以便在我连接到该端口后它会执行一个 shell——一个简陋的 telnetd。毕竟,许多运行 Linux 的消费类设备都使用 BusyBox 作为其 shell,而 BusyBox 通常包含一个支持此选项的 netcat 版本。不幸的是,我尝试的任何 netcat 参数组合似乎都没有任何作用。我开始认为我根本没有获得 shell——也就是说,直到我将 reboot 括在反引号中,它重启了路由器。
在机器重新启动后,我认为可能是 netcat 只是没有安装,所以我当时尝试了命运攸关的 URL:http://<router ip>/sys_config_valid.xgi?exeshell=%60telnetd%20%26%60。
如果你不想查找它,它会转换为 `telnetd &`
作为输入。果然,在我运行该命令后,我的 nmap 输出看起来有点不同
PORT STATE SERVICE
21/tcp open ftp
23/tcp open telnet
80/tcp open http
139/tcp open netbios-ssn
445/tcp open microsoft-ds
然后,我从同一台机器启动了 telnet
$ telnet <router ip>
Trying <router ip>...
Connected to <router ip>.
Escape character is '^]'.
BusyBox v1.00 (2009.07.27-14:12+0000) Built-in shell (msh)
Enter 'help' for a list of built-in commands.
#
我不仅获得了 shell,还获得了 root shell!当我运行 ps
命令时,我注意到我的 telnetd 进程在命令行上
sh -c `telnetd &` > /dev/console
事实证明,你传递给 exeshell 的任何命令都会传递给 sh -c
,所以我不需要任何花哨的转义反引号或 & 符号,exeshell=telnetd
就可以正常工作。
那么,这个故事的寓意是什么?好吧,首先,当你可以通过 Web 界面获得 shell 时,不要打开硬件并使其保修失效以连接到串行控制台。其次,JavaScript 不足以清理输入——如果你接受 POST 数据,你也需要清理它。第三,将输入变量直接传递给 sh 可能不是一个好主意。最后,下次你想尝试一下渗透测试时,你无需超出自己的网络范围。黑客攻击你自己的硬件可能与黑客攻击别人的硬件一样有趣(也更安全)。