mirror of
https://github.com/github/codeql.git
synced 2026-05-01 11:45:14 +02:00
Merge branch 'main' of github.com:github/codeql into python/promote-xpath-injection
This commit is contained in:
38
python/.vscode/ql.code-snippets
vendored
38
python/.vscode/ql.code-snippets
vendored
@@ -222,26 +222,6 @@
|
||||
],
|
||||
"description": "Type tracking class (select full class path before inserting)",
|
||||
},
|
||||
"foo": {
|
||||
"scope": "ql",
|
||||
"prefix": "foo",
|
||||
"body": [
|
||||
" /**",
|
||||
" * Taint propagation for `$1`.",
|
||||
" */",
|
||||
" private class InstanceTaintSteps extends InstanceTaintStepsHelper {",
|
||||
" InstanceTaintSteps() { this = \"$1\" }",
|
||||
"",
|
||||
" override DataFlow::Node getInstance() { result = instance() }",
|
||||
"",
|
||||
" override string getAttributeName() { none() }",
|
||||
"",
|
||||
" override string getMethodName() { none() }",
|
||||
"",
|
||||
" override string getAsyncMethodName() { none() }",
|
||||
" }",
|
||||
],
|
||||
},
|
||||
"API graph .getMember chain": {
|
||||
"scope": "ql",
|
||||
"prefix": "api graph .getMember chain",
|
||||
@@ -250,4 +230,22 @@
|
||||
],
|
||||
"description": "API graph .getMember chain (select full path before inserting)",
|
||||
},
|
||||
"debug partial flow": {
|
||||
"scope": "ql",
|
||||
"prefix": "debug partial flow",
|
||||
"body": [
|
||||
"// put the line below inside the configuration",
|
||||
"// override int explorationLimit() { result = 5 }",
|
||||
"// and then run quick evaluation on the predicate below",
|
||||
"// (and potentially limit the set of sources)",
|
||||
"predicate debugPartialFlow(Location loc, DataFlow::PartialPathNode node, int dist) {",
|
||||
" loc = node.getNode().getLocation() and",
|
||||
" exists(loc.getFile().getRelativePath()) and",
|
||||
" exists(Configuration config, DataFlow::PartialPathNode source |",
|
||||
" config.hasPartialFlow(source, node, dist)",
|
||||
" )",
|
||||
"}",
|
||||
],
|
||||
"description": "debug partial flow",
|
||||
},
|
||||
}
|
||||
|
||||
5
python/ql/consistency-queries/qlpack.yml
Normal file
5
python/ql/consistency-queries/qlpack.yml
Normal file
@@ -0,0 +1,5 @@
|
||||
name: codeql/python-consistency-queries
|
||||
groups: [python, test, consistency-queries]
|
||||
dependencies:
|
||||
codeql/python-all: "*"
|
||||
extractor: python
|
||||
@@ -1,3 +1,18 @@
|
||||
## 0.0.10
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
* The old points-to based modeling has been deprecated. Use the new type-tracking/API-graphs based modeling instead.
|
||||
|
||||
## 0.0.9
|
||||
|
||||
## 0.0.8
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
* Moved the files defining regex injection configuration and customization, instead of `import semmle.python.security.injection.RegexInjection` please use `import semmle.python.security.dataflow.RegexInjection` (the same for `RegexInjectionCustomizations`).
|
||||
* The `codeql/python-upgrades` CodeQL pack has been removed. All upgrades scripts have been merged into the `codeql/python-all` CodeQL pack.
|
||||
|
||||
## 0.0.7
|
||||
|
||||
## 0.0.6
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: deprecated
|
||||
---
|
||||
* The `codeql/python-upgrades` CodeQL pack has been removed. All upgrades scripts have been merged into the `codeql/python-all` CodeQL pack.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Improved analysis of attributes for data-flow and taint tracking queries, so `getattr`/`setattr` are supported, and a write to an attribute properly stops flow for the old value in that attribute.
|
||||
* Added post-update nodes (`DataFlow::PostUpdateNode`) for arguments in calls that can't be resolved.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Fixed taint propagation for attribute assignment. In the assignment `x.foo = tainted` we no longer treat the entire object `x` as tainted, just because the attribute `foo` contains tainted data. This leads to slightly fewer false positives.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The regular expression parser now groups sequences of normal characters. This reduces the number of instances of `RegExpNormalChar`.
|
||||
5
python/ql/lib/change-notes/released/0.0.10.md
Normal file
5
python/ql/lib/change-notes/released/0.0.10.md
Normal file
@@ -0,0 +1,5 @@
|
||||
## 0.0.10
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
* The old points-to based modeling has been deprecated. Use the new type-tracking/API-graphs based modeling instead.
|
||||
@@ -1,4 +1,6 @@
|
||||
---
|
||||
category: deprecated
|
||||
---
|
||||
## 0.0.8
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
* Moved the files defining regex injection configuration and customization, instead of `import semmle.python.security.injection.RegexInjection` please use `import semmle.python.security.dataflow.RegexInjection` (the same for `RegexInjectionCustomizations`).
|
||||
* The `codeql/python-upgrades` CodeQL pack has been removed. All upgrades scripts have been merged into the `codeql/python-all` CodeQL pack.
|
||||
1
python/ql/lib/change-notes/released/0.0.9.md
Normal file
1
python/ql/lib/change-notes/released/0.0.9.md
Normal file
@@ -0,0 +1 @@
|
||||
## 0.0.9
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.0.7
|
||||
lastReleaseVersion: 0.0.10
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/python-all
|
||||
version: 0.0.8-dev
|
||||
version: 0.0.11-dev
|
||||
groups: python
|
||||
dbscheme: semmlecode.python.dbscheme
|
||||
extractor: python
|
||||
|
||||
@@ -552,6 +552,44 @@ module XML {
|
||||
}
|
||||
}
|
||||
|
||||
/** Provides classes for modeling LDAP-related APIs. */
|
||||
module LDAP {
|
||||
/**
|
||||
* A data-flow node that executes an LDAP query.
|
||||
*
|
||||
* Extend this class to refine existing API models. If you want to model new APIs,
|
||||
* extend `LDAPQuery::Range` instead.
|
||||
*/
|
||||
class LdapExecution extends DataFlow::Node {
|
||||
LdapExecution::Range range;
|
||||
|
||||
LdapExecution() { this = range }
|
||||
|
||||
/** Gets the argument containing the filter string. */
|
||||
DataFlow::Node getFilter() { result = range.getFilter() }
|
||||
|
||||
/** Gets the argument containing the base DN. */
|
||||
DataFlow::Node getBaseDn() { result = range.getBaseDn() }
|
||||
}
|
||||
|
||||
/** Provides classes for modeling new LDAP query execution-related APIs. */
|
||||
module LdapExecution {
|
||||
/**
|
||||
* A data-flow node that executes an LDAP query.
|
||||
*
|
||||
* Extend this class to model new APIs. If you want to refine existing API models,
|
||||
* extend `LDAPQuery` instead.
|
||||
*/
|
||||
abstract class Range extends DataFlow::Node {
|
||||
/** Gets the argument containing the filter string. */
|
||||
abstract DataFlow::Node getFilter();
|
||||
|
||||
/** Gets the argument containing the base DN. */
|
||||
abstract DataFlow::Node getBaseDn();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A data-flow node that escapes meta-characters, which could be used to prevent
|
||||
* injection attacks.
|
||||
@@ -609,8 +647,20 @@ module Escaping {
|
||||
/** Gets the escape-kind for escaping a string so it can safely be included in HTML. */
|
||||
string getHtmlKind() { result = "html" }
|
||||
|
||||
/** Gets the escape-kind for escaping a string so it can safely be included in HTML. */
|
||||
/** Gets the escape-kind for escaping a string so it can safely be included in a regular expression. */
|
||||
string getRegexKind() { result = "regex" }
|
||||
|
||||
/**
|
||||
* Gets the escape-kind for escaping a string so it can safely be used as a
|
||||
* distinguished name (DN) in an LDAP search.
|
||||
*/
|
||||
string getLdapDnKind() { result = "ldap_dn" }
|
||||
|
||||
/**
|
||||
* Gets the escape-kind for escaping a string so it can safely be used as a
|
||||
* filter in an LDAP search.
|
||||
*/
|
||||
string getLdapFilterKind() { result = "ldap_filter" }
|
||||
// TODO: If adding an XML kind, update the modeling of the `MarkupSafe` PyPI package.
|
||||
//
|
||||
// Technically it claims to escape for both HTML and XML, but for now we don't have
|
||||
@@ -635,9 +685,28 @@ class RegexEscaping extends Escaping {
|
||||
RegexEscaping() { range.getKind() = Escaping::getRegexKind() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An escape of a string so it can be safely used as a distinguished name (DN)
|
||||
* in an LDAP search.
|
||||
*/
|
||||
class LdapDnEscaping extends Escaping {
|
||||
LdapDnEscaping() { range.getKind() = Escaping::getLdapDnKind() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An escape of a string so it can be safely used as a filter in an LDAP search.
|
||||
*/
|
||||
class LdapFilterEscaping extends Escaping {
|
||||
LdapFilterEscaping() { range.getKind() = Escaping::getLdapFilterKind() }
|
||||
}
|
||||
|
||||
/** Provides classes for modeling HTTP-related APIs. */
|
||||
module HTTP {
|
||||
import semmle.python.web.HttpConstants
|
||||
/** Gets an HTTP verb, in upper case */
|
||||
string httpVerb() { result in ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", "HEAD"] }
|
||||
|
||||
/** Gets an HTTP verb, in lower case */
|
||||
string httpVerbLower() { result = httpVerb().toLowerCase() }
|
||||
|
||||
/** Provides classes for modeling HTTP servers. */
|
||||
module Server {
|
||||
|
||||
@@ -22,6 +22,8 @@ private import semmle.python.frameworks.FlaskSqlAlchemy
|
||||
private import semmle.python.frameworks.Idna
|
||||
private import semmle.python.frameworks.Invoke
|
||||
private import semmle.python.frameworks.Jmespath
|
||||
private import semmle.python.frameworks.Ldap
|
||||
private import semmle.python.frameworks.Ldap3
|
||||
private import semmle.python.frameworks.Libxml2
|
||||
private import semmle.python.frameworks.Lxml
|
||||
private import semmle.python.frameworks.MarkupSafe
|
||||
|
||||
@@ -39,7 +39,12 @@ newtype TRegExpParent =
|
||||
/** A special character */
|
||||
TRegExpSpecialChar(Regex re, int start, int end) { re.specialCharacter(start, end, _) } or
|
||||
/** A normal character */
|
||||
TRegExpNormalChar(Regex re, int start, int end) { re.normalCharacter(start, end) } or
|
||||
TRegExpNormalChar(Regex re, int start, int end) {
|
||||
re.normalCharacterSequence(start, end)
|
||||
or
|
||||
re.escapedCharacter(start, end) and
|
||||
not re.specialCharacter(start, end, _)
|
||||
} or
|
||||
/** A back reference */
|
||||
TRegExpBackRef(Regex re, int start, int end) { re.backreference(start, end) }
|
||||
|
||||
|
||||
@@ -204,6 +204,8 @@ abstract class AttrRead extends AttrRef, Node, LocalSourceNode { }
|
||||
private class AttributeReadAsAttrRead extends AttrRead, CfgNode {
|
||||
override AttrNode node;
|
||||
|
||||
AttributeReadAsAttrRead() { node.isLoad() }
|
||||
|
||||
override Node getObject() { result.asCfgNode() = node.getObject() }
|
||||
|
||||
override ExprNode getAttributeNameExpr() {
|
||||
|
||||
@@ -126,7 +126,7 @@ module syntheticPostUpdateNode {
|
||||
* Certain arguments, such as implicit self arguments are already post-update nodes
|
||||
* and should not have an extra node synthesised.
|
||||
*/
|
||||
ArgumentNode argumentPreUpdateNode() {
|
||||
Node argumentPreUpdateNode() {
|
||||
result = any(FunctionCall c).getArg(_)
|
||||
or
|
||||
// Avoid argument 0 of method calls as those have read post-update nodes.
|
||||
@@ -136,6 +136,11 @@ module syntheticPostUpdateNode {
|
||||
or
|
||||
// Avoid argument 0 of class calls as those have non-synthetic post-update nodes.
|
||||
exists(ClassCall c, int n | n > 0 | result = c.getArg(n))
|
||||
or
|
||||
// any argument of any call that we have not been able to resolve
|
||||
exists(CallNode call | not call = any(DataFlowCall c).getNode() |
|
||||
result.(CfgNode).getNode() in [call.getArg(_), call.getArgByName(_)]
|
||||
)
|
||||
}
|
||||
|
||||
/** An object might have its value changed after a store. */
|
||||
@@ -704,7 +709,7 @@ newtype TDataFlowCall =
|
||||
TFunctionCall(CallNode call) { call = any(FunctionValue f).getAFunctionCall() } or
|
||||
/** Bound methods need to make room for the explicit self parameter */
|
||||
TMethodCall(CallNode call) { call = any(FunctionValue f).getAMethodCall() } or
|
||||
TClassCall(CallNode call) { call = any(ClassValue c).getACall() } or
|
||||
TClassCall(CallNode call) { call = any(ClassValue c | not c.isAbsent()).getACall() } or
|
||||
TSpecialCall(SpecialMethodCallNode special)
|
||||
|
||||
/** Represents a call. */
|
||||
@@ -1002,7 +1007,7 @@ predicate listStoreStep(CfgNode nodeFrom, ListElementContent c, CfgNode nodeTo)
|
||||
}
|
||||
|
||||
/** Data flows from an element of a set to the set. */
|
||||
predicate setStoreStep(CfgNode nodeFrom, ListElementContent c, CfgNode nodeTo) {
|
||||
predicate setStoreStep(CfgNode nodeFrom, SetElementContent c, CfgNode nodeTo) {
|
||||
// Set
|
||||
// `{..., 42, ...}`
|
||||
// nodeFrom is `42`, cfg node
|
||||
@@ -1067,19 +1072,18 @@ predicate comprehensionStoreStep(CfgNode nodeFrom, Content c, CfgNode nodeTo) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `nodeFrom` flows into an attribute (corresponding to `c`) of `nodeTo` via an attribute assignment.
|
||||
* Holds if `nodeFrom` flows into the attribute `c` of `nodeTo` via an attribute assignment.
|
||||
*
|
||||
* For example, in
|
||||
* ```python
|
||||
* obj.foo = x
|
||||
* ```
|
||||
* data flows from `x` to (the post-update node for) `obj` via assignment to `foo`.
|
||||
* data flows from `x` to the attribute `foo` of (the post-update node for) `obj`.
|
||||
*/
|
||||
predicate attributeStoreStep(CfgNode nodeFrom, AttributeContent c, PostUpdateNode nodeTo) {
|
||||
exists(AttrNode attr |
|
||||
nodeFrom.asCfgNode() = attr.(DefinitionNode).getValue() and
|
||||
attr.getName() = c.getAttribute() and
|
||||
attr.getObject() = nodeTo.getPreUpdateNode().(CfgNode).getNode()
|
||||
predicate attributeStoreStep(Node nodeFrom, AttributeContent c, PostUpdateNode nodeTo) {
|
||||
exists(AttrWrite write |
|
||||
write.accesses(nodeTo.getPreUpdateNode(), c.getAttribute()) and
|
||||
nodeFrom = write.getValue()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1923,21 +1927,16 @@ pragma[noinline]
|
||||
TupleElementContent small_tuple() { result.getIndex() <= 7 }
|
||||
|
||||
/**
|
||||
* Holds if `nodeTo` is a read of an attribute (corresponding to `c`) of the object in `nodeFrom`.
|
||||
* Holds if `nodeTo` is a read of the attribute `c` of the object `nodeFrom`.
|
||||
*
|
||||
* For example, in
|
||||
* For example
|
||||
* ```python
|
||||
* obj.foo
|
||||
* ```
|
||||
* data flows from `obj` to `obj.foo` via a read from `foo`.
|
||||
* is a read of the attribute `foo` from the object `obj`.
|
||||
*/
|
||||
predicate attributeReadStep(CfgNode nodeFrom, AttributeContent c, CfgNode nodeTo) {
|
||||
exists(AttrNode attr |
|
||||
nodeFrom.asCfgNode() = attr.getObject() and
|
||||
nodeTo.asCfgNode() = attr and
|
||||
attr.getName() = c.getAttribute() and
|
||||
attr.isLoad()
|
||||
)
|
||||
predicate attributeReadStep(Node nodeFrom, AttributeContent c, AttrRead nodeTo) {
|
||||
nodeTo.accesses(nodeFrom, c.getAttribute())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1973,6 +1972,18 @@ predicate clearsContent(Node n, Content c) {
|
||||
kwOverflowClearStep(n, c)
|
||||
or
|
||||
matchClearStep(n, c)
|
||||
or
|
||||
attributeClearStep(n, c)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if values stored inside attribute `c` are cleared at node `n`.
|
||||
*
|
||||
* In `obj.foo = x` any old value stored in `foo` is cleared at the pre-update node
|
||||
* associated with `obj`
|
||||
*/
|
||||
predicate attributeClearStep(Node n, AttributeContent c) {
|
||||
exists(PostUpdateNode post | post.getPreUpdateNode() = n | attributeStoreStep(_, c, post))
|
||||
}
|
||||
|
||||
//--------
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
private import python
|
||||
private import semmle.python.dataflow.new.DataFlow
|
||||
private import semmle.python.dataflow.new.internal.DataFlowPrivate as DataFlowPrivate
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
@@ -66,7 +67,12 @@ string prettyNodeForInlineTest(DataFlow::Node node) {
|
||||
result = "[post]" + prettyExpr(e)
|
||||
)
|
||||
or
|
||||
exists(Expr e | e = node.(DataFlowPrivate::SyntheticPreUpdateNode).getPostUpdateNode().asExpr() |
|
||||
result = "[pre]" + prettyExpr(e)
|
||||
)
|
||||
or
|
||||
not exists(node.asExpr()) and
|
||||
not exists(node.(DataFlow::PostUpdateNode).getPreUpdateNode().asExpr()) and
|
||||
not exists(node.(DataFlowPrivate::SyntheticPreUpdateNode).getPostUpdateNode().asExpr()) and
|
||||
result = node.toString()
|
||||
}
|
||||
|
||||
@@ -167,8 +167,25 @@ predicate stringManipulation(DataFlow::CfgNode nodeFrom, DataFlow::CfgNode nodeT
|
||||
*/
|
||||
predicate containerStep(DataFlow::CfgNode nodeFrom, DataFlow::Node nodeTo) {
|
||||
// construction by literal
|
||||
// TODO: Not limiting the content argument here feels like a BIG hack, but we currently get nothing for free :|
|
||||
DataFlowPrivate::storeStep(nodeFrom, _, nodeTo)
|
||||
//
|
||||
// TODO: once we have proper flow-summary modeling, we might not need this step any
|
||||
// longer -- but there needs to be a matching read-step for the store-step, and we
|
||||
// don't provide that right now.
|
||||
DataFlowPrivate::listStoreStep(nodeFrom, _, nodeTo)
|
||||
or
|
||||
DataFlowPrivate::setStoreStep(nodeFrom, _, nodeTo)
|
||||
or
|
||||
DataFlowPrivate::tupleStoreStep(nodeFrom, _, nodeTo)
|
||||
or
|
||||
DataFlowPrivate::dictStoreStep(nodeFrom, _, nodeTo)
|
||||
or
|
||||
// comprehension, so there is taint-flow from `x` in `[x for x in xs]` to the
|
||||
// resulting list of the list-comprehension.
|
||||
//
|
||||
// TODO: once we have proper flow-summary modeling, we might not need this step any
|
||||
// longer -- but there needs to be a matching read-step for the store-step, and we
|
||||
// don't provide that right now.
|
||||
DataFlowPrivate::comprehensionStoreStep(nodeFrom, _, nodeTo)
|
||||
or
|
||||
// constructor call
|
||||
exists(DataFlow::CallCfgNode call | call = nodeTo |
|
||||
|
||||
@@ -2295,4 +2295,22 @@ module PrivateDjango {
|
||||
|
||||
override string getMimetypeDefault() { none() }
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Logging
|
||||
// ---------------------------------------------------------------------------
|
||||
/**
|
||||
* A standard Python logger instance from Django.
|
||||
* see https://github.com/django/django/blob/stable/4.0.x/django/utils/log.py#L11
|
||||
*/
|
||||
private class DjangoLogger extends Stdlib::Logger::InstanceSource {
|
||||
DjangoLogger() {
|
||||
this =
|
||||
API::moduleImport("django")
|
||||
.getMember("utils")
|
||||
.getMember("log")
|
||||
.getMember("request_logger")
|
||||
.getAnImmediateUse()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ private import semmle.python.dataflow.new.RemoteFlowSources
|
||||
private import semmle.python.dataflow.new.TaintTracking
|
||||
private import semmle.python.Concepts
|
||||
private import semmle.python.frameworks.Werkzeug
|
||||
private import semmle.python.frameworks.Stdlib
|
||||
private import semmle.python.ApiGraphs
|
||||
private import semmle.python.frameworks.internal.InstanceTaintStepsHelper
|
||||
private import semmle.python.security.dataflow.PathInjectionCustomizations
|
||||
@@ -569,4 +570,18 @@ module Flask {
|
||||
result in [this.getArg(0), this.getArgByName("filename_or_fp")]
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Logging
|
||||
// ---------------------------------------------------------------------------
|
||||
/**
|
||||
* A Flask application provides a standard Python logger via the `logger` attribute.
|
||||
*
|
||||
* See
|
||||
* - https://flask.palletsprojects.com/en/2.0.x/api/#flask.Flask.logger
|
||||
* - https://flask.palletsprojects.com/en/2.0.x/logging/
|
||||
*/
|
||||
private class FlaskLogger extends Stdlib::Logger::InstanceSource {
|
||||
FlaskLogger() { this = FlaskApp::instance().getMember("logger").getAnImmediateUse() }
|
||||
}
|
||||
}
|
||||
|
||||
75
python/ql/lib/semmle/python/frameworks/Ldap.qll
Normal file
75
python/ql/lib/semmle/python/frameworks/Ldap.qll
Normal file
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* Provides classes modeling security-relevant aspects of the `python-ldap` PyPI package (imported as `ldap`).
|
||||
* See https://www.python-ldap.org/en/python-ldap-3.3.0/index.html
|
||||
*/
|
||||
|
||||
private import python
|
||||
private import semmle.python.dataflow.new.DataFlow
|
||||
private import semmle.python.Concepts
|
||||
private import semmle.python.ApiGraphs
|
||||
|
||||
/**
|
||||
* Provides models for the `python-ldap` PyPI package (imported as `ldap`).
|
||||
*
|
||||
* See https://www.python-ldap.org/en/python-ldap-3.3.0/index.html
|
||||
*/
|
||||
private module Ldap {
|
||||
/**
|
||||
* The execution of an `ldap` query.
|
||||
*
|
||||
* See https://www.python-ldap.org/en/python-ldap-3.3.0/reference/ldap.html#functions
|
||||
*/
|
||||
private class LdapQueryExecution extends DataFlow::CallCfgNode, LDAP::LdapExecution::Range {
|
||||
LdapQueryExecution() {
|
||||
this =
|
||||
API::moduleImport("ldap")
|
||||
.getMember("initialize")
|
||||
.getReturn()
|
||||
.getMember(["search", "search_s", "search_st", "search_ext", "search_ext_s"])
|
||||
.getACall()
|
||||
}
|
||||
|
||||
override DataFlow::Node getFilter() {
|
||||
result in [this.getArg(2), this.getArgByName("filterstr")]
|
||||
}
|
||||
|
||||
override DataFlow::Node getBaseDn() { result in [this.getArg(0), this.getArgByName("base")] }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `ldap.dn.escape_dn_chars`.
|
||||
*
|
||||
* See https://github.com/python-ldap/python-ldap/blob/7ce471e238cdd9a4dd8d17baccd1c9e05e6f894a/Lib/ldap/dn.py#L17
|
||||
*/
|
||||
private class LdapEscapeDnCall extends DataFlow::CallCfgNode, Escaping::Range {
|
||||
LdapEscapeDnCall() {
|
||||
this = API::moduleImport("ldap").getMember("dn").getMember("escape_dn_chars").getACall()
|
||||
}
|
||||
|
||||
override DataFlow::Node getAnInput() { result in [this.getArg(0), this.getArgByName("s")] }
|
||||
|
||||
override DataFlow::Node getOutput() { result = this }
|
||||
|
||||
override string getKind() { result = Escaping::getLdapDnKind() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `ldap.filter.escape_filter_chars`.
|
||||
*
|
||||
* See https://www.python-ldap.org/en/python-ldap-3.3.0/reference/ldap-filter.html#ldap.filter.escape_filter_chars
|
||||
*/
|
||||
private class LdapEscapeFilterCall extends DataFlow::CallCfgNode, Escaping::Range {
|
||||
LdapEscapeFilterCall() {
|
||||
this =
|
||||
API::moduleImport("ldap").getMember("filter").getMember("escape_filter_chars").getACall()
|
||||
}
|
||||
|
||||
override DataFlow::Node getAnInput() {
|
||||
result in [this.getArg(0), this.getArgByName("assertion_value")]
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput() { result = this }
|
||||
|
||||
override string getKind() { result = Escaping::getLdapFilterKind() }
|
||||
}
|
||||
}
|
||||
80
python/ql/lib/semmle/python/frameworks/Ldap3.qll
Normal file
80
python/ql/lib/semmle/python/frameworks/Ldap3.qll
Normal file
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* Provides classes modeling security-relevant aspects of the `ldap3` PyPI package
|
||||
* See https://pypi.org/project/ldap3/
|
||||
*/
|
||||
|
||||
private import python
|
||||
private import semmle.python.dataflow.new.DataFlow
|
||||
private import semmle.python.Concepts
|
||||
private import semmle.python.ApiGraphs
|
||||
|
||||
/**
|
||||
* Provides models for the `ldap3` PyPI package
|
||||
*
|
||||
* See https://pypi.org/project/ldap3/
|
||||
*/
|
||||
private module Ldap3 {
|
||||
/** The execution of an `ldap` query. */
|
||||
private class LdapQueryExecution extends DataFlow::CallCfgNode, LDAP::LdapExecution::Range {
|
||||
LdapQueryExecution() {
|
||||
this =
|
||||
API::moduleImport("ldap3")
|
||||
.getMember("Connection")
|
||||
.getReturn()
|
||||
.getMember("search")
|
||||
.getACall()
|
||||
}
|
||||
|
||||
override DataFlow::Node getFilter() {
|
||||
result in [this.getArg(1), this.getArgByName("search_filter")]
|
||||
}
|
||||
|
||||
override DataFlow::Node getBaseDn() {
|
||||
result in [this.getArg(0), this.getArgByName("search_base")]
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `ldap3.utils.dn.escape_rdn`.
|
||||
*
|
||||
* See https://github.com/cannatag/ldap3/blob/4d33166f0869b929f59c6e6825a1b9505eb99967/ldap3/utils/dn.py#L390
|
||||
*/
|
||||
private class LdapEscapeDnCall extends DataFlow::CallCfgNode, Escaping::Range {
|
||||
LdapEscapeDnCall() {
|
||||
this =
|
||||
API::moduleImport("ldap3")
|
||||
.getMember("utils")
|
||||
.getMember("dn")
|
||||
.getMember("escape_rdn")
|
||||
.getACall()
|
||||
}
|
||||
|
||||
override DataFlow::Node getAnInput() { result in [this.getArg(0), this.getArgByName("rdn")] }
|
||||
|
||||
override DataFlow::Node getOutput() { result = this }
|
||||
|
||||
override string getKind() { result = Escaping::getLdapDnKind() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `ldap3.utils.conv.escape_filter_chars`.
|
||||
*
|
||||
* See https://github.com/cannatag/ldap3/blob/4d33166f0869b929f59c6e6825a1b9505eb99967/ldap3/utils/conv.py#L91
|
||||
*/
|
||||
private class LdapEscapeFilterCall extends DataFlow::CallCfgNode, Escaping::Range {
|
||||
LdapEscapeFilterCall() {
|
||||
this =
|
||||
API::moduleImport("ldap3")
|
||||
.getMember("utils")
|
||||
.getMember("conv")
|
||||
.getMember("escape_filter_chars")
|
||||
.getACall()
|
||||
}
|
||||
|
||||
override DataFlow::Node getAnInput() { result in [this.getArg(0), this.getArgByName("text")] }
|
||||
|
||||
override DataFlow::Node getOutput() { result = this }
|
||||
|
||||
override string getKind() { result = Escaping::getLdapFilterKind() }
|
||||
}
|
||||
}
|
||||
@@ -237,6 +237,54 @@ module Stdlib {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// logging
|
||||
// ---------------------------------------------------------------------------
|
||||
/**
|
||||
* Provides models for the `logging.Logger` class and subclasses.
|
||||
*
|
||||
* See https://docs.python.org/3.9/library/logging.html#logging.Logger.
|
||||
*/
|
||||
module Logger {
|
||||
/** Gets a reference to the `logging.Logger` class or any subclass. */
|
||||
private API::Node subclassRef() {
|
||||
result = API::moduleImport("logging").getMember("Logger").getASubclass*()
|
||||
}
|
||||
|
||||
/**
|
||||
* A source of instances of `logging.Logger`, extend this class to model new instances.
|
||||
*
|
||||
* This can include instantiations of the class, return values from function
|
||||
* calls, or a special parameter that will be set when functions are called by an external
|
||||
* library.
|
||||
*
|
||||
* Use the predicate `Logger::instance()` to get references to instances of `logging.Logger`.
|
||||
*/
|
||||
abstract class InstanceSource extends DataFlow::LocalSourceNode { }
|
||||
|
||||
/** A direct instantiation of `logging.Logger`. */
|
||||
private class ClassInstantiation extends InstanceSource, DataFlow::CfgNode {
|
||||
ClassInstantiation() {
|
||||
this = subclassRef().getACall()
|
||||
or
|
||||
this = API::moduleImport("logging").getMember("root").getAnImmediateUse()
|
||||
or
|
||||
this = API::moduleImport("logging").getMember("getLogger").getACall()
|
||||
}
|
||||
}
|
||||
|
||||
/** Gets a reference to an instance of `logging.Logger`. */
|
||||
private DataFlow::TypeTrackingNode instance(DataFlow::TypeTracker t) {
|
||||
t.start() and
|
||||
result instanceof InstanceSource
|
||||
or
|
||||
exists(DataFlow::TypeTracker t2 | result = instance(t2).track(t2, t))
|
||||
}
|
||||
|
||||
/** Gets a reference to an instance of `logging.Logger`. */
|
||||
DataFlow::Node instance() { instance(DataFlow::TypeTracker::end()).flowsTo(result) }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2642,27 +2690,6 @@ private module StdlibPrivate {
|
||||
// ---------------------------------------------------------------------------
|
||||
// logging
|
||||
// ---------------------------------------------------------------------------
|
||||
/**
|
||||
* Provides models for the `logging.Logger` class and subclasses.
|
||||
*
|
||||
* See https://docs.python.org/3.9/library/logging.html#logging.Logger.
|
||||
*/
|
||||
module Logger {
|
||||
/** Gets a reference to the `logging.Logger` class or any subclass. */
|
||||
API::Node subclassRef() {
|
||||
result = API::moduleImport("logging").getMember("Logger").getASubclass*()
|
||||
}
|
||||
|
||||
/** Gets a reference to an instance of `logging.Logger` or any subclass. */
|
||||
API::Node instance() {
|
||||
result = subclassRef().getReturn()
|
||||
or
|
||||
result = API::moduleImport("logging").getMember("root")
|
||||
or
|
||||
result = API::moduleImport("logging").getMember("getLogger").getReturn()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to one of the logging methods from `logging` or on a `logging.Logger`
|
||||
* subclass.
|
||||
@@ -2683,14 +2710,14 @@ private module StdlibPrivate {
|
||||
method = "log" and
|
||||
msgIndex = 1
|
||||
|
|
||||
this = Logger::instance().getMember(method).getACall()
|
||||
this.(DataFlow::MethodCallNode).calls(Stdlib::Logger::instance(), method)
|
||||
or
|
||||
this = API::moduleImport("logging").getMember(method).getACall()
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getAnInput() {
|
||||
result = this.getArgByName("msg")
|
||||
result = this.getArgByName(["msg", "extra"])
|
||||
or
|
||||
result = this.getArg(any(int i | i >= msgIndex))
|
||||
}
|
||||
|
||||
@@ -114,49 +114,33 @@ class ClassList extends TClassList {
|
||||
this = Empty() and result = Empty()
|
||||
}
|
||||
|
||||
predicate legalMergeHead(ClassObjectInternal cls) {
|
||||
this.getTail().doesNotContain(cls)
|
||||
or
|
||||
this = Empty()
|
||||
}
|
||||
|
||||
predicate contains(ClassObjectInternal cls) {
|
||||
cls = this.getHead()
|
||||
or
|
||||
this.getTail().contains(cls)
|
||||
}
|
||||
|
||||
/** Use negative formulation to avoid negative recursion */
|
||||
predicate doesNotContain(ClassObjectInternal cls) {
|
||||
this.relevantForContains(cls) and
|
||||
cls != this.getHead() and
|
||||
this.getTail().doesNotContain(cls)
|
||||
or
|
||||
this = Empty()
|
||||
}
|
||||
|
||||
private predicate relevantForContains(ClassObjectInternal cls) {
|
||||
exists(ClassListList list |
|
||||
list.getItem(_).getHead() = cls and
|
||||
list.getItem(_) = this
|
||||
)
|
||||
or
|
||||
exists(ClassList l |
|
||||
l.relevantForContains(cls) and
|
||||
this = l.getTail()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
ClassObjectInternal findDeclaringClass(string name) {
|
||||
exists(ClassDecl head | head = this.getHead().getClassDeclaration() |
|
||||
if head.declaresAttribute(name)
|
||||
then result = this.getHead()
|
||||
else result = this.getTail().findDeclaringClass(name)
|
||||
exists(ClassObjectInternal head, ClassList tail, ClassDecl decl |
|
||||
this = Cons(head, tail) and decl = head.getClassDeclaration()
|
||||
|
|
||||
if decl.declaresAttribute(name) then result = head else result = tail.findDeclaringClass(name)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private ClassObjectInternal findDeclaringClassAttribute(string name) {
|
||||
result = this.findDeclaringClass(name) and
|
||||
(
|
||||
exists(any(Builtin b).getMember(name))
|
||||
or
|
||||
declaredAttributeVar(_, name, _)
|
||||
)
|
||||
}
|
||||
|
||||
predicate lookup(string name, ObjectInternal value, CfgOrigin origin) {
|
||||
exists(ClassObjectInternal decl | decl = this.findDeclaringClass(name) |
|
||||
exists(ClassObjectInternal decl | decl = this.findDeclaringClassAttribute(name) |
|
||||
Types::declaredAttribute(decl, name, value, origin)
|
||||
)
|
||||
}
|
||||
@@ -199,12 +183,18 @@ class ClassList extends TClassList {
|
||||
or
|
||||
this.duplicate(n) and result = this.deduplicate(n + 1)
|
||||
or
|
||||
exists(ClassObjectInternal cls |
|
||||
n = this.firstIndex(cls) and
|
||||
result = Cons(cls, this.deduplicate(n + 1))
|
||||
exists(ClassObjectInternal cls, ClassList tail |
|
||||
this.deduplicateCons(n, cls, tail) and
|
||||
result = Cons(cls, tail)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate deduplicateCons(int n, ClassObjectInternal cls, ClassList tail) {
|
||||
n = this.firstIndex(cls) and
|
||||
tail = this.deduplicate(n + 1)
|
||||
}
|
||||
|
||||
predicate isEmpty() { this = Empty() }
|
||||
|
||||
ClassList reverse() { reverse_step(this, Empty(), result) }
|
||||
@@ -273,6 +263,24 @@ private class ClassListList extends TClassListList {
|
||||
result = this.getTail().getItem(n - 1)
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as
|
||||
*
|
||||
* ```ql
|
||||
* result = this.getItem(n) and n = this.length() - 1
|
||||
* ```
|
||||
*
|
||||
* but avoids non-linear recursion.
|
||||
*/
|
||||
ClassList getLastItem(int n) {
|
||||
n = 0 and this = ConsList(result, EmptyList())
|
||||
or
|
||||
exists(ClassListList tail |
|
||||
this = ConsList(_, tail) and
|
||||
result = tail.getLastItem(n - 1)
|
||||
)
|
||||
}
|
||||
|
||||
private ClassObjectInternal getAHead() {
|
||||
result = this.getHead().getHead()
|
||||
or
|
||||
@@ -295,17 +303,26 @@ private class ClassListList extends TClassListList {
|
||||
ClassObjectInternal cls, ClassList removed_head, ClassListList removed_tail, int n
|
||||
) {
|
||||
cls = this.bestMergeCandidate() and
|
||||
n = this.length() - 1 and
|
||||
removed_head = this.getItem(n).removeHead(cls) and
|
||||
removed_head = this.getLastItem(n).removeHead(cls) and
|
||||
removed_tail = EmptyList()
|
||||
or
|
||||
removed_head = this.removedClassPartsCons1(cls, removed_tail, n).removeHead(cls)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate removedClassPartsCons0(ClassObjectInternal cls, ClassListList removed_tail, int n) {
|
||||
exists(ClassList prev_head, ClassListList prev_tail |
|
||||
this.removedClassParts(cls, prev_head, prev_tail, n + 1) and
|
||||
removed_head = this.getItem(n).removeHead(cls) and
|
||||
removed_tail = ConsList(prev_head, prev_tail)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
ClassList removedClassPartsCons1(ClassObjectInternal cls, ClassListList removed_tail, int n) {
|
||||
this.removedClassPartsCons0(cls, removed_tail, n) and
|
||||
result = this.getItem(n)
|
||||
}
|
||||
|
||||
ClassListList remove(ClassObjectInternal cls) {
|
||||
exists(ClassList removed_head, ClassListList removed_tail |
|
||||
this.removedClassParts(cls, removed_head, removed_tail, 0) and
|
||||
@@ -315,18 +332,34 @@ private class ClassListList extends TClassListList {
|
||||
this = EmptyList() and result = EmptyList()
|
||||
}
|
||||
|
||||
predicate legalMergeCandidate(ClassObjectInternal cls, int n) {
|
||||
cls = this.getAHead() and n = this.length()
|
||||
pragma[nomagic]
|
||||
private predicate legalMergeCandidateNonEmpty(
|
||||
ClassObjectInternal cls, ClassListList remainingList, ClassList remaining
|
||||
) {
|
||||
this.legalMergeCandidate(cls, ConsList(Cons(_, remaining), remainingList))
|
||||
or
|
||||
this.getItem(n).legalMergeHead(cls) and
|
||||
this.legalMergeCandidate(cls, n + 1)
|
||||
exists(ClassObjectInternal head |
|
||||
this.legalMergeCandidateNonEmpty(cls, remainingList, Cons(head, remaining)) and
|
||||
cls != head
|
||||
)
|
||||
}
|
||||
|
||||
predicate legalMergeCandidate(ClassObjectInternal cls) { this.legalMergeCandidate(cls, 0) }
|
||||
private predicate legalMergeCandidate(ClassObjectInternal cls, ClassListList remaining) {
|
||||
cls = this.getAHead() and remaining = this
|
||||
or
|
||||
this.legalMergeCandidate(cls, ConsList(Empty(), remaining))
|
||||
or
|
||||
this.legalMergeCandidateNonEmpty(cls, remaining, Empty())
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
predicate legalMergeCandidate(ClassObjectInternal cls) {
|
||||
this.legalMergeCandidate(cls, EmptyList())
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
predicate illegalMergeCandidate(ClassObjectInternal cls) {
|
||||
cls = this.getAHead() and
|
||||
this.getItem(_).getTail().contains(cls)
|
||||
this.legalMergeCandidateNonEmpty(cls, _, Cons(cls, _))
|
||||
}
|
||||
|
||||
ClassObjectInternal bestMergeCandidate(int n) {
|
||||
@@ -337,6 +370,7 @@ private class ClassListList extends TClassListList {
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
ClassObjectInternal bestMergeCandidate() { result = this.bestMergeCandidate(0) }
|
||||
|
||||
/**
|
||||
@@ -417,16 +451,27 @@ private predicate merge_step(
|
||||
remaining_list = original
|
||||
or
|
||||
/* Removes the best merge candidate from `remaining_list` and prepends it to `reversed_mro` */
|
||||
exists(ClassObjectInternal head, ClassList prev_reverse_mro, ClassListList prev_list |
|
||||
merge_step(prev_reverse_mro, prev_list, original) and
|
||||
head = prev_list.bestMergeCandidate() and
|
||||
reversed_mro = Cons(head, prev_reverse_mro) and
|
||||
remaining_list = prev_list.remove(head)
|
||||
exists(ClassObjectInternal head, ClassList prev_reverse_mro |
|
||||
merge_stepCons(head, prev_reverse_mro, remaining_list, original) and
|
||||
reversed_mro = Cons(head, prev_reverse_mro)
|
||||
)
|
||||
or
|
||||
merge_step(reversed_mro, ConsList(Empty(), remaining_list), original)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate merge_stepCons(
|
||||
ClassObjectInternal head, ClassList prev_reverse_mro, ClassListList remaining_list,
|
||||
ClassListList original
|
||||
) {
|
||||
/* Removes the best merge candidate from `remaining_list` and prepends it to `reversed_mro` */
|
||||
exists(ClassListList prev_list |
|
||||
merge_step(prev_reverse_mro, prev_list, original) and
|
||||
head = prev_list.bestMergeCandidate() and
|
||||
remaining_list = prev_list.remove(head)
|
||||
)
|
||||
}
|
||||
|
||||
/* Helpers for `ClassList.reverse()` */
|
||||
private predicate needs_reversing(ClassList lst) {
|
||||
merge_step(lst, EmptyList(), _)
|
||||
@@ -439,10 +484,17 @@ private predicate reverse_step(ClassList lst, ClassList remainder, ClassList rev
|
||||
or
|
||||
exists(ClassObjectInternal head, ClassList tail |
|
||||
reversed = Cons(head, tail) and
|
||||
reverse_step(lst, Cons(head, remainder), tail)
|
||||
reverse_stepCons(lst, remainder, head, tail)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate reverse_stepCons(
|
||||
ClassList lst, ClassList remainder, ClassObjectInternal head, ClassList tail
|
||||
) {
|
||||
reverse_step(lst, Cons(head, remainder), tail)
|
||||
}
|
||||
|
||||
module Mro {
|
||||
cached
|
||||
ClassList newStyleMro(ClassObjectInternal cls) {
|
||||
|
||||
@@ -1429,20 +1429,51 @@ module Expressions {
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
predicate subscriptPointsTo(
|
||||
private predicate indexPointsToInt(ControlFlowNode index, PointsToContext context, int n) {
|
||||
index = any(SubscriptNode subscr).getIndex() and
|
||||
PointsToInternal::pointsTo(index, context, TInt(n), _)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate getItemSequenceObjectInternal(
|
||||
ObjectInternal value, SequenceObjectInternal objvalue, int n
|
||||
) {
|
||||
value = objvalue.getItem(n)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate subscriptObjectAndIndexPointsToInt(
|
||||
SubscriptNode subscr, PointsToContext context, ControlFlowNode obj, ObjectInternal objvalue,
|
||||
int n
|
||||
) {
|
||||
exists(ControlFlowNode index |
|
||||
subscriptObjectAndIndex(subscr, context, obj, objvalue, index) and
|
||||
indexPointsToInt(index, context, n)
|
||||
)
|
||||
}
|
||||
|
||||
deprecated predicate subscriptPointsTo(
|
||||
SubscriptNode subscr, PointsToContext context, ObjectInternal value, ControlFlowNode origin,
|
||||
ControlFlowNode obj, ObjectInternal objvalue
|
||||
) {
|
||||
subscriptPointsTo(subscr, context, value, obj, objvalue) and
|
||||
origin = subscr
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate subscriptPointsTo(
|
||||
SubscriptNode subscr, PointsToContext context, ObjectInternal value, ControlFlowNode obj,
|
||||
ObjectInternal objvalue
|
||||
) {
|
||||
exists(ControlFlowNode index | subscriptObjectAndIndex(subscr, context, obj, objvalue, index) |
|
||||
objvalue.subscriptUnknown() and
|
||||
value = ObjectInternal::unknown()
|
||||
or
|
||||
exists(int n |
|
||||
PointsToInternal::pointsTo(index, context, TInt(n), _) and
|
||||
value = objvalue.(SequenceObjectInternal).getItem(n)
|
||||
)
|
||||
) and
|
||||
origin = subscr
|
||||
)
|
||||
or
|
||||
exists(int n |
|
||||
subscriptObjectAndIndexPointsToInt(subscr, context, obj, objvalue, n) and
|
||||
getItemSequenceObjectInternal(value, objvalue, n)
|
||||
)
|
||||
}
|
||||
|
||||
predicate subscriptPartsPointsTo(
|
||||
@@ -1466,15 +1497,22 @@ module Expressions {
|
||||
index = subscr.getIndex()
|
||||
}
|
||||
|
||||
deprecated predicate binaryPointsTo(
|
||||
BinaryExprNode b, PointsToContext context, ObjectInternal value, ControlFlowNode origin,
|
||||
ControlFlowNode operand, ObjectInternal opvalue
|
||||
) {
|
||||
binaryPointsTo(b, context, value, operand, opvalue) and
|
||||
origin = b
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracking too many binary expressions is likely to kill performance, so just say anything other than addition or bitwise or is 'unknown'.
|
||||
*/
|
||||
pragma[noinline]
|
||||
predicate binaryPointsTo(
|
||||
BinaryExprNode b, PointsToContext context, ObjectInternal value, ControlFlowNode origin,
|
||||
ControlFlowNode operand, ObjectInternal opvalue
|
||||
private predicate binaryPointsTo(
|
||||
BinaryExprNode b, PointsToContext context, ObjectInternal value, ControlFlowNode operand,
|
||||
ObjectInternal opvalue
|
||||
) {
|
||||
origin = b and
|
||||
operand = genericBinaryOperand(b) and
|
||||
PointsToInternal::pointsTo(operand, context, opvalue, _) and
|
||||
value = ObjectInternal::unknown()
|
||||
@@ -1491,12 +1529,19 @@ module Expressions {
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
predicate addPointsTo(
|
||||
deprecated predicate addPointsTo(
|
||||
BinaryExprNode b, PointsToContext context, ObjectInternal value, ControlFlowNode origin,
|
||||
ControlFlowNode operand, ObjectInternal opvalue
|
||||
) {
|
||||
origin = b and
|
||||
addPointsTo(b, context, value, operand, opvalue) and
|
||||
origin = b
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate addPointsTo(
|
||||
BinaryExprNode b, PointsToContext context, ObjectInternal value, ControlFlowNode operand,
|
||||
ObjectInternal opvalue
|
||||
) {
|
||||
exists(Operator op |
|
||||
b.operands(operand, op, _)
|
||||
or
|
||||
@@ -1508,12 +1553,19 @@ module Expressions {
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
predicate bitOrPointsTo(
|
||||
deprecated predicate bitOrPointsTo(
|
||||
BinaryExprNode b, PointsToContext context, ObjectInternal value, ControlFlowNode origin,
|
||||
ControlFlowNode operand, ObjectInternal opvalue
|
||||
) {
|
||||
origin = b and
|
||||
bitOrPointsTo(b, context, value, operand, opvalue) and
|
||||
origin = b
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate bitOrPointsTo(
|
||||
BinaryExprNode b, PointsToContext context, ObjectInternal value, ControlFlowNode operand,
|
||||
ObjectInternal opvalue
|
||||
) {
|
||||
exists(Operator op, ControlFlowNode other |
|
||||
b.operands(operand, op, other)
|
||||
or
|
||||
@@ -1533,10 +1585,18 @@ module Expressions {
|
||||
value = obj.intValue()
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
predicate unaryPointsTo(
|
||||
deprecated predicate unaryPointsTo(
|
||||
UnaryExprNode u, PointsToContext context, ObjectInternal value, ControlFlowNode origin,
|
||||
ControlFlowNode operand, ObjectInternal opvalue
|
||||
) {
|
||||
unaryPointsTo(u, context, value, operand, opvalue) and
|
||||
origin = u
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate unaryPointsTo(
|
||||
UnaryExprNode u, PointsToContext context, ObjectInternal value, ControlFlowNode operand,
|
||||
ObjectInternal opvalue
|
||||
) {
|
||||
exists(Unaryop op |
|
||||
op = u.getNode().getOp() and
|
||||
@@ -1548,14 +1608,21 @@ module Expressions {
|
||||
op instanceof USub and value = ObjectInternal::fromInt(-opvalue.intValue())
|
||||
or
|
||||
not op instanceof Not and opvalue = ObjectInternal::unknown() and value = opvalue
|
||||
) and
|
||||
origin = u
|
||||
)
|
||||
}
|
||||
|
||||
deprecated predicate builtinCallPointsTo(
|
||||
CallNode call, PointsToContext context, ObjectInternal value, ControlFlowNode origin,
|
||||
ControlFlowNode arg, ObjectInternal argvalue
|
||||
) {
|
||||
builtinCallPointsTo(call, context, value, arg, argvalue) and
|
||||
origin = call
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
predicate builtinCallPointsTo(
|
||||
CallNode call, PointsToContext context, ObjectInternal value, ControlFlowNode origin,
|
||||
ControlFlowNode arg, ObjectInternal argvalue
|
||||
private predicate builtinCallPointsTo(
|
||||
CallNode call, PointsToContext context, ObjectInternal value, ControlFlowNode arg,
|
||||
ObjectInternal argvalue
|
||||
) {
|
||||
PointsToInternal::pointsTo(arg, context, argvalue, _) and
|
||||
arg = call.getArg(0) and
|
||||
@@ -1569,8 +1636,7 @@ module Expressions {
|
||||
callable != ObjectInternal::builtin("hasattr") and
|
||||
callable.isClass() = false and
|
||||
value = ObjectInternal::unknown()
|
||||
) and
|
||||
origin = call
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
@@ -1585,11 +1651,10 @@ module Expressions {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate lenCallPointsTo(
|
||||
CallNode call, PointsToContext context, ObjectInternal value, ControlFlowNode origin,
|
||||
ControlFlowNode arg, ObjectInternal argvalue
|
||||
CallNode call, PointsToContext context, ObjectInternal value, ControlFlowNode arg,
|
||||
ObjectInternal argvalue
|
||||
) {
|
||||
len_call(call, arg, context, argvalue) and
|
||||
origin = call and
|
||||
exists(int len | len = argvalue.length() |
|
||||
value = TInt(len) and len >= 0
|
||||
or
|
||||
@@ -1815,19 +1880,26 @@ module Expressions {
|
||||
) {
|
||||
attributePointsTo(expr, context, value, origin, subexpr, subvalue)
|
||||
or
|
||||
subscriptPointsTo(expr, context, value, origin, subexpr, subvalue)
|
||||
subscriptPointsTo(expr, context, value, subexpr, subvalue) and
|
||||
origin = expr
|
||||
or
|
||||
addPointsTo(expr, context, value, origin, subexpr, subvalue)
|
||||
addPointsTo(expr, context, value, subexpr, subvalue) and
|
||||
origin = expr
|
||||
or
|
||||
bitOrPointsTo(expr, context, value, origin, subexpr, subvalue)
|
||||
bitOrPointsTo(expr, context, value, subexpr, subvalue) and
|
||||
origin = expr
|
||||
or
|
||||
binaryPointsTo(expr, context, value, origin, subexpr, subvalue)
|
||||
binaryPointsTo(expr, context, value, subexpr, subvalue) and
|
||||
origin = expr
|
||||
or
|
||||
unaryPointsTo(expr, context, value, origin, subexpr, subvalue)
|
||||
unaryPointsTo(expr, context, value, subexpr, subvalue) and
|
||||
origin = expr
|
||||
or
|
||||
builtinCallPointsTo(expr, context, value, origin, subexpr, subvalue)
|
||||
builtinCallPointsTo(expr, context, value, subexpr, subvalue) and
|
||||
origin = expr
|
||||
or
|
||||
lenCallPointsTo(expr, context, value, origin, subexpr, subvalue)
|
||||
lenCallPointsTo(expr, context, value, subexpr, subvalue) and
|
||||
origin = expr
|
||||
or
|
||||
typeCallPointsTo(expr, context, value, origin, subexpr, subvalue)
|
||||
or
|
||||
@@ -2068,6 +2140,12 @@ module Conditionals {
|
||||
}
|
||||
}
|
||||
|
||||
/** INTERNAL: Do not use. */
|
||||
predicate declaredAttributeVar(PythonClassObjectInternal cls, string name, EssaVariable var) {
|
||||
name = var.getName() and
|
||||
var.getAUse() = cls.getScope().getANormalExit()
|
||||
}
|
||||
|
||||
cached
|
||||
module Types {
|
||||
cached
|
||||
@@ -2163,8 +2241,7 @@ module Types {
|
||||
or
|
||||
value != ObjectInternal::undefined() and
|
||||
exists(EssaVariable var |
|
||||
name = var.getName() and
|
||||
var.getAUse() = cls.(PythonClassObjectInternal).getScope().getANormalExit() and
|
||||
declaredAttributeVar(cls, name, var) and
|
||||
PointsToInternal::variablePointsTo(var, _, value, origin)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -427,6 +427,7 @@ abstract class RegexString extends Expr {
|
||||
}
|
||||
|
||||
predicate normalCharacter(int start, int end) {
|
||||
end = start + 1 and
|
||||
this.character(start, end) and
|
||||
not this.specialCharacter(start, end, _)
|
||||
}
|
||||
@@ -446,6 +447,49 @@ abstract class RegexString extends Expr {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the range [start:end) consists of only 'normal' characters.
|
||||
*/
|
||||
predicate normalCharacterSequence(int start, int end) {
|
||||
// a normal character inside a character set is interpreted on its own
|
||||
this.normalCharacter(start, end) and
|
||||
this.inCharSet(start)
|
||||
or
|
||||
// a maximal run of normal characters is considered as one constant
|
||||
exists(int s, int e |
|
||||
e = max(int i | this.normalCharacterRun(s, i)) and
|
||||
not this.inCharSet(s)
|
||||
|
|
||||
// 'abc' can be considered one constant, but
|
||||
// 'abc+' has to be broken up into 'ab' and 'c+',
|
||||
// as the qualifier only applies to 'c'.
|
||||
if this.qualifier(e, _, _, _)
|
||||
then
|
||||
end = e and start = e - 1
|
||||
or
|
||||
end = e - 1 and start = s and start < end
|
||||
else (
|
||||
end = e and
|
||||
start = s
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate normalCharacterRun(int start, int end) {
|
||||
(
|
||||
this.normalCharacterRun(start, end - 1)
|
||||
or
|
||||
start = end - 1 and not this.normalCharacter(start - 1, start)
|
||||
) and
|
||||
this.normalCharacter(end - 1, end)
|
||||
}
|
||||
|
||||
private predicate characterItem(int start, int end) {
|
||||
this.normalCharacterSequence(start, end) or
|
||||
this.escapedCharacter(start, end) or
|
||||
this.specialCharacter(start, end, _)
|
||||
}
|
||||
|
||||
/** Whether the text in the range start,end is a group */
|
||||
predicate group(int start, int end) {
|
||||
this.groupContents(start, end, _, _)
|
||||
@@ -717,7 +761,7 @@ abstract class RegexString extends Expr {
|
||||
string getBackrefName(int start, int end) { this.named_backreference(start, end, result) }
|
||||
|
||||
private predicate baseItem(int start, int end) {
|
||||
this.character(start, end) and
|
||||
this.characterItem(start, end) and
|
||||
not exists(int x, int y | this.charSet(x, y) and x <= start and y >= end)
|
||||
or
|
||||
this.group(start, end)
|
||||
@@ -837,14 +881,14 @@ abstract class RegexString extends Expr {
|
||||
}
|
||||
|
||||
private predicate item_start(int start) {
|
||||
this.character(start, _) or
|
||||
this.characterItem(start, _) or
|
||||
this.isGroupStart(start) or
|
||||
this.charSet(start, _) or
|
||||
this.backreference(start, _)
|
||||
}
|
||||
|
||||
private predicate item_end(int end) {
|
||||
this.character(_, end)
|
||||
this.characterItem(_, end)
|
||||
or
|
||||
exists(int endm1 | this.isGroupEnd(endm1) and end = endm1 + 1)
|
||||
or
|
||||
@@ -953,7 +997,7 @@ abstract class RegexString extends Expr {
|
||||
*/
|
||||
predicate firstItem(int start, int end) {
|
||||
(
|
||||
this.character(start, end)
|
||||
this.characterItem(start, end)
|
||||
or
|
||||
this.qualifiedItem(start, end, _, _)
|
||||
or
|
||||
@@ -968,7 +1012,7 @@ abstract class RegexString extends Expr {
|
||||
*/
|
||||
predicate lastItem(int start, int end) {
|
||||
(
|
||||
this.character(start, end)
|
||||
this.characterItem(start, end)
|
||||
or
|
||||
this.qualifiedItem(start, end, _, _)
|
||||
or
|
||||
|
||||
@@ -4,7 +4,7 @@ import semmle.python.security.SensitiveData
|
||||
import semmle.python.dataflow.Files
|
||||
import semmle.python.web.Http
|
||||
|
||||
module ClearTextStorage {
|
||||
deprecated module ClearTextStorage {
|
||||
abstract class Sink extends TaintSink {
|
||||
override predicate sinks(TaintKind kind) { kind instanceof SensitiveData }
|
||||
}
|
||||
@@ -26,7 +26,7 @@ module ClearTextStorage {
|
||||
}
|
||||
}
|
||||
|
||||
module ClearTextLogging {
|
||||
deprecated module ClearTextLogging {
|
||||
abstract class Sink extends TaintSink {
|
||||
override predicate sinks(TaintKind kind) { kind instanceof SensitiveData }
|
||||
}
|
||||
|
||||
@@ -3,12 +3,12 @@ import semmle.python.dataflow.TaintTracking
|
||||
private import semmle.python.security.SensitiveData
|
||||
private import semmle.crypto.Crypto as CryptoLib
|
||||
|
||||
abstract class WeakCryptoSink extends TaintSink {
|
||||
abstract deprecated class WeakCryptoSink extends TaintSink {
|
||||
override predicate sinks(TaintKind taint) { taint instanceof SensitiveData }
|
||||
}
|
||||
|
||||
/** Modeling the 'pycrypto' package https://github.com/dlitz/pycrypto (latest release 2013) */
|
||||
module Pycrypto {
|
||||
deprecated module Pycrypto {
|
||||
ModuleValue cipher(string name) { result = Module::named("Crypto.Cipher").attr(name) }
|
||||
|
||||
class CipherInstance extends TaintKind {
|
||||
@@ -58,7 +58,7 @@ module Pycrypto {
|
||||
}
|
||||
}
|
||||
|
||||
module Cryptography {
|
||||
deprecated module Cryptography {
|
||||
ModuleValue ciphers() {
|
||||
result = Module::named("cryptography.hazmat.primitives.ciphers") and
|
||||
result.isPackage()
|
||||
@@ -128,7 +128,7 @@ module Cryptography {
|
||||
}
|
||||
}
|
||||
|
||||
private class CipherConfig extends TaintTracking::Configuration {
|
||||
deprecated private class CipherConfig extends TaintTracking::Configuration {
|
||||
CipherConfig() { this = "Crypto cipher config" }
|
||||
|
||||
override predicate isSource(TaintTracking::Source source) {
|
||||
|
||||
@@ -7,13 +7,15 @@ import python
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.security.strings.Basic
|
||||
|
||||
private Value traceback_function(string name) { result = Module::named("traceback").attr(name) }
|
||||
deprecated private Value traceback_function(string name) {
|
||||
result = Module::named("traceback").attr(name)
|
||||
}
|
||||
|
||||
/**
|
||||
* This represents information relating to an exception, for instance the
|
||||
* message, arguments or parts of the exception traceback.
|
||||
*/
|
||||
class ExceptionInfo extends StringKind {
|
||||
deprecated class ExceptionInfo extends StringKind {
|
||||
ExceptionInfo() { this = "exception.info" }
|
||||
|
||||
override string repr() { result = "exception info" }
|
||||
@@ -23,12 +25,12 @@ class ExceptionInfo extends StringKind {
|
||||
* A class representing sources of information about
|
||||
* execution state exposed in tracebacks and the like.
|
||||
*/
|
||||
abstract class ErrorInfoSource extends TaintSource { }
|
||||
abstract deprecated class ErrorInfoSource extends TaintSource { }
|
||||
|
||||
/**
|
||||
* This kind represents exceptions themselves.
|
||||
*/
|
||||
class ExceptionKind extends TaintKind {
|
||||
deprecated class ExceptionKind extends TaintKind {
|
||||
ExceptionKind() { this = "exception.kind" }
|
||||
|
||||
override string repr() { result = "exception" }
|
||||
@@ -44,7 +46,7 @@ class ExceptionKind extends TaintKind {
|
||||
* A source of exception objects, either explicitly created, or captured by an
|
||||
* `except` statement.
|
||||
*/
|
||||
class ExceptionSource extends ErrorInfoSource {
|
||||
deprecated class ExceptionSource extends ErrorInfoSource {
|
||||
ExceptionSource() {
|
||||
exists(ClassValue cls |
|
||||
cls.getASuperType() = ClassValue::baseException() and
|
||||
@@ -63,7 +65,7 @@ class ExceptionSource extends ErrorInfoSource {
|
||||
* Represents a sequence of pieces of information relating to an exception,
|
||||
* for instance the contents of the `args` attribute, or the stack trace.
|
||||
*/
|
||||
class ExceptionInfoSequence extends SequenceKind {
|
||||
deprecated class ExceptionInfoSequence extends SequenceKind {
|
||||
ExceptionInfoSequence() { this.getItem() instanceof ExceptionInfo }
|
||||
}
|
||||
|
||||
@@ -71,7 +73,7 @@ class ExceptionInfoSequence extends SequenceKind {
|
||||
* Represents calls to functions in the `traceback` module that return
|
||||
* sequences of exception information.
|
||||
*/
|
||||
class CallToTracebackFunction extends ErrorInfoSource {
|
||||
deprecated class CallToTracebackFunction extends ErrorInfoSource {
|
||||
CallToTracebackFunction() {
|
||||
exists(string name |
|
||||
name in [
|
||||
@@ -92,7 +94,7 @@ class CallToTracebackFunction extends ErrorInfoSource {
|
||||
* Represents calls to functions in the `traceback` module that return a single
|
||||
* string of information about an exception.
|
||||
*/
|
||||
class FormattedTracebackSource extends ErrorInfoSource {
|
||||
deprecated class FormattedTracebackSource extends ErrorInfoSource {
|
||||
FormattedTracebackSource() { this = traceback_function("format_exc").getACall() }
|
||||
|
||||
override string toString() { result = "exception.info.source" }
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import semmle.python.dataflow.Implementation
|
||||
|
||||
module TaintTrackingPaths {
|
||||
deprecated module TaintTrackingPaths {
|
||||
predicate edge(TaintTrackingNode src, TaintTrackingNode dest, string label) {
|
||||
exists(TaintTrackingNode source, TaintTrackingNode sink |
|
||||
source.getConfiguration().hasFlowPath(source, sink) and
|
||||
@@ -11,6 +11,6 @@ module TaintTrackingPaths {
|
||||
}
|
||||
}
|
||||
|
||||
query predicate edges(TaintTrackingNode fromnode, TaintTrackingNode tonode) {
|
||||
deprecated query predicate edges(TaintTrackingNode fromnode, TaintTrackingNode tonode) {
|
||||
TaintTrackingPaths::edge(fromnode, tonode, _)
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ import semmle.python.web.HttpRequest
|
||||
import semmle.python.security.internal.SensitiveDataHeuristics
|
||||
private import HeuristicNames
|
||||
|
||||
abstract class SensitiveData extends TaintKind {
|
||||
abstract deprecated class SensitiveData extends TaintKind {
|
||||
bindingset[this]
|
||||
SensitiveData() { this = this }
|
||||
|
||||
@@ -23,7 +23,7 @@ abstract class SensitiveData extends TaintKind {
|
||||
abstract SensitiveDataClassification getClassification();
|
||||
}
|
||||
|
||||
module SensitiveData {
|
||||
deprecated module SensitiveData {
|
||||
class Secret extends SensitiveData {
|
||||
Secret() { this = "sensitive.data.secret" }
|
||||
|
||||
@@ -115,4 +115,4 @@ module SensitiveData {
|
||||
}
|
||||
|
||||
//Backwards compatibility
|
||||
class SensitiveDataSource = SensitiveData::Source;
|
||||
deprecated class SensitiveDataSource = SensitiveData::Source;
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* Provides taint-tracking configurations for detecting LDAP injection vulnerabilities
|
||||
*
|
||||
* Note, for performance reasons: only import this file if
|
||||
* `LdapInjection::Configuration` is needed, otherwise
|
||||
* `LdapInjectionCustomizations` should be imported instead.
|
||||
*/
|
||||
|
||||
import python
|
||||
import semmle.python.Concepts
|
||||
import semmle.python.dataflow.new.DataFlow
|
||||
import semmle.python.dataflow.new.TaintTracking
|
||||
import semmle.python.dataflow.new.RemoteFlowSources
|
||||
|
||||
/**
|
||||
* Provides aint-tracking configurations for detecting LDAP injection vulnerabilities.class
|
||||
*
|
||||
* Two configurations are provided. One is for detecting LDAP injection
|
||||
* via the distinguished name (DN). The other is for detecting LDAP injection
|
||||
* via the filter. These require different escapings.
|
||||
*/
|
||||
module LdapInjection {
|
||||
import LdapInjectionCustomizations::LdapInjection
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for detecting LDAP injection vulnerabilities
|
||||
* via the distinguished name (DN) parameter of an LDAP search.
|
||||
*/
|
||||
class DnConfiguration extends TaintTracking::Configuration {
|
||||
DnConfiguration() { this = "LdapDnInjection" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof DnSink }
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) { node instanceof DnSanitizer }
|
||||
|
||||
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
|
||||
guard instanceof DnSanitizerGuard
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for detecting LDAP injection vulnerabilities
|
||||
* via the filter parameter of an LDAP search.
|
||||
*/
|
||||
class FilterConfiguration extends TaintTracking::Configuration {
|
||||
FilterConfiguration() { this = "LdapFilterInjection" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof FilterSink }
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) { node instanceof FilterSanitizer }
|
||||
|
||||
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
|
||||
guard instanceof FilterSanitizerGuard
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* Provides default sources, sinks and sanitizers for detecting
|
||||
* "ldap injection"
|
||||
* vulnerabilities, as well as extension points for adding your own.
|
||||
*/
|
||||
|
||||
private import python
|
||||
private import semmle.python.dataflow.new.DataFlow
|
||||
private import semmle.python.Concepts
|
||||
private import semmle.python.dataflow.new.RemoteFlowSources
|
||||
private import semmle.python.dataflow.new.BarrierGuards
|
||||
|
||||
/**
|
||||
* Provides default sources, sinks and sanitizers for detecting
|
||||
* "ldap injection"
|
||||
* vulnerabilities, as well as extension points for adding your own.
|
||||
*/
|
||||
module LdapInjection {
|
||||
/**
|
||||
* A data flow source for "ldap injection" vulnerabilities.
|
||||
*/
|
||||
abstract class Source extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* A data flow sink for "ldap injection" vulnerabilities.
|
||||
*/
|
||||
abstract class DnSink extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* A data flow sink for "ldap injection" vulnerabilities.
|
||||
*/
|
||||
abstract class FilterSink extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* A sanitizer for "ldap injection" vulnerabilities.
|
||||
*/
|
||||
abstract class DnSanitizer extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* A sanitizer for "ldap injection" vulnerabilities.
|
||||
*/
|
||||
abstract class FilterSanitizer extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* A sanitizer guard for "ldap injection" vulnerabilities.
|
||||
*/
|
||||
abstract class DnSanitizerGuard extends DataFlow::BarrierGuard { }
|
||||
|
||||
/**
|
||||
* A sanitizer guard for "ldap injection" vulnerabilities.
|
||||
*/
|
||||
abstract class FilterSanitizerGuard extends DataFlow::BarrierGuard { }
|
||||
|
||||
/**
|
||||
* A source of remote user input, considered as a flow source.
|
||||
*/
|
||||
class RemoteFlowSourceAsSource extends Source, RemoteFlowSource { }
|
||||
|
||||
/**
|
||||
* A logging operation, considered as a flow sink.
|
||||
*/
|
||||
class LdapExecutionAsDnSink extends DnSink {
|
||||
LdapExecutionAsDnSink() { this = any(LDAP::LdapExecution ldap).getBaseDn() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A logging operation, considered as a flow sink.
|
||||
*/
|
||||
class LdapExecutionAsFilterSink extends FilterSink {
|
||||
LdapExecutionAsFilterSink() { this = any(LDAP::LdapExecution ldap).getFilter() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A comparison with a constant string, considered as a sanitizer-guard.
|
||||
*/
|
||||
class StringConstCompareAsDnSanitizerGuard extends DnSanitizerGuard, StringConstCompare { }
|
||||
|
||||
/**
|
||||
* A comparison with a constant string, considered as a sanitizer-guard.
|
||||
*/
|
||||
class StringConstCompareAsFilterSanitizerGuard extends FilterSanitizerGuard, StringConstCompare {
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to replace line breaks functions as a sanitizer.
|
||||
*/
|
||||
class LdapDnEscapingSanitizer extends DnSanitizer, DataFlow::CallCfgNode {
|
||||
LdapDnEscapingSanitizer() { this = any(LdapDnEscaping ldapDnEsc).getOutput() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to replace line breaks functions as a sanitizer.
|
||||
*/
|
||||
class LdapFilterEscapingSanitizer extends FilterSanitizer, DataFlow::CallCfgNode {
|
||||
LdapFilterEscapingSanitizer() { this = any(LdapFilterEscaping ldapDnEsc).getOutput() }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* Provides a taint-tracking configuration for tracking untrusted user input used in log entries.
|
||||
*
|
||||
* Note, for performance reasons: only import this file if
|
||||
* `LogInjection::Configuration` is needed, otherwise
|
||||
* `LogInjectionCustomizations` should be imported instead.
|
||||
*/
|
||||
|
||||
import python
|
||||
import semmle.python.dataflow.new.DataFlow
|
||||
import semmle.python.dataflow.new.TaintTracking
|
||||
|
||||
/**
|
||||
* Provides a taint-tracking configuration for tracking untrusted user input used in log entries.
|
||||
*/
|
||||
module LogInjection {
|
||||
import LogInjectionCustomizations::LogInjection
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for tracking untrusted user input used in log entries.
|
||||
*/
|
||||
class Configuration extends TaintTracking::Configuration {
|
||||
Configuration() { this = "LogInjection" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
|
||||
|
||||
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
|
||||
guard instanceof SanitizerGuard
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* Provides default sources, sinks and sanitizers for detecting
|
||||
* "log injection"
|
||||
* vulnerabilities, as well as extension points for adding your own.
|
||||
*/
|
||||
|
||||
private import python
|
||||
private import semmle.python.dataflow.new.DataFlow
|
||||
private import semmle.python.Concepts
|
||||
private import semmle.python.dataflow.new.RemoteFlowSources
|
||||
private import semmle.python.dataflow.new.BarrierGuards
|
||||
|
||||
/**
|
||||
* Provides default sources, sinks and sanitizers for detecting
|
||||
* "log injection"
|
||||
* vulnerabilities, as well as extension points for adding your own.
|
||||
*/
|
||||
module LogInjection {
|
||||
/**
|
||||
* A data flow source for "log injection" vulnerabilities.
|
||||
*/
|
||||
abstract class Source extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* A data flow sink for "log injection" vulnerabilities.
|
||||
*/
|
||||
abstract class Sink extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* A sanitizer for "log injection" vulnerabilities.
|
||||
*/
|
||||
abstract class Sanitizer extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* A sanitizer guard for "log injection" vulnerabilities.
|
||||
*/
|
||||
abstract class SanitizerGuard extends DataFlow::BarrierGuard { }
|
||||
|
||||
/**
|
||||
* A source of remote user input, considered as a flow source.
|
||||
*/
|
||||
class RemoteFlowSourceAsSource extends Source, RemoteFlowSource { }
|
||||
|
||||
/**
|
||||
* A logging operation, considered as a flow sink.
|
||||
*/
|
||||
class LoggingAsSink extends Sink {
|
||||
LoggingAsSink() { this = any(Logging write).getAnInput() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A comparison with a constant string, considered as a sanitizer-guard.
|
||||
*/
|
||||
class StringConstCompareAsSanitizerGuard extends SanitizerGuard, StringConstCompare { }
|
||||
|
||||
/**
|
||||
* A call to replace line breaks, considered as a sanitizer.
|
||||
*/
|
||||
class ReplaceLineBreaksSanitizer extends Sanitizer, DataFlow::CallCfgNode {
|
||||
// Note: This sanitizer is not 100% accurate, since:
|
||||
// - we do not check that all kinds of line breaks are replaced
|
||||
// - we do not check that one kind of line breaks is not replaced by another
|
||||
//
|
||||
// However, we lack a simple way to do better, and the query would likely
|
||||
// be too noisy without this.
|
||||
//
|
||||
// TODO: Consider rewriting using flow states.
|
||||
ReplaceLineBreaksSanitizer() {
|
||||
this.getFunction().(DataFlow::AttrRead).getAttributeName() = "replace" and
|
||||
this.getArg(0).asExpr().(StrConst).getText() in ["\r\n", "\n"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import python
|
||||
import semmle.python.security.strings.Basic
|
||||
|
||||
/** Assume that taint flows from argument to result for *any* call */
|
||||
class AnyCallStringFlow extends DataFlowExtension::DataFlowNode {
|
||||
deprecated class AnyCallStringFlow extends DataFlowExtension::DataFlowNode {
|
||||
AnyCallStringFlow() { any(CallNode call).getAnArg() = this }
|
||||
|
||||
override ControlFlowNode getASuccessorNode() { result.(CallNode).getAnArg() = this }
|
||||
|
||||
@@ -11,18 +11,18 @@ import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.security.strings.Untrusted
|
||||
|
||||
/** Abstract taint sink that is potentially vulnerable to malicious shell commands. */
|
||||
abstract class CommandSink extends TaintSink { }
|
||||
abstract deprecated class CommandSink extends TaintSink { }
|
||||
|
||||
private ModuleObject osOrPopenModule() { result.getName() = ["os", "popen2"] }
|
||||
deprecated private ModuleObject osOrPopenModule() { result.getName() = ["os", "popen2"] }
|
||||
|
||||
private Object makeOsCall() {
|
||||
deprecated private Object makeOsCall() {
|
||||
exists(string name | result = ModuleObject::named("subprocess").attr(name) |
|
||||
name = ["Popen", "call", "check_call", "check_output", "run"]
|
||||
)
|
||||
}
|
||||
|
||||
/**Special case for first element in sequence. */
|
||||
class FirstElementKind extends TaintKind {
|
||||
deprecated class FirstElementKind extends TaintKind {
|
||||
FirstElementKind() { this = "sequence[" + any(ExternalStringKind key) + "][0]" }
|
||||
|
||||
override string repr() { result = "first item in sequence of " + this.getItem().repr() }
|
||||
@@ -31,7 +31,7 @@ class FirstElementKind extends TaintKind {
|
||||
ExternalStringKind getItem() { this = "sequence[" + result + "][0]" }
|
||||
}
|
||||
|
||||
class FirstElementFlow extends DataFlowExtension::DataFlowNode {
|
||||
deprecated class FirstElementFlow extends DataFlowExtension::DataFlowNode {
|
||||
FirstElementFlow() { this = any(SequenceNode s).getElement(0) }
|
||||
|
||||
override ControlFlowNode getASuccessorNode(TaintKind fromkind, TaintKind tokind) {
|
||||
@@ -43,7 +43,7 @@ class FirstElementFlow extends DataFlowExtension::DataFlowNode {
|
||||
* A taint sink that is potentially vulnerable to malicious shell commands.
|
||||
* The `vuln` in `subprocess.call(shell=vuln)` and similar calls.
|
||||
*/
|
||||
class ShellCommand extends CommandSink {
|
||||
deprecated class ShellCommand extends CommandSink {
|
||||
override string toString() { result = "shell command" }
|
||||
|
||||
ShellCommand() {
|
||||
@@ -81,7 +81,7 @@ class ShellCommand extends CommandSink {
|
||||
* A taint sink that is potentially vulnerable to malicious shell commands.
|
||||
* The `vuln` in `subprocess.call(vuln, ...)` and similar calls.
|
||||
*/
|
||||
class OsCommandFirstArgument extends CommandSink {
|
||||
deprecated class OsCommandFirstArgument extends CommandSink {
|
||||
override string toString() { result = "OS command first argument" }
|
||||
|
||||
OsCommandFirstArgument() {
|
||||
@@ -111,7 +111,7 @@ class OsCommandFirstArgument extends CommandSink {
|
||||
* A taint sink that is potentially vulnerable to malicious shell commands.
|
||||
* The `vuln` in `invoke.run(vuln, ...)` and similar calls.
|
||||
*/
|
||||
class InvokeRun extends CommandSink {
|
||||
deprecated class InvokeRun extends CommandSink {
|
||||
InvokeRun() {
|
||||
this = Value::named("invoke.run").(FunctionValue).getArgumentForCall(_, 0)
|
||||
or
|
||||
@@ -127,12 +127,12 @@ class InvokeRun extends CommandSink {
|
||||
* Internal TaintKind to track the invoke.Context instance passed to functions
|
||||
* marked with @invoke.task
|
||||
*/
|
||||
private class InvokeContextArg extends TaintKind {
|
||||
deprecated private class InvokeContextArg extends TaintKind {
|
||||
InvokeContextArg() { this = "InvokeContextArg" }
|
||||
}
|
||||
|
||||
/** Internal TaintSource to track the context passed to functions marked with @invoke.task */
|
||||
private class InvokeContextArgSource extends TaintSource {
|
||||
deprecated private class InvokeContextArgSource extends TaintSource {
|
||||
InvokeContextArgSource() {
|
||||
exists(Function f, Expr decorator |
|
||||
count(f.getADecorator()) = 1 and
|
||||
@@ -158,7 +158,7 @@ private class InvokeContextArgSource extends TaintSource {
|
||||
* A taint sink that is potentially vulnerable to malicious shell commands.
|
||||
* The `vuln` in `invoke.Context().run(vuln, ...)` and similar calls.
|
||||
*/
|
||||
class InvokeContextRun extends CommandSink {
|
||||
deprecated class InvokeContextRun extends CommandSink {
|
||||
InvokeContextRun() {
|
||||
exists(CallNode call |
|
||||
any(InvokeContextArg k).taints(call.getFunction().(AttrNode).getObject("run"))
|
||||
@@ -187,7 +187,7 @@ class InvokeContextRun extends CommandSink {
|
||||
* A taint sink that is potentially vulnerable to malicious shell commands.
|
||||
* The `vuln` in `fabric.Group().run(vuln, ...)` and similar calls.
|
||||
*/
|
||||
class FabricGroupRun extends CommandSink {
|
||||
deprecated class FabricGroupRun extends CommandSink {
|
||||
FabricGroupRun() {
|
||||
exists(ClassValue cls |
|
||||
cls.getASuperType() = Value::named("fabric.Group") and
|
||||
@@ -203,7 +203,7 @@ class FabricGroupRun extends CommandSink {
|
||||
// -------------------------------------------------------------------------- //
|
||||
// Modeling of the 'invoke' package and 'fabric' package (v 1.x)
|
||||
// -------------------------------------------------------------------------- //
|
||||
class FabricV1Commands extends CommandSink {
|
||||
deprecated class FabricV1Commands extends CommandSink {
|
||||
FabricV1Commands() {
|
||||
// since `run` and `sudo` are decorated, we can't use FunctionValue's :(
|
||||
exists(CallNode call |
|
||||
@@ -228,7 +228,7 @@ class FabricV1Commands extends CommandSink {
|
||||
* An extension that propagates taint from the arguments of `fabric.api.execute(func, arg0, arg1, ...)`
|
||||
* to the parameters of `func`, since this will call `func(arg0, arg1, ...)`.
|
||||
*/
|
||||
class FabricExecuteExtension extends DataFlowExtension::DataFlowNode {
|
||||
deprecated class FabricExecuteExtension extends DataFlowExtension::DataFlowNode {
|
||||
CallNode call;
|
||||
|
||||
FabricExecuteExtension() {
|
||||
|
||||
@@ -2,7 +2,7 @@ import python
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
|
||||
/** `pickle.loads(untrusted)` vulnerability. */
|
||||
abstract class DeserializationSink extends TaintSink {
|
||||
abstract deprecated class DeserializationSink extends TaintSink {
|
||||
bindingset[this]
|
||||
DeserializationSink() { this = this }
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import semmle.python.security.strings.Untrusted
|
||||
* A taint sink that represents an argument to exec or eval that is vulnerable to malicious input.
|
||||
* The `vuln` in `exec(vuln)` or similar.
|
||||
*/
|
||||
class StringEvaluationNode extends TaintSink {
|
||||
deprecated class StringEvaluationNode extends TaintSink {
|
||||
override string toString() { result = "exec or eval" }
|
||||
|
||||
StringEvaluationNode() {
|
||||
|
||||
@@ -11,13 +11,15 @@ import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.security.strings.Untrusted
|
||||
import semmle.python.security.injection.Deserialization
|
||||
|
||||
private FunctionObject marshalLoads() { result = ModuleObject::named("marshal").attr("loads") }
|
||||
deprecated private FunctionObject marshalLoads() {
|
||||
result = ModuleObject::named("marshal").attr("loads")
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint sink that is potentially vulnerable to malicious marshaled objects.
|
||||
* The `vuln` in `marshal.loads(vuln)`.
|
||||
*/
|
||||
class UnmarshalingNode extends DeserializationSink {
|
||||
deprecated class UnmarshalingNode extends DeserializationSink {
|
||||
override string toString() { result = "unmarshaling vulnerability" }
|
||||
|
||||
UnmarshalingNode() {
|
||||
|
||||
@@ -6,7 +6,7 @@ import semmle.python.security.strings.Untrusted
|
||||
* Prevents taint flowing through ntpath.normpath()
|
||||
* NormalizedPath below handles that case.
|
||||
*/
|
||||
class PathSanitizer extends Sanitizer {
|
||||
deprecated class PathSanitizer extends Sanitizer {
|
||||
PathSanitizer() { this = "path.sanitizer" }
|
||||
|
||||
override predicate sanitizingNode(TaintKind taint, ControlFlowNode node) {
|
||||
@@ -15,7 +15,7 @@ class PathSanitizer extends Sanitizer {
|
||||
}
|
||||
}
|
||||
|
||||
private FunctionObject abspath() {
|
||||
deprecated private FunctionObject abspath() {
|
||||
exists(ModuleObject os_path | ModuleObject::named("os").attr("path") = os_path |
|
||||
os_path.attr("abspath") = result
|
||||
or
|
||||
@@ -24,18 +24,18 @@ private FunctionObject abspath() {
|
||||
}
|
||||
|
||||
/** A path that has been normalized, but not verified to be safe */
|
||||
class NormalizedPath extends TaintKind {
|
||||
deprecated class NormalizedPath extends TaintKind {
|
||||
NormalizedPath() { this = "normalized.path.injection" }
|
||||
|
||||
override string repr() { result = "normalized path" }
|
||||
}
|
||||
|
||||
private predicate abspath_call(CallNode call, ControlFlowNode arg) {
|
||||
deprecated private predicate abspath_call(CallNode call, ControlFlowNode arg) {
|
||||
call.getFunction().refersTo(abspath()) and
|
||||
arg = call.getArg(0)
|
||||
}
|
||||
|
||||
class AbsPath extends DataFlowExtension::DataFlowNode {
|
||||
deprecated class AbsPath extends DataFlowExtension::DataFlowNode {
|
||||
AbsPath() { abspath_call(_, this) }
|
||||
|
||||
override ControlFlowNode getASuccessorNode(TaintKind fromkind, TaintKind tokind) {
|
||||
@@ -45,7 +45,7 @@ class AbsPath extends DataFlowExtension::DataFlowNode {
|
||||
}
|
||||
}
|
||||
|
||||
class NormalizedPathSanitizer extends Sanitizer {
|
||||
deprecated class NormalizedPathSanitizer extends Sanitizer {
|
||||
NormalizedPathSanitizer() { this = "normalized.path.sanitizer" }
|
||||
|
||||
override predicate sanitizingEdge(TaintKind taint, PyEdgeRefinement test) {
|
||||
@@ -59,7 +59,7 @@ class NormalizedPathSanitizer extends Sanitizer {
|
||||
* A taint sink that is vulnerable to malicious paths.
|
||||
* The `vuln` in `open(vuln)` and similar.
|
||||
*/
|
||||
class OpenNode extends TaintSink {
|
||||
deprecated class OpenNode extends TaintSink {
|
||||
override string toString() { result = "argument to open()" }
|
||||
|
||||
OpenNode() {
|
||||
|
||||
@@ -11,7 +11,7 @@ import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.security.strings.Untrusted
|
||||
import semmle.python.security.injection.Deserialization
|
||||
|
||||
private ModuleObject pickleModule() {
|
||||
deprecated private ModuleObject pickleModule() {
|
||||
result.getName() = "pickle"
|
||||
or
|
||||
result.getName() = "cPickle"
|
||||
@@ -19,10 +19,10 @@ private ModuleObject pickleModule() {
|
||||
result.getName() = "dill"
|
||||
}
|
||||
|
||||
private FunctionObject pickleLoads() { result = pickleModule().attr("loads") }
|
||||
deprecated private FunctionObject pickleLoads() { result = pickleModule().attr("loads") }
|
||||
|
||||
/** `pickle.loads(untrusted)` vulnerability. */
|
||||
class UnpicklingNode extends DeserializationSink {
|
||||
deprecated class UnpicklingNode extends DeserializationSink {
|
||||
override string toString() { result = "unpickling untrusted data" }
|
||||
|
||||
UnpicklingNode() {
|
||||
|
||||
@@ -11,7 +11,7 @@ import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.security.strings.Untrusted
|
||||
import semmle.python.security.SQL
|
||||
|
||||
private StringObject first_part(ControlFlowNode command) {
|
||||
deprecated private StringObject first_part(ControlFlowNode command) {
|
||||
command.(BinaryExprNode).getOp() instanceof Add and
|
||||
command.(BinaryExprNode).getLeft().refersTo(result)
|
||||
or
|
||||
@@ -26,7 +26,7 @@ private StringObject first_part(ControlFlowNode command) {
|
||||
}
|
||||
|
||||
/** Holds if `command` appears to be a SQL command string of which `inject` is a part. */
|
||||
predicate probable_sql_command(ControlFlowNode command, ControlFlowNode inject) {
|
||||
deprecated predicate probable_sql_command(ControlFlowNode command, ControlFlowNode inject) {
|
||||
exists(string prefix |
|
||||
inject = command.getAChild*() and
|
||||
first_part(command).getText().regexpMatch(" *" + prefix + ".*")
|
||||
@@ -39,7 +39,7 @@ predicate probable_sql_command(ControlFlowNode command, ControlFlowNode inject)
|
||||
* A taint kind representing a DB cursor.
|
||||
* This will be overridden to provide specific kinds of DB cursor.
|
||||
*/
|
||||
abstract class DbCursor extends TaintKind {
|
||||
abstract deprecated class DbCursor extends TaintKind {
|
||||
bindingset[this]
|
||||
DbCursor() { any() }
|
||||
|
||||
@@ -50,7 +50,7 @@ abstract class DbCursor extends TaintKind {
|
||||
* A part of a string that appears to be a SQL command and is thus
|
||||
* vulnerable to malicious input.
|
||||
*/
|
||||
class SimpleSqlStringInjection extends SqlInjectionSink {
|
||||
deprecated class SimpleSqlStringInjection extends SqlInjectionSink {
|
||||
override string toString() { result = "simple SQL string injection" }
|
||||
|
||||
SimpleSqlStringInjection() { probable_sql_command(_, this) }
|
||||
@@ -62,13 +62,13 @@ class SimpleSqlStringInjection extends SqlInjectionSink {
|
||||
* A taint source representing sources of DB connections.
|
||||
* This will be overridden to provide specific kinds of DB connection sources.
|
||||
*/
|
||||
abstract class DbConnectionSource extends TaintSource { }
|
||||
abstract deprecated class DbConnectionSource extends TaintSource { }
|
||||
|
||||
/**
|
||||
* A taint sink that is vulnerable to malicious SQL queries.
|
||||
* The `vuln` in `db.connection.execute(vuln)` and similar.
|
||||
*/
|
||||
class DbConnectionExecuteArgument extends SqlInjectionSink {
|
||||
deprecated class DbConnectionExecuteArgument extends SqlInjectionSink {
|
||||
override string toString() { result = "db.connection.execute" }
|
||||
|
||||
DbConnectionExecuteArgument() {
|
||||
|
||||
@@ -11,23 +11,25 @@ import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.security.strings.Untrusted
|
||||
import semmle.python.security.injection.Deserialization
|
||||
|
||||
private ModuleObject xmlElementTreeModule() { result.getName() = "xml.etree.ElementTree" }
|
||||
deprecated private ModuleObject xmlElementTreeModule() {
|
||||
result.getName() = "xml.etree.ElementTree"
|
||||
}
|
||||
|
||||
private ModuleObject xmlMiniDomModule() { result.getName() = "xml.dom.minidom" }
|
||||
deprecated private ModuleObject xmlMiniDomModule() { result.getName() = "xml.dom.minidom" }
|
||||
|
||||
private ModuleObject xmlPullDomModule() { result.getName() = "xml.dom.pulldom" }
|
||||
deprecated private ModuleObject xmlPullDomModule() { result.getName() = "xml.dom.pulldom" }
|
||||
|
||||
private ModuleObject xmlSaxModule() { result.getName() = "xml.sax" }
|
||||
deprecated private ModuleObject xmlSaxModule() { result.getName() = "xml.sax" }
|
||||
|
||||
private class ExpatParser extends TaintKind {
|
||||
deprecated private class ExpatParser extends TaintKind {
|
||||
ExpatParser() { this = "expat.parser" }
|
||||
}
|
||||
|
||||
private FunctionObject expatCreateParseFunction() {
|
||||
deprecated private FunctionObject expatCreateParseFunction() {
|
||||
result = ModuleObject::named("xml.parsers.expat").attr("ParserCreate")
|
||||
}
|
||||
|
||||
private class ExpatCreateParser extends TaintSource {
|
||||
deprecated private class ExpatCreateParser extends TaintSource {
|
||||
ExpatCreateParser() { expatCreateParseFunction().getACall() = this }
|
||||
|
||||
override predicate isSourceOf(TaintKind kind) { kind instanceof ExpatParser }
|
||||
@@ -35,7 +37,7 @@ private class ExpatCreateParser extends TaintSource {
|
||||
override string toString() { result = "expat.create.parser" }
|
||||
}
|
||||
|
||||
private FunctionObject xmlFromString() {
|
||||
deprecated private FunctionObject xmlFromString() {
|
||||
result = xmlElementTreeModule().attr("fromstring")
|
||||
or
|
||||
result = xmlMiniDomModule().attr("parseString")
|
||||
@@ -46,7 +48,7 @@ private FunctionObject xmlFromString() {
|
||||
}
|
||||
|
||||
/** A (potentially) malicious XML string. */
|
||||
class ExternalXmlString extends ExternalStringKind {
|
||||
deprecated class ExternalXmlString extends ExternalStringKind {
|
||||
ExternalXmlString() { this = "external xml encoded object" }
|
||||
}
|
||||
|
||||
@@ -54,7 +56,7 @@ class ExternalXmlString extends ExternalStringKind {
|
||||
* A call to an XML library function that is potentially vulnerable to a
|
||||
* specially crafted XML string.
|
||||
*/
|
||||
class XmlLoadNode extends DeserializationSink {
|
||||
deprecated class XmlLoadNode extends DeserializationSink {
|
||||
override string toString() { result = "xml.load vulnerability" }
|
||||
|
||||
XmlLoadNode() {
|
||||
|
||||
@@ -11,10 +11,10 @@ import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.security.strings.Untrusted
|
||||
import semmle.python.security.injection.Deserialization
|
||||
|
||||
private FunctionObject yamlLoad() { result = ModuleObject::named("yaml").attr("load") }
|
||||
deprecated private FunctionObject yamlLoad() { result = ModuleObject::named("yaml").attr("load") }
|
||||
|
||||
/** `yaml.load(untrusted)` vulnerability. */
|
||||
class YamlLoadNode extends DeserializationSink {
|
||||
deprecated class YamlLoadNode extends DeserializationSink {
|
||||
override string toString() { result = "yaml.load vulnerability" }
|
||||
|
||||
YamlLoadNode() {
|
||||
|
||||
@@ -3,7 +3,7 @@ private import Common
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
|
||||
/** An extensible kind of taint representing any kind of string. */
|
||||
abstract class StringKind extends TaintKind {
|
||||
abstract deprecated class StringKind extends TaintKind {
|
||||
bindingset[this]
|
||||
StringKind() { this = this }
|
||||
|
||||
@@ -42,7 +42,7 @@ abstract class StringKind extends TaintKind {
|
||||
}
|
||||
}
|
||||
|
||||
private class StringEqualitySanitizer extends Sanitizer {
|
||||
deprecated private class StringEqualitySanitizer extends Sanitizer {
|
||||
StringEqualitySanitizer() { this = "string equality sanitizer" }
|
||||
|
||||
/** The test `if untrusted == "KNOWN_VALUE":` sanitizes `untrusted` on its `true` edge. */
|
||||
@@ -64,13 +64,13 @@ private class StringEqualitySanitizer extends Sanitizer {
|
||||
}
|
||||
|
||||
/** tonode = ....format(fromnode) */
|
||||
private predicate str_format(ControlFlowNode fromnode, CallNode tonode) {
|
||||
deprecated private predicate str_format(ControlFlowNode fromnode, CallNode tonode) {
|
||||
tonode.getFunction().(AttrNode).getName() = "format" and
|
||||
tonode.getAnArg() = fromnode
|
||||
}
|
||||
|
||||
/** tonode = codec.[en|de]code(fromnode) */
|
||||
private predicate encode_decode(ControlFlowNode fromnode, CallNode tonode) {
|
||||
deprecated private predicate encode_decode(ControlFlowNode fromnode, CallNode tonode) {
|
||||
exists(FunctionObject func, string name |
|
||||
not func.getFunction().isMethod() and
|
||||
func.getACall() = tonode and
|
||||
@@ -84,7 +84,7 @@ private predicate encode_decode(ControlFlowNode fromnode, CallNode tonode) {
|
||||
}
|
||||
|
||||
/** tonode = str(fromnode) */
|
||||
private predicate to_str(ControlFlowNode fromnode, CallNode tonode) {
|
||||
deprecated private predicate to_str(ControlFlowNode fromnode, CallNode tonode) {
|
||||
tonode.getAnArg() = fromnode and
|
||||
(
|
||||
tonode = ClassValue::bytes().getACall()
|
||||
@@ -94,7 +94,7 @@ private predicate to_str(ControlFlowNode fromnode, CallNode tonode) {
|
||||
}
|
||||
|
||||
/** tonode = fromnode[:] */
|
||||
private predicate slice(ControlFlowNode fromnode, SubscriptNode tonode) {
|
||||
deprecated private predicate slice(ControlFlowNode fromnode, SubscriptNode tonode) {
|
||||
exists(Slice all |
|
||||
all = tonode.getIndex().getNode() and
|
||||
not exists(all.getStart()) and
|
||||
@@ -104,13 +104,13 @@ private predicate slice(ControlFlowNode fromnode, SubscriptNode tonode) {
|
||||
}
|
||||
|
||||
/** tonode = os.path.join(..., fromnode, ...) */
|
||||
private predicate os_path_join(ControlFlowNode fromnode, CallNode tonode) {
|
||||
deprecated private predicate os_path_join(ControlFlowNode fromnode, CallNode tonode) {
|
||||
tonode = Value::named("os.path.join").getACall() and
|
||||
tonode.getAnArg() = fromnode
|
||||
}
|
||||
|
||||
/** tonode = f"... {fromnode} ..." */
|
||||
private predicate f_string(ControlFlowNode fromnode, ControlFlowNode tonode) {
|
||||
deprecated private predicate f_string(ControlFlowNode fromnode, ControlFlowNode tonode) {
|
||||
tonode.getNode().(Fstring).getAValue() = fromnode.getNode()
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import python
|
||||
|
||||
/* A call that returns a copy (or similar) of the argument */
|
||||
predicate copy_call(ControlFlowNode fromnode, CallNode tonode) {
|
||||
deprecated predicate copy_call(ControlFlowNode fromnode, CallNode tonode) {
|
||||
tonode.getFunction().(AttrNode).getObject("copy") = fromnode
|
||||
or
|
||||
exists(ModuleValue copy, string name | name = "copy" or name = "deepcopy" |
|
||||
|
||||
@@ -5,7 +5,7 @@ private import Common
|
||||
/**
|
||||
* An extensible kind of taint representing an externally controlled string.
|
||||
*/
|
||||
abstract class ExternalStringKind extends StringKind {
|
||||
abstract deprecated class ExternalStringKind extends StringKind {
|
||||
bindingset[this]
|
||||
ExternalStringKind() { this = this }
|
||||
|
||||
@@ -30,7 +30,7 @@ abstract class ExternalStringKind extends StringKind {
|
||||
}
|
||||
|
||||
/** A kind of "taint", representing a sequence, with a "taint" member */
|
||||
class ExternalStringSequenceKind extends SequenceKind {
|
||||
deprecated class ExternalStringSequenceKind extends SequenceKind {
|
||||
ExternalStringSequenceKind() { this.getItem() instanceof ExternalStringKind }
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ class ExternalStringSequenceKind extends SequenceKind {
|
||||
* An hierachical dictionary or list where the entire structure is externally controlled
|
||||
* This is typically a parsed JSON object.
|
||||
*/
|
||||
class ExternalJsonKind extends TaintKind {
|
||||
deprecated class ExternalJsonKind extends TaintKind {
|
||||
ExternalJsonKind() { this = "json[" + any(ExternalStringKind key) + "]" }
|
||||
|
||||
/** Gets the taint kind for item in this sequence */
|
||||
@@ -61,7 +61,7 @@ class ExternalJsonKind extends TaintKind {
|
||||
}
|
||||
|
||||
/** A kind of "taint", representing a dictionary mapping keys to tainted strings. */
|
||||
class ExternalStringDictKind extends DictKind {
|
||||
deprecated class ExternalStringDictKind extends DictKind {
|
||||
ExternalStringDictKind() { this.getValue() instanceof ExternalStringKind }
|
||||
}
|
||||
|
||||
@@ -69,12 +69,12 @@ class ExternalStringDictKind extends DictKind {
|
||||
* A kind of "taint", representing a dictionary mapping keys to sequences of
|
||||
* tainted strings.
|
||||
*/
|
||||
class ExternalStringSequenceDictKind extends DictKind {
|
||||
deprecated class ExternalStringSequenceDictKind extends DictKind {
|
||||
ExternalStringSequenceDictKind() { this.getValue() instanceof ExternalStringSequenceKind }
|
||||
}
|
||||
|
||||
/** TaintKind for the result of `urlsplit(tainted_string)` */
|
||||
class ExternalUrlSplitResult extends ExternalStringSequenceKind {
|
||||
deprecated class ExternalUrlSplitResult extends ExternalStringSequenceKind {
|
||||
// https://docs.python.org/3/library/urllib.parse.html#urllib.parse.urlsplit
|
||||
override TaintKind getTaintOfAttribute(string name) {
|
||||
result = super.getTaintOfAttribute(name)
|
||||
@@ -103,7 +103,7 @@ class ExternalUrlSplitResult extends ExternalStringSequenceKind {
|
||||
}
|
||||
|
||||
/** TaintKind for the result of `urlparse(tainted_string)` */
|
||||
class ExternalUrlParseResult extends ExternalStringSequenceKind {
|
||||
deprecated class ExternalUrlParseResult extends ExternalStringSequenceKind {
|
||||
// https://docs.python.org/3/library/urllib.parse.html#urllib.parse.urlparse
|
||||
override TaintKind getTaintOfAttribute(string name) {
|
||||
result = super.getTaintOfAttribute(name)
|
||||
@@ -134,7 +134,7 @@ class ExternalUrlParseResult extends ExternalStringSequenceKind {
|
||||
|
||||
/* Helper for getTaintForStep() */
|
||||
pragma[noinline]
|
||||
private predicate json_subscript_taint(
|
||||
deprecated private predicate json_subscript_taint(
|
||||
SubscriptNode sub, ControlFlowNode obj, ExternalJsonKind seq, TaintKind key
|
||||
) {
|
||||
sub.isLoad() and
|
||||
@@ -142,12 +142,12 @@ private predicate json_subscript_taint(
|
||||
key = seq.getValue()
|
||||
}
|
||||
|
||||
private predicate json_load(ControlFlowNode fromnode, CallNode tonode) {
|
||||
deprecated private predicate json_load(ControlFlowNode fromnode, CallNode tonode) {
|
||||
tonode = Value::named("json.loads").getACall() and
|
||||
tonode.getArg(0) = fromnode
|
||||
}
|
||||
|
||||
private predicate urlsplit(ControlFlowNode fromnode, CallNode tonode) {
|
||||
deprecated private predicate urlsplit(ControlFlowNode fromnode, CallNode tonode) {
|
||||
// This could be implemented as `exists(FunctionValue` without the explicit six part,
|
||||
// but then our tests will need to import +100 modules, so for now this slightly
|
||||
// altered version gets to live on.
|
||||
@@ -166,7 +166,7 @@ private predicate urlsplit(ControlFlowNode fromnode, CallNode tonode) {
|
||||
)
|
||||
}
|
||||
|
||||
private predicate urlparse(ControlFlowNode fromnode, CallNode tonode) {
|
||||
deprecated private predicate urlparse(ControlFlowNode fromnode, CallNode tonode) {
|
||||
// This could be implemented as `exists(FunctionValue` without the explicit six part,
|
||||
// but then our tests will need to import +100 modules, so for now this slightly
|
||||
// altered version gets to live on.
|
||||
@@ -185,7 +185,7 @@ private predicate urlparse(ControlFlowNode fromnode, CallNode tonode) {
|
||||
)
|
||||
}
|
||||
|
||||
private predicate parse_qs(ControlFlowNode fromnode, CallNode tonode) {
|
||||
deprecated private predicate parse_qs(ControlFlowNode fromnode, CallNode tonode) {
|
||||
// This could be implemented as `exists(FunctionValue` without the explicit six part,
|
||||
// but then our tests will need to import +100 modules, so for now this slightly
|
||||
// altered version gets to live on.
|
||||
@@ -211,7 +211,7 @@ private predicate parse_qs(ControlFlowNode fromnode, CallNode tonode) {
|
||||
)
|
||||
}
|
||||
|
||||
private predicate parse_qsl(ControlFlowNode fromnode, CallNode tonode) {
|
||||
deprecated private predicate parse_qsl(ControlFlowNode fromnode, CallNode tonode) {
|
||||
// This could be implemented as `exists(FunctionValue` without the explicit six part,
|
||||
// but then our tests will need to import +100 modules, so for now this slightly
|
||||
// altered version gets to live on.
|
||||
@@ -238,7 +238,7 @@ private predicate parse_qsl(ControlFlowNode fromnode, CallNode tonode) {
|
||||
}
|
||||
|
||||
/** A kind of "taint", representing an open file-like object from an external source. */
|
||||
class ExternalFileObject extends TaintKind {
|
||||
deprecated class ExternalFileObject extends TaintKind {
|
||||
ExternalStringKind valueKind;
|
||||
|
||||
ExternalFileObject() { this = "file[" + valueKind + "]" }
|
||||
@@ -266,7 +266,7 @@ class ExternalFileObject extends TaintKind {
|
||||
* - `if splitres.netloc == "KNOWN_VALUE"`
|
||||
* - `if splitres[0] == "KNOWN_VALUE"`
|
||||
*/
|
||||
class UrlsplitUrlparseTempSanitizer extends Sanitizer {
|
||||
deprecated class UrlsplitUrlparseTempSanitizer extends Sanitizer {
|
||||
// TODO: remove this once we have better support for named tuples
|
||||
UrlsplitUrlparseTempSanitizer() { this = "UrlsplitUrlparseTempSanitizer" }
|
||||
|
||||
|
||||
@@ -5,6 +5,6 @@ import External
|
||||
* A kind of taint representing an externally controlled string.
|
||||
* This class is a simple sub-class of `ExternalStringKind`.
|
||||
*/
|
||||
class UntrustedStringKind extends ExternalStringKind {
|
||||
deprecated class UntrustedStringKind extends ExternalStringKind {
|
||||
UntrustedStringKind() { this = "externally controlled string" }
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ class RangeIterationVariableFact extends PointsToExtension {
|
||||
}
|
||||
|
||||
/* bottle module route constants */
|
||||
class BottleRoutePointToExtension extends PointsToExtension {
|
||||
deprecated class BottleRoutePointToExtension extends PointsToExtension {
|
||||
string name;
|
||||
|
||||
BottleRoutePointToExtension() {
|
||||
|
||||
@@ -4,13 +4,13 @@ import semmle.python.security.strings.External
|
||||
import HttpConstants
|
||||
|
||||
/** Generic taint source from a http request */
|
||||
abstract class HttpRequestTaintSource extends TaintSource { }
|
||||
abstract deprecated class HttpRequestTaintSource extends TaintSource { }
|
||||
|
||||
/**
|
||||
* Taint kind representing the WSGI environment.
|
||||
* As specified in PEP 3333. https://www.python.org/dev/peps/pep-3333/#environ-variables
|
||||
*/
|
||||
class WsgiEnvironment extends TaintKind {
|
||||
deprecated class WsgiEnvironment extends TaintKind {
|
||||
WsgiEnvironment() { this = "wsgi.environment" }
|
||||
|
||||
override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) {
|
||||
@@ -43,7 +43,7 @@ class WsgiEnvironment extends TaintKind {
|
||||
* A standard morsel object from a HTTP request, a value in a cookie,
|
||||
* typically an instance of `http.cookies.Morsel`
|
||||
*/
|
||||
class UntrustedMorsel extends TaintKind {
|
||||
deprecated class UntrustedMorsel extends TaintKind {
|
||||
UntrustedMorsel() { this = "http.Morsel" }
|
||||
|
||||
override TaintKind getTaintOfAttribute(string name) {
|
||||
@@ -53,7 +53,7 @@ class UntrustedMorsel extends TaintKind {
|
||||
}
|
||||
|
||||
/** A standard cookie object from a HTTP request, typically an instance of `http.cookies.SimpleCookie` */
|
||||
class UntrustedCookie extends TaintKind {
|
||||
deprecated class UntrustedCookie extends TaintKind {
|
||||
UntrustedCookie() { this = "http.Cookie" }
|
||||
|
||||
override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) {
|
||||
@@ -62,7 +62,7 @@ class UntrustedCookie extends TaintKind {
|
||||
}
|
||||
}
|
||||
|
||||
abstract class CookieOperation extends @py_flow_node {
|
||||
abstract deprecated class CookieOperation extends @py_flow_node {
|
||||
/** Gets a textual representation of this element. */
|
||||
abstract string toString();
|
||||
|
||||
@@ -71,20 +71,20 @@ abstract class CookieOperation extends @py_flow_node {
|
||||
abstract ControlFlowNode getValue();
|
||||
}
|
||||
|
||||
abstract class CookieGet extends CookieOperation { }
|
||||
abstract deprecated class CookieGet extends CookieOperation { }
|
||||
|
||||
abstract class CookieSet extends CookieOperation { }
|
||||
abstract deprecated class CookieSet extends CookieOperation { }
|
||||
|
||||
/** Generic taint sink in a http response */
|
||||
abstract class HttpResponseTaintSink extends TaintSink {
|
||||
abstract deprecated class HttpResponseTaintSink extends TaintSink {
|
||||
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
|
||||
}
|
||||
|
||||
abstract class HttpRedirectTaintSink extends TaintSink {
|
||||
abstract deprecated class HttpRedirectTaintSink extends TaintSink {
|
||||
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
|
||||
}
|
||||
|
||||
module Client {
|
||||
deprecated module Client {
|
||||
// TODO: user-input in other than URL:
|
||||
// - `data`, `json` for `requests.post`
|
||||
// - `body` for `HTTPConnection.request`
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
/** Gets an HTTP verb, in upper case */
|
||||
string httpVerb() { result in ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", "HEAD"] }
|
||||
deprecated string httpVerb() {
|
||||
result in ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", "HEAD"]
|
||||
}
|
||||
|
||||
/** Gets an HTTP verb, in lower case */
|
||||
string httpVerbLower() { result = httpVerb().toLowerCase() }
|
||||
deprecated string httpVerbLower() { result = httpVerb().toLowerCase() }
|
||||
|
||||
@@ -3,16 +3,16 @@ import semmle.python.web.Http
|
||||
import semmle.python.types.Extensions
|
||||
|
||||
/** The bottle module */
|
||||
ModuleValue theBottleModule() { result = Module::named("bottle") }
|
||||
deprecated ModuleValue theBottleModule() { result = Module::named("bottle") }
|
||||
|
||||
/** The bottle.Bottle class */
|
||||
ClassValue theBottleClass() { result = theBottleModule().attr("Bottle") }
|
||||
deprecated ClassValue theBottleClass() { result = theBottleModule().attr("Bottle") }
|
||||
|
||||
/**
|
||||
* Holds if `route` is routed to `func`
|
||||
* by decorating `func` with `app.route(route)` or `route(route)`
|
||||
*/
|
||||
predicate bottle_route(CallNode route_call, ControlFlowNode route, Function func) {
|
||||
deprecated predicate bottle_route(CallNode route_call, ControlFlowNode route, Function func) {
|
||||
exists(CallNode decorator_call, string name |
|
||||
route_call.getFunction().(AttrNode).getObject(name).pointsTo().getClass() = theBottleClass() or
|
||||
route_call.getFunction().pointsTo(theBottleModule().attr(name))
|
||||
@@ -24,7 +24,7 @@ predicate bottle_route(CallNode route_call, ControlFlowNode route, Function func
|
||||
)
|
||||
}
|
||||
|
||||
class BottleRoute extends ControlFlowNode {
|
||||
deprecated class BottleRoute extends ControlFlowNode {
|
||||
BottleRoute() { bottle_route(this, _, _) }
|
||||
|
||||
string getUrl() {
|
||||
|
||||
@@ -9,12 +9,12 @@ import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.security.strings.Basic
|
||||
import semmle.python.web.bottle.General
|
||||
|
||||
FunctionValue bottle_redirect() { result = theBottleModule().attr("redirect") }
|
||||
deprecated FunctionValue bottle_redirect() { result = theBottleModule().attr("redirect") }
|
||||
|
||||
/**
|
||||
* Represents an argument to the `bottle.redirect` function.
|
||||
*/
|
||||
class BottleRedirect extends TaintSink {
|
||||
deprecated class BottleRedirect extends TaintSink {
|
||||
override string toString() { result = "bottle.redirect" }
|
||||
|
||||
BottleRedirect() {
|
||||
|
||||
@@ -4,9 +4,9 @@ import semmle.python.security.strings.External
|
||||
import semmle.python.web.Http
|
||||
import semmle.python.web.bottle.General
|
||||
|
||||
private Value theBottleRequestObject() { result = theBottleModule().attr("request") }
|
||||
deprecated private Value theBottleRequestObject() { result = theBottleModule().attr("request") }
|
||||
|
||||
class BottleRequestKind extends TaintKind {
|
||||
deprecated class BottleRequestKind extends TaintKind {
|
||||
BottleRequestKind() { this = "bottle.request" }
|
||||
|
||||
override TaintKind getTaintOfAttribute(string name) {
|
||||
@@ -21,13 +21,13 @@ class BottleRequestKind extends TaintKind {
|
||||
}
|
||||
}
|
||||
|
||||
private class RequestSource extends HttpRequestTaintSource {
|
||||
deprecated private class RequestSource extends HttpRequestTaintSource {
|
||||
RequestSource() { this.(ControlFlowNode).pointsTo(theBottleRequestObject()) }
|
||||
|
||||
override predicate isSourceOf(TaintKind kind) { kind instanceof BottleRequestKind }
|
||||
}
|
||||
|
||||
class BottleFormsDict extends TaintKind {
|
||||
deprecated class BottleFormsDict extends TaintKind {
|
||||
BottleFormsDict() { this = "bottle.FormsDict" }
|
||||
|
||||
override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) {
|
||||
@@ -48,7 +48,7 @@ class BottleFormsDict extends TaintKind {
|
||||
}
|
||||
}
|
||||
|
||||
class FileUpload extends TaintKind {
|
||||
deprecated class FileUpload extends TaintKind {
|
||||
FileUpload() { this = "bottle.FileUpload" }
|
||||
|
||||
override TaintKind getTaintOfAttribute(string name) {
|
||||
@@ -60,7 +60,7 @@ class FileUpload extends TaintKind {
|
||||
}
|
||||
}
|
||||
|
||||
class UntrustedFile extends TaintKind {
|
||||
deprecated class UntrustedFile extends TaintKind {
|
||||
UntrustedFile() { this = "Untrusted file" }
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ class UntrustedFile extends TaintKind {
|
||||
// Move UntrustedFile to shared location
|
||||
//
|
||||
/** Parameter to a bottle request handler function */
|
||||
class BottleRequestParameter extends HttpRequestTaintSource {
|
||||
deprecated class BottleRequestParameter extends HttpRequestTaintSource {
|
||||
BottleRequestParameter() {
|
||||
exists(BottleRoute route | route.getANamedArgument() = this.(ControlFlowNode).getNode())
|
||||
}
|
||||
|
||||
@@ -9,13 +9,13 @@ import semmle.python.web.bottle.General
|
||||
* This isn't really a "taint", but we use the value tracking machinery to
|
||||
* track the flow of response objects.
|
||||
*/
|
||||
class BottleResponse extends TaintKind {
|
||||
deprecated class BottleResponse extends TaintKind {
|
||||
BottleResponse() { this = "bottle.response" }
|
||||
}
|
||||
|
||||
private Value theBottleResponseObject() { result = theBottleModule().attr("response") }
|
||||
deprecated private Value theBottleResponseObject() { result = theBottleModule().attr("response") }
|
||||
|
||||
class BottleResponseBodyAssignment extends HttpResponseTaintSink {
|
||||
deprecated class BottleResponseBodyAssignment extends HttpResponseTaintSink {
|
||||
BottleResponseBodyAssignment() {
|
||||
exists(DefinitionNode lhs |
|
||||
lhs.getValue() = this and
|
||||
@@ -26,7 +26,7 @@ class BottleResponseBodyAssignment extends HttpResponseTaintSink {
|
||||
override predicate sinks(TaintKind kind) { kind instanceof StringKind }
|
||||
}
|
||||
|
||||
class BottleHandlerFunctionResult extends HttpResponseTaintSink {
|
||||
deprecated class BottleHandlerFunctionResult extends HttpResponseTaintSink {
|
||||
BottleHandlerFunctionResult() {
|
||||
exists(BottleRoute route, Return ret |
|
||||
ret.getScope() = route.getFunction() and
|
||||
@@ -39,7 +39,7 @@ class BottleHandlerFunctionResult extends HttpResponseTaintSink {
|
||||
override string toString() { result = "bottle handler function result" }
|
||||
}
|
||||
|
||||
class BottleCookieSet extends CookieSet, CallNode {
|
||||
deprecated class BottleCookieSet extends CookieSet, CallNode {
|
||||
BottleCookieSet() {
|
||||
any(BottleResponse r).taints(this.getFunction().(AttrNode).getObject("set_cookie"))
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import python
|
||||
import semmle.python.web.Http
|
||||
|
||||
module CherryPy {
|
||||
deprecated module CherryPy {
|
||||
FunctionValue expose() { result = Value::named("cherrypy.expose") }
|
||||
}
|
||||
|
||||
class CherryPyExposedFunction extends Function {
|
||||
deprecated class CherryPyExposedFunction extends Function {
|
||||
CherryPyExposedFunction() {
|
||||
this.getADecorator().pointsTo(CherryPy::expose())
|
||||
or
|
||||
@@ -13,7 +13,7 @@ class CherryPyExposedFunction extends Function {
|
||||
}
|
||||
}
|
||||
|
||||
class CherryPyRoute extends CallNode {
|
||||
deprecated class CherryPyRoute extends CallNode {
|
||||
CherryPyRoute() {
|
||||
/* cherrypy.quickstart(root, script_name, config) */
|
||||
Value::named("cherrypy.quickstart").(FunctionValue).getACall() = this
|
||||
|
||||
@@ -5,7 +5,7 @@ import semmle.python.web.Http
|
||||
import semmle.python.web.cherrypy.General
|
||||
|
||||
/** The cherrypy.request local-proxy object */
|
||||
class CherryPyRequest extends TaintKind {
|
||||
deprecated class CherryPyRequest extends TaintKind {
|
||||
CherryPyRequest() { this = "cherrypy.request" }
|
||||
|
||||
override TaintKind getTaintOfAttribute(string name) {
|
||||
@@ -20,7 +20,7 @@ class CherryPyRequest extends TaintKind {
|
||||
}
|
||||
}
|
||||
|
||||
class CherryPyExposedFunctionParameter extends HttpRequestTaintSource {
|
||||
deprecated class CherryPyExposedFunctionParameter extends HttpRequestTaintSource {
|
||||
CherryPyExposedFunctionParameter() {
|
||||
exists(Parameter p |
|
||||
p = any(CherryPyExposedFunction f).getAnArg() and
|
||||
@@ -34,7 +34,7 @@ class CherryPyExposedFunctionParameter extends HttpRequestTaintSource {
|
||||
override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind }
|
||||
}
|
||||
|
||||
class CherryPyRequestSource extends HttpRequestTaintSource {
|
||||
deprecated class CherryPyRequestSource extends HttpRequestTaintSource {
|
||||
CherryPyRequestSource() { this.(ControlFlowNode).pointsTo(Value::named("cherrypy.request")) }
|
||||
|
||||
override predicate isSourceOf(TaintKind kind) { kind instanceof CherryPyRequest }
|
||||
|
||||
@@ -4,7 +4,7 @@ import semmle.python.security.strings.Untrusted
|
||||
import semmle.python.web.Http
|
||||
import semmle.python.web.cherrypy.General
|
||||
|
||||
class CherryPyExposedFunctionResult extends HttpResponseTaintSink {
|
||||
deprecated class CherryPyExposedFunctionResult extends HttpResponseTaintSink {
|
||||
CherryPyExposedFunctionResult() {
|
||||
exists(Return ret |
|
||||
ret.getScope() instanceof CherryPyExposedFunction and
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import python
|
||||
private import semmle.python.web.Http
|
||||
|
||||
class RequestsHttpRequest extends Client::HttpRequest, CallNode {
|
||||
deprecated class RequestsHttpRequest extends Client::HttpRequest, CallNode {
|
||||
CallableValue func;
|
||||
string method;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import python
|
||||
private import semmle.python.web.Http
|
||||
|
||||
ClassValue httpConnectionClass() {
|
||||
deprecated ClassValue httpConnectionClass() {
|
||||
// Python 2
|
||||
result = Value::named("httplib.HTTPConnection")
|
||||
or
|
||||
@@ -18,7 +18,7 @@ ClassValue httpConnectionClass() {
|
||||
result = Value::named("six.moves.http_client.HTTPSConnection")
|
||||
}
|
||||
|
||||
class HttpConnectionHttpRequest extends Client::HttpRequest, CallNode {
|
||||
deprecated class HttpConnectionHttpRequest extends Client::HttpRequest, CallNode {
|
||||
CallNode constructor_call;
|
||||
CallableValue func;
|
||||
|
||||
|
||||
@@ -4,16 +4,18 @@ import semmle.python.security.injection.Sql
|
||||
/**
|
||||
* A taint kind representing a django cursor object.
|
||||
*/
|
||||
class DjangoDbCursor extends DbCursor {
|
||||
deprecated class DjangoDbCursor extends DbCursor {
|
||||
DjangoDbCursor() { this = "django.db.connection.cursor" }
|
||||
}
|
||||
|
||||
private Value theDjangoConnectionObject() { result = Value::named("django.db.connection") }
|
||||
deprecated private Value theDjangoConnectionObject() {
|
||||
result = Value::named("django.db.connection")
|
||||
}
|
||||
|
||||
/**
|
||||
* A kind of taint source representing sources of django cursor objects.
|
||||
*/
|
||||
class DjangoDbCursorSource extends DbConnectionSource {
|
||||
deprecated class DjangoDbCursorSource extends DbConnectionSource {
|
||||
DjangoDbCursorSource() {
|
||||
exists(AttrNode cursor |
|
||||
this.(CallNode).getFunction() = cursor and
|
||||
@@ -26,13 +28,15 @@ class DjangoDbCursorSource extends DbConnectionSource {
|
||||
override predicate isSourceOf(TaintKind kind) { kind instanceof DjangoDbCursor }
|
||||
}
|
||||
|
||||
ClassValue theDjangoRawSqlClass() { result = Value::named("django.db.models.expressions.RawSQL") }
|
||||
deprecated ClassValue theDjangoRawSqlClass() {
|
||||
result = Value::named("django.db.models.expressions.RawSQL")
|
||||
}
|
||||
|
||||
/**
|
||||
* A sink of taint on calls to `django.db.models.expressions.RawSQL`. This
|
||||
* allows arbitrary SQL statements to be executed, which is a security risk.
|
||||
*/
|
||||
class DjangoRawSqlSink extends SqlInjectionSink {
|
||||
deprecated class DjangoRawSqlSink extends SqlInjectionSink {
|
||||
DjangoRawSqlSink() {
|
||||
exists(CallNode call |
|
||||
call = theDjangoRawSqlClass().getACall() and
|
||||
|
||||
@@ -5,7 +5,7 @@ import semmle.python.web.Http
|
||||
// TODO: Since django uses `path = partial(...)`, our analysis doesn't understand this is
|
||||
// a FunctionValue, so we can't use `FunctionValue.getArgumentForCall`
|
||||
// https://github.com/django/django/blob/master/django/urls/conf.py#L76
|
||||
abstract class DjangoRoute extends CallNode {
|
||||
abstract deprecated class DjangoRoute extends CallNode {
|
||||
DjangoViewHandler getViewHandler() {
|
||||
result = view_handler_from_view_arg(this.getArg(1))
|
||||
or
|
||||
@@ -26,7 +26,7 @@ abstract class DjangoRoute extends CallNode {
|
||||
* https://docs.djangoproject.com/en/1.11/topics/http/views/
|
||||
* https://docs.djangoproject.com/en/3.0/topics/http/views/
|
||||
*/
|
||||
class DjangoViewHandler extends PythonFunctionValue {
|
||||
deprecated class DjangoViewHandler extends PythonFunctionValue {
|
||||
/** Gets the index of the 'request' argument */
|
||||
int getRequestArgIndex() { result = 0 }
|
||||
}
|
||||
@@ -36,7 +36,7 @@ class DjangoViewHandler extends PythonFunctionValue {
|
||||
* https://docs.djangoproject.com/en/1.11/topics/class-based-views/
|
||||
* https://docs.djangoproject.com/en/3.0/topics/class-based-views/
|
||||
*/
|
||||
private class DjangoViewClass extends ClassValue {
|
||||
deprecated private class DjangoViewClass extends ClassValue {
|
||||
DjangoViewClass() {
|
||||
Value::named("django.views.generic.View") = this.getASuperType()
|
||||
or
|
||||
@@ -44,7 +44,7 @@ private class DjangoViewClass extends ClassValue {
|
||||
}
|
||||
}
|
||||
|
||||
class DjangoClassBasedViewHandler extends DjangoViewHandler {
|
||||
deprecated class DjangoClassBasedViewHandler extends DjangoViewHandler {
|
||||
DjangoClassBasedViewHandler() { exists(DjangoViewClass cls | cls.lookup(httpVerbLower()) = this) }
|
||||
|
||||
override int getRequestArgIndex() {
|
||||
@@ -57,7 +57,7 @@ class DjangoClassBasedViewHandler extends DjangoViewHandler {
|
||||
* Gets the function that will handle requests when `view_arg` is used as the view argument to a
|
||||
* django route. That is, this methods handles Class-based Views and its `as_view()` function.
|
||||
*/
|
||||
private DjangoViewHandler view_handler_from_view_arg(ControlFlowNode view_arg) {
|
||||
deprecated private DjangoViewHandler view_handler_from_view_arg(ControlFlowNode view_arg) {
|
||||
// Function-based view
|
||||
result = view_arg.pointsTo()
|
||||
or
|
||||
@@ -70,11 +70,11 @@ private DjangoViewHandler view_handler_from_view_arg(ControlFlowNode view_arg) {
|
||||
|
||||
// We need this "dummy" class, since otherwise the regex argument would not be considered
|
||||
// a regex (RegexString is abstract)
|
||||
class DjangoRouteRegex extends RegexString {
|
||||
deprecated class DjangoRouteRegex extends RegexString {
|
||||
DjangoRouteRegex() { exists(DjangoRegexRoute route | route.getRouteArg() = this.getAFlowNode()) }
|
||||
}
|
||||
|
||||
class DjangoRegexRoute extends DjangoRoute {
|
||||
deprecated class DjangoRegexRoute extends DjangoRoute {
|
||||
ControlFlowNode route;
|
||||
|
||||
DjangoRegexRoute() {
|
||||
@@ -109,7 +109,7 @@ class DjangoRegexRoute extends DjangoRoute {
|
||||
}
|
||||
}
|
||||
|
||||
class DjangoPathRoute extends DjangoRoute {
|
||||
deprecated class DjangoPathRoute extends DjangoRoute {
|
||||
ControlFlowNode route;
|
||||
|
||||
DjangoPathRoute() {
|
||||
|
||||
@@ -5,12 +5,12 @@ import semmle.python.web.Http
|
||||
import semmle.python.security.injection.Sql
|
||||
|
||||
/** A django model class */
|
||||
class DjangoModel extends ClassValue {
|
||||
deprecated class DjangoModel extends ClassValue {
|
||||
DjangoModel() { Value::named("django.db.models.Model") = this.getASuperType() }
|
||||
}
|
||||
|
||||
/** A "taint" for django database tables */
|
||||
class DjangoDbTableObjects extends TaintKind {
|
||||
deprecated class DjangoDbTableObjects extends TaintKind {
|
||||
DjangoDbTableObjects() { this = "django.db.models.Model.objects" }
|
||||
|
||||
override TaintKind getTaintOfMethodResult(string name) {
|
||||
@@ -24,7 +24,7 @@ class DjangoDbTableObjects extends TaintKind {
|
||||
}
|
||||
|
||||
/** Django model objects, which are sources of django database table "taint" */
|
||||
class DjangoModelObjects extends TaintSource {
|
||||
deprecated class DjangoModelObjects extends TaintSource {
|
||||
DjangoModelObjects() {
|
||||
this.(AttrNode).isLoad() and this.(AttrNode).getObject("objects").pointsTo(any(DjangoModel m))
|
||||
}
|
||||
@@ -38,7 +38,7 @@ class DjangoModelObjects extends TaintSource {
|
||||
* A call to the `raw` method on a django model. This allows a raw SQL query
|
||||
* to be sent to the database, which is a security risk.
|
||||
*/
|
||||
class DjangoModelRawCall extends SqlInjectionSink {
|
||||
deprecated class DjangoModelRawCall extends SqlInjectionSink {
|
||||
DjangoModelRawCall() {
|
||||
exists(CallNode raw_call, ControlFlowNode queryset | this = raw_call.getArg(0) |
|
||||
raw_call.getFunction().(AttrNode).getObject("raw") = queryset and
|
||||
@@ -55,7 +55,7 @@ class DjangoModelRawCall extends SqlInjectionSink {
|
||||
* A call to the `extra` method on a django model. This allows a raw SQL query
|
||||
* to be sent to the database, which is a security risk.
|
||||
*/
|
||||
class DjangoModelExtraCall extends SqlInjectionSink {
|
||||
deprecated class DjangoModelExtraCall extends SqlInjectionSink {
|
||||
DjangoModelExtraCall() {
|
||||
exists(CallNode extra_call, ControlFlowNode queryset | this = extra_call.getArg(0) |
|
||||
extra_call.getFunction().(AttrNode).getObject("extra") = queryset and
|
||||
|
||||
@@ -13,7 +13,7 @@ private import semmle.python.web.Http
|
||||
/**
|
||||
* The URL argument for a call to the `django.shortcuts.redirect` function.
|
||||
*/
|
||||
class DjangoShortcutsRedirectSink extends HttpRedirectTaintSink {
|
||||
deprecated class DjangoShortcutsRedirectSink extends HttpRedirectTaintSink {
|
||||
override string toString() { result = "DjangoShortcutsRedirectSink" }
|
||||
|
||||
DjangoShortcutsRedirectSink() {
|
||||
@@ -27,7 +27,7 @@ deprecated class DjangoRedirect = DjangoShortcutsRedirectSink;
|
||||
/**
|
||||
* The URL argument when instantiating a Django Redirect Response.
|
||||
*/
|
||||
class DjangoRedirectResponseSink extends HttpRedirectTaintSink {
|
||||
deprecated class DjangoRedirectResponseSink extends HttpRedirectTaintSink {
|
||||
DjangoRedirectResponseSink() {
|
||||
exists(CallNode call | call = any(DjangoRedirectResponseClass cls).getACall() |
|
||||
this = call.getArg(0)
|
||||
|
||||
@@ -4,7 +4,7 @@ import semmle.python.web.Http
|
||||
import semmle.python.web.django.General
|
||||
|
||||
/** A django.request.HttpRequest object */
|
||||
class DjangoRequest extends TaintKind {
|
||||
deprecated class DjangoRequest extends TaintKind {
|
||||
DjangoRequest() { this = "django.request.HttpRequest" }
|
||||
|
||||
override TaintKind getTaintOfAttribute(string name) {
|
||||
@@ -20,13 +20,13 @@ class DjangoRequest extends TaintKind {
|
||||
|
||||
/* Helper for getTaintForStep() */
|
||||
pragma[noinline]
|
||||
private predicate subscript_taint(SubscriptNode sub, ControlFlowNode obj, TaintKind kind) {
|
||||
deprecated private predicate subscript_taint(SubscriptNode sub, ControlFlowNode obj, TaintKind kind) {
|
||||
sub.getObject() = obj and
|
||||
kind instanceof ExternalStringKind
|
||||
}
|
||||
|
||||
/** A django.request.QueryDict object */
|
||||
class DjangoQueryDict extends TaintKind {
|
||||
deprecated class DjangoQueryDict extends TaintKind {
|
||||
DjangoQueryDict() { this = "django.http.request.QueryDict" }
|
||||
|
||||
override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) {
|
||||
@@ -40,7 +40,7 @@ class DjangoQueryDict extends TaintKind {
|
||||
}
|
||||
|
||||
/** A Django request parameter */
|
||||
class DjangoRequestSource extends HttpRequestTaintSource {
|
||||
deprecated class DjangoRequestSource extends HttpRequestTaintSource {
|
||||
DjangoRequestSource() {
|
||||
exists(DjangoRoute route, DjangoViewHandler view, int request_arg_index |
|
||||
route.getViewHandler() = view and
|
||||
@@ -55,7 +55,7 @@ class DjangoRequestSource extends HttpRequestTaintSource {
|
||||
}
|
||||
|
||||
/** An argument specified in a url routing table */
|
||||
class DjangoRequestParameter extends HttpRequestTaintSource {
|
||||
deprecated class DjangoRequestParameter extends HttpRequestTaintSource {
|
||||
DjangoRequestParameter() {
|
||||
exists(DjangoRoute route, Function f, DjangoViewHandler view, int request_arg_index |
|
||||
route.getViewHandler() = view and
|
||||
|
||||
@@ -15,12 +15,12 @@ private import semmle.python.web.Http
|
||||
deprecated class DjangoResponse = DjangoResponseKind;
|
||||
|
||||
/** INTERNAL class used for tracking a django response object. */
|
||||
private class DjangoResponseKind extends TaintKind {
|
||||
deprecated private class DjangoResponseKind extends TaintKind {
|
||||
DjangoResponseKind() { this = "django.response.HttpResponse" }
|
||||
}
|
||||
|
||||
/** INTERNAL taint-source used for tracking a django response object. */
|
||||
private class DjangoResponseSource extends TaintSource {
|
||||
deprecated private class DjangoResponseSource extends TaintSource {
|
||||
DjangoResponseSource() { exists(DjangoContentResponseClass cls | cls.getACall() = this) }
|
||||
|
||||
override predicate isSourceOf(TaintKind kind) { kind instanceof DjangoResponseKind }
|
||||
@@ -29,7 +29,7 @@ private class DjangoResponseSource extends TaintSource {
|
||||
}
|
||||
|
||||
/** A write to a django response, which is vulnerable to external data (xss) */
|
||||
class DjangoResponseWrite extends HttpResponseTaintSink {
|
||||
deprecated class DjangoResponseWrite extends HttpResponseTaintSink {
|
||||
DjangoResponseWrite() {
|
||||
exists(AttrNode meth, CallNode call |
|
||||
call.getFunction() = meth and
|
||||
@@ -46,7 +46,7 @@ class DjangoResponseWrite extends HttpResponseTaintSink {
|
||||
/**
|
||||
* An argument to initialization of a django response.
|
||||
*/
|
||||
class DjangoResponseContent extends HttpResponseTaintSink {
|
||||
deprecated class DjangoResponseContent extends HttpResponseTaintSink {
|
||||
DjangoContentResponseClass cls;
|
||||
CallNode call;
|
||||
|
||||
@@ -63,7 +63,7 @@ class DjangoResponseContent extends HttpResponseTaintSink {
|
||||
/**
|
||||
* An argument to initialization of a django response, which is vulnerable to external data (XSS).
|
||||
*/
|
||||
class DjangoResponseContentXSSVulnerable extends DjangoResponseContent {
|
||||
deprecated class DjangoResponseContentXSSVulnerable extends DjangoResponseContent {
|
||||
override DjangoXSSVulnerableResponseClass cls;
|
||||
|
||||
DjangoResponseContentXSSVulnerable() {
|
||||
@@ -76,7 +76,7 @@ class DjangoResponseContentXSSVulnerable extends DjangoResponseContent {
|
||||
}
|
||||
}
|
||||
|
||||
class DjangoCookieSet extends CookieSet, CallNode {
|
||||
deprecated class DjangoCookieSet extends CookieSet, CallNode {
|
||||
DjangoCookieSet() {
|
||||
any(DjangoResponseKind r).taints(this.getFunction().(AttrNode).getObject("set_cookie"))
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ deprecated ClassValue theDjangoHttpRedirectClass() {
|
||||
}
|
||||
|
||||
/** A class that is a Django Redirect Response (subclass of `django.http.HttpResponseRedirectBase`). */
|
||||
class DjangoRedirectResponseClass extends ClassValue {
|
||||
deprecated class DjangoRedirectResponseClass extends ClassValue {
|
||||
DjangoRedirectResponseClass() {
|
||||
exists(ClassValue redirect_base |
|
||||
// version 1.x
|
||||
@@ -31,7 +31,7 @@ class DjangoRedirectResponseClass extends ClassValue {
|
||||
* A class that is a Django Response, which can contain content.
|
||||
* A subclass of `django.http.HttpResponse` that is not a `DjangoRedirectResponseClass`.
|
||||
*/
|
||||
class DjangoContentResponseClass extends ClassValue {
|
||||
deprecated class DjangoContentResponseClass extends ClassValue {
|
||||
ClassValue base;
|
||||
|
||||
DjangoContentResponseClass() {
|
||||
@@ -59,7 +59,7 @@ class DjangoContentResponseClass extends ClassValue {
|
||||
}
|
||||
|
||||
/** A class that is a Django Response, and is vulnerable to XSS. */
|
||||
class DjangoXSSVulnerableResponseClass extends DjangoContentResponseClass {
|
||||
deprecated class DjangoXSSVulnerableResponseClass extends DjangoContentResponseClass {
|
||||
DjangoXSSVulnerableResponseClass() {
|
||||
// We want to avoid FPs on subclasses that are not exposed to XSS, for example `JsonResponse`.
|
||||
// The easiest way is to disregard any subclass that has a special `__init__` method.
|
||||
|
||||
@@ -2,21 +2,23 @@ import python
|
||||
import semmle.python.web.Http
|
||||
|
||||
/** The falcon API class */
|
||||
ClassValue theFalconAPIClass() { result = Value::named("falcon.API") }
|
||||
deprecated ClassValue theFalconAPIClass() { result = Value::named("falcon.API") }
|
||||
|
||||
/** Holds if `route` is routed to `resource` */
|
||||
private predicate api_route(CallNode route_call, ControlFlowNode route, ClassValue resource) {
|
||||
deprecated private predicate api_route(
|
||||
CallNode route_call, ControlFlowNode route, ClassValue resource
|
||||
) {
|
||||
route_call.getFunction().(AttrNode).getObject("add_route").pointsTo().getClass() =
|
||||
theFalconAPIClass() and
|
||||
route_call.getArg(0) = route and
|
||||
route_call.getArg(1).pointsTo().getClass() = resource
|
||||
}
|
||||
|
||||
private predicate route(FalconRoute route, Function target, string funcname) {
|
||||
deprecated private predicate route(FalconRoute route, Function target, string funcname) {
|
||||
route.getResourceClass().lookup("on_" + funcname).(FunctionValue).getScope() = target
|
||||
}
|
||||
|
||||
class FalconRoute extends ControlFlowNode {
|
||||
deprecated class FalconRoute extends ControlFlowNode {
|
||||
FalconRoute() { api_route(this, _, _) }
|
||||
|
||||
string getUrl() {
|
||||
@@ -31,7 +33,7 @@ class FalconRoute extends ControlFlowNode {
|
||||
FalconHandlerFunction getHandlerFunction(string method) { route(this, result, method) }
|
||||
}
|
||||
|
||||
class FalconHandlerFunction extends Function {
|
||||
deprecated class FalconHandlerFunction extends Function {
|
||||
FalconHandlerFunction() { route(_, this, _) }
|
||||
|
||||
private string methodName() { route(_, this, result) }
|
||||
|
||||
@@ -5,7 +5,7 @@ import semmle.python.web.falcon.General
|
||||
import semmle.python.security.strings.External
|
||||
|
||||
/** https://falcon.readthedocs.io/en/stable/api/request_and_response.html */
|
||||
class FalconRequest extends TaintKind {
|
||||
deprecated class FalconRequest extends TaintKind {
|
||||
FalconRequest() { this = "falcon.request" }
|
||||
|
||||
override TaintKind getTaintOfAttribute(string name) {
|
||||
@@ -29,7 +29,7 @@ class FalconRequest extends TaintKind {
|
||||
}
|
||||
}
|
||||
|
||||
class FalconRequestParameter extends HttpRequestTaintSource {
|
||||
deprecated class FalconRequestParameter extends HttpRequestTaintSource {
|
||||
FalconRequestParameter() {
|
||||
exists(FalconHandlerFunction f | f.getRequest() = this.(ControlFlowNode).getNode())
|
||||
}
|
||||
|
||||
@@ -5,12 +5,12 @@ import semmle.python.web.falcon.General
|
||||
import semmle.python.security.strings.External
|
||||
|
||||
/** https://falcon.readthedocs.io/en/stable/api/request_and_response.html */
|
||||
class FalconResponse extends TaintKind {
|
||||
deprecated class FalconResponse extends TaintKind {
|
||||
FalconResponse() { this = "falcon.response" }
|
||||
}
|
||||
|
||||
/** Only used internally to track the response parameter */
|
||||
private class FalconResponseParameter extends TaintSource {
|
||||
deprecated private class FalconResponseParameter extends TaintSource {
|
||||
FalconResponseParameter() {
|
||||
exists(FalconHandlerFunction f | f.getResponse() = this.(ControlFlowNode).getNode())
|
||||
}
|
||||
@@ -18,7 +18,7 @@ private class FalconResponseParameter extends TaintSource {
|
||||
override predicate isSourceOf(TaintKind k) { k instanceof FalconResponse }
|
||||
}
|
||||
|
||||
class FalconResponseBodySink extends HttpResponseTaintSink {
|
||||
deprecated class FalconResponseBodySink extends HttpResponseTaintSink {
|
||||
FalconResponseBodySink() {
|
||||
exists(AttrNode attr | any(FalconResponse f).taints(attr.getObject("body")) |
|
||||
attr.(DefinitionNode).getValue() = this
|
||||
|
||||
@@ -3,18 +3,18 @@ import semmle.python.web.Http
|
||||
import semmle.python.web.flask.Response
|
||||
|
||||
/** The flask app class */
|
||||
ClassValue theFlaskClass() { result = Value::named("flask.Flask") }
|
||||
deprecated ClassValue theFlaskClass() { result = Value::named("flask.Flask") }
|
||||
|
||||
/** The flask MethodView class */
|
||||
ClassValue theFlaskMethodViewClass() { result = Value::named("flask.views.MethodView") }
|
||||
deprecated ClassValue theFlaskMethodViewClass() { result = Value::named("flask.views.MethodView") }
|
||||
|
||||
ClassValue theFlaskReponseClass() { result = Value::named("flask.Response") }
|
||||
deprecated ClassValue theFlaskReponseClass() { result = Value::named("flask.Response") }
|
||||
|
||||
/**
|
||||
* Holds if `route` is routed to `func`
|
||||
* by decorating `func` with `app.route(route)`
|
||||
*/
|
||||
predicate app_route(ControlFlowNode route, Function func) {
|
||||
deprecated predicate app_route(ControlFlowNode route, Function func) {
|
||||
exists(CallNode route_call, CallNode decorator_call |
|
||||
route_call.getFunction().(AttrNode).getObject("route").pointsTo().getClass() = theFlaskClass() and
|
||||
decorator_call.getFunction() = route_call and
|
||||
@@ -24,7 +24,7 @@ predicate app_route(ControlFlowNode route, Function func) {
|
||||
}
|
||||
|
||||
/* Helper for add_url_rule */
|
||||
private predicate add_url_rule_call(ControlFlowNode regex, ControlFlowNode callable) {
|
||||
deprecated private predicate add_url_rule_call(ControlFlowNode regex, ControlFlowNode callable) {
|
||||
exists(CallNode call |
|
||||
call.getFunction().(AttrNode).getObject("add_url_rule").pointsTo().getClass() = theFlaskClass() and
|
||||
regex = call.getArg(0)
|
||||
@@ -35,7 +35,7 @@ private predicate add_url_rule_call(ControlFlowNode regex, ControlFlowNode calla
|
||||
}
|
||||
|
||||
/** Holds if urls matching `regex` are routed to `func` */
|
||||
predicate add_url_rule(ControlFlowNode regex, Function func) {
|
||||
deprecated predicate add_url_rule(ControlFlowNode regex, Function func) {
|
||||
exists(ControlFlowNode callable | add_url_rule_call(regex, callable) |
|
||||
exists(PythonFunctionValue f | f.getScope() = func and callable.pointsTo(f))
|
||||
or
|
||||
@@ -51,14 +51,14 @@ predicate add_url_rule(ControlFlowNode regex, Function func) {
|
||||
* Holds if urls matching `regex` are routed to `func` using
|
||||
* any of flask's routing mechanisms.
|
||||
*/
|
||||
predicate flask_routing(ControlFlowNode regex, Function func) {
|
||||
deprecated predicate flask_routing(ControlFlowNode regex, Function func) {
|
||||
app_route(regex, func)
|
||||
or
|
||||
add_url_rule(regex, func)
|
||||
}
|
||||
|
||||
/** A class that extends flask.views.MethodView */
|
||||
private class MethodViewClass extends ClassValue {
|
||||
deprecated private class MethodViewClass extends ClassValue {
|
||||
MethodViewClass() { this.getASuperType() = theFlaskMethodViewClass() }
|
||||
|
||||
/* As we are restricted to strings for taint kinds, we need to map these classes to strings. */
|
||||
@@ -68,12 +68,12 @@ private class MethodViewClass extends ClassValue {
|
||||
TaintKind asTaint() { result = this.taintString() }
|
||||
}
|
||||
|
||||
private class MethodViewTaint extends TaintKind {
|
||||
deprecated private class MethodViewTaint extends TaintKind {
|
||||
MethodViewTaint() { any(MethodViewClass cls).taintString() = this }
|
||||
}
|
||||
|
||||
/** A source of method view "taint"s. */
|
||||
private class AsView extends TaintSource {
|
||||
deprecated private class AsView extends TaintSource {
|
||||
AsView() {
|
||||
exists(ClassValue view_class |
|
||||
view_class.getASuperType() = theFlaskMethodViewClass() and
|
||||
@@ -91,7 +91,7 @@ private class AsView extends TaintSource {
|
||||
}
|
||||
}
|
||||
|
||||
class FlaskCookieSet extends CookieSet, CallNode {
|
||||
deprecated class FlaskCookieSet extends CookieSet, CallNode {
|
||||
FlaskCookieSet() {
|
||||
any(FlaskResponseTaintKind t).taints(this.getFunction().(AttrNode).getObject("set_cookie"))
|
||||
}
|
||||
|
||||
@@ -9,12 +9,12 @@ import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.security.strings.Basic
|
||||
import semmle.python.web.flask.General
|
||||
|
||||
FunctionValue flask_redirect() { result = Value::named("flask.redirect") }
|
||||
deprecated FunctionValue flask_redirect() { result = Value::named("flask.redirect") }
|
||||
|
||||
/**
|
||||
* Represents an argument to the `flask.redirect` function.
|
||||
*/
|
||||
class FlaskRedirect extends HttpRedirectTaintSink {
|
||||
deprecated class FlaskRedirect extends HttpRedirectTaintSink {
|
||||
override string toString() { result = "flask.redirect" }
|
||||
|
||||
FlaskRedirect() {
|
||||
|
||||
@@ -3,16 +3,16 @@ import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.web.Http
|
||||
import semmle.python.web.flask.General
|
||||
|
||||
private Value theFlaskRequestObject() { result = Value::named("flask.request") }
|
||||
deprecated private Value theFlaskRequestObject() { result = Value::named("flask.request") }
|
||||
|
||||
/** Holds if `attr` is an access of attribute `name` of the flask request object */
|
||||
private predicate flask_request_attr(AttrNode attr, string name) {
|
||||
deprecated private predicate flask_request_attr(AttrNode attr, string name) {
|
||||
attr.isLoad() and
|
||||
attr.getObject(name).pointsTo(theFlaskRequestObject())
|
||||
}
|
||||
|
||||
/** Source of external data from a flask request */
|
||||
class FlaskRequestData extends HttpRequestTaintSource {
|
||||
deprecated class FlaskRequestData extends HttpRequestTaintSource {
|
||||
FlaskRequestData() {
|
||||
not this instanceof FlaskRequestArgs and
|
||||
exists(string name | flask_request_attr(this, name) |
|
||||
@@ -26,7 +26,7 @@ class FlaskRequestData extends HttpRequestTaintSource {
|
||||
}
|
||||
|
||||
/** Source of dictionary whose values are externally controlled */
|
||||
class FlaskRequestArgs extends HttpRequestTaintSource {
|
||||
deprecated class FlaskRequestArgs extends HttpRequestTaintSource {
|
||||
FlaskRequestArgs() {
|
||||
exists(string attr | flask_request_attr(this, attr) |
|
||||
attr in ["args", "form", "values", "files", "headers", "json"]
|
||||
@@ -39,7 +39,7 @@ class FlaskRequestArgs extends HttpRequestTaintSource {
|
||||
}
|
||||
|
||||
/** Source of dictionary whose values are externally controlled */
|
||||
class FlaskRequestJson extends HttpRequestTaintSource {
|
||||
deprecated class FlaskRequestJson extends HttpRequestTaintSource {
|
||||
FlaskRequestJson() { flask_request_attr(this, "json") }
|
||||
|
||||
override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalJsonKind }
|
||||
@@ -57,7 +57,7 @@ class FlaskRequestJson extends HttpRequestTaintSource {
|
||||
* def hello(name):
|
||||
* ```
|
||||
*/
|
||||
class FlaskRoutedParameter extends HttpRequestTaintSource {
|
||||
deprecated class FlaskRoutedParameter extends HttpRequestTaintSource {
|
||||
FlaskRoutedParameter() {
|
||||
exists(string name, Function func, StrConst url_pattern |
|
||||
this.(ControlFlowNode).getNode() = func.getArgByName(name) and
|
||||
@@ -72,7 +72,7 @@ class FlaskRoutedParameter extends HttpRequestTaintSource {
|
||||
override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind }
|
||||
}
|
||||
|
||||
private string werkzeug_rule_re() {
|
||||
deprecated private string werkzeug_rule_re() {
|
||||
// since flask uses werkzeug internally, we are using its routing rules from
|
||||
// https://github.com/pallets/werkzeug/blob/4dc8d6ab840d4b78cbd5789cef91b01e3bde01d5/src/werkzeug/routing.py#L138-L151
|
||||
result =
|
||||
|
||||
@@ -7,7 +7,7 @@ import semmle.python.web.flask.General
|
||||
* A flask response, which is vulnerable to any sort of
|
||||
* http response malice.
|
||||
*/
|
||||
class FlaskRoutedResponse extends HttpResponseTaintSink {
|
||||
deprecated class FlaskRoutedResponse extends HttpResponseTaintSink {
|
||||
FlaskRoutedResponse() {
|
||||
exists(PythonFunctionValue response |
|
||||
flask_routing(_, response.getScope()) and
|
||||
@@ -20,7 +20,7 @@ class FlaskRoutedResponse extends HttpResponseTaintSink {
|
||||
override string toString() { result = "flask.routed.response" }
|
||||
}
|
||||
|
||||
class FlaskResponseArgument extends HttpResponseTaintSink {
|
||||
deprecated class FlaskResponseArgument extends HttpResponseTaintSink {
|
||||
FlaskResponseArgument() {
|
||||
exists(CallNode call |
|
||||
(
|
||||
@@ -37,11 +37,11 @@ class FlaskResponseArgument extends HttpResponseTaintSink {
|
||||
override string toString() { result = "flask.response.argument" }
|
||||
}
|
||||
|
||||
class FlaskResponseTaintKind extends TaintKind {
|
||||
deprecated class FlaskResponseTaintKind extends TaintKind {
|
||||
FlaskResponseTaintKind() { this = "flask.Response" }
|
||||
}
|
||||
|
||||
class FlaskResponseConfiguration extends TaintTracking::Configuration {
|
||||
deprecated class FlaskResponseConfiguration extends TaintTracking::Configuration {
|
||||
FlaskResponseConfiguration() { this = "Flask response configuration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node node, TaintKind kind) {
|
||||
|
||||
@@ -9,7 +9,7 @@ import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.security.strings.Basic
|
||||
import semmle.python.web.Http
|
||||
|
||||
private ClassValue redirectClass() {
|
||||
deprecated private ClassValue redirectClass() {
|
||||
exists(ModuleValue ex | ex.getName() = "pyramid.httpexceptions" |
|
||||
ex.attr("HTTPFound") = result
|
||||
or
|
||||
@@ -20,7 +20,7 @@ private ClassValue redirectClass() {
|
||||
/**
|
||||
* Represents an argument to the `tornado.redirect` function.
|
||||
*/
|
||||
class PyramidRedirect extends HttpRedirectTaintSink {
|
||||
deprecated class PyramidRedirect extends HttpRedirectTaintSink {
|
||||
override string toString() { result = "pyramid.redirect" }
|
||||
|
||||
PyramidRedirect() {
|
||||
|
||||
@@ -4,14 +4,14 @@ import semmle.python.web.Http
|
||||
private import semmle.python.web.webob.Request
|
||||
private import semmle.python.web.pyramid.View
|
||||
|
||||
class PyramidRequest extends BaseWebobRequest {
|
||||
deprecated class PyramidRequest extends BaseWebobRequest {
|
||||
PyramidRequest() { this = "pyramid.request" }
|
||||
|
||||
override ClassValue getType() { result = Value::named("pyramid.request.Request") }
|
||||
}
|
||||
|
||||
/** Source of pyramid request objects */
|
||||
class PyramidViewArgument extends HttpRequestTaintSource {
|
||||
deprecated class PyramidViewArgument extends HttpRequestTaintSource {
|
||||
PyramidViewArgument() {
|
||||
exists(Function view_func |
|
||||
is_pyramid_view_function(view_func) and
|
||||
|
||||
@@ -9,7 +9,7 @@ private import semmle.python.web.Http
|
||||
* A pyramid response, which is vulnerable to any sort of
|
||||
* http response malice.
|
||||
*/
|
||||
class PyramidRoutedResponse extends HttpResponseTaintSink {
|
||||
deprecated class PyramidRoutedResponse extends HttpResponseTaintSink {
|
||||
PyramidRoutedResponse() {
|
||||
exists(PythonFunctionValue view |
|
||||
is_pyramid_view_function(view.getScope()) and
|
||||
@@ -22,7 +22,7 @@ class PyramidRoutedResponse extends HttpResponseTaintSink {
|
||||
override string toString() { result = "pyramid.routed.response" }
|
||||
}
|
||||
|
||||
class PyramidCookieSet extends CookieSet, CallNode {
|
||||
deprecated class PyramidCookieSet extends CookieSet, CallNode {
|
||||
PyramidCookieSet() {
|
||||
exists(ControlFlowNode f |
|
||||
f = this.getFunction().(AttrNode).getObject("set_cookie") and
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import python
|
||||
|
||||
ModuleValue thePyramidViewModule() { result.getName() = "pyramid.view" }
|
||||
deprecated ModuleValue thePyramidViewModule() { result.getName() = "pyramid.view" }
|
||||
|
||||
Value thePyramidViewConfig() { result = thePyramidViewModule().attr("view_config") }
|
||||
deprecated Value thePyramidViewConfig() { result = thePyramidViewModule().attr("view_config") }
|
||||
|
||||
predicate is_pyramid_view_function(Function func) {
|
||||
deprecated predicate is_pyramid_view_function(Function func) {
|
||||
func.getADecorator().pointsTo().getClass() = thePyramidViewConfig()
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.web.Http
|
||||
|
||||
/** Source of BaseHTTPRequestHandler instances. */
|
||||
class StdLibRequestSource extends HttpRequestTaintSource {
|
||||
deprecated class StdLibRequestSource extends HttpRequestTaintSource {
|
||||
StdLibRequestSource() {
|
||||
exists(ClassValue cls |
|
||||
cls.getABaseType+() = Value::named("BaseHTTPServer.BaseHTTPRequestHandler")
|
||||
@@ -24,7 +24,7 @@ class StdLibRequestSource extends HttpRequestTaintSource {
|
||||
}
|
||||
|
||||
/** TaintKind for an instance of BaseHTTPRequestHandler. */
|
||||
class BaseHTTPRequestHandlerKind extends TaintKind {
|
||||
deprecated class BaseHTTPRequestHandlerKind extends TaintKind {
|
||||
BaseHTTPRequestHandlerKind() { this = "BaseHTTPRequestHandlerKind" }
|
||||
|
||||
override TaintKind getTaintOfAttribute(string name) {
|
||||
@@ -40,7 +40,7 @@ class BaseHTTPRequestHandlerKind extends TaintKind {
|
||||
}
|
||||
|
||||
/** TaintKind for headers (instance of HTTPMessage). */
|
||||
class HTTPMessageKind extends ExternalStringDictKind {
|
||||
deprecated class HTTPMessageKind extends ExternalStringDictKind {
|
||||
override TaintKind getTaintOfMethodResult(string name) {
|
||||
result = super.getTaintOfMethodResult(name)
|
||||
or
|
||||
@@ -63,14 +63,14 @@ class HTTPMessageKind extends ExternalStringDictKind {
|
||||
}
|
||||
|
||||
/** Source of parsed HTTP forms (by using the `cgi` module). */
|
||||
class CgiFieldStorageSource extends HttpRequestTaintSource {
|
||||
deprecated class CgiFieldStorageSource extends HttpRequestTaintSource {
|
||||
CgiFieldStorageSource() { this = Value::named("cgi.FieldStorage").getACall() }
|
||||
|
||||
override predicate isSourceOf(TaintKind kind) { kind instanceof CgiFieldStorageFormKind }
|
||||
}
|
||||
|
||||
/** TaintKind for a parsed HTTP form. */
|
||||
class CgiFieldStorageFormKind extends TaintKind {
|
||||
deprecated class CgiFieldStorageFormKind extends TaintKind {
|
||||
/*
|
||||
* There is a slight difference between how we model form/fields and how it is handled by the code.
|
||||
* In the code
|
||||
@@ -115,7 +115,7 @@ class CgiFieldStorageFormKind extends TaintKind {
|
||||
}
|
||||
|
||||
/** TaintKind for the field of a parsed HTTP form. */
|
||||
class CgiFieldStorageFieldKind extends TaintKind {
|
||||
deprecated class CgiFieldStorageFieldKind extends TaintKind {
|
||||
CgiFieldStorageFieldKind() { this = "CgiFieldStorageFieldKind" }
|
||||
|
||||
override TaintKind getTaintOfAttribute(string name) {
|
||||
|
||||
@@ -6,7 +6,7 @@ import python
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.web.Http
|
||||
|
||||
private predicate is_wfile(AttrNode wfile) {
|
||||
deprecated private predicate is_wfile(AttrNode wfile) {
|
||||
exists(ClassValue cls |
|
||||
// Python 2
|
||||
cls.getABaseType+() = Value::named("BaseHTTPServer.BaseHTTPRequestHandler")
|
||||
@@ -19,7 +19,7 @@ private predicate is_wfile(AttrNode wfile) {
|
||||
}
|
||||
|
||||
/** Sink for `h.wfile.write` where `h` is an instance of BaseHTTPRequestHandler. */
|
||||
class StdLibWFileWriteSink extends HttpResponseTaintSink {
|
||||
deprecated class StdLibWFileWriteSink extends HttpResponseTaintSink {
|
||||
StdLibWFileWriteSink() {
|
||||
exists(CallNode call |
|
||||
is_wfile(call.getFunction().(AttrNode).getObject("write")) and
|
||||
@@ -31,7 +31,7 @@ class StdLibWFileWriteSink extends HttpResponseTaintSink {
|
||||
}
|
||||
|
||||
/** Sink for `h.wfile.writelines` where `h` is an instance of BaseHTTPRequestHandler. */
|
||||
class StdLibWFileWritelinesSink extends HttpResponseTaintSink {
|
||||
deprecated class StdLibWFileWritelinesSink extends HttpResponseTaintSink {
|
||||
StdLibWFileWritelinesSink() {
|
||||
exists(CallNode call |
|
||||
is_wfile(call.getFunction().(AttrNode).getObject("writelines")) and
|
||||
|
||||
@@ -13,7 +13,7 @@ import Tornado
|
||||
/**
|
||||
* Represents an argument to the `tornado.redirect` function.
|
||||
*/
|
||||
class TornadoHttpRequestHandlerRedirect extends HttpRedirectTaintSink {
|
||||
deprecated class TornadoHttpRequestHandlerRedirect extends HttpRedirectTaintSink {
|
||||
override string toString() { result = "tornado.HttpRequestHandler.redirect" }
|
||||
|
||||
TornadoHttpRequestHandlerRedirect() {
|
||||
|
||||
@@ -4,7 +4,7 @@ import semmle.python.web.Http
|
||||
import Tornado
|
||||
|
||||
/** A tornado.request.HttpRequest object */
|
||||
class TornadoRequest extends TaintKind {
|
||||
deprecated class TornadoRequest extends TaintKind {
|
||||
TornadoRequest() { this = "tornado.request.HttpRequest" }
|
||||
|
||||
override TaintKind getTaintOfAttribute(string name) {
|
||||
@@ -30,7 +30,7 @@ class TornadoRequest extends TaintKind {
|
||||
}
|
||||
}
|
||||
|
||||
class TornadoRequestSource extends HttpRequestTaintSource {
|
||||
deprecated class TornadoRequestSource extends HttpRequestTaintSource {
|
||||
TornadoRequestSource() { isTornadoRequestHandlerInstance(this.(AttrNode).getObject("request")) }
|
||||
|
||||
override string toString() { result = "Tornado request source" }
|
||||
@@ -38,7 +38,7 @@ class TornadoRequestSource extends HttpRequestTaintSource {
|
||||
override predicate isSourceOf(TaintKind kind) { kind instanceof TornadoRequest }
|
||||
}
|
||||
|
||||
class TornadoExternalInputSource extends HttpRequestTaintSource {
|
||||
deprecated class TornadoExternalInputSource extends HttpRequestTaintSource {
|
||||
TornadoExternalInputSource() {
|
||||
exists(string name |
|
||||
name in ["get_argument", "get_query_argument", "get_body_argument", "decode_argument"]
|
||||
@@ -52,7 +52,7 @@ class TornadoExternalInputSource extends HttpRequestTaintSource {
|
||||
override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind }
|
||||
}
|
||||
|
||||
class TornadoExternalInputListSource extends HttpRequestTaintSource {
|
||||
deprecated class TornadoExternalInputListSource extends HttpRequestTaintSource {
|
||||
TornadoExternalInputListSource() {
|
||||
exists(string name |
|
||||
name = "get_arguments" or
|
||||
|
||||
@@ -4,11 +4,11 @@ import semmle.python.security.strings.Basic
|
||||
private import semmle.python.web.Http
|
||||
import Tornado
|
||||
|
||||
class TornadoConnection extends TaintKind {
|
||||
deprecated class TornadoConnection extends TaintKind {
|
||||
TornadoConnection() { this = "tornado.http.connection" }
|
||||
}
|
||||
|
||||
class TornadoConnectionSource extends TaintSource {
|
||||
deprecated class TornadoConnectionSource extends TaintSource {
|
||||
TornadoConnectionSource() {
|
||||
isTornadoRequestHandlerInstance(this.(AttrNode).getObject("connection"))
|
||||
}
|
||||
@@ -18,7 +18,7 @@ class TornadoConnectionSource extends TaintSource {
|
||||
override predicate isSourceOf(TaintKind kind) { kind instanceof TornadoConnection }
|
||||
}
|
||||
|
||||
class TornadoConnectionWrite extends HttpResponseTaintSink {
|
||||
deprecated class TornadoConnectionWrite extends HttpResponseTaintSink {
|
||||
override string toString() { result = "tornado.connection.write" }
|
||||
|
||||
TornadoConnectionWrite() {
|
||||
@@ -32,7 +32,7 @@ class TornadoConnectionWrite extends HttpResponseTaintSink {
|
||||
override predicate sinks(TaintKind kind) { kind instanceof StringKind }
|
||||
}
|
||||
|
||||
class TornadoHttpRequestHandlerWrite extends HttpResponseTaintSink {
|
||||
deprecated class TornadoHttpRequestHandlerWrite extends HttpResponseTaintSink {
|
||||
override string toString() { result = "tornado.HttpRequestHandler.write" }
|
||||
|
||||
TornadoHttpRequestHandlerWrite() {
|
||||
|
||||
@@ -2,11 +2,11 @@ import python
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.web.Http
|
||||
|
||||
private ClassValue theTornadoRequestHandlerClass() {
|
||||
deprecated private ClassValue theTornadoRequestHandlerClass() {
|
||||
result = Value::named("tornado.web.RequestHandler")
|
||||
}
|
||||
|
||||
ClassValue aTornadoRequestHandlerClass() {
|
||||
deprecated ClassValue aTornadoRequestHandlerClass() {
|
||||
result.getABaseType+() = theTornadoRequestHandlerClass()
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ ClassValue aTornadoRequestHandlerClass() {
|
||||
* Holds if `node` is likely to refer to an instance of a tornado
|
||||
* `RequestHandler` class.
|
||||
*/
|
||||
predicate isTornadoRequestHandlerInstance(ControlFlowNode node) {
|
||||
deprecated predicate isTornadoRequestHandlerInstance(ControlFlowNode node) {
|
||||
node.pointsTo().getClass() = aTornadoRequestHandlerClass()
|
||||
or
|
||||
/*
|
||||
@@ -30,11 +30,11 @@ predicate isTornadoRequestHandlerInstance(ControlFlowNode node) {
|
||||
node.(NameNode).isSelf()
|
||||
}
|
||||
|
||||
CallNode callToNamedTornadoRequestHandlerMethod(string name) {
|
||||
deprecated CallNode callToNamedTornadoRequestHandlerMethod(string name) {
|
||||
isTornadoRequestHandlerInstance(result.getFunction().(AttrNode).getObject(name))
|
||||
}
|
||||
|
||||
class TornadoCookieSet extends CookieSet, CallNode {
|
||||
deprecated class TornadoCookieSet extends CookieSet, CallNode {
|
||||
TornadoCookieSet() {
|
||||
exists(ControlFlowNode f |
|
||||
f = this.getFunction().(AttrNode).getObject("set_cookie") and
|
||||
|
||||
@@ -3,7 +3,7 @@ import semmle.python.security.strings.External
|
||||
import semmle.python.web.Http
|
||||
import TurboGears
|
||||
|
||||
private class ValidatedMethodParameter extends Parameter {
|
||||
deprecated private class ValidatedMethodParameter extends Parameter {
|
||||
ValidatedMethodParameter() {
|
||||
exists(string name, TurboGearsControllerMethod method |
|
||||
method.getArgByName(name) = this and
|
||||
@@ -12,7 +12,7 @@ private class ValidatedMethodParameter extends Parameter {
|
||||
}
|
||||
}
|
||||
|
||||
class UnvalidatedControllerMethodParameter extends HttpRequestTaintSource {
|
||||
deprecated class UnvalidatedControllerMethodParameter extends HttpRequestTaintSource {
|
||||
UnvalidatedControllerMethodParameter() {
|
||||
exists(Parameter p |
|
||||
any(TurboGearsControllerMethod m | not m.getName() = "onerror").getAnArg() = p and
|
||||
|
||||
@@ -4,7 +4,7 @@ import semmle.python.security.strings.Basic
|
||||
import semmle.python.web.Http
|
||||
import TurboGears
|
||||
|
||||
class ControllerMethodReturnValue extends HttpResponseTaintSink {
|
||||
deprecated class ControllerMethodReturnValue extends HttpResponseTaintSink {
|
||||
override string toString() { result = "TurboGears ControllerMethodReturnValue" }
|
||||
|
||||
ControllerMethodReturnValue() {
|
||||
@@ -17,7 +17,7 @@ class ControllerMethodReturnValue extends HttpResponseTaintSink {
|
||||
override predicate sinks(TaintKind kind) { kind instanceof StringKind }
|
||||
}
|
||||
|
||||
class ControllerMethodTemplatedReturnValue extends HttpResponseTaintSink {
|
||||
deprecated class ControllerMethodTemplatedReturnValue extends HttpResponseTaintSink {
|
||||
override string toString() { result = "TurboGears ControllerMethodTemplatedReturnValue" }
|
||||
|
||||
ControllerMethodTemplatedReturnValue() {
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
import python
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
|
||||
private ClassValue theTurboGearsControllerClass() { result = Value::named("tg.TGController") }
|
||||
deprecated private ClassValue theTurboGearsControllerClass() {
|
||||
result = Value::named("tg.TGController")
|
||||
}
|
||||
|
||||
ClassValue aTurboGearsControllerClass() { result.getABaseType+() = theTurboGearsControllerClass() }
|
||||
deprecated ClassValue aTurboGearsControllerClass() {
|
||||
result.getABaseType+() = theTurboGearsControllerClass()
|
||||
}
|
||||
|
||||
class TurboGearsControllerMethod extends Function {
|
||||
deprecated class TurboGearsControllerMethod extends Function {
|
||||
ControlFlowNode decorator;
|
||||
|
||||
TurboGearsControllerMethod() {
|
||||
|
||||
@@ -4,7 +4,7 @@ import semmle.python.web.Http
|
||||
import Twisted
|
||||
|
||||
/** A twisted.web.http.Request object */
|
||||
class TwistedRequest extends TaintKind {
|
||||
deprecated class TwistedRequest extends TaintKind {
|
||||
TwistedRequest() { this = "twisted.request.http.Request" }
|
||||
|
||||
override TaintKind getTaintOfAttribute(string name) {
|
||||
@@ -21,7 +21,7 @@ class TwistedRequest extends TaintKind {
|
||||
}
|
||||
}
|
||||
|
||||
class TwistedRequestSource extends HttpRequestTaintSource {
|
||||
deprecated class TwistedRequestSource extends HttpRequestTaintSource {
|
||||
TwistedRequestSource() { isTwistedRequestInstance(this) }
|
||||
|
||||
override string toString() { result = "Twisted request source" }
|
||||
|
||||
@@ -5,7 +5,7 @@ import semmle.python.security.strings.Basic
|
||||
import Twisted
|
||||
import Request
|
||||
|
||||
class TwistedResponse extends HttpResponseTaintSink {
|
||||
deprecated class TwistedResponse extends HttpResponseTaintSink {
|
||||
TwistedResponse() {
|
||||
exists(PythonFunctionValue func, string name |
|
||||
isKnownRequestHandlerMethodName(name) and
|
||||
@@ -25,7 +25,7 @@ class TwistedResponse extends HttpResponseTaintSink {
|
||||
* object, which affects the properties of the subsequent response sent to this
|
||||
* request.
|
||||
*/
|
||||
class TwistedRequestSetter extends HttpResponseTaintSink {
|
||||
deprecated class TwistedRequestSetter extends HttpResponseTaintSink {
|
||||
TwistedRequestSetter() {
|
||||
exists(CallNode call, ControlFlowNode node, string name |
|
||||
(
|
||||
|
||||
@@ -1,22 +1,24 @@
|
||||
import python
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
|
||||
private ClassValue theTwistedHttpRequestClass() {
|
||||
deprecated private ClassValue theTwistedHttpRequestClass() {
|
||||
result = Value::named("twisted.web.http.Request")
|
||||
}
|
||||
|
||||
private ClassValue theTwistedHttpResourceClass() {
|
||||
deprecated private ClassValue theTwistedHttpResourceClass() {
|
||||
result = Value::named("twisted.web.resource.Resource")
|
||||
}
|
||||
|
||||
ClassValue aTwistedRequestHandlerClass() { result.getABaseType+() = theTwistedHttpResourceClass() }
|
||||
deprecated ClassValue aTwistedRequestHandlerClass() {
|
||||
result.getABaseType+() = theTwistedHttpResourceClass()
|
||||
}
|
||||
|
||||
FunctionValue getTwistedRequestHandlerMethod(string name) {
|
||||
deprecated FunctionValue getTwistedRequestHandlerMethod(string name) {
|
||||
result = aTwistedRequestHandlerClass().declaredAttribute(name)
|
||||
}
|
||||
|
||||
bindingset[name]
|
||||
predicate isKnownRequestHandlerMethodName(string name) {
|
||||
deprecated predicate isKnownRequestHandlerMethodName(string name) {
|
||||
name = "render" or
|
||||
name.matches("render_%")
|
||||
}
|
||||
@@ -25,7 +27,7 @@ predicate isKnownRequestHandlerMethodName(string name) {
|
||||
* Holds if `node` is likely to refer to an instance of the twisted
|
||||
* `Request` class.
|
||||
*/
|
||||
predicate isTwistedRequestInstance(NameNode node) {
|
||||
deprecated predicate isTwistedRequestInstance(NameNode node) {
|
||||
node.pointsTo().getClass() = theTwistedHttpRequestClass()
|
||||
or
|
||||
/*
|
||||
|
||||
@@ -2,7 +2,7 @@ import python
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.web.Http
|
||||
|
||||
abstract class BaseWebobRequest extends TaintKind {
|
||||
abstract deprecated class BaseWebobRequest extends TaintKind {
|
||||
bindingset[this]
|
||||
BaseWebobRequest() { any() }
|
||||
|
||||
@@ -31,7 +31,7 @@ abstract class BaseWebobRequest extends TaintKind {
|
||||
}
|
||||
}
|
||||
|
||||
class WebobRequest extends BaseWebobRequest {
|
||||
deprecated class WebobRequest extends BaseWebobRequest {
|
||||
WebobRequest() { this = "webob.Request" }
|
||||
|
||||
override ClassValue getType() { result = Value::named("webob.request.Request") }
|
||||
|
||||
837
python/ql/lib/upgrades/initial/semmlecode.python.dbscheme
Normal file
837
python/ql/lib/upgrades/initial/semmlecode.python.dbscheme
Normal file
@@ -0,0 +1,837 @@
|
||||
/*
|
||||
* This dbscheme is auto-generated by 'semmle/dbscheme_gen.py'.
|
||||
* WARNING: Any modifications to this file will be lost.
|
||||
* Relations can be changed by modifying master.py or
|
||||
* by adding rules to dbscheme.template
|
||||
*/
|
||||
|
||||
/*
|
||||
* External artifacts
|
||||
*/
|
||||
|
||||
externalDefects(
|
||||
unique int id : @externalDefect,
|
||||
varchar(900) queryPath : string ref,
|
||||
int location : @location ref,
|
||||
varchar(900) message : string ref,
|
||||
float severity : float ref
|
||||
);
|
||||
|
||||
externalMetrics(
|
||||
unique int id : @externalMetric,
|
||||
varchar(900) queryPath : string ref,
|
||||
int location : @location ref,
|
||||
float value : float ref
|
||||
);
|
||||
|
||||
externalData(
|
||||
int id : @externalDataElement,
|
||||
varchar(900) queryPath : string ref,
|
||||
int column: int ref,
|
||||
varchar(900) data : string ref
|
||||
);
|
||||
|
||||
snapshotDate(unique date snapshotDate : date ref);
|
||||
|
||||
sourceLocationPrefix(varchar(900) prefix : string ref);
|
||||
|
||||
|
||||
/*
|
||||
* Duplicate code
|
||||
*/
|
||||
|
||||
duplicateCode(
|
||||
unique int id : @duplication,
|
||||
varchar(900) relativePath : string ref,
|
||||
int equivClass : int ref);
|
||||
|
||||
similarCode(
|
||||
unique int id : @similarity,
|
||||
varchar(900) relativePath : string ref,
|
||||
int equivClass : int ref);
|
||||
|
||||
@duplication_or_similarity = @duplication | @similarity
|
||||
|
||||
tokens(
|
||||
int id : @duplication_or_similarity ref,
|
||||
int offset : int ref,
|
||||
int beginLine : int ref,
|
||||
int beginColumn : int ref,
|
||||
int endLine : int ref,
|
||||
int endColumn : int ref);
|
||||
|
||||
/*
|
||||
* Line metrics
|
||||
*/
|
||||
py_codelines(int id : @py_scope ref,
|
||||
int count : int ref);
|
||||
|
||||
py_commentlines(int id : @py_scope ref,
|
||||
int count : int ref);
|
||||
|
||||
py_docstringlines(int id : @py_scope ref,
|
||||
int count : int ref);
|
||||
|
||||
py_alllines(int id : @py_scope ref,
|
||||
int count : int ref);
|
||||
|
||||
/*
|
||||
* Version history
|
||||
*/
|
||||
|
||||
svnentries(
|
||||
int id : @svnentry,
|
||||
varchar(500) revision : string ref,
|
||||
varchar(500) author : string ref,
|
||||
date revisionDate : date ref,
|
||||
int changeSize : int ref
|
||||
)
|
||||
|
||||
svnaffectedfiles(
|
||||
int id : @svnentry ref,
|
||||
int file : @file ref,
|
||||
varchar(500) action : string ref
|
||||
)
|
||||
|
||||
svnentrymsg(
|
||||
int id : @svnentry ref,
|
||||
varchar(500) message : string ref
|
||||
)
|
||||
|
||||
svnchurn(
|
||||
int commit : @svnentry ref,
|
||||
int file : @file ref,
|
||||
int churnedLines : int ref
|
||||
)
|
||||
|
||||
/****************************
|
||||
Python dbscheme
|
||||
****************************/
|
||||
|
||||
/*
|
||||
fromSource(0) = unknown,
|
||||
fromSource(1) = from source,
|
||||
fromSource(2) = from library
|
||||
*/
|
||||
files(unique int id: @file,
|
||||
varchar(900) name: string ref,
|
||||
varchar(900) simple: string ref,
|
||||
varchar(900) ext: string ref,
|
||||
int fromSource: int ref);
|
||||
|
||||
folders(unique int id: @folder,
|
||||
varchar(900) name: string ref,
|
||||
varchar(900) simple: string ref);
|
||||
|
||||
@container = @folder | @file;
|
||||
|
||||
containerparent(int parent: @container ref,
|
||||
unique int child: @container ref);
|
||||
|
||||
@sourceline = @file | @py_Module;
|
||||
|
||||
numlines(int element_id: @sourceline ref,
|
||||
int num_lines: int ref,
|
||||
int num_code: int ref,
|
||||
int num_comment: int ref
|
||||
);
|
||||
|
||||
@location = @location_ast | @location_default ;
|
||||
|
||||
locations_default(unique int id: @location_default,
|
||||
int file: @file ref,
|
||||
int beginLine: int ref,
|
||||
int beginColumn: int ref,
|
||||
int endLine: int ref,
|
||||
int endColumn: int ref);
|
||||
|
||||
locations_ast(unique int id: @location_ast,
|
||||
int module: @py_Module ref,
|
||||
int beginLine: int ref,
|
||||
int beginColumn: int ref,
|
||||
int endLine: int ref,
|
||||
int endColumn: int ref);
|
||||
|
||||
py_module_path(int module: @py_Module ref, int file: @file ref);
|
||||
|
||||
variable(unique int id : @py_variable,
|
||||
int scope : @py_scope ref,
|
||||
varchar(1) name : string ref);
|
||||
|
||||
py_line_lengths(unique int id : @py_line,
|
||||
int file: @py_Module ref,
|
||||
int line : int ref,
|
||||
int length : int ref);
|
||||
|
||||
/* AUTO GENERATED PART STARTS HERE */
|
||||
|
||||
|
||||
/* <Field> Assert.location = 0, location */
|
||||
/* <Field> Assert.test = 1, expr */
|
||||
/* <Field> Assert.msg = 2, expr */
|
||||
|
||||
/* <Field> Assign.location = 0, location */
|
||||
/* <Field> Assign.value = 1, expr */
|
||||
/* <Field> Assign.targets = 2, expr_list */
|
||||
|
||||
/* <Field> Attribute.location = 0, location */
|
||||
/* <Field> Attribute.value = 1, expr */
|
||||
/* <Field> Attribute.attr = 2, str */
|
||||
/* <Field> Attribute.ctx = 3, expr_context */
|
||||
|
||||
/* <Field> AugAssign.location = 0, location */
|
||||
/* <Field> AugAssign.operation = 1, BinOp */
|
||||
|
||||
/* <Field> BinaryExpr.location = 0, location */
|
||||
/* <Field> BinaryExpr.left = 1, expr */
|
||||
/* <Field> BinaryExpr.op = 2, operator */
|
||||
/* <Field> BinaryExpr.right = 3, expr */
|
||||
/* <Parent> BinaryExpr = AugAssign */
|
||||
|
||||
/* <Field> BoolExpr.location = 0, location */
|
||||
/* <Field> BoolExpr.op = 1, boolop */
|
||||
/* <Field> BoolExpr.values = 2, expr_list */
|
||||
|
||||
/* <Field> Break.location = 0, location */
|
||||
|
||||
/* <Field> Bytes.location = 0, location */
|
||||
/* <Field> Bytes.s = 1, bytes */
|
||||
|
||||
/* <Field> Call.location = 0, location */
|
||||
/* <Field> Call.func = 1, expr */
|
||||
/* <Field> Call.args = 2, expr_list */
|
||||
/* <Field> Call.keywords = 3, keyword_list */
|
||||
/* <Field> Call.starargs = 4, expr */
|
||||
/* <Field> Call.kwargs = 5, expr */
|
||||
|
||||
/* <Field> Class.name = 0, str */
|
||||
/* <Field> Class.body = 1, stmt_list */
|
||||
/* <Parent> Class = ClassExpr */
|
||||
|
||||
/* <Field> ClassExpr.location = 0, location */
|
||||
/* <Field> ClassExpr.name = 1, str */
|
||||
/* <Field> ClassExpr.bases = 2, expr_list */
|
||||
/* <Field> ClassExpr.keywords = 3, keyword_list */
|
||||
/* <Field> ClassExpr.starargs = 4, expr */
|
||||
/* <Field> ClassExpr.kwargs = 5, expr */
|
||||
/* <Field> ClassExpr.inner_scope = 6, Class */
|
||||
|
||||
/* <Field> Compare.location = 0, location */
|
||||
/* <Field> Compare.left = 1, expr */
|
||||
/* <Field> Compare.ops = 2, cmpop_list */
|
||||
/* <Field> Compare.comparators = 3, expr_list */
|
||||
|
||||
/* <Field> Continue.location = 0, location */
|
||||
|
||||
/* <Field> Delete.location = 0, location */
|
||||
/* <Field> Delete.targets = 1, expr_list */
|
||||
|
||||
/* <Field> Dict.location = 0, location */
|
||||
/* <Field> Dict.keys = 1, expr_list */
|
||||
/* <Field> Dict.values = 2, expr_list */
|
||||
|
||||
/* <Field> DictComp.location = 0, location */
|
||||
/* <Field> DictComp.function = 1, Function */
|
||||
/* <Field> DictComp.iterable = 2, expr */
|
||||
|
||||
/* <Field> Ellipsis.location = 0, location */
|
||||
|
||||
/* <Field> ExceptStmt.location = 0, location */
|
||||
/* <Field> ExceptStmt.type = 1, expr */
|
||||
/* <Field> ExceptStmt.name = 2, expr */
|
||||
/* <Field> ExceptStmt.body = 3, stmt_list */
|
||||
|
||||
/* <Field> Exec.location = 0, location */
|
||||
/* <Field> Exec.body = 1, expr */
|
||||
/* <Field> Exec.globals = 2, expr */
|
||||
/* <Field> Exec.locals = 3, expr */
|
||||
|
||||
/* <Field> ExprStmt.location = 0, location */
|
||||
/* <Field> ExprStmt.value = 1, expr */
|
||||
|
||||
/* <Field> For.location = 0, location */
|
||||
/* <Field> For.target = 1, expr */
|
||||
/* <Field> For.iter = 2, expr */
|
||||
/* <Field> For.body = 3, stmt_list */
|
||||
/* <Field> For.orelse = 4, stmt_list */
|
||||
|
||||
/* <Field> Function.name = 0, str */
|
||||
/* <Field> Function.args = 1, parameter_list */
|
||||
/* <Field> Function.vararg = 2, expr */
|
||||
/* <Field> Function.kwonlyargs = 3, str_list */
|
||||
/* <Field> Function.kwarg = 4, expr */
|
||||
/* <Field> Function.body = 5, stmt_list */
|
||||
/* <Parent> Function = FunctionParent */
|
||||
|
||||
/* <Field> FunctionExpr.location = 0, location */
|
||||
/* <Field> FunctionExpr.name = 1, str */
|
||||
/* <Field> FunctionExpr.args = 2, arguments */
|
||||
/* <Field> FunctionExpr.returns = 3, expr */
|
||||
/* <Field> FunctionExpr.inner_scope = 4, Function */
|
||||
|
||||
/* <Field> GeneratorExp.location = 0, location */
|
||||
/* <Field> GeneratorExp.function = 1, Function */
|
||||
/* <Field> GeneratorExp.iterable = 2, expr */
|
||||
|
||||
/* <Field> Global.location = 0, location */
|
||||
/* <Field> Global.names = 1, str_list */
|
||||
|
||||
/* <Field> If.location = 0, location */
|
||||
/* <Field> If.test = 1, expr */
|
||||
/* <Field> If.body = 2, stmt_list */
|
||||
/* <Field> If.orelse = 3, stmt_list */
|
||||
|
||||
/* <Field> IfExp.location = 0, location */
|
||||
/* <Field> IfExp.test = 1, expr */
|
||||
/* <Field> IfExp.body = 2, expr */
|
||||
/* <Field> IfExp.orelse = 3, expr */
|
||||
|
||||
/* <Field> Import.location = 0, location */
|
||||
/* <Field> Import.names = 1, alias_list */
|
||||
|
||||
/* <Field> ImportExpr.location = 0, location */
|
||||
/* <Field> ImportExpr.level = 1, int */
|
||||
/* <Field> ImportExpr.name = 2, str */
|
||||
/* <Field> ImportExpr.top = 3, bool */
|
||||
|
||||
/* <Field> ImportStar.location = 0, location */
|
||||
/* <Field> ImportStar.module = 1, expr */
|
||||
|
||||
/* <Field> ImportMember.location = 0, location */
|
||||
/* <Field> ImportMember.module = 1, expr */
|
||||
/* <Field> ImportMember.name = 2, str */
|
||||
|
||||
/* <Field> Lambda.location = 0, location */
|
||||
/* <Field> Lambda.args = 1, arguments */
|
||||
/* <Field> Lambda.inner_scope = 2, Function */
|
||||
|
||||
/* <Field> List.location = 0, location */
|
||||
/* <Field> List.elts = 1, expr_list */
|
||||
/* <Field> List.ctx = 2, expr_context */
|
||||
|
||||
/* <Field> ListComp.location = 0, location */
|
||||
/* <Field> ListComp.function = 1, Function */
|
||||
/* <Field> ListComp.iterable = 2, expr */
|
||||
/* <Field> ListComp.generators = 3, comprehension_list */
|
||||
/* <Field> ListComp.elt = 4, expr */
|
||||
|
||||
/* <Field> Module.name = 0, str */
|
||||
/* <Field> Module.hash = 1, str */
|
||||
/* <Field> Module.body = 2, stmt_list */
|
||||
/* <Field> Module.kind = 3, str */
|
||||
|
||||
/* <Field> Name.location = 0, location */
|
||||
/* <Field> Name.variable = 1, variable */
|
||||
/* <Field> Name.ctx = 2, expr_context */
|
||||
/* <Parent> Name = ParameterList */
|
||||
|
||||
/* <Field> Nonlocal.location = 0, location */
|
||||
/* <Field> Nonlocal.names = 1, str_list */
|
||||
|
||||
/* <Field> Num.location = 0, location */
|
||||
/* <Field> Num.n = 1, number */
|
||||
/* <Field> Num.text = 2, number */
|
||||
|
||||
/* <Field> Pass.location = 0, location */
|
||||
|
||||
/* <Field> Print.location = 0, location */
|
||||
/* <Field> Print.dest = 1, expr */
|
||||
/* <Field> Print.values = 2, expr_list */
|
||||
/* <Field> Print.nl = 3, bool */
|
||||
|
||||
/* <Field> Raise.location = 0, location */
|
||||
/* <Field> Raise.exc = 1, expr */
|
||||
/* <Field> Raise.cause = 2, expr */
|
||||
/* <Field> Raise.type = 3, expr */
|
||||
/* <Field> Raise.inst = 4, expr */
|
||||
/* <Field> Raise.tback = 5, expr */
|
||||
|
||||
/* <Field> Repr.location = 0, location */
|
||||
/* <Field> Repr.value = 1, expr */
|
||||
|
||||
/* <Field> Return.location = 0, location */
|
||||
/* <Field> Return.value = 1, expr */
|
||||
|
||||
/* <Field> Set.location = 0, location */
|
||||
/* <Field> Set.elts = 1, expr_list */
|
||||
|
||||
/* <Field> SetComp.location = 0, location */
|
||||
/* <Field> SetComp.function = 1, Function */
|
||||
/* <Field> SetComp.iterable = 2, expr */
|
||||
|
||||
/* <Field> Slice.location = 0, location */
|
||||
/* <Field> Slice.start = 1, expr */
|
||||
/* <Field> Slice.stop = 2, expr */
|
||||
/* <Field> Slice.step = 3, expr */
|
||||
|
||||
/* <Field> Starred.location = 0, location */
|
||||
/* <Field> Starred.value = 1, expr */
|
||||
/* <Field> Starred.ctx = 2, expr_context */
|
||||
|
||||
/* <Field> Str.location = 0, location */
|
||||
/* <Field> Str.s = 1, str */
|
||||
|
||||
/* <Field> Subscript.location = 0, location */
|
||||
/* <Field> Subscript.value = 1, expr */
|
||||
/* <Field> Subscript.index = 2, expr */
|
||||
/* <Field> Subscript.ctx = 3, expr_context */
|
||||
|
||||
/* <Field> Try.location = 0, location */
|
||||
/* <Field> Try.body = 1, stmt_list */
|
||||
/* <Field> Try.orelse = 2, stmt_list */
|
||||
/* <Field> Try.handlers = 3, stmt_list */
|
||||
/* <Field> Try.finalbody = 4, stmt_list */
|
||||
|
||||
/* <Field> Tuple.location = 0, location */
|
||||
/* <Field> Tuple.elts = 1, expr_list */
|
||||
/* <Field> Tuple.ctx = 2, expr_context */
|
||||
/* <Parent> Tuple = ParameterList */
|
||||
|
||||
/* <Field> UnaryExpr.location = 0, location */
|
||||
/* <Field> UnaryExpr.op = 1, unaryop */
|
||||
/* <Field> UnaryExpr.operand = 2, expr */
|
||||
|
||||
/* <Field> While.location = 0, location */
|
||||
/* <Field> While.test = 1, expr */
|
||||
/* <Field> While.body = 2, stmt_list */
|
||||
/* <Field> While.orelse = 3, stmt_list */
|
||||
|
||||
/* <Field> With.location = 0, location */
|
||||
/* <Field> With.context_expr = 1, expr */
|
||||
/* <Field> With.optional_vars = 2, expr */
|
||||
/* <Field> With.body = 3, stmt_list */
|
||||
|
||||
/* <Field> Yield.location = 0, location */
|
||||
/* <Field> Yield.value = 1, expr */
|
||||
|
||||
/* <Field> YieldFrom.location = 0, location */
|
||||
/* <Field> YieldFrom.value = 1, expr */
|
||||
|
||||
/* <Field> Alias.value = 0, expr */
|
||||
/* <Field> Alias.asname = 1, expr */
|
||||
/* <Parent> Alias = AliasList */
|
||||
/* <Parent> AliasList = Import */
|
||||
|
||||
/* <Field> Arguments.kw_defaults = 0, expr_list */
|
||||
/* <Field> Arguments.defaults = 1, expr_list */
|
||||
/* <Field> Arguments.annotations = 2, expr_list */
|
||||
/* <Field> Arguments.varargannotation = 3, expr */
|
||||
/* <Field> Arguments.kwargannotation = 4, expr */
|
||||
/* <Parent> Arguments = ArgumentsParent */
|
||||
/* <Parent> boolean = BoolParent */
|
||||
/* <Parent> Boolop = BoolExpr */
|
||||
/* <Parent> string = Bytes */
|
||||
/* <Parent> Cmpop = CmpopList */
|
||||
/* <Parent> CmpopList = Compare */
|
||||
|
||||
/* <Field> Comprehension.iter = 0, expr */
|
||||
/* <Field> Comprehension.target = 1, expr */
|
||||
/* <Field> Comprehension.ifs = 2, expr_list */
|
||||
/* <Parent> Comprehension = ComprehensionList */
|
||||
/* <Parent> ComprehensionList = ListComp */
|
||||
|
||||
/* <Field> Expr.location = 0, location */
|
||||
/* <Parent> Expr = ExprParent */
|
||||
/* <Parent> ExprContext = ExprContextParent */
|
||||
/* <Parent> ExprList = ExprListParent */
|
||||
/* <Parent> int = ImportExpr */
|
||||
|
||||
/* <Field> Keyword.arg = 0, str */
|
||||
/* <Field> Keyword.value = 1, expr */
|
||||
/* <Parent> Keyword = KeywordList */
|
||||
/* <Parent> KeywordList = KeywordListParent */
|
||||
/* <Parent> Location = ExprOrStmt */
|
||||
/* <Parent> string = Num */
|
||||
/* <Parent> Operator = BinaryExpr */
|
||||
/* <Parent> ParameterList = Function */
|
||||
|
||||
/* <Field> Stmt.location = 0, location */
|
||||
/* <Parent> Stmt = StmtList */
|
||||
/* <Parent> StmtList = StmtListParent */
|
||||
/* <Parent> string = StrParent */
|
||||
/* <Parent> StringList = StrListParent */
|
||||
/* <Parent> Unaryop = UnaryExpr */
|
||||
/* <Parent> Variable = Name */
|
||||
py_Classes(unique int id : @py_Class,
|
||||
unique int parent : @py_ClassExpr ref);
|
||||
|
||||
py_Functions(unique int id : @py_Function,
|
||||
int parent : @py_Function_parent ref,
|
||||
int idx : int ref);
|
||||
|
||||
py_Modules(unique int id : @py_Module);
|
||||
|
||||
py_aliases(unique int id : @py_alias,
|
||||
int parent : @py_alias_list ref,
|
||||
int idx : int ref);
|
||||
|
||||
py_alias_lists(unique int id : @py_alias_list,
|
||||
unique int parent : @py_Import ref);
|
||||
|
||||
py_arguments(unique int id : @py_arguments,
|
||||
int parent : @py_arguments_parent ref,
|
||||
int idx : int ref);
|
||||
|
||||
py_bools(boolean id : boolean ref,
|
||||
unique int parent : @py_bool_parent ref);
|
||||
|
||||
py_boolops(unique int id : @py_boolop,
|
||||
int kind: int ref,
|
||||
unique int parent : @py_BoolExpr ref);
|
||||
|
||||
py_bytes(varchar(1) id : string ref,
|
||||
unique int parent : @py_Bytes ref);
|
||||
|
||||
py_cmpops(unique int id : @py_cmpop,
|
||||
int kind: int ref,
|
||||
int parent : @py_cmpop_list ref,
|
||||
int idx : int ref);
|
||||
|
||||
py_cmpop_lists(unique int id : @py_cmpop_list,
|
||||
unique int parent : @py_Compare ref);
|
||||
|
||||
py_comprehensions(unique int id : @py_comprehension,
|
||||
int parent : @py_comprehension_list ref,
|
||||
int idx : int ref);
|
||||
|
||||
py_comprehension_lists(unique int id : @py_comprehension_list,
|
||||
unique int parent : @py_ListComp ref);
|
||||
|
||||
py_exprs(unique int id : @py_expr,
|
||||
int kind: int ref,
|
||||
int parent : @py_expr_parent ref,
|
||||
int idx : int ref);
|
||||
|
||||
py_expr_contexts(unique int id : @py_expr_context,
|
||||
int kind: int ref,
|
||||
int parent : @py_expr_context_parent ref,
|
||||
int idx : int ref);
|
||||
|
||||
py_expr_lists(unique int id : @py_expr_list,
|
||||
int parent : @py_expr_list_parent ref,
|
||||
int idx : int ref);
|
||||
|
||||
py_ints(int id : int ref,
|
||||
unique int parent : @py_ImportExpr ref);
|
||||
|
||||
py_keywords(unique int id : @py_keyword,
|
||||
int parent : @py_keyword_list ref,
|
||||
int idx : int ref);
|
||||
|
||||
py_keyword_lists(unique int id : @py_keyword_list,
|
||||
unique int parent : @py_keyword_list_parent ref);
|
||||
|
||||
py_locations(unique int id : @location ref,
|
||||
unique int parent : @py_expr_or_stmt ref);
|
||||
|
||||
py_numbers(varchar(1) id : string ref,
|
||||
int parent : @py_Num ref,
|
||||
int idx : int ref);
|
||||
|
||||
py_operators(unique int id : @py_operator,
|
||||
int kind: int ref,
|
||||
unique int parent : @py_BinaryExpr ref);
|
||||
|
||||
py_parameter_lists(unique int id : @py_parameter_list,
|
||||
unique int parent : @py_Function ref);
|
||||
|
||||
py_stmts(unique int id : @py_stmt,
|
||||
int kind: int ref,
|
||||
int parent : @py_stmt_list ref,
|
||||
int idx : int ref);
|
||||
|
||||
py_stmt_lists(unique int id : @py_stmt_list,
|
||||
int parent : @py_stmt_list_parent ref,
|
||||
int idx : int ref);
|
||||
|
||||
py_strs(varchar(1) id : string ref,
|
||||
int parent : @py_str_parent ref,
|
||||
int idx : int ref);
|
||||
|
||||
py_str_lists(unique int id : @py_str_list,
|
||||
int parent : @py_str_list_parent ref,
|
||||
int idx : int ref);
|
||||
|
||||
py_unaryops(unique int id : @py_unaryop,
|
||||
int kind: int ref,
|
||||
unique int parent : @py_UnaryExpr ref);
|
||||
|
||||
py_variables(int id : @py_variable ref,
|
||||
unique int parent : @py_Name ref);
|
||||
|
||||
@py_Function_parent = @py_DictComp | @py_FunctionExpr | @py_GeneratorExp | @py_Lambda | @py_ListComp | @py_SetComp;
|
||||
|
||||
@py_arguments_parent = @py_FunctionExpr | @py_Lambda;
|
||||
|
||||
@py_ast_node = @py_Class | @py_Function | @py_Module | @py_expr | @py_stmt;
|
||||
|
||||
@py_bool_parent = @py_ImportExpr | @py_Print;
|
||||
|
||||
case @py_boolop.kind of
|
||||
0 = @py_And
|
||||
| 1 = @py_Or;
|
||||
|
||||
case @py_cmpop.kind of
|
||||
0 = @py_Eq
|
||||
| 1 = @py_Gt
|
||||
| 2 = @py_GtE
|
||||
| 3 = @py_In
|
||||
| 4 = @py_Is
|
||||
| 5 = @py_IsNot
|
||||
| 6 = @py_Lt
|
||||
| 7 = @py_LtE
|
||||
| 8 = @py_NotEq
|
||||
| 9 = @py_NotIn;
|
||||
|
||||
case @py_expr.kind of
|
||||
0 = @py_Attribute
|
||||
| 1 = @py_BinaryExpr
|
||||
| 2 = @py_BoolExpr
|
||||
| 3 = @py_Bytes
|
||||
| 4 = @py_Call
|
||||
| 5 = @py_ClassExpr
|
||||
| 6 = @py_Compare
|
||||
| 7 = @py_Dict
|
||||
| 8 = @py_DictComp
|
||||
| 9 = @py_Ellipsis
|
||||
| 10 = @py_FunctionExpr
|
||||
| 11 = @py_GeneratorExp
|
||||
| 12 = @py_IfExp
|
||||
| 13 = @py_ImportExpr
|
||||
| 14 = @py_ImportMember
|
||||
| 15 = @py_Lambda
|
||||
| 16 = @py_List
|
||||
| 17 = @py_ListComp
|
||||
| 18 = @py_Name
|
||||
| 19 = @py_Num
|
||||
| 20 = @py_Repr
|
||||
| 21 = @py_Set
|
||||
| 22 = @py_SetComp
|
||||
| 23 = @py_Slice
|
||||
| 24 = @py_Starred
|
||||
| 25 = @py_Str
|
||||
| 26 = @py_Subscript
|
||||
| 27 = @py_Tuple
|
||||
| 28 = @py_UnaryExpr
|
||||
| 29 = @py_Yield
|
||||
| 30 = @py_YieldFrom;
|
||||
|
||||
case @py_expr_context.kind of
|
||||
0 = @py_AugLoad
|
||||
| 1 = @py_AugStore
|
||||
| 2 = @py_Del
|
||||
| 3 = @py_Load
|
||||
| 4 = @py_Param
|
||||
| 5 = @py_Store;
|
||||
|
||||
@py_expr_context_parent = @py_Attribute | @py_List | @py_Name | @py_Starred | @py_Subscript | @py_Tuple;
|
||||
|
||||
@py_expr_list_parent = @py_Assign | @py_BoolExpr | @py_Call | @py_ClassExpr | @py_Compare | @py_Delete | @py_Dict | @py_List | @py_Print | @py_Set | @py_Tuple | @py_arguments | @py_comprehension;
|
||||
|
||||
@py_expr_or_stmt = @py_expr | @py_stmt;
|
||||
|
||||
@py_expr_parent = @py_Assert | @py_Assign | @py_Attribute | @py_AugAssign | @py_BinaryExpr | @py_Call | @py_ClassExpr | @py_Compare | @py_DictComp | @py_ExceptStmt | @py_Exec | @py_Expr_stmt | @py_For | @py_Function | @py_FunctionExpr | @py_GeneratorExp | @py_If | @py_IfExp | @py_ImportMember | @py_ImportStar | @py_ListComp | @py_Print | @py_Raise | @py_Repr | @py_Return | @py_SetComp | @py_Slice | @py_Starred | @py_Subscript | @py_UnaryExpr | @py_While | @py_With | @py_Yield | @py_YieldFrom | @py_alias | @py_arguments | @py_comprehension | @py_expr_list | @py_keyword | @py_parameter_list;
|
||||
|
||||
@py_keyword_list_parent = @py_Call | @py_ClassExpr;
|
||||
|
||||
case @py_operator.kind of
|
||||
0 = @py_Add
|
||||
| 1 = @py_BitAnd
|
||||
| 2 = @py_BitOr
|
||||
| 3 = @py_BitXor
|
||||
| 4 = @py_Div
|
||||
| 5 = @py_FloorDiv
|
||||
| 6 = @py_LShift
|
||||
| 7 = @py_Mod
|
||||
| 8 = @py_Mult
|
||||
| 9 = @py_Pow
|
||||
| 10 = @py_RShift
|
||||
| 11 = @py_Sub;
|
||||
|
||||
@py_parameter = @py_Name | @py_Tuple;
|
||||
|
||||
@py_scope = @py_Class | @py_Function | @py_Module;
|
||||
|
||||
case @py_stmt.kind of
|
||||
0 = @py_Assert
|
||||
| 1 = @py_Assign
|
||||
| 2 = @py_AugAssign
|
||||
| 3 = @py_Break
|
||||
| 4 = @py_Continue
|
||||
| 5 = @py_Delete
|
||||
| 6 = @py_ExceptStmt
|
||||
| 7 = @py_Exec
|
||||
| 8 = @py_Expr_stmt
|
||||
| 9 = @py_For
|
||||
| 10 = @py_Global
|
||||
| 11 = @py_If
|
||||
| 12 = @py_Import
|
||||
| 13 = @py_ImportStar
|
||||
| 14 = @py_Nonlocal
|
||||
| 15 = @py_Pass
|
||||
| 16 = @py_Print
|
||||
| 17 = @py_Raise
|
||||
| 18 = @py_Return
|
||||
| 19 = @py_Try
|
||||
| 20 = @py_While
|
||||
| 21 = @py_With;
|
||||
|
||||
@py_stmt_list_parent = @py_Class | @py_ExceptStmt | @py_For | @py_Function | @py_If | @py_Module | @py_Try | @py_While | @py_With;
|
||||
|
||||
@py_str_list_parent = @py_Function | @py_Global | @py_Nonlocal;
|
||||
|
||||
@py_str_parent = @py_Attribute | @py_Class | @py_ClassExpr | @py_Function | @py_FunctionExpr | @py_ImportExpr | @py_ImportMember | @py_Module | @py_Str | @py_keyword | @py_str_list;
|
||||
|
||||
case @py_unaryop.kind of
|
||||
0 = @py_Invert
|
||||
| 1 = @py_Not
|
||||
| 2 = @py_UAdd
|
||||
| 3 = @py_USub;
|
||||
|
||||
|
||||
/*
|
||||
* End of auto-generated part
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* Map relative names to absolute names for imports */
|
||||
py_absolute_names(int module : @py_Module ref,
|
||||
varchar(1) relname : string ref,
|
||||
varchar(1) absname : string ref);
|
||||
|
||||
py_exports(int id : @py_Module ref,
|
||||
varchar(1) name : string ref);
|
||||
|
||||
/* Successor information */
|
||||
py_successors(int predecessor : @py_flow_node ref,
|
||||
int successor : @py_flow_node ref);
|
||||
|
||||
py_true_successors(int predecessor : @py_flow_node ref,
|
||||
int successor : @py_flow_node ref);
|
||||
|
||||
py_exception_successors(int predecessor : @py_flow_node ref,
|
||||
int successor : @py_flow_node ref);
|
||||
|
||||
py_false_successors(int predecessor : @py_flow_node ref,
|
||||
int successor : @py_flow_node ref);
|
||||
|
||||
py_flow_bb_node(unique int flownode : @py_flow_node,
|
||||
int realnode : @py_ast_node ref,
|
||||
int basicblock : @py_flow_node ref,
|
||||
int index : int ref);
|
||||
|
||||
py_scope_flow(int flow : @py_flow_node ref,
|
||||
int scope : @py_scope ref,
|
||||
int kind : int ref);
|
||||
|
||||
py_idoms(unique int node : @py_flow_node ref,
|
||||
int immediate_dominator : @py_flow_node ref);
|
||||
|
||||
py_ssa_phi(int phi : @py_ssa_var ref,
|
||||
int arg: @py_ssa_var ref);
|
||||
|
||||
py_ssa_var(unique int id : @py_ssa_var,
|
||||
int var : @py_variable ref);
|
||||
|
||||
py_ssa_use(int node: @py_flow_node ref,
|
||||
int var : @py_ssa_var ref);
|
||||
|
||||
py_ssa_defn(unique int id : @py_ssa_var ref,
|
||||
int node: @py_flow_node ref);
|
||||
|
||||
@py_base_var = @py_variable | @py_ssa_var;
|
||||
|
||||
py_scopes(unique int node : @py_expr_or_stmt ref,
|
||||
int scope : @py_scope ref);
|
||||
|
||||
py_scope_location(unique int id : @location ref,
|
||||
unique int scope : @py_scope ref);
|
||||
|
||||
py_flags(unique varchar(1) name : string ref,
|
||||
varchar(1) value : string ref);
|
||||
|
||||
py_syntax_error(unique int id : @location ref,
|
||||
varchar(1) message : string ref);
|
||||
|
||||
py_comments(unique int id : @py_comment,
|
||||
varchar(1) text : string ref,
|
||||
unique int location : @location ref);
|
||||
|
||||
/* Type information support */
|
||||
|
||||
py_cobjects(unique int obj : @py_cobject,
|
||||
int typeof : @py_cobject ref);
|
||||
|
||||
py_cmembers(int object : @py_cobject ref,
|
||||
varchar(1) name : string ref,
|
||||
int member : @py_cobject ref);
|
||||
|
||||
py_citems(int object : @py_cobject ref,
|
||||
int index : int ref,
|
||||
int member : @py_cobject ref);
|
||||
|
||||
py_cobjectnames(unique int obj : @py_cobject ref,
|
||||
varchar(1) name : string ref);
|
||||
|
||||
py_special_objects(unique int obj : @py_cobject ref,
|
||||
unique varchar(1) name : string ref);
|
||||
|
||||
py_decorated_object(int object : @py_object ref,
|
||||
int level: int ref);
|
||||
|
||||
@py_object = @py_cobject | @py_flow_node;
|
||||
|
||||
@py_source_element = @py_ast_node | @container;
|
||||
|
||||
/* XML Files */
|
||||
|
||||
xmlEncoding (unique int id: @file ref, varchar(900) encoding: string ref);
|
||||
|
||||
xmlDTDs (unique int id: @xmldtd,
|
||||
varchar(900) root: string ref,
|
||||
varchar(900) publicId: string ref,
|
||||
varchar(900) systemId: string ref,
|
||||
int fileid: @file ref);
|
||||
|
||||
xmlElements (unique int id: @xmlelement,
|
||||
varchar(900) name: string ref,
|
||||
int parentid: @xmlparent ref,
|
||||
int idx: int ref,
|
||||
int fileid: @file ref);
|
||||
|
||||
xmlAttrs (unique int id: @xmlattribute,
|
||||
int elementid: @xmlelement ref,
|
||||
varchar(900) name: string ref,
|
||||
varchar(3600) value: string ref,
|
||||
int idx: int ref,
|
||||
int fileid: @file ref);
|
||||
|
||||
xmlNs (int id: @xmlnamespace,
|
||||
varchar(900) prefixName: string ref,
|
||||
varchar(900) URI: string ref,
|
||||
int fileid: @file ref);
|
||||
|
||||
xmlHasNs (int elementId: @xmlnamespaceable ref,
|
||||
int nsId: @xmlnamespace ref,
|
||||
int fileid: @file ref);
|
||||
|
||||
xmlComments (unique int id: @xmlcomment,
|
||||
varchar(3600) text: string ref,
|
||||
int parentid: @xmlparent ref,
|
||||
int fileid: @file ref);
|
||||
|
||||
xmlChars (unique int id: @xmlcharacters,
|
||||
varchar(3600) text: string ref,
|
||||
int parentid: @xmlparent ref,
|
||||
int idx: int ref,
|
||||
int isCDATA: int ref,
|
||||
int fileid: @file ref);
|
||||
|
||||
@xmlparent = @file | @xmlelement;
|
||||
@xmlnamespaceable = @xmlelement | @xmlattribute;
|
||||
|
||||
xmllocations(int xmlElement: @xmllocatable ref,
|
||||
int location: @location_default ref);
|
||||
|
||||
@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace;
|
||||
@@ -1,3 +1,22 @@
|
||||
## 0.0.10
|
||||
|
||||
### New Queries
|
||||
|
||||
* The query "LDAP query built from user-controlled sources" (`py/ldap-injection`) has been promoted from experimental to the main query pack. Its results will now appear by default. This query was originally [submitted as an experimental query by @jorgectf](https://github.com/github/codeql/pull/5443).
|
||||
* The query "Log Injection" (`py/log-injection`) has been promoted from experimental to the main query pack. Its results will now appear when `security-extended` is used. This query was originally [submitted as an experimental query by @haby0](https://github.com/github/codeql/pull/6182).
|
||||
|
||||
## 0.0.9
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* The [View AST functionality](https://codeql.github.com/docs/codeql-for-visual-studio-code/exploring-the-structure-of-your-source-code/) no longer prints detailed information about regular expressions, greatly improving performance.
|
||||
|
||||
## 0.0.8
|
||||
|
||||
### Major Analysis Improvements
|
||||
|
||||
* User names and other account information is no longer considered to be sensitive data for the queries `py/clear-text-logging-sensitive-data` and `py/clear-text-storage-sensitive-data`, since this lead to many false positives.
|
||||
|
||||
## 0.0.7
|
||||
|
||||
## 0.0.6
|
||||
|
||||
@@ -4,22 +4,22 @@
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>If an LDAP query or DN is built using string concatenation or string formatting, and the
|
||||
components of the concatenation include user input without any proper sanitization, a user
|
||||
components of the concatenation include user input without any proper sanitization, a user
|
||||
is likely to be able to run malicious LDAP queries.</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>If user input must be included in an LDAP query or DN, it should be escaped to
|
||||
avoid a malicious user providing special characters that change the meaning
|
||||
of the query. In Python2, user input should be escaped with <code>ldap.dn.escape_dn_chars</code>
|
||||
or <code>ldap.filter.escape_filter_chars</code>, while in Python3, user input should be escaped with
|
||||
of the query. In Python2, user input should be escaped with <code>ldap.dn.escape_dn_chars</code>
|
||||
or <code>ldap.filter.escape_filter_chars</code>, while in Python3, user input should be escaped with
|
||||
<code>ldap3.utils.dn.escape_rdn</code> or <code>ldap3.utils.conv.escape_filter_chars</code>
|
||||
depending on the component tainted by the user. A good practice is to escape filter characters
|
||||
depending on the component tainted by the user. A good practice is to escape filter characters
|
||||
that could change the meaning of the query (https://tools.ietf.org/search/rfc4515#section-3).</p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
<p>In the following examples, the code accepts both <code>username</code> and <code>dc</code> from the user,
|
||||
<p>In the following examples, the code accepts both <code>username</code> and <code>dc</code> from the user,
|
||||
which it then uses to build a LDAP query and DN.</p>
|
||||
|
||||
<p>The first and the second example uses the unsanitized user input directly
|
||||
@@ -30,7 +30,7 @@ components, and search for a completely different set of values.</p>
|
||||
<sample src="examples/example_bad1.py" />
|
||||
<sample src="examples/example_bad2.py" />
|
||||
|
||||
<p>In the third and four example, the input provided by the user is sanitized before it is included in the search filter or DN.
|
||||
<p>In the third and fourth example, the input provided by the user is sanitized before it is included in the search filter or DN.
|
||||
This ensures the meaning of the query cannot be changed by a malicious user.</p>
|
||||
|
||||
<sample src="examples/example_good1.py" />
|
||||
28
python/ql/src/Security/CWE-090/LdapInjection.ql
Normal file
28
python/ql/src/Security/CWE-090/LdapInjection.ql
Normal file
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* @name LDAP query built from user-controlled sources
|
||||
* @description Building an LDAP query from user-controlled sources is vulnerable to insertion of
|
||||
* malicious LDAP code by the user.
|
||||
* @kind path-problem
|
||||
* @problem.severity error
|
||||
* @security-severity 9.8
|
||||
* @precision high
|
||||
* @id py/ldap-injection
|
||||
* @tags security
|
||||
* external/cwe/cwe-090
|
||||
*/
|
||||
|
||||
// Determine precision above
|
||||
import python
|
||||
import semmle.python.security.dataflow.LdapInjection
|
||||
import DataFlow::PathGraph
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, string parameterName
|
||||
where
|
||||
any(LdapInjection::DnConfiguration dnConfig).hasFlowPath(source, sink) and
|
||||
parameterName = "DN"
|
||||
or
|
||||
any(LdapInjection::FilterConfiguration filterConfig).hasFlowPath(source, sink) and
|
||||
parameterName = "filter"
|
||||
select sink.getNode(), source, sink,
|
||||
"$@ LDAP query parameter (" + parameterName + ") comes from $@.", sink.getNode(), "This",
|
||||
source.getNode(), "a user-provided value"
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user