mirror of
https://github.com/github/codeql.git
synced 2026-04-30 19:26:02 +02:00
Port to Decoding
This commit is contained in:
@@ -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" }
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user