-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Java: CWE-502 Add UnsafeDeserialization sinks #5881
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
/** | ||
* The class `com.caucho.hessian.io.HessianInput` or `com.caucho.hessian.io.Hessian2Input`. | ||
*/ | ||
class UnSafeHessianInput extends RefType { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
class UnSafeHessianInput extends RefType { | |
class UnsafeHessianInput extends RefType { |
And similarly elsewhere
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok
* A JYaml unsafe load method. This is either `YAML.load` or | ||
* `YAML.loadType` or `YAML.loadStream` or `YAML.loadStreamOfType`. | ||
*/ | ||
class JYamlUnSafeLoadMethod extends Method { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
class JYamlUnSafeLoadMethod extends Method { | |
class JYamlUnsafeLoadMethod extends Method { |
And similarly elsewhere
@@ -50,6 +55,29 @@ class SafeKryo extends DataFlow2::Configuration { | |||
} | |||
} | |||
|
|||
class SafeJsonIo extends DataFlow2::Configuration { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
class SafeJsonIo extends DataFlow2::Configuration { | |
class SafeJsonIoConfig extends DataFlow2::Configuration { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also missing qldoc
} | ||
|
||
@GetMapping(value = "jsonio") | ||
public void bad2(HttpServletRequest request) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rename test case (it contains both good and bad cases)
cie.getConstructor().getDeclaringType() instanceof JsonReader and | ||
cie.getArgument(0) = prod.asExpr() and | ||
cie = succ.asExpr() and | ||
not exists(SafeJsonIo sji | sji.hasFlowToExpr(cie.getArgument(1))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This and the other similar exclusion would be better expressed using isSanitizer
not exists(SafeJsonIo sji | sji.hasFlowToExpr(cie.getArgument(1))) | ||
) | ||
or | ||
exists(ClassInstanceExpr cie | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Once the not exists(SafeJsonIo sji | sji.hasFlowToExpr(cie.getArgument(1)))
has been moved to isSanitizer
, you can factor this like
exists(ClassInstanceExpr cie |
cie.getArgument(0) = prod.asExpr() and
cie = succ.asExpr() and
(
cie.getConstructor().getDeclaringType() instanceof YamlReader or
cie.getConstructor().getDeclaringType() instanceof JsonReader or
...
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the suggestion.
@@ -50,6 +55,29 @@ class SafeKryo extends DataFlow2::Configuration { | |||
} | |||
} | |||
|
|||
class SafeJsonIo extends DataFlow2::Configuration { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be moved to the JsonIO.qll lib
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Haha, I see other tracing flows are in this qll
file, so put it here.
@@ -21,6 +21,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 prod, DataFlow::Node succ) { | |||
exists(ClassInstanceExpr cie | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@smowton, is ClassInstanceExpr
preferred over ConstructorCall
? I find the later more readable but it seems the former is a subtype of the later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ConstructorCall includes super(...)
and this(...)
, while ClassInstanceExpr
is strictly new XYZ(...)
/** | ||
* The class `org.exolab.castor.xml.Unmarshaller`. | ||
*/ | ||
class Unmarshaller extends RefType { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please rename to CastorUnmarshaller
, otherwise, its not clear what lib this class belongs to when reading UnsafeDeserialization
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok
*/ | ||
class UnSafeHessianInput extends RefType { | ||
UnSafeHessianInput() { | ||
this.hasQualifiedName("com.caucho.hessian.io", ["HessianInput", "Hessian2Input"]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this.hasQualifiedName("com.caucho.hessian.io", ["HessianInput", "Hessian2Input"]) | |
this.hasQualifiedName(["com.caucho.hessian.io", "com.alibaba.com.caucho.hessian.io"], ["AbstractHessianInput", "Hessian2StreamingInput"]) |
Ive used this in the past, I think it covers more classes
*/ | ||
class UnSafeHessianInputReadObjectMethod extends Method { | ||
UnSafeHessianInputReadObjectMethod() { | ||
this.getDeclaringType() instanceof UnSafeHessianInput and |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If using the above suggestion, this one should account for getASupertype*()
* Provides classes and predicates for working with the Hession framework. | ||
*/ | ||
|
||
import java |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps rename this file to HessianBurlap
and adapt file top comment
/** | ||
* The class `com.esotericsoftware.yamlbeans.YamlReader`. | ||
*/ | ||
class YamlReader extends RefType { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps rename it to YamlBeansReader
to make it clear that this class belongs to this library when reading UnsafeDeserialization
files
/** | ||
* The class `com.cedarsoftware.util.io.JsonReader`. | ||
*/ | ||
class JsonReader extends RefType { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here, please rename it to JsonIoJsonReader
or alike
@smowton Modified based on the suggestions of the two reviewers, please review again. Thank you. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this is targeting non-experimental, please add a change note
import java | ||
|
||
/** | ||
* The class `com.caucho.hessian.io.AbstractHessianInput` or `com.alibaba.com.caucho.hessian.io.Hessian2StreamingInput`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* The class `com.caucho.hessian.io.AbstractHessianInput` or `com.alibaba.com.caucho.hessian.io.Hessian2StreamingInput`. | |
* The classes `[com.alibaba.]com.caucho.hessian.io.AbstractHessianInput` or `[com.alibaba.]com.caucho.hessian.io.Hessian2StreamingInput`. |
* A JYaml unsafe load method. This is either `YAML.load` or | ||
* `YAML.loadType` or `YAML.loadStream` or `YAML.loadStreamOfType`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* A JYaml unsafe load method. This is either `YAML.load` or | |
* `YAML.loadType` or `YAML.loadStream` or `YAML.loadStreamOfType`. | |
* A JYaml unsafe load method, declared on either `Yaml` or `YamlConfig`. |
* The class `org.ho.yaml.Yaml`. | ||
*/ | ||
class JYaml extends RefType { | ||
JYaml() { this.hasQualifiedName("org.ho.yaml", "Yaml") } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JYaml() { this.hasQualifiedName("org.ho.yaml", "Yaml") } | |
JYamlLoader() { this.hasQualifiedName("org.ho.yaml", ["Yaml", "YamlConfig"]) } |
|
||
/** | ||
* The class `org.ho.yaml.YamlConfig`. | ||
*/ | ||
class JYamlConfig extends RefType { | ||
JYamlConfig() { this.hasQualifiedName("org.ho.yaml", "YamlConfig") } | ||
} | ||
|
||
/** | ||
* A JYamlConfig unsafe load method. This is either `YamlConfig.load` or | ||
* `YAML.loadType` or `YamlConfig.loadStream` or `YamlConfig.loadStreamOfType`. | ||
*/ | ||
class JYamlConfigUnsafeLoadMethod extends Method { | ||
JYamlConfigUnsafeLoadMethod() { | ||
this.getDeclaringType() instanceof JYamlConfig and | ||
this.getName() in ["load", "loadType", "loadStream", "loadStreamOfType"] | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/** | |
* The class `org.ho.yaml.YamlConfig`. | |
*/ | |
class JYamlConfig extends RefType { | |
JYamlConfig() { this.hasQualifiedName("org.ho.yaml", "YamlConfig") } | |
} | |
/** | |
* A JYamlConfig unsafe load method. This is either `YamlConfig.load` or | |
* `YAML.loadType` or `YamlConfig.loadStream` or `YamlConfig.loadStreamOfType`. | |
*/ | |
class JYamlConfigUnsafeLoadMethod extends Method { | |
JYamlConfigUnsafeLoadMethod() { | |
this.getDeclaringType() instanceof JYamlConfig and | |
this.getName() in ["load", "loadType", "loadStream", "loadStreamOfType"] | |
} | |
} |
/** | ||
* A call to `Map.put` method, set the value of the `USE_MAPS` key to `true`. | ||
*/ | ||
class JsonIoSafeOptionalArgs extends MethodAccess { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
class JsonIoSafeOptionalArgs extends MethodAccess { | |
class JsonIoUseMapsSetter extends MethodAccess { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
^^
or | ||
ma.getMethod() instanceof JYamlConfigUnsafeLoadMethod and | ||
sink = ma.getArgument(0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
or | |
ma.getMethod() instanceof JYamlConfigUnsafeLoadMethod and | |
sink = ma.getArgument(0) |
java/change-notes/2021-05-17-add-unsafe-deserialization-sinks.md
Outdated
Show resolved
Hide resolved
/** | ||
* A call to `Map.put` method, set the value of the `USE_MAPS` key to `true`. | ||
*/ | ||
class JsonIoSafeOptionalArgs extends MethodAccess { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
^^
Otherwise looks good to me; over to @aschackmull for final review. Note you need to rebase to resolve the UnsafeDeserialization.expected conflict. |
Co-authored-by: Chris Smowton <smowton@github.com>
@smowton @pwntester Thanks for review. |
@aschackmull Please do the final review, thank you. |
} | ||
|
||
/** A method with the name `unmarshal` declared in `org.exolab.castor.xml.Unmarshaller`. */ | ||
class UnmarshalMethod extends Method { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This name is a little too generic, let's include Castor
in the name:
class UnmarshalMethod extends Method { | |
class CastorUnmarshalMethod extends Method { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I made a change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One minor comment, otherwise just needs a rebase to resolve the conflict. LGTM.
Still needs a rebase to resolve the conflict in |
Can you review it again? |
The expected output of |
You try again. |
It is strange that there is no file conflict reported this time, did I do something wrong... |
That fix looks incorrect to me. I guess you're testing against the merge base rather than current main?
|
There is no
|
The test is still failing. You likely forgot to pull latest main when you merged main into your branch. Please fix the test. |
Please review again. |
@aschackmull Thank you. |
In the study of Java deserialization vulnerabilities, some sinks were recorded. This pr adds these sinks to the CodeQL query. A total of 8 sinks have been added.
Mainly known:
JYaml.load
,JsonReader.jsonToJava
,YamlReader.read
,HessianInput.readObject
,Hessian2Input.readObject
,Unmarshaller.unmarshal
,BurlapInput.readObject
. There are also some sink points not mentioned:YamlConfig.load
,JsonReader.readObject
.