mirror of
https://github.com/github/codeql.git
synced 2025-12-24 04:36:35 +01:00
Merge pull request #5881 from haby0/java/UnsafeDeserialization
Java: CWE-502 Add UnsafeDeserialization sinks
This commit is contained in:
@@ -14,8 +14,8 @@ may have unforeseen effects, such as the execution of arbitrary code.
|
||||
</p>
|
||||
<p>
|
||||
There are many different serialization frameworks. This query currently
|
||||
supports Kryo, XmlDecoder, XStream, SnakeYaml, and Java IO serialization through
|
||||
<code>ObjectInputStream</code>/<code>ObjectOutputStream</code>.
|
||||
supports Kryo, XmlDecoder, XStream, SnakeYaml, JYaml, JsonIO, YAMLBeans, HessianBurlap, Castor, Burlap
|
||||
and Java IO serialization through <code>ObjectInputStream</code>/<code>ObjectOutputStream</code>.
|
||||
</p>
|
||||
</overview>
|
||||
|
||||
@@ -75,6 +75,22 @@ Alvaro Muñoz & Christian Schneider, RSAConference 2016:
|
||||
SnakeYaml documentation on deserialization:
|
||||
<a href="https://bitbucket.org/asomov/snakeyaml/wiki/Documentation#markdown-header-loading-yaml">SnakeYaml deserialization</a>.
|
||||
</li>
|
||||
<li>
|
||||
Hessian deserialization and related gadget chains:
|
||||
<a href="https://paper.seebug.org/1137/">Hessian deserialization</a>.
|
||||
</li>
|
||||
<li>
|
||||
Castor and Hessian java deserialization vulnerabilities:
|
||||
<a href="https://securitylab.github.com/research/hessian-java-deserialization-castor-vulnerabilities/">Castor and Hessian deserialization</a>.
|
||||
</li>
|
||||
<li>
|
||||
Remote code execution in JYaml library:
|
||||
<a href="https://www.cybersecurity-help.cz/vdb/SB2020022512">JYaml deserialization</a>.
|
||||
</li>
|
||||
<li>
|
||||
JsonIO deserialization vulnerabilities:
|
||||
<a href="https://klezvirus.github.io/Advanced-Web-Hacking/Serialisation/">JsonIO deserialization</a>.
|
||||
</li>
|
||||
</references>
|
||||
|
||||
</qhelp>
|
||||
|
||||
@@ -22,6 +22,39 @@ class UnsafeDeserializationConfig extends TaintTracking::Configuration {
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof UnsafeDeserializationSink }
|
||||
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(ClassInstanceExpr cie |
|
||||
cie.getArgument(0) = pred.asExpr() and
|
||||
cie = succ.asExpr() and
|
||||
(
|
||||
cie.getConstructor().getDeclaringType() instanceof JsonIoJsonReader or
|
||||
cie.getConstructor().getDeclaringType() instanceof YamlBeansReader or
|
||||
cie.getConstructor().getDeclaringType().getASupertype*() instanceof UnsafeHessianInput or
|
||||
cie.getConstructor().getDeclaringType() instanceof BurlapInput
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(MethodAccess ma |
|
||||
ma.getMethod() instanceof BurlapInputInitMethod and
|
||||
ma.getArgument(0) = pred.asExpr() and
|
||||
ma.getQualifier() = succ.asExpr()
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
exists(ClassInstanceExpr cie |
|
||||
cie.getConstructor().getDeclaringType() instanceof JsonIoJsonReader and
|
||||
cie = node.asExpr() and
|
||||
exists(SafeJsonIoConfig sji | sji.hasFlowToExpr(cie.getArgument(1)))
|
||||
)
|
||||
or
|
||||
exists(MethodAccess ma |
|
||||
ma.getMethod() instanceof JsonIoJsonToJavaMethod and
|
||||
ma.getArgument(0) = node.asExpr() and
|
||||
exists(SafeJsonIoConfig sji | sji.hasFlowToExpr(ma.getArgument(1)))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, UnsafeDeserializationConfig conf
|
||||
|
||||
20
java/ql/src/semmle/code/java/frameworks/Castor.qll
Normal file
20
java/ql/src/semmle/code/java/frameworks/Castor.qll
Normal file
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* Provides classes and predicates for working with the Castor framework.
|
||||
*/
|
||||
|
||||
import java
|
||||
|
||||
/**
|
||||
* The class `org.exolab.castor.xml.Unmarshaller`.
|
||||
*/
|
||||
class CastorUnmarshaller extends RefType {
|
||||
CastorUnmarshaller() { this.hasQualifiedName("org.exolab.castor.xml", "Unmarshaller") }
|
||||
}
|
||||
|
||||
/** A method with the name `unmarshal` declared in `org.exolab.castor.xml.Unmarshaller`. */
|
||||
class CastorUnmarshalMethod extends Method {
|
||||
CastorUnmarshalMethod() {
|
||||
this.getDeclaringType() instanceof CastorUnmarshaller and
|
||||
this.getName() = "unmarshal"
|
||||
}
|
||||
}
|
||||
49
java/ql/src/semmle/code/java/frameworks/HessianBurlap.qll
Normal file
49
java/ql/src/semmle/code/java/frameworks/HessianBurlap.qll
Normal file
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* Provides classes and predicates for working with the HessianBurlap framework.
|
||||
*/
|
||||
|
||||
import java
|
||||
|
||||
/**
|
||||
* The classes `[com.alibaba.]com.caucho.hessian.io.AbstractHessianInput` or `[com.alibaba.]com.caucho.hessian.io.Hessian2StreamingInput`.
|
||||
*/
|
||||
class UnsafeHessianInput extends RefType {
|
||||
UnsafeHessianInput() {
|
||||
this.hasQualifiedName(["com.caucho.hessian.io", "com.alibaba.com.caucho.hessian.io"],
|
||||
["AbstractHessianInput", "Hessian2StreamingInput"])
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A AbstractHessianInput or Hessian2StreamingInput subclass readObject method.
|
||||
* This is either `AbstractHessianInput.readObject` or `Hessian2StreamingInput.readObject`.
|
||||
*/
|
||||
class UnsafeHessianInputReadObjectMethod extends Method {
|
||||
UnsafeHessianInputReadObjectMethod() {
|
||||
this.getDeclaringType().getASupertype*() instanceof UnsafeHessianInput and
|
||||
this.getName() = "readObject"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The class `com.caucho.burlap.io.BurlapInput`.
|
||||
*/
|
||||
class BurlapInput extends RefType {
|
||||
BurlapInput() { this.hasQualifiedName("com.caucho.burlap.io", "BurlapInput") }
|
||||
}
|
||||
|
||||
/** A method with the name `readObject` declared in `com.caucho.burlap.io.BurlapInput`. */
|
||||
class BurlapInputReadObjectMethod extends Method {
|
||||
BurlapInputReadObjectMethod() {
|
||||
this.getDeclaringType() instanceof BurlapInput and
|
||||
this.getName() = "readObject"
|
||||
}
|
||||
}
|
||||
|
||||
/** A method with the name `init` declared in `com.caucho.burlap.io.BurlapInput`. */
|
||||
class BurlapInputInitMethod extends Method {
|
||||
BurlapInputInitMethod() {
|
||||
this.getDeclaringType() instanceof BurlapInput and
|
||||
this.getName() = "init"
|
||||
}
|
||||
}
|
||||
22
java/ql/src/semmle/code/java/frameworks/JYaml.qll
Normal file
22
java/ql/src/semmle/code/java/frameworks/JYaml.qll
Normal file
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Provides classes and predicates for working with the JYaml framework.
|
||||
*/
|
||||
|
||||
import java
|
||||
|
||||
/**
|
||||
* The class `org.ho.yaml.Yaml` or `org.ho.yaml.YamlConfig`.
|
||||
*/
|
||||
class JYamlLoader extends RefType {
|
||||
JYamlLoader() { this.hasQualifiedName("org.ho.yaml", ["Yaml", "YamlConfig"]) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A JYaml unsafe load method, declared on either `Yaml` or `YamlConfig`.
|
||||
*/
|
||||
class JYamlLoaderUnsafeLoadMethod extends Method {
|
||||
JYamlLoaderUnsafeLoadMethod() {
|
||||
this.getDeclaringType() instanceof JYamlLoader and
|
||||
this.getName() in ["load", "loadType", "loadStream", "loadStreamOfType"]
|
||||
}
|
||||
}
|
||||
67
java/ql/src/semmle/code/java/frameworks/JsonIo.qll
Normal file
67
java/ql/src/semmle/code/java/frameworks/JsonIo.qll
Normal file
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* Provides classes and predicates for working with the Json-io framework.
|
||||
*/
|
||||
|
||||
import java
|
||||
import semmle.code.java.Maps
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
import semmle.code.java.dataflow.DataFlow2
|
||||
|
||||
/**
|
||||
* The class `com.cedarsoftware.util.io.JsonReader`.
|
||||
*/
|
||||
class JsonIoJsonReader extends RefType {
|
||||
JsonIoJsonReader() { this.hasQualifiedName("com.cedarsoftware.util.io", "JsonReader") }
|
||||
}
|
||||
|
||||
/** A method with the name `jsonToJava` declared in `com.cedarsoftware.util.io.JsonReader`. */
|
||||
class JsonIoJsonToJavaMethod extends Method {
|
||||
JsonIoJsonToJavaMethod() {
|
||||
this.getDeclaringType() instanceof JsonIoJsonReader and
|
||||
this.getName() = "jsonToJava"
|
||||
}
|
||||
}
|
||||
|
||||
/** A method with the name `readObject` declared in `com.cedarsoftware.util.io.JsonReader`. */
|
||||
class JsonIoReadObjectMethod extends Method {
|
||||
JsonIoReadObjectMethod() {
|
||||
this.getDeclaringType() instanceof JsonIoJsonReader and
|
||||
this.getName() = "readObject"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `Map.put` method, set the value of the `USE_MAPS` key to `true`.
|
||||
*/
|
||||
class JsonIoUseMapsSetter extends MethodAccess {
|
||||
JsonIoUseMapsSetter() {
|
||||
this.getMethod().getDeclaringType().getASourceSupertype*() instanceof MapType and
|
||||
this.getMethod().hasName("put") and
|
||||
this.getArgument(0).(CompileTimeConstantExpr).getStringValue() = "USE_MAPS" and
|
||||
this.getArgument(1).(CompileTimeConstantExpr).getBooleanValue() = true
|
||||
}
|
||||
}
|
||||
|
||||
/** A data flow configuration tracing flow from JsonIo safe settings. */
|
||||
class SafeJsonIoConfig extends DataFlow2::Configuration {
|
||||
SafeJsonIoConfig() { this = "UnsafeDeserialization::SafeJsonIoConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node src) {
|
||||
exists(MethodAccess ma |
|
||||
ma instanceof JsonIoUseMapsSetter and
|
||||
src.asExpr() = ma.getQualifier()
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
exists(MethodAccess ma |
|
||||
ma.getMethod() instanceof JsonIoJsonToJavaMethod and
|
||||
sink.asExpr() = ma.getArgument(1)
|
||||
)
|
||||
or
|
||||
exists(ClassInstanceExpr cie |
|
||||
cie.getConstructor().getDeclaringType() instanceof JsonIoJsonReader and
|
||||
sink.asExpr() = cie.getArgument(1)
|
||||
)
|
||||
}
|
||||
}
|
||||
20
java/ql/src/semmle/code/java/frameworks/YamlBeans.qll
Normal file
20
java/ql/src/semmle/code/java/frameworks/YamlBeans.qll
Normal file
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* Provides classes and predicates for working with the YamlBeans framework.
|
||||
*/
|
||||
|
||||
import java
|
||||
|
||||
/**
|
||||
* The class `com.esotericsoftware.yamlbeans.YamlReader`.
|
||||
*/
|
||||
class YamlBeansReader extends RefType {
|
||||
YamlBeansReader() { this.hasQualifiedName("com.esotericsoftware.yamlbeans", "YamlReader") }
|
||||
}
|
||||
|
||||
/** A method with the name `read` declared in `com.esotericsoftware.yamlbeans.YamlReader`. */
|
||||
class YamlBeansReaderReadMethod extends Method {
|
||||
YamlBeansReaderReadMethod() {
|
||||
this.getDeclaringType() instanceof YamlBeansReader and
|
||||
this.getName() = "read"
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,11 @@ import semmle.code.java.frameworks.Kryo
|
||||
import semmle.code.java.frameworks.XStream
|
||||
import semmle.code.java.frameworks.SnakeYaml
|
||||
import semmle.code.java.frameworks.FastJson
|
||||
import semmle.code.java.frameworks.JYaml
|
||||
import semmle.code.java.frameworks.JsonIo
|
||||
import semmle.code.java.frameworks.YamlBeans
|
||||
import semmle.code.java.frameworks.HessianBurlap
|
||||
import semmle.code.java.frameworks.Castor
|
||||
import semmle.code.java.frameworks.apache.Lang
|
||||
|
||||
class ObjectInputStreamReadObjectMethod extends Method {
|
||||
@@ -140,6 +145,23 @@ predicate unsafeDeserialization(MethodAccess ma, Expr sink) {
|
||||
ma.getMethod() instanceof FastJsonParseMethod and
|
||||
not fastJsonLooksSafe() and
|
||||
sink = ma.getArgument(0)
|
||||
or
|
||||
ma.getMethod() instanceof JYamlLoaderUnsafeLoadMethod and
|
||||
sink = ma.getArgument(0)
|
||||
or
|
||||
ma.getMethod() instanceof JsonIoJsonToJavaMethod and
|
||||
sink = ma.getArgument(0)
|
||||
or
|
||||
ma.getMethod() instanceof JsonIoReadObjectMethod and
|
||||
sink = ma.getQualifier()
|
||||
or
|
||||
ma.getMethod() instanceof YamlBeansReaderReadMethod and sink = ma.getQualifier()
|
||||
or
|
||||
ma.getMethod() instanceof UnsafeHessianInputReadObjectMethod and sink = ma.getQualifier()
|
||||
or
|
||||
ma.getMethod() instanceof CastorUnmarshalMethod and sink = ma.getAnArgument()
|
||||
or
|
||||
ma.getMethod() instanceof BurlapInputReadObjectMethod and sink = ma.getQualifier()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user