Removed fromSource() check in looksLikeResolveClassStep()

This commit is contained in:
Artem Smotrakov
2021-06-23 10:48:50 +02:00
parent c98f1a479e
commit 09ae779b21
63 changed files with 2 additions and 198 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,50 +0,0 @@
# Deserialization of user-controlled data
Deserializing untrusted data using any deserialization framework that allows the construction of arbitrary serializable objects is easily exploitable and in many cases allows an attacker to execute arbitrary code. Even before a deserialized object is returned to the caller of a deserialization method a lot of code may have been executed, including static initializers, constructors, and finalizers. Automatic deserialization of fields means that an attacker may craft a nested combination of objects on which the executed initialization code may have unforeseen effects, such as the execution of arbitrary code.
There are many different serialization frameworks. This query currently supports Kryo, XmlDecoder, XStream, SnakeYaml, Jackson and Java IO serialization through `ObjectInputStream`/`ObjectOutputStream`.
## Recommendation
Avoid deserialization of untrusted data if at all possible. If the architecture permits it then use other formats instead of serialized objects, for example JSON or XML. However, these formats should not be deserialized into complex objects because this provides further opportunities for attack. For example, XML-based deserialization attacks are possible through libraries such as XStream and XmlDecoder. Alternatively, a tightly controlled whitelist can limit the vulnerability of code, but be aware of the existence of so-called Bypass Gadgets, which can circumvent such protection measures.
## Example
The following example calls `readObject` directly on an `ObjectInputStream` that is constructed from untrusted data, and is therefore inherently unsafe.
```java
public MyObject {
public int field;
MyObject(int field) {
this.field = field;
}
}
public MyObject deserialize(Socket sock) {
try(ObjectInputStream in = new ObjectInputStream(sock.getInputStream())) {
return (MyObject)in.readObject(); // unsafe
}
}
```
Rewriting the communication protocol to only rely on reading primitive types from the input stream removes the vulnerability.
```java
public MyObject deserialize(Socket sock) {
try(DataInputStream in = new DataInputStream(sock.getInputStream())) {
return new MyObject(in.readInt());
}
}
```
## References
* OWASP vulnerability description: [Deserialization of untrusted data](https://www.owasp.org/index.php/Deserialization_of_untrusted_data).
* OWASP guidance on deserializing objects: [Deserialization Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html).
* Talks by Chris Frohoff & Gabriel Lawrence: [ AppSecCali 2015: Marshalling Pickles - how deserializing objects will ruin your day](http://frohoff.github.io/appseccali-marshalling-pickles/), [OWASP SD: Deserialize My Shorts: Or How I Learned to Start Worrying and Hate Java Object Deserialization](http://frohoff.github.io/owaspsd-deserialize-my-shorts/).
* Alvaro Muñoz & Christian Schneider, RSAConference 2016: [Serial Killer: Silently Pwning Your Java Endpoints](https://speakerdeck.com/pwntester/serial-killer-silently-pwning-your-java-endpoints).
* SnakeYaml documentation on deserialization: [SnakeYaml deserialization](https://bitbucket.org/asomov/snakeyaml/wiki/Documentation#markdown-header-loading-yaml).
* Research by Moritz Bechler: [Java Unmarshaller Security - Turning your data into code execution](https://www.github.com/mbechler/marshalsec/blob/master/marshalsec.pdf?raw=true)
* Blog posts by the developer of Jackson libraries: [On Jackson CVEs: Dont Panic — Here is what you need to know](https://cowtowncoder.medium.com/on-jackson-cves-dont-panic-here-is-what-you-need-to-know-54cd0d6e8062) [Jackson 2.10: Safe Default Typing](https://cowtowncoder.medium.com/jackson-2-10-safe-default-typing-2d018f0ce2ba)
* Common Weakness Enumeration: [CWE-502](https://cwe.mitre.org/data/definitions/502.html).

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,75 +0,0 @@
# Unsafe deserialization in a remotely callable method.
Java RMI uses the default Java serialization mechanism (in other words, `ObjectInputStream`) to pass parameters in remote method invocations. This mechanism is known to be unsafe when deserializing untrusted data. If a registered remote object has a method that accepts a complex object, an attacker can take advantage of the unsafe deserialization mechanism. In the worst case, it results in remote code execution.
## Recommendation
Use only strings and primitive types in parameters of remote objects.
Set a filter for incoming serialized data by wrapping remote objects using either `UnicastRemoteObject.exportObject(Remote, int, ObjectInputFilter)` or `UnicastRemoteObject.exportObject(Remote, int, RMIClientSocketFactory, RMIServerSocketFactory, ObjectInputFilter)` methods. Those methods accept an `ObjectInputFilter` that decides which classes are allowed for deserialization. The filter should allow deserializing only safe classes.
It is also possible to set a process-wide deserialization filter. The filter can be set by with `ObjectInputFilter.Config.setSerialFilter(ObjectInputFilter)` method, or by setting system or security property `jdk.serialFilter`. Make sure that you use the latest Java versions that include JEP 290. Please note that the query is not sensitive to this mitigation.
If switching to the latest Java versions is not possible, consider using other implementations of remote procedure calls. For example, HTTP API with JSON. Make sure that the underlying deserialization mechanism is properly configured so that deserialization attacks are not possible.
## Example
The following code registers a remote object with a vulnerable method that accepts a complex object:
```java
public class Server {
public void bindRemoteObject(Registry registry) throws Exception {
registry.bind("unsafe", new RemoteObjectImpl());
}
}
interface RemoteObject extends Remote {
void action(Object obj) throws RemoteException;
}
class RemoteObjectImpl implements RemoteObject {
// ...
}
```
The next example registers a safe remote object whose methods use only primitive types and strings:
```java
public class Server {
public void bindRemoteObject(Registry registry) throws Exception {
registry.bind("safe", new RemoteObjectImpl());
}
}
interface RemoteObject extends Remote {
void calculate(int a, double b) throws RemoteException;
void save(String s) throws RemoteException;
}
class RemoteObjectImpl implements RemoteObject {
// ...
}
```
The next example shows how to set a deserilization filter for a remote object:
```java
public void bindRemoteObject(Registry registry, int port) throws Exception {
ObjectInputFilter filter = info -> {
if (info.serialClass().getCanonicalName().startsWith("com.safe.package.")) {
return ObjectInputFilter.Status.ALLOWED;
}
return ObjectInputFilter.Status.REJECTED;
};
registry.bind("safer", UnicastRemoteObject.exportObject(new RemoteObjectImpl(), port, filter));
}
```
## References
* Oracle: [Remote Method Invocation (RMI)](https://www.oracle.com/java/technologies/javase/remote-method-invocation-home.html).
* ITNEXT: [Java RMI for pentesters part two - reconnaissance & attack against non-JMX registries](https://itnext.io/java-rmi-for-pentesters-part-two-reconnaissance-attack-against-non-jmx-registries-187a6561314d).
* MOGWAI LABS: [Attacking Java RMI services after JEP 290](https://mogwailabs.de/en/blog/2019/03/attacking-java-rmi-services-after-jep-290)
* OWASP: [Deserialization of untrusted data](https://www.owasp.org/index.php/Deserialization_of_untrusted_data).
* OpenJDK: [JEP 290: Filter Incoming Serialization Data](https://openjdk.java.net/jeps/290)
* Common Weakness Enumeration: [CWE-502](https://cwe.mitre.org/data/definitions/502.html).

View File

@@ -76,7 +76,6 @@ SnakeYaml documentation on deserialization:
<a href="https://bitbucket.org/asomov/snakeyaml/wiki/Documentation#markdown-header-loading-yaml">SnakeYaml deserialization</a>.
</li>
<li>
<<<<<<< HEAD
Hessian deserialization and related gadget chains:
<a href="https://paper.seebug.org/1137/">Hessian deserialization</a>.
</li>
@@ -91,7 +90,8 @@ Remote code execution in JYaml library:
<li>
JsonIO deserialization vulnerabilities:
<a href="https://klezvirus.github.io/Advanced-Web-Hacking/Serialisation/">JsonIO deserialization</a>.
=======
</li>
<li>
Research by Moritz Bechler:
<a href="https://www.github.com/mbechler/marshalsec/blob/master/marshalsec.pdf?raw=true">Java Unmarshaller Security - Turning your data into code execution</a>
</li>
@@ -99,7 +99,6 @@ Research by Moritz Bechler:
Blog posts by the developer of Jackson libraries:
<a href="https://cowtowncoder.medium.com/on-jackson-cves-dont-panic-here-is-what-you-need-to-know-54cd0d6e8062">On Jackson CVEs: Dont Panic — Here is what you need to know</a>
<a href="https://cowtowncoder.medium.com/jackson-2-10-safe-default-typing-2d018f0ce2ba">Jackson 2.10: Safe Default Typing</a>
>>>>>>> Added Jackson to UnsafeDeserialization.qhelp
</li>
</references>

View File

@@ -1,28 +0,0 @@
---
sourceLocationPrefix: "/media/i504100/Artem_Flash_1T/codeql-bounties/codeql-repo/java/ql/src"
unicodeNewlines: false
columnKind: "utf16"
primaryLanguage: "java"
inProgress:
primaryLanguage: "java"
installedExtractors:
cpp:
- "file:///media/i504100/Artem_Flash_1T/codeql-bounties/codeql-cli/cpp/"
csharp:
- "file:///media/i504100/Artem_Flash_1T/codeql-bounties/codeql-cli/csharp/"
csv:
- "file:///media/i504100/Artem_Flash_1T/codeql-bounties/codeql-cli/csv/"
go:
- "file:///media/i504100/Artem_Flash_1T/codeql-bounties/codeql-cli/go/"
html:
- "file:///media/i504100/Artem_Flash_1T/codeql-bounties/codeql-cli/html/"
java:
- "file:///media/i504100/Artem_Flash_1T/codeql-bounties/codeql-cli/java/"
javascript:
- "file:///media/i504100/Artem_Flash_1T/codeql-bounties/codeql-cli/javascript/"
properties:
- "file:///media/i504100/Artem_Flash_1T/codeql-bounties/codeql-cli/properties/"
python:
- "file:///media/i504100/Artem_Flash_1T/codeql-bounties/codeql-cli/python/"
xml:
- "file:///media/i504100/Artem_Flash_1T/codeql-bounties/codeql-cli/xml/"

View File

@@ -1 +0,0 @@
[2021-06-14 08:53:54] [javac-extractor-9926] [ERROR] 10 errors were reported by javac.

View File

@@ -1,9 +0,0 @@
[2021-06-14 08:53:53] [javac-extractor-9926] Starting extraction for:
sun.java.command=com.semmle.extractor.java.JavaExtractor --javacOptions -source 8 --strict-javac-errors --encoding UTF-8 --files SafeMacComparison.java UnsafeMacComparison.java
user.dir=/media/i504100/Artem_Flash_1T/codeql-bounties/codeql-repo/java/ql/src/experimental/Security/CWE/CWE-208
[2021-06-14 08:53:54] [javac-extractor-9926] Javac init time: 0.6s
[2021-06-14 08:53:54] [javac-extractor-9926] Javac attr time: 0.0s
[2021-06-14 08:53:54] [javac-extractor-9926] Extractor time: 0.0s
[2021-06-14 08:53:54] [javac-extractor-9926] Other time: 0.2s
[2021-06-14 08:53:54] [javac-extractor-9926] Total time: 0.7s
[2021-06-14 08:53:54] [javac-extractor-9926] [ERROR] 10 errors were reported by javac.

View File

@@ -1,31 +0,0 @@
[2021-06-14 08:53:53] [javac-output-9926] warning: [options] bootstrap class path not set in conjunction with -source 8
[2021-06-14 08:53:53] [javac-output-9926] SafeMacComparison.java:1: error: class, interface, or enum expected
[2021-06-14 08:53:53] [javac-output-9926] public boolean check(byte[] expected, byte[] data, SecretKey key) throws Exception {
[2021-06-14 08:53:53] [javac-output-9926] ^
[2021-06-14 08:53:53] [javac-output-9926] SafeMacComparison.java:3: error: class, interface, or enum expected
[2021-06-14 08:53:53] [javac-output-9926] mac.init(new SecretKeySpec(key.getEncoded(), "HmacSHA256"));
[2021-06-14 08:53:53] [javac-output-9926] ^
[2021-06-14 08:53:53] [javac-output-9926] SafeMacComparison.java:4: error: class, interface, or enum expected
[2021-06-14 08:53:53] [javac-output-9926] byte[] actual = mac.doFinal(data);
[2021-06-14 08:53:53] [javac-output-9926] ^
[2021-06-14 08:53:53] [javac-output-9926] SafeMacComparison.java:5: error: class, interface, or enum expected
[2021-06-14 08:53:53] [javac-output-9926] return MessageDigest.isEqual(expected, actual);
[2021-06-14 08:53:53] [javac-output-9926] ^
[2021-06-14 08:53:53] [javac-output-9926] SafeMacComparison.java:6: error: class, interface, or enum expected
[2021-06-14 08:53:53] [javac-output-9926] }
[2021-06-14 08:53:53] [javac-output-9926] ^
[2021-06-14 08:53:53] [javac-output-9926] UnsafeMacComparison.java:1: error: class, interface, or enum expected
[2021-06-14 08:53:53] [javac-output-9926] public boolean check(byte[] expected, byte[] data, SecretKey key) throws Exception {
[2021-06-14 08:53:53] [javac-output-9926] ^
[2021-06-14 08:53:53] [javac-output-9926] UnsafeMacComparison.java:3: error: class, interface, or enum expected
[2021-06-14 08:53:53] [javac-output-9926] mac.init(new SecretKeySpec(key.getEncoded(), "HmacSHA256"));
[2021-06-14 08:53:53] [javac-output-9926] ^
[2021-06-14 08:53:53] [javac-output-9926] UnsafeMacComparison.java:4: error: class, interface, or enum expected
[2021-06-14 08:53:53] [javac-output-9926] byte[] actual = mac.doFinal(data);
[2021-06-14 08:53:53] [javac-output-9926] ^
[2021-06-14 08:53:53] [javac-output-9926] UnsafeMacComparison.java:5: error: class, interface, or enum expected
[2021-06-14 08:53:53] [javac-output-9926] return Arrays.equals(expected, actual);
[2021-06-14 08:53:53] [javac-output-9926] ^
[2021-06-14 08:53:53] [javac-output-9926] UnsafeMacComparison.java:6: error: class, interface, or enum expected
[2021-06-14 08:53:53] [javac-output-9926] }
[2021-06-14 08:53:53] [javac-output-9926] ^

View File

@@ -281,7 +281,6 @@ private predicate looksLikeResolveClassStep(DataFlow::Node fromNode, DataFlow::N
|
m.getReturnType() instanceof JacksonTypeDescriptorType and
m.getName().toLowerCase().regexpMatch("resolve|load|class|type") and
m.fromSource() and
arg.getType() instanceof TypeString and
arg = fromNode.asExpr() and
ma = toNode.asExpr()