QNAP QSA-22-15 : PhotoStation - Application Privileges Checking Bypass

CVE 2021-44057 QNAP QSA-22-15

QTS vQTS PhotoStation 6.0.19

Timeline (DD/MM/YYYY)

CVE-2021-44057 - Application Privileges Checking Bypass

A Simple user with no privileges can access a few applications by bypassing the privilege checking system. The behavior occurs at least on Video Station and Photo Station, but other applications may be impacted.

The following exploitation show how to bypass privilege checking for the VideoStation application.


We need to create a user without any privileges to exploit the vulnerability.



First, we can try to connect on Video Station with the “dummy user


Here, the privilege checking denies access.

Then, we can try to get a valid “NAS_SID” for this user by connecting to the QTS dashboard.


Once connected, we got a valid “NAS_SID” and can try to access Video Station by using this token.


The application access is still denied.

During the authentication process with this kind of token. A request is done on the “/cgi-bin/authLogin.cgi” endpoint. Some parameters are added to this request :

//File: /api/user.php
$auth_by = 'qts';
$baseURL = "$protocol://".$port."/cgi-bin/authLogin.cgi?sid=".$NAS_SID;
$loginURL = $baseURL."&service=101&remote_ip=".$SESSION->ip;

The variable “$NAS_SID” is defined by using this code :

if (isset($_COOKIE['NAS_SID']) || isset($_COOKIE['QTS_SSID']) || isset($_COOKIE['QTS_SSL_SSID'])) {
	if (empty($_SERVER['HTTPS'])) {
	} else { //https connection
} else {
	$NAS_SID = '';

The function “simplexml_load_file” load an XML document at the provided URL. The “NAS_SID” is the first parameter and can be used to comment on all next parameters. The privilege checking parameter is the last.

Thus, to bypass the security, we can use the character “#” at the end of our “NAS_ID” token. The URL will be the following:

All parameters after the “#” will be ignored and the final authentication URL is :


We can now use the Video Station application as usual.



To fix this issue, the function “rawurlencode” can be used to sanitize the input while using in concatenation with the URL. The fix should be applied to each location where “$NAS_SID” is concatenated to an URL.

//File: api/libs/inc_common.php
if(!$IS_LOGIN && empty($SID) && !empty($NAS_SID)){
			//try to validate with NAS SID
			$port = exec('/bin/cat /var/lock/._thttpd_.port');
			$baseURL = "".$port."/cgi-bin/authLogin.cgi?sid=".rawurlencode($NAS_SID)."&service=103&remote_ip=".getClientIP();
			if($_SESSION['NASVARS']['application_privilege'] == 'TRUE')
				$loginURL = $baseURL."&check_privilege=VIDEO_STATION";

			$xml = simplexml_load_file($loginURL);
// File: api/libs/user.php
}else if(!empty($NAS_SID)) {


					$auth_by = 'qts';
					$baseURL = "$protocol://".$port."/cgi-bin/authLogin.cgi?sid=".rawurlencode($NAS_SID);
					$loginURL = $baseURL."&service=103&remote_ip=".getClientIP();
					$auth_by = 'nobody';
					$loginURL = "";