Port to Decoding

This commit is contained in:
jorgectf
2021-06-17 15:43:54 +02:00
parent 8e3d5ff3f9
commit 7e6032f5b4
2 changed files with 62 additions and 30 deletions

View File

@@ -8,6 +8,7 @@ private import semmle.python.dataflow.new.DataFlow
private import semmle.python.dataflow.new.TaintTracking
private import semmle.python.dataflow.new.RemoteFlowSources
private import experimental.semmle.python.Concepts
private import semmle.python.Concepts
private import semmle.python.ApiGraphs
/**
@@ -98,3 +99,47 @@ private module Re {
override DataFlow::Node getRegexNode() { result = regexNode }
}
}
// ---------------------------------------------------------------------------
// xmltodict
// ---------------------------------------------------------------------------
/** Gets a reference to the `xmltodict` module. */
API::Node xmltodict() { result = API::moduleImport("xmltodict") }
/**
* A call to `xmltodict.parse`
* See https://github.com/martinblech/xmltodict/blob/ae19c452ca000bf243bfc16274c060bf3bf7cf51/xmltodict.py#L198
*/
private class XmlToDictParseCall extends Decoding::Range, DataFlow::CallCfgNode {
XmlToDictParseCall() { this = xmltodict().getMember("parse").getACall() }
override predicate mayExecuteInput() { none() }
override DataFlow::Node getAnInput() { result = this.getArg(0) }
override DataFlow::Node getOutput() { result = this }
override string getFormat() { result = "JSON" }
}
// ---------------------------------------------------------------------------
// ujson
// ---------------------------------------------------------------------------
/** Gets a reference to the `ujson` module. */
API::Node ujson() { result = API::moduleImport("ujson") }
/**
* A call to `ujson.loads`
* See https://pypi.org/project/ujson/#usage
*/
private class UltraJsonLoadsCall extends Decoding::Range, DataFlow::CallCfgNode {
UltraJsonLoadsCall() { this = ujson().getMember("loads").getACall() }
override predicate mayExecuteInput() { none() }
override DataFlow::Node getAnInput() { result = this.getArg(0) }
override DataFlow::Node getOutput() { result = this }
override string getFormat() { result = "JSON" }
}

View File

@@ -3,53 +3,37 @@ import semmle.python.dataflow.new.DataFlow
import semmle.python.dataflow.new.DataFlow2
import semmle.python.dataflow.new.TaintTracking
import semmle.python.dataflow.new.TaintTracking2
import experimental.semmle.python.Concepts
import semmle.python.dataflow.new.RemoteFlowSources
import semmle.python.ApiGraphs
import semmle.python.security.dataflow.ChainedConfigs12
import experimental.semmle.python.Concepts
import semmle.python.Concepts
class JsonLoadsCall extends DataFlow::CallCfgNode {
JsonLoadsCall() { this = API::moduleImport("json").getMember("loads").getACall() }
DataFlow::Node getLoadNode() { result = this.getArg(0) }
}
class XmlToDictParseCall extends DataFlow::CallCfgNode {
XmlToDictParseCall() { this = API::moduleImport("xmltodict").getMember("parse").getACall() }
DataFlow::Node getParseNode() { result = this.getArg(0) }
}
class UltraJsonLoadsCall extends DataFlow::CallCfgNode {
UltraJsonLoadsCall() { this = API::moduleImport("ujson").getMember("loads").getACall() }
DataFlow::Node getLoadNode() { result = this.getArg(0) }
}
class DataToDictSink extends DataFlow::Node {
DataToDictSink() {
this = any(JsonLoadsCall jsonLoads).getLoadNode() or
this = any(XmlToDictParseCall jsonLoads).getParseNode() or
this = any(UltraJsonLoadsCall jsonLoads).getLoadNode()
}
}
/**
* A taint-tracking configuration for detecting string-to-dict conversions.
*/
class RFSToDictConfig extends TaintTracking::Configuration {
RFSToDictConfig() { this = "RFSToDictConfig" }
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
override predicate isSink(DataFlow::Node sink) { sink instanceof DataToDictSink }
override predicate isSink(DataFlow::Node sink) {
exists(Decoding decoding | decoding.getFormat() = "JSON" and sink = decoding)
}
override predicate isSanitizer(DataFlow::Node sanitizer) {
sanitizer = any(NoSQLSanitizer noSQLSanitizer).getAnInput()
}
}
/**
* A taint-tracking configuration for detecting NoSQL injections (previously converted to a dict).
*/
class FromDataDictToSink extends TaintTracking2::Configuration {
FromDataDictToSink() { this = "FromDataDictToSink" }
override predicate isSource(DataFlow::Node source) { source instanceof DataToDictSink }
override predicate isSource(DataFlow::Node source) {
exists(Decoding decoding | decoding.getFormat() = "JSON" and source = decoding)
}
override predicate isSink(DataFlow::Node sink) { sink = any(NoSQLQuery noSQLQuery).getQuery() }
@@ -58,6 +42,9 @@ class FromDataDictToSink extends TaintTracking2::Configuration {
}
}
/**
* A predicate checking string-to-dict conversion and its arrival to a NoSQL injection sink.
*/
predicate noSQLInjectionFlow(CustomPathNode source, CustomPathNode sink) {
exists(
RFSToDictConfig config, DataFlow::PathNode mid1, DataFlow2::PathNode mid2,