CVE-2021-22909- 深入研究 UBIQUITI 固件更新错误
https://www.zerodayinitiative.com/blog/2021/5/24/cve-2021-22909-digging-into-a-ubiquiti-firmware-update-bug
早在二月份,Ubiquiti 发布了 Ubiquiti EdgeRouter 的新固件更新,修复了CVE-2021-22909/ZDI-21-601。该漏洞存在于固件更新过程中,允许中间人 (MiTM) 攻击者在系统执行自动固件更新时提供恶意固件映像,从而以 root 身份在设备上执行代码。该漏洞是由名为 awxylitol 的研究人员发现并报告给 ZDI 程序的。
这个漏洞听起来可能是人为的。坏人给设备提供坏固件,坏事就会发生。然而,不安全的下载漏洞自成立以来一直是路由器类别中多个Pwn2Own 获奖条目的支柱。此漏洞的影响非常微妙,值得进一步讨论。
路由器究竟如何执行固件更新?
根据Ubiquiti 文档,新的模板化操作命令add system image可用于通过命令行界面 (CLI) 更新路由器的固件。模板化的操作命令允许用户快速修改路由器的操作状态,而无需摆弄复杂的命令行参数。这简化了日常操作的过程并最大限度地减少了用户错误。我相信我们都听说过系统管理员不小心删除了关键文件、将自己锁在远离文明的设备之外等等的恐怖故事。模板化命令试图缓解这些问题。
Ubiquiti EdgeRouter 使用的模板系统由vyatta-op包提供。命令add system image在/opt/vyatta/share/vyatta-op/templates/add/system/image/node.def文件中定义。
$ cat node.def
help: Add a new image to the system
run: sudo /usr/sbin/ubnt-fw-latest --upgradeview rawCVE-2021-22909-snippet-1.console hosted with ❤ by GitHub
通过运行此操作命令,用户可以有效地调用ubnt-fw-latest带有--upgrade选项的脚本。此选项会导致ubnt-fw-latest脚本运行该upgrade_firmware()功能,该功能将检查Ubiquiti 更新服务器以获取有关最新固件版本的信息,包括固件下载 URL。
#!/bin/bash
#-------------------------------------------------------------------------------
STATUS_FILE="/var/run/fw-latest-status"
UPGRADING_FILE="/var/run/upgrading"
REBOOT_NEEDED_FILE="/var/run/needsareboot"
DOWNLOADING_FILE="/var/run/downloading"
URL="https://fw-update.ubnt.com/api/firmware-latest"
ACTION="refresh"
CHANNEL="release"
DEFAULT_URL="https://localhost/eat/my/shorts.tar"
#-------------------------------------------------------------------------------
while [[ $# -gt 0 ]]
do
key="$1"
case $key in
-r|--refresh) # Refresh status of latest firmware by
ACTION="refresh" # fetching it from fw-update.ubnt.com
shift
;;
-s|--status) # Read latest firmware status from cache
ACTION="status"
shift
;;
-u|--upgrade) # Upgrade to latest firmware
ACTION="upgrade"
shift
;;
-c|--channel) # Target channel (release or public-beta)
CHANNEL="$2"
shift
shift
;;
*) # Ignore unknown arguments
shift
;;
esac
done
# ...
upgrade_firmware() {
# Fetch version number of latest firmware
echo -n "Fetching version number of latest firmware... "
refresh_status_file @> /dev/null
# Parse status file
local fw_version=`cat $STATUS_FILE | jq -r .version 2> /dev/null` || fw_version=""
local fw_url=`cat $STATUS_FILE | jq -r .url 2> /dev/null` || fw_version=""
local fw_md5=`cat $STATUS_FILE | jq -r .md5 2> /dev/null` || fw_version=""
local fw_state=`cat $STATUS_FILE | jq -r .state 2> /dev/null` || fw_version=""
if [ -z "$fw_version" ] || [ "$fw_url" = "$DEFAULT_URL" ]; then
echo "failed"
exit 42
else
echo "ok"
echo " > version : $fw_version"
echo " > url : $fw_url"
echo " > md5 : $fw_md5"
echo " > state : $fw_state"
echo
fi
if [ "$fw_state" == "can-upgrade" ]; then
echo "New firmware $fw_version is available"
echo
sudo /usr/bin/ubnt-upgrade --upgrade-force-prompt "$fw_url"
elif [ "$fw_state" == "up-to-date" ]; then
echo "Current firmware is already up-to-date (!!!)"
echo
sudo /usr/bin/ubnt-upgrade --upgrade-force-prompt "$fw_url"
elif [ "$fw_state" == "reboot-needed" ]; then
echo "Reboot is needed before upgrading to version $fw_version"
else
echo "Upgrade is already in progress"
fi
}
#-------------------------------------------------------------------------------
if [ "$ACTION" == "refresh" ]; then
refresh_status_file
elif [ "$ACTION" == "status" ]; then
read_status_file
elif [ "$ACTION" == "upgrade" ]; then
upgrade_firmware
fiview rawCVE-2021-22909-snippet-2.bash hosted with ❤ by GitHub
该函数继续解析服务器的结果并将其与当前固件版本进行比较。如果有可用更新,脚本将调用ubnt-upgrade以从fw-download.ubnt.com升级服务器提供的域中获取固件。然后它将执行实际的固件升级。
错误 - ZDI-21-601
问题在于/usr/bin/ubnt-upgradebash 脚本下载固件的方式。该get_tar_by_url()函数使用该curl命令来执行提取。但是,开发人员指定了 -k 选项(也称为–insecure选项),该选项禁用了 TLS 连接的证书验证。
view rawCVE-2021-22909-snippet-3.bash hosted with ❤ by GitHub
由于/usr/sbin/ubnt-upgrade不检查证书的有效性,攻击者可以使用自签名证书来欺骗fw-download.ubnt.com域,而不会在设备上触发任何警告或投诉来提醒用户。此漏洞显着降低了发起成功攻击所需的技能障碍。
要利用此漏洞,攻击者可以修改现有的 EdgeRouter 固件映像并修复文件中包含的校验和。在提交的概念验证中,研究人员修改了rc.local文件以使用反向 shell 连接回攻击者。重新启动是升级过程的一部分,会触发rc.local脚本。
结论
如果攻击者将自己作为 MiTM 插入,他们就可以冒充 Ubiquiti 控制的“fw-download.ubnt.com”域。但是,要成功地从该域中提供恶意固件,攻击者通常需要获取带有域私钥的有效证书。要继续进行,攻击者可能需要侵入 Ubiquiti 或说服受信任的证书颁发机构 (CA) 为攻击者颁发 Ubiquiti 域的证书,这绝非易事。但是,由于此错误,无需获取证书。
问题的核心是固件二进制文件缺乏身份验证。安全通信通道的功能是提供机密性、完整性和身份验证。在 TLS 中,加密提供机密性,消息摘要(或TLS 1.3 中的AEAD)提供完整性,证书验证提供身份验证。如果没有验证证书,客户端将在通信通道中进行身份验证。在这种情况下,客户端可能会“安全地”与恶意行为者对话。
还应该注意校验和不是加密签名的替代品。校验和可以帮助检测传输中的随机错误,但不能提供数据真实性的硬证明。
最后一个考虑因素是供应商的网站可能会受到损害。在这种情况下,固件及其关联的哈希值都可能被恶意版本替换。这种情况只能通过对固件文件本身应用加密签名来缓解。也许 Ubiquity 会转而使用加密方式签署固件二进制文件,这将提高其客户的整体安全性。
Ubiquity 在其v2.0.9-hotfix.1安全更新中通过从模板化命令中删除-k( --insecure) 标志来解决此错误。
脚注
谨慎的 EdgeRouter 用户寻求如何正确升级设备的建议,应避免使用自动升级功能进行此更新。他们可能希望从浏览器手动下载固件文件,并在通过 Web 界面将固件文件上传到设备执行手动升级之前验证固件的哈希值。
Last updated