mirror of
https://github.com/github/codeql.git
synced 2026-04-29 18:55:14 +02:00
Added test cases with sanitizers for UnsafeDeserializationRmi.ql
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @name Unsafe remote object.
|
||||
* @name Unsafe deserialization in a remotely callable method.
|
||||
* @description If a registered remote object has a method that accepts a complex object,
|
||||
* an attacker can take advantage of the unsafe deserialization mechanism
|
||||
* which is used to pass parameters in RMI.
|
||||
@@ -31,7 +31,7 @@ private class BindMethod extends Method {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `type` has an unsafe remote method.
|
||||
* Holds if `type` has an vulnerable remote method.
|
||||
*/
|
||||
private predicate hasVulnerableMethod(RefType type) {
|
||||
exists(RemoteCallableMethod m, Type parameterType |
|
||||
@@ -57,13 +57,13 @@ private class BindingUnsafeRemoteObjectConfig extends TaintTracking::Configurati
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
exists(StaticMethodAccess ma | ma.getArgument(1) = sink.asExpr() |
|
||||
exists(MethodAccess ma | ma.getArgument(1) = sink.asExpr() |
|
||||
ma.getMethod() instanceof BindMethod
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||
exists(StaticMethodAccess ma, Method m | m = ma.getMethod() |
|
||||
exists(MethodAccess ma, Method m | m = ma.getMethod() |
|
||||
m.getDeclaringType().hasQualifiedName("java.rmi.server", "UnicastRemoteObject") and
|
||||
m.hasName("exportObject") and
|
||||
not ma.getArgument([2, 4])
|
||||
@@ -79,4 +79,4 @@ private class BindingUnsafeRemoteObjectConfig extends TaintTracking::Configurati
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, BindingUnsafeRemoteObjectConfig conf
|
||||
where conf.hasFlowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "Binding an unsafe remote object."
|
||||
select sink.getNode(), source, sink, "Unsafe deserialization in a remote object."
|
||||
|
||||
@@ -1,4 +1,15 @@
|
||||
| RmiUnsafeDeserialization.java:13:9:13:59 | bind(...) | Unsafe deserialization with RMI in '$@' method | RmiUnsafeDeserialization.java:42:17:42:20 | take | take(Object) |
|
||||
| RmiUnsafeDeserialization.java:14:9:14:61 | rebind(...) | Unsafe deserialization with RMI in '$@' method | RmiUnsafeDeserialization.java:42:17:42:20 | take | take(Object) |
|
||||
| RmiUnsafeDeserialization.java:26:9:26:57 | bind(...) | Unsafe deserialization with RMI in '$@' method | RmiUnsafeDeserialization.java:42:17:42:20 | take | take(Object) |
|
||||
| RmiUnsafeDeserialization.java:27:9:27:59 | rebind(...) | Unsafe deserialization with RMI in '$@' method | RmiUnsafeDeserialization.java:42:17:42:20 | take | take(Object) |
|
||||
edges
|
||||
| UnsafeDeserializationRmi.java:17:68:17:95 | new UnsafeRemoteObjectImpl(...) : UnsafeRemoteObjectImpl | UnsafeDeserializationRmi.java:17:35:17:96 | exportObject(...) |
|
||||
nodes
|
||||
| UnsafeDeserializationRmi.java:15:33:15:60 | new UnsafeRemoteObjectImpl(...) | semmle.label | new UnsafeRemoteObjectImpl(...) |
|
||||
| UnsafeDeserializationRmi.java:16:35:16:62 | new UnsafeRemoteObjectImpl(...) | semmle.label | new UnsafeRemoteObjectImpl(...) |
|
||||
| UnsafeDeserializationRmi.java:17:35:17:96 | exportObject(...) | semmle.label | exportObject(...) |
|
||||
| UnsafeDeserializationRmi.java:17:68:17:95 | new UnsafeRemoteObjectImpl(...) : UnsafeRemoteObjectImpl | semmle.label | new UnsafeRemoteObjectImpl(...) : UnsafeRemoteObjectImpl |
|
||||
| UnsafeDeserializationRmi.java:29:31:29:58 | new UnsafeRemoteObjectImpl(...) | semmle.label | new UnsafeRemoteObjectImpl(...) |
|
||||
| UnsafeDeserializationRmi.java:30:33:30:60 | new UnsafeRemoteObjectImpl(...) | semmle.label | new UnsafeRemoteObjectImpl(...) |
|
||||
#select
|
||||
| UnsafeDeserializationRmi.java:15:33:15:60 | new UnsafeRemoteObjectImpl(...) | UnsafeDeserializationRmi.java:15:33:15:60 | new UnsafeRemoteObjectImpl(...) | UnsafeDeserializationRmi.java:15:33:15:60 | new UnsafeRemoteObjectImpl(...) | Unsafe deserialization in a remote object. |
|
||||
| UnsafeDeserializationRmi.java:16:35:16:62 | new UnsafeRemoteObjectImpl(...) | UnsafeDeserializationRmi.java:16:35:16:62 | new UnsafeRemoteObjectImpl(...) | UnsafeDeserializationRmi.java:16:35:16:62 | new UnsafeRemoteObjectImpl(...) | Unsafe deserialization in a remote object. |
|
||||
| UnsafeDeserializationRmi.java:17:35:17:96 | exportObject(...) | UnsafeDeserializationRmi.java:17:68:17:95 | new UnsafeRemoteObjectImpl(...) : UnsafeRemoteObjectImpl | UnsafeDeserializationRmi.java:17:35:17:96 | exportObject(...) | Unsafe deserialization in a remote object. |
|
||||
| UnsafeDeserializationRmi.java:29:31:29:58 | new UnsafeRemoteObjectImpl(...) | UnsafeDeserializationRmi.java:29:31:29:58 | new UnsafeRemoteObjectImpl(...) | UnsafeDeserializationRmi.java:29:31:29:58 | new UnsafeRemoteObjectImpl(...) | Unsafe deserialization in a remote object. |
|
||||
| UnsafeDeserializationRmi.java:30:33:30:60 | new UnsafeRemoteObjectImpl(...) | UnsafeDeserializationRmi.java:30:33:30:60 | new UnsafeRemoteObjectImpl(...) | UnsafeDeserializationRmi.java:30:33:30:60 | new UnsafeRemoteObjectImpl(...) | Unsafe deserialization in a remote object. |
|
||||
|
||||
@@ -1,58 +1,73 @@
|
||||
import java.io.ObjectInputFilter;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.rmi.Naming;
|
||||
import java.rmi.Remote;
|
||||
import java.rmi.RemoteException;
|
||||
import java.rmi.registry.LocateRegistry;
|
||||
import java.rmi.registry.Registry;
|
||||
import java.rmi.server.UnicastRemoteObject;
|
||||
|
||||
public class UnsafeDeserializationRmi {
|
||||
|
||||
// BAD (bind a remote object that has a vulnerable method that takes Object)
|
||||
// BAD (bind a remote object that has a vulnerable method)
|
||||
public static void testRegistryBindWithObjectParameter() throws Exception {
|
||||
Registry registry = LocateRegistry.createRegistry(1099);
|
||||
registry.bind("test", new RemoteObjectWithObject());
|
||||
registry.rebind("test", new RemoteObjectWithObject());
|
||||
registry.bind("unsafe", new UnsafeRemoteObjectImpl());
|
||||
registry.rebind("unsafe", new UnsafeRemoteObjectImpl());
|
||||
registry.rebind("unsafe", UnicastRemoteObject.exportObject(new UnsafeRemoteObjectImpl()));
|
||||
}
|
||||
|
||||
// GOOD (bind a remote object that has methods that takes safe parameters)
|
||||
public static void testRegistryBindWithIntParameter() throws Exception {
|
||||
Registry registry = LocateRegistry.createRegistry(1099);
|
||||
registry.bind("test", new SafeRemoteObject());
|
||||
registry.rebind("test", new SafeRemoteObject());
|
||||
registry.bind("safe", new SafeRemoteObjectImpl());
|
||||
registry.rebind("safe", new SafeRemoteObjectImpl());
|
||||
}
|
||||
|
||||
// BAD (bind a remote object that has a vulnerable method that takes Object)
|
||||
// BAD (bind a remote object that has a vulnerable method)
|
||||
public static void testNamingBindWithObjectParameter() throws Exception {
|
||||
Naming.bind("test", new RemoteObjectWithObject());
|
||||
Naming.rebind("test", new RemoteObjectWithObject());
|
||||
Naming.bind("unsafe", new UnsafeRemoteObjectImpl());
|
||||
Naming.rebind("unsafe", new UnsafeRemoteObjectImpl());
|
||||
}
|
||||
|
||||
// GOOD (bind a remote object that has methods that takes safe parameters)
|
||||
public static void testNamingBindWithIntParameter() throws Exception {
|
||||
Naming.bind("test", new SafeRemoteObject());
|
||||
Naming.rebind("test", new SafeRemoteObject());
|
||||
Naming.bind("safe", new SafeRemoteObjectImpl());
|
||||
Naming.rebind("safe", new SafeRemoteObjectImpl());
|
||||
}
|
||||
|
||||
// GOOD (bind a remote object with a deserialization filter)
|
||||
public static void testRegistryBindWithDeserializationFilter() throws Exception {
|
||||
Registry registry = LocateRegistry.createRegistry(1099);
|
||||
ObjectInputFilter filter = info -> {
|
||||
if (info.serialClass().getCanonicalName().startsWith("com.safe.package.")) {
|
||||
return ObjectInputFilter.Status.ALLOWED;
|
||||
}
|
||||
return ObjectInputFilter.Status.REJECTED;
|
||||
};
|
||||
registry.rebind("safe", UnicastRemoteObject.exportObject(new UnsafeRemoteObjectImpl(), 12345, filter));
|
||||
}
|
||||
}
|
||||
|
||||
interface RemoteObjectWithObjectInterface extends Remote {
|
||||
interface UnsafeRemoteObject extends Remote {
|
||||
void take(Object obj) throws RemoteException;
|
||||
}
|
||||
|
||||
class RemoteObjectWithObject implements RemoteObjectWithObjectInterface {
|
||||
class UnsafeRemoteObjectImpl implements UnsafeRemoteObject {
|
||||
public void take(Object obj) throws RemoteException {}
|
||||
}
|
||||
|
||||
interface SafeRemoteObjectInterface extends Remote {
|
||||
interface SafeRemoteObject extends Remote {
|
||||
void take(int n) throws RemoteException;
|
||||
void take(double n) throws RemoteException;
|
||||
void take(String s) throws RemoteException;
|
||||
void take(ObjectInputStream ois) throws RemoteException;
|
||||
}
|
||||
|
||||
class SafeRemoteObject implements SafeRemoteObjectInterface {
|
||||
class SafeRemoteObjectImpl implements SafeRemoteObject {
|
||||
public void take(int n) throws RemoteException {}
|
||||
public void take(double n) throws RemoteException {}
|
||||
public void take(String s) throws RemoteException {}
|
||||
public void take(ObjectInputStream ois) throws RemoteException {}
|
||||
public void safeMethod(Object object) {} // this method is not declared in SafeRemoteObjectInterface
|
||||
public void safeMethod(Object object) {} // this method is not declared in SafeRemoteObject
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user