Skip to content

Latest commit

 

History

History
219 lines (172 loc) · 12 KB

Adobe_ColdFusion_WDDX_Serialization_Vulnerability_Exploitation_en_US.md

File metadata and controls

219 lines (172 loc) · 12 KB

Summary

In our previous article on the Adobe ColdFusion Serialization Vulnerability (CVE-2023-29300), we reproduced the published JNDI exploit chain (CVE-2023-38204). The JNDI utilization chain is restricted by the target's access to the network, and cannot be used well without going out of the network. In this article, we will share the exploitation methods that cannot go out of the network, and propose two new exploitation chains based on service error deployment, C3P0 and JGroups. After testing, C3P0 may be exploited, and the JGroups exploitation success rate is 0.1%. Although the probability of being successfully exploited is low, we have also realized the complete utilization of C3P0 and JGroups exploit chains in Goby, fully supporting command execution and result echo functions.

Apache Felix

ColdFusion calls the BundleClassLoader#loadClass() method through its own implementation of FelixClassloader, which is used to start and disable a plug-in downloaded by a service called Package Manager in the background, and dynamically load various Jar packages under the bundles folder. We can see that there are many more fields in the MANIFEST files of these Jar packages:

Manifest-Version: 1.0
Bnd-LastModified: 1490514990031
Build-Jdk: 1.8.0_111
Built-By: uriel
Bundle-Description: Java reflect give poor performance on getter sette
 r an constructor calls, accessors-smart use ASM to speed up those cal
 ls.
Bundle-DocURL: http://www.minidev.net/
Bundle-License: http://www.apache.org/licenses/LICENSE-2.0.txt
Bundle-ManifestVersion: 2
Bundle-Name: accessors-smart
Bundle-SymbolicName: net.minidev.accessors-smart
Bundle-Vendor: Chemouni Uriel
Bundle-Version: 1.2
Created-By: Apache Maven Bundle Plugin
Export-Package: net.minidev.asm;version="1.2.0";uses:="org.objectweb.a
 sm",net.minidev.asm.ex;version="1.2.0"
Import-Package: net.minidev.asm.ex;version="[1.2,2)",org.objectweb.asm
 ;version="[5.0,6)"
Tool: Bnd-3.3.0.201609221906

Search shows that Apache Felix is ​​an open source implementation framework of OSGi (Open Service Gateway Initiative, Open Service Gateway Protocol). By adding metadata to the Jar package to define which classes are exposed and which classes are hidden, the modularization of dependencies and its control are achieved. The unit is called a bundle. The most important of them are the two fields Export-Package and Import-Package, which are used to tell OSGi which classes it provides to the outside world and which classes it references from other packages. Without these two fields, OSGi or its implementation Felix will not work properly.

Construct exploit chain

Felix ClassLoader

During the process of WDDX serialization, ColdFusion will call BundleClassLoader to load the target class. The implemented findClass() method is as follows:

protected Class findClass(String name) throws ClassNotFoundException {
    Class clazz = this.findLoadedClass(name);
    if (clazz == null) {
        // ...

        String actual = name.replace('.', '/') + ".class";
        byte[] bytes = null;
        List<Content> contentPath = this.m_wiring.m_revision.getContentPath();
        Content content = null;

        for(int i = 0; bytes == null && i < contentPath.size(); ++i) {
            bytes = ((Content)contentPath.get(i)).getEntryAsBytes(actual);
            content = (Content)contentPath.get(i);
        }

        if (bytes != null) {
            String pkgName = Util.getClassPackage(name);
            Felix felix = this.m_wiring.m_revision.getBundle().getFramework();
            Set<ServiceReference<WeavingHook>> hooks = felix.getHookRegistry().getHooks(WeavingHook.class);
            Set<ServiceReference<WovenClassListener>> wovenClassListeners = felix.getHookRegistry().getHooks(WovenClassListener.class);
            WovenClassImpl wci = null;
            // ...

            try {
                clazz = this.isParallel() ? this.defineClassParallel(name, felix, wovenClassListeners, wci, bytes, content, pkgName) : this.defineClassNotParallel(name, felix, wovenClassListeners, wci, bytes, content, pkgName);
            } catch (ClassFormatError var17) {
                // ...
            }

            // ...
        }
    }

    return clazz;
}

Here, the fully qualified class name will be converted to a relative file path. If javax.sql.ConnectionPoolDataSource is passed in, it will try to read the bytecode in the relative path javax/sql/ConnectionPoolDataSource.class file, and then Go to the defineClassParallel() method and call defineClass(). Due to this special class loading mode, even if ConnectionPoolDataSource is stored in rt.jar, NoClassDefFoundError will be thrown because the class file cannot be located.

java.lang.NoClassDefFoundError: javax/sql/ConnectionPoolDataSource
	at java.lang.ClassLoader.defineClass1(Native Method)
	at java.lang.ClassLoader.defineClass(ClassLoader.java:760)
	at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.defineClass(BundleWiringImpl.java:2338)
	at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.defineClassParallel(BundleWiringImpl.java:2156)
	at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.findClass(BundleWiringImpl.java:2090)
	at org.apache.felix.framework.BundleWiringImpl.findClassOrResourceByDelegation(BundleWiringImpl.java:1556)
	at org.apache.felix.framework.BundleWiringImpl.access$300(BundleWiringImpl.java:79)
	at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.loadClass(BundleWiringImpl.java:1976)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
...

However, there is another possibility. If the target class has been loaded in advance, ClassLoader#findLoadedClass() will directly return the target class and will not enter the branch that throws the error. So will someone take an unusual approach when deploying services and concentrate all the dependency packages that were originally scattered everywhere into a custom lib? In line with the principle of following objective facts, we conducted an exploit test, and the results showed that there are indeed targets that can be exploited:

image.png image.png

Without exception, these targets manually changed the service's dependency package path. Rather than using the Package Manager service, they prefer to manually manage dependencies themselves, which will also bypass the dependency loading mechanism of BundleClassLoader, leaving us with considerable room for operation.

C3P0

With WrapperConnectionPoolDataSourceBase#setUserOverridesAsString() method as the entry point, the call chain constructed is as follows, and finally the incoming bytes are decoded and native deserialization is called.

WddxDeserializer
	-> deserialize()

...

WrapperConnectionPoolDataSourceBase
	-> setUserOverridesAsString()

VetoableChangeSupport
	-> fireVetoableChange()

VetoableChangeListener
	-> vetoableChange()

C3P0ImplUtils
	-> parseUserOverridesAsString()

SerializableUtils
	-> fromByteArray()
	-> deserializeFromByteArray()

ObjectInputStream
	-> readObject()

The parseUserOverridesAsString() method will intercept and Hex-decode the incoming byte stream, so we need to fill in the placeholders and encode accordingly when constructing a native serialized stream.

    public static Map parseUserOverridesAsString(String userOverridesAsString) throws IOException, ClassNotFoundException {
        if (userOverridesAsString != null) {
            String hexAscii = userOverridesAsString.substring("HexAsciiSerializedMap".length() + 1, userOverridesAsString.length() - 1);
            byte[] serBytes = ByteUtils.fromHexAscii(hexAscii);
            return Collections.unmodifiableMap((Map)SerializableUtils.fromByteArray(serBytes));
        }
        // ...
    }

5db20be14d804ed14721d4d90a25560c-1996400489_图片.gif

JGroups

Similar to C3P0, the ReplicatedTree#setState() method of JGroups accepts a byte array parameter and calls native deserialization. The utilization chain is as follows.

WddxDeserializer
	-> deserialize()

...

ReplicatedTree
	-> setState()

Util
	-> objectFromByteBuffer()
	-> oldObjectFromByteBuffer()

ObjectInputStream
	-> readObject()

Since the parameter received by the setState() method is not a basic type, we need to use the <binary> tag to trigger BinaryHandler to pass in the byte array and perform base64 encoding.

public void onEndElement() throws WddxDeserializationException {
	this.setValue(Base64Encoder.decode(this.m_buffer.toString()));
	this.setType(-3, "VARBINARY");
}

The objectFromByteBuffer() method will call different readObject() according to the first byte passed in, so a 0x2 needs to be added at the beginning when constructing a native serialization stream.

public static Object objectFromByteBuffer(byte[] buffer, int offset, int length) throws Exception {
    // ...
    ByteArrayInputStream in_stream = new ByteArrayInputStream(buffer, offset, length);
    byte b = (byte)in_stream.read();
    // ...
    try {
        ObjectInputStream ois;
        switch (b) {
            // ...
            case 2:
                in = new ObjectInputStream(in_stream);
                retval = ((ObjectInputStream)in).readObject();
                break;
            // ...
        }
        // ...
    }
    // ...
}

aaa.jpg_a5b5e3b901682635665925c370e2e751_-696553035_图片(1).gif

Summarize

By digging deeper into the exploitation method of CVE-2023-29300, we found out more details of the product, such as the class loading mechanism of BundleClassLoader, and finally proposed two exploitation chains that do not go online: C3P0 and JGroups. Although it cannot be successfully exploited in the default deployment environment, and we did not believe that someone would manually break the dependency management mechanism at first, the fact is that someone always breaks the rules, and this also allows attackers to take advantage of it. I hope that after reading this article, I can bring you some inspiration for new ideas.

Reference link

https://helpx.adobe.com/security.html

https://felix.apache.org/documentation/index.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