add more additional steps, change parse* sinks to reciever of them

This commit is contained in:
amammad
2023-06-12 23:23:09 +10:00
committed by Harry Maclean
parent 474a4f8abd
commit a75a004942
2 changed files with 29 additions and 20 deletions

View File

@@ -27,18 +27,18 @@ private class YamlParseStep extends AdditionalTaintStep {
exists(API::Node yamlParserMethod |
succ = yamlParserMethod.getReturn().asSource() and
(
yamlParserMethod = yamlNode().getMethod(["parse", "parse_stream"]) and
yamlParserMethod = yamlLibrary().getMethod(["parse", "parse_stream"]) and
pred =
[yamlParserMethod.getParameter(0), yamlParserMethod.getKeywordParameter("yaml")].asSink()
or
yamlParserMethod = yamlNode().getMethod("parse_file") and
yamlParserMethod = yamlLibrary().getMethod("parse_file") and
pred =
[yamlParserMethod.getParameter(0), yamlParserMethod.getKeywordParameter("filename")]
.asSink()
)
)
or
exists(API::Node parseSuccessors | parseSuccessors = yamlParseChildNodeAccess(_) |
exists(API::Node parseSuccessors | parseSuccessors = yamlNode() |
succ =
[
parseSuccessors.getMethod("to_ruby").getReturn().asSource(),
@@ -46,17 +46,26 @@ private class YamlParseStep extends AdditionalTaintStep {
] and
pred = parseSuccessors.asSource()
)
or
exists(API::Node parseSuccessors | parseSuccessors = yamlNode() |
succ =
[
parseSuccessors.getMethod(_).getBlock().getParameter(_).asSource(),
parseSuccessors.getMethod(_).getReturn().asSource()
] and
pred = parseSuccessors.asSource()
)
}
}
API::Node yamlParseChildNodeAccess(API::Node source) {
source = yamlNode().getMethod(["parse", "parse_stream"]).getReturn() and source = result
API::Node yamlNode() {
result = yamlLibrary().getMethod(["parse", "parse_stream", "parse_file"]).getReturn()
or
result = yamlParseChildNodeAccess(source).getMethod(_).getReturn()
result = yamlNode().getMethod(_).getReturn()
or
result = yamlParseChildNodeAccess(source).getMethod(_).getBlock().getParameter(_)
result = yamlNode().getMethod(_).getBlock().getParameter(_)
or
result = yamlParseChildNodeAccess(source).getAnElement()
result = yamlNode().getAnElement()
}
private API::Node yamlNode() { result = API::getTopLevelMember(["YAML", "Psych"]) }
API::Node yamlLibrary() { result = API::getTopLevelMember(["YAML", "Psych"]) }

View File

@@ -83,30 +83,30 @@ module UnsafeDeserialization {
class YamlLoadArgument extends Sink {
YamlLoadArgument() {
// Note: this is safe in psych/yaml >= 4.0.0.
this = yamlNode().getAMethodCall("load").getArgument(0)
this = yamlLibrary().getAMethodCall("load").getArgument(0)
or
this =
yamlNode().getAMethodCall(["unsafe_load_file", "unsafe_load", "load_stream"]).getArgument(0)
yamlLibrary()
.getAMethodCall(["unsafe_load_file", "unsafe_load", "load_stream"])
.getArgument(0)
or
this = yamlNode().getAMethodCall(["unsafe_load", "load_stream"]).getKeywordArgument("yaml")
this = yamlLibrary().getAMethodCall(["unsafe_load", "load_stream"]).getKeywordArgument("yaml")
or
this = yamlNode().getAMethodCall("unsafe_load_file").getKeywordArgument("filename")
this = yamlLibrary().getAMethodCall("unsafe_load_file").getKeywordArgument("filename")
}
}
private API::Node yamlNode() { result = API::getTopLevelMember(["YAML", "Psych"]) }
/**
* An argument in a call to `YAML.parse*`, considered a sink for unsafe deserialization
* if there is a call to `to_ruby` on the returned value of any Successor.
*/
class YamlParseArgument extends Sink {
YamlParseArgument() {
this =
[
yamlParseChildNodeAccess(_).getMethod("to_ruby").getReturn().asSource(),
yamlParseChildNodeAccess(_).getMethod("to_ruby").getReturn().getAnElement().asSource()
]
exists(API::Node toRubyReceiver |
toRubyReceiver = yamlNode() and this = toRubyReceiver.asSource()
|
exists(toRubyReceiver.getMethod("to_ruby"))
)
}
}