概述
D-Link DIR-3060(运行固件版本低于 v1.11b04)存在认证后命令注入漏洞。认证用户能够以系统管理员 “admin” 的身份执行任意命令,并且具有 root 权限。D-Link 已发布新版固件 v1.11b04 Hotfix 2 进行修复,建议受此漏洞影响的用户升级固件到最新版本。
影响产品 | D-Link DIR-3060 (www.dlink.com) |
---|---|
影响版本 | 运行固件版本低于 v1.11b04 |
修复版本 | v1.11b04 Hotfix 2 |
CVE 编号 | CVE-2021-28144 |
危害级别 | 8.8 (高) CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H |
漏洞来源 | T. Shiomitsu, IoT Inspector Research Lab |
受影响组件
DIR-3060 的 web 管理功能主要由二进制文件prog.cgi
处理。用户通过请求 /HNAP1/
或后缀名为 .fcgi
的文件,就可以修改lighttpd
服务器的fastcgi
配置。/etc_ro/lighttpd/www/web/HNAP1/prog.fcgi
负责处理发来的修改请求,但这个文件只是符号链接,它真正指向的文件是/bin/prog.cgi
。
// ...
fastcgi.server = (
"/HNAP1/" =>
((
"socket" => "/var/prog.fcgi.socket-0",
"check-local" => "enable",
"bin-path" => "/etc_ro/lighttpd/www/web/HNAP1/prog.fcgi",
"idle-timeout" => 10,
"min-procs" => 1,
"max-procs" => 2
)),
".fcgi" =>
((
"socket" => "/var/prog.fcgi.socket-0",
"check-local" => "enable",
"bin-path" => "/etc_ro/lighttpd/www/web/HNAP1/prog.fcgi",
"idle-timeout" => 10,
"min-procs" => 1,
"max-procs" => 2
)),
"/common/" =>
((
"socket" => "/var/myinfo.fcgi.socket-0",
"check-local" => "disable",
"bin-path" => "/sbin/myinfo.cgi",
"idle-timeout" => 10,
"min-procs" => 1,
"max-procs" => 1
))
)
// ...
默认情况下,用户向管理界面地址 http://[ROUTER]/HNAP1/
发送 SOAP 请求修改配置,最后由 prog.cgi
处理。
漏洞分析
当请求 SOAP endpoint 为SetVirtualServerSettings
时,prog.cgi
会调用函数 00461918
。函数遍历 SOAP XML 格式的请求正文,取得指定的 SOAP 字段值,不同的值对应不同路径。
如果请求中LocalIPAddress
非空,Enabled
为 “True”,InternalPort
为 “9” 而且 ProtocolType
是 “UDP” 的话,函数CheckArpTables
(作者命名,地址0046163c
)会被调用。
// ...snip
iVar5 = strcmp(Enabled,"true");
if ((((iVar5 == 0) && (LocalIPAddress != (char *)0x0)) &&
(iVar5 = strcmp(InternalPort,"9"), iVar5 == 0)) &&
(iVar5 = strcmp(ProtocolType,"UDP"), iVar5 == 0)) {
local_4154 = local_4154 + 1;
iVar5 = CheckArpTables(LocalIPAddress, InternalPort, ProtocolType, 0xdc, local_4154);
if (iVar5 == -1) {
local_4160 = 0xb;
goto LAB_00462504;
}
}
// ...snip
有趣的是,抛弃协议(Discard Protocol)中 UDP 端口也是 9 号端口。抛弃协议与 Unix 文件系统中的/dev/null
等价,会将接收到的数据直接抛弃。
看下面的代码,函数CheckArpTables()
执行系统命令 arp 后用 grep 命令搜索输出内容,检查设备中LocalIPAddress
的 ARP 记录。但是用户数据LocalIPAddress
传入后直接被snprint()
写到命令行格式化字符串里,拼接好又传送给了函数FCGI_popen()
。FCGI_popen()
是一个来自libfcgi.so
的库函数。
undefined CheckArpTables(char *LocalIPAddress, char *InternalPort, char *ProtocolType, undefined param_4, int param_5) {
// ...snip...
memset(buffer, 0, 0x40);
// ...snip...
snprintf(buffer, 0x40, "arp | grep %s | awk \'{printf $4}\'", LocalIPAddress);
iVar1 = FCGI_popen(buffer, "r");
// ...snip...
}
在libfcgi.so
里我们发现,FCGI_popen()
只是对 stdio 库函数popen()
做了一层简单的封装,传入的参数会被径直发给popen()
。
int FCGI_popen(char *param_1, char *param_2)
{
FILE *__stream;
int iVar1;
__stream = popen(param_1,param_2);
iVar1 = FCGI_OpenFromFILE(__stream);
if ((__stream != (FILE *)0x0) && (iVar1 == 0)) {
pclose(__stream);
}
return iVar1;
}
由于LocalIPAddress
的值没有经过任何处理或检查,当一条精心构造的字符串作为LocalIPAddress
的值传入时,会被直接写入到 arp 命令行,然后传给 popen()
。
关键点
在嵌入式开发领域,导入公共库函数通常要考虑到安全性,所以很多开发人员也会试着在公共库函数里加入更多安全的可替代函数。
但是这次 D-Link 没有做到安全开发。或许是为了让代码实现更加规范整洁,也可能是出于安全考虑,开发人员用函数FCGI_popen()
代替了popen()
。不过,在FCGI_popen()
实际代码里并没有额外的清理或检查步骤,所以也就没有什么安全价值可言。
一些读者可能对我们团队不怎么了解,我们对嵌入式设备固件进行自动化安全分析,在我们看来,以上做法值得认真研究。因为供应商会经常从函数库中导入这种替代函数,所以在我们对 ELF 可执行文件进行自动安全分析时,也必须考虑在 ELF 中都使用了哪些导入函数,以及这些函数中暴露的潜在危险程度,帮我们更有目的性地深入研究这些可执行文件,从而让自动化分析更快地识别出潜在安全问题。
披露时间表
2020-11-16:首次联系 ipsecure@dlinkcorp.com,请求加密密钥。
2020-11-20:未回复,再次发送邮件。
2020-11-27:未回复,发送未加密通知邮件。
2021-02-03:未回复,再次发送邮件。
2021-02-12:未回复,采用 support.dlink.com 和 eu.dlink.com/uk/en/contact-d-link 上的表格发送通知邮件。
2021-02-17:收到 USA D-Link 支持团队回复,让我们登录 US-specific D-Link security 页面。
2021-02-17:发送邮件给 US-specific D-Link security。
2021-02-19:收到 D-Link USA SIRT 成员的回复。
2021-02-19:向 USA D-Link 请求用于发送通知邮件的公钥。
2021-02-19:D-Link USA 提供 PGP 公钥 。
2021-02-19:发送加密后的通知邮件给 D-Link USA。
2021-02-19:D-Link USA SIRT 确认收到了通知邮件。
2021-02-19:我们回复要求 D-Link USA 向我们通报最新情况。
2021-02-20:D-Link 回复官方邮箱应该是 security@dlink.com,ipsecure@dlinkcorp.com 是一个备用邮箱。但是之前我们在 D-Link 安全告示页面找到的只有备用邮箱。
2021-02-22:D-Link USA 回复 D-Link 安全主页上的邮件地址已更改。
2021-03-02:我们向 D-Link USA 发送邮件,要求了解最新进展。
2021-03-02:D-Link USA 回复最新进展。
2021-03-08:D-Link USA 提供补丁固件进行测试。
2021-03-08:我们回复需要分配 CVE 编号。
2021-03-08:D-Link USA 回复他们并不负责申请或管理与其产品相关的 CVE 编号。
2021-03-08:我们为此次漏洞申请 CVE 编号。
2021-03-08:D-Link USA 发布 安全公告。
2021-03-11:CVE 编号申请成功, IoT Inspector Research Lab 发布公告。