apache / apache/carbondata

[SECURITY] Apache Security report one issue - in Apache CarbonData 2.3.2, unauthenticated Java deserialization RCE on the Distributed Index Server IPC endpoint (IndexInputFormat filter, no ObjectInputFilter)

Open
#4,399 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Scala
Stars
1.5k
Forks
694
PR merge metrics
No merged PRs in 30d

Description

The issue detail info as below :

Summary:
The Index Server is a Hadoop IPC service whose RPC methods take an IndexInputFormat argument:

// integration/spark/.../indexserver/IndexServer.scala
@ProtocolInfo(protocolName = "org.apache.carbondata.indexserver.ServerInterface", ...)
@KerberosInfo(...)
trait ServerInterface {
def getSplits(request: IndexInputFormat): ExtendedBlockletWrapperContainer
def getCount(request: IndexInputFormat): LongWritable
def getPrunedSegments(request: IndexInputFormat): SegmentWrapperContainer
}
val server = new RPC.Builder(conf).setInstance(this).setProtocol(classOf[ServerInterface]).build

IndexInputFormat is a Hadoop Writable, so IPC reconstructs the argument via readFields(DataInput), reading an attacker-controlled blob straight off the wire and deserializing it:

// core/.../index/IndexInputFormat.java:319-324 (readFields)
byte[] filterResolverBytes = new byte[in.readInt()];
in.readFully(filterResolverBytes, 0, filterResolverBytes.length);
this.filterResolverIntf = (FilterResolverIntf) ObjectSerializationUtil
.convertStringToObject(new String(filterResolverBytes, Charset.defaultCharset()));

// core/.../util/ObjectSerializationUtil.java:84-99 (the sink, no filter)
ois = new ClassLoaderObjectInputStream(Thread.currentThread().getContextClassLoader(), gis);
return ois.readObject(); // no ObjectInputFilter / allow-list

The cast to FilterResolverIntf happens after readObject() returns, so a gadget chain fires during deserialization. Any client that can reach the Index Server IPC port can send getSplits() with a crafted IndexInputFormat and trigger deserialization of arbitrary classes on the server JVM.

Authentication:
On a non-Kerberized cluster (SIMPLE Hadoop auth, the default) the endpoint is unauthenticated: the protocol is @KerberosInfo and the server registers an IndexServerPolicyProvider ACL via refreshServiceAcl, but that ACL is only enforced when hadoop.security.authorization=true, and in SIMPLE auth the remote identity (Server.getRemoteUser) is client-asserted/spoofable. Kerberized clusters with the ACL configured require valid Kerberos (an authenticated insider could still reach the sink). The Index Server is an opt-in feature (carbon.enable.index.server defaults to false).

Impact:
Remote Java-deserialization code execution on the Index Server JVM (runs in the Spark driver of the Index Cache Server, typically with cluster/service privileges). CarbonData runs on Spark + Hadoop, so deserialization gadget libraries are typically on the classpath, making this arbitrary command execution; without a code-exec gadget it is still a DoS / object-injection primitive. (CWE-502 Deserialization of Untrusted Data; CWE-306 in the default non-Kerberized deployment.)

Proof of concept:
A green harness that loads the real carbondata-core-2.3.2.jar and calls the real ObjectSerializationUtil.convertStringToObject(...) on an attacker-crafted string, an arbitrary class is instantiated and its readObject() executes, proving the sink has no ObjectInputFilter. Output: >>> GREEN: EvilGreen.readObject() executed during REAL CarbonData deser sink >>> CONFIRMED: unfiltered readObject on the real CarbonData sink executed attacker code.

Confirmation status:
The unfiltered-deserialization sink is executed live against the real release jar; the wire->sink reachability (IPC getSplits -> IndexInputFormat.readFields -> convertStringToObject) is traced in source. Not stood up end-to-end against a live Index Server; the live check is to start an Index Server on a SIMPLE-auth cluster and send getSplits with a ysoserial payload in filterResolverBytes.

Contributor guide

No contributing guide indexed for this repository

Research direction

Start with integration/spark/.../indexserver/IndexServer.scala, core/.../index/IndexInputFormat.java, and core/.../util/ObjectSerializationUtil.java; trace getSplits through readFields to convertStringToObject. Determine an approved mitigation for untrusted deserialization and SIMPLE-auth access, then verify the sink no longer accepts attacker-controlled objects and cover the path with a regression test.

Written by the indexing model from the issue text.

Assessment

Tech stack
hadoop, java, scala, spark
Domain
distributed-systems, security
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.