CVE-2024-23683 (Java, published 2024-01-19T21:15Z)
Description: value: Artemis Java Test Sandbox versions less than 1.7.6 are vulnerable to a sandbox escape when an attacker crafts a special subclass of InvocationTargetException. An attacker can abuse this issue to execute arbitrary Java when a victim executes the supposedly sandboxed code.






Severity: nan (CVSS v3 base score: 8.2)
Weakness: NVD-CWE-noinfo \u2014 Insufficient Information
There is insufficient information about the issue to classify it; details are unkown or unspecified.
Repository: https://github.com/ls1intum/Ares
Files changed:
src/main/java/de/tum/in/test/api/security/ArtemisSecurityManager.java
src/main/java/de/tum/in/test/api/security/SecurityConstants.java
src/test/java/de/tum/in/test/api/SecurityTest.java
src/test/java/de/tum/in/testuser/SecurityUser.java
src/test/java/de/tum/in/testuser/subject/SecurityPenguin.java
src/test/java/org/apache/xyz/MaliciousInvocationTargetException.java
Commit message: Merge pull request from GHSA-883x-6fch-6wjx

* Blacklist ReflectionUtils.getUnderlyingCause as it is in the invocation

This means that trusted classes are no longer have a fully whitelisted
stack when the cause is fetched and exception methods are invoked.

* Allow security manager to work with method names when checking the stack

* Add security test for a malicious InvocationTargetException

A variant of the exploit found by Daniel, related to GHSA-883x-6fch-6wjx

Co-authored-by: Daniel Kirschten <melodicahaspa@gmail.com>
Co-authored-by: Christian Femers <c.femers@tum.de>

Co-authored-by: Daniel Kirschten <melodicahaspa@gmail.com>

Vulnerable code:
	private boolean isCallNotWhitelisted(String call) {
						&& (configuration == null || !(configuration.whitelistedClassNames().contains(call)
								|| configuration.trustedPackages().stream().anyMatch(pm -> pm.matches(call)))));
		return isCallNotWhitelisted(sf.getClassName());
		return isCallNotWhitelisted(ste.getClassName());
	static final Set<String> STACK_BLACKLIST = Set.of(BlacklistedInvoker.class.getName());

Fixed code:
	private boolean isCallNotWhitelisted(String className, String methodName) {
		String call = className + "." + methodName; //$NON-NLS-1$
						&& (configuration == null || !(configuration.whitelistedClassNames().contains(className)
								|| configuration.trustedPackages().stream().anyMatch(pm -> pm.matches(className)))));
		return isCallNotWhitelisted(sf.getClassName(), sf.getMethodName());
		return isCallNotWhitelisted(ste.getClassName(), ste.getMethodName());
	static final Set<String> STACK_BLACKLIST = Set.of(BlacklistedInvoker.class.getName(),
			"org.junit.platform.commons.util.ReflectionUtils.getUnderlyingCause"); //$NON-NLS-1$
	private final String testMaliciousInvocationTargetException = "testMaliciousInvocationTargetException";
	@TestTest
	void test_testMaliciousInvocationTargetException() {
		tests.assertThatEvents().haveExactly(1,
				testFailedWith(testMaliciousInvocationTargetException, SecurityException.class));
	}

	@Test
	void testMaliciousInvocationTargetException() throws Exception {
		SecurityPenguin.maliciousInvocationTargetException();
	}

import org.apache.xyz.MaliciousInvocationTargetException;
	public static void maliciousInvocationTargetException() throws Exception {
		throw new MaliciousInvocationTargetException();
	}

package org.apache.xyz;

import java.io.IOException;
import java.io.UncheckedIOException;
import java.lang.reflect.InvocationTargetException;
import java.nio.file.Files;
import java.nio.file.Path;

public class MaliciousInvocationTargetException extends InvocationTargetException {

	private static final long serialVersionUID = 1L;

	@Override
	public Throwable getTargetException() {
		try {
			Files.readString(Path.of("pom.xml"));
		} catch (IOException e) {
			throw new UncheckedIOException(e);
		}
		return new Error("succeeded");
	}
}