mirror of
https://github.com/github/codeql.git
synced 2026-05-01 03:35:13 +02:00
Python: Autoformat security.
This commit is contained in:
@@ -5,17 +5,12 @@ import semmle.python.dataflow.Files
|
||||
import semmle.python.web.Http
|
||||
|
||||
module ClearTextStorage {
|
||||
|
||||
abstract class Sink extends TaintSink {
|
||||
override predicate sinks(TaintKind kind) {
|
||||
kind instanceof SensitiveData
|
||||
}
|
||||
override predicate sinks(TaintKind kind) { kind instanceof SensitiveData }
|
||||
}
|
||||
|
||||
class CookieStorageSink extends Sink {
|
||||
CookieStorageSink() {
|
||||
any(CookieSet cookie).getValue() = this
|
||||
}
|
||||
CookieStorageSink() { any(CookieSet cookie).getValue() = this }
|
||||
}
|
||||
|
||||
class FileStorageSink extends Sink {
|
||||
@@ -23,20 +18,17 @@ module ClearTextStorage {
|
||||
exists(CallNode call, AttrNode meth, string name |
|
||||
any(OpenFile fd).taints(meth.getObject(name)) and
|
||||
call.getFunction() = meth and
|
||||
call.getAnArg() = this |
|
||||
call.getAnArg() = this
|
||||
|
|
||||
name = "write"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module ClearTextLogging {
|
||||
|
||||
abstract class Sink extends TaintSink {
|
||||
override predicate sinks(TaintKind kind) {
|
||||
kind instanceof SensitiveData
|
||||
}
|
||||
override predicate sinks(TaintKind kind) { kind instanceof SensitiveData }
|
||||
}
|
||||
|
||||
class PrintSink extends Sink {
|
||||
@@ -53,7 +45,8 @@ module ClearTextLogging {
|
||||
exists(CallNode call, AttrNode meth, string name |
|
||||
call.getFunction() = meth and
|
||||
meth.getObject(name).(NameNode).getId().matches("logg%") and
|
||||
call.getAnArg() = this |
|
||||
call.getAnArg() = this
|
||||
|
|
||||
name = "error" or
|
||||
name = "warn" or
|
||||
name = "warning" or
|
||||
@@ -62,5 +55,4 @@ module ClearTextLogging {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,49 +1,32 @@
|
||||
import python
|
||||
import semmle.python.security.TaintTracking
|
||||
|
||||
private import semmle.python.security.SensitiveData
|
||||
private import semmle.crypto.Crypto as CryptoLib
|
||||
|
||||
|
||||
abstract class WeakCryptoSink extends TaintSink {
|
||||
|
||||
override predicate sinks(TaintKind taint) {
|
||||
taint instanceof SensitiveData
|
||||
}
|
||||
override predicate sinks(TaintKind taint) { taint instanceof SensitiveData }
|
||||
}
|
||||
|
||||
/** Modeling the 'pycrypto' package https://github.com/dlitz/pycrypto (latest release 2013) */
|
||||
module Pycrypto {
|
||||
|
||||
ModuleValue cipher(string name) {
|
||||
result = Module::named("Crypto.Cipher").attr(name)
|
||||
}
|
||||
ModuleValue cipher(string name) { result = Module::named("Crypto.Cipher").attr(name) }
|
||||
|
||||
class CipherInstance extends TaintKind {
|
||||
|
||||
string name;
|
||||
|
||||
CipherInstance() {
|
||||
this = "Crypto.Cipher." + name and
|
||||
this = "Crypto.Cipher." + name and
|
||||
exists(cipher(name))
|
||||
}
|
||||
|
||||
string getName() {
|
||||
result = name
|
||||
}
|
||||
string getName() { result = name }
|
||||
|
||||
CryptoLib::CryptographicAlgorithm getAlgorithm() {
|
||||
result.getName() = name
|
||||
}
|
||||
|
||||
predicate isWeak() {
|
||||
this.getAlgorithm().isWeak()
|
||||
}
|
||||
CryptoLib::CryptographicAlgorithm getAlgorithm() { result.getName() = name }
|
||||
|
||||
predicate isWeak() { this.getAlgorithm().isWeak() }
|
||||
}
|
||||
|
||||
class CipherInstanceSource extends TaintSource {
|
||||
|
||||
CipherInstance instance;
|
||||
|
||||
CipherInstanceSource() {
|
||||
@@ -53,18 +36,12 @@ module Pycrypto {
|
||||
)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "Source of " + instance
|
||||
}
|
||||
|
||||
override predicate isSourceOf(TaintKind kind) {
|
||||
kind = instance
|
||||
}
|
||||
override string toString() { result = "Source of " + instance }
|
||||
|
||||
override predicate isSourceOf(TaintKind kind) { kind = instance }
|
||||
}
|
||||
|
||||
class PycryptoWeakCryptoSink extends WeakCryptoSink {
|
||||
|
||||
string name;
|
||||
|
||||
PycryptoWeakCryptoSink() {
|
||||
@@ -77,36 +54,24 @@ module Pycrypto {
|
||||
)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "Use of weak crypto algorithm " + name
|
||||
}
|
||||
|
||||
override string toString() { result = "Use of weak crypto algorithm " + name }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module Cryptography {
|
||||
|
||||
ModuleValue ciphers() {
|
||||
result = Module::named("cryptography.hazmat.primitives.ciphers") and
|
||||
result.isPackage()
|
||||
}
|
||||
|
||||
class CipherClass extends ClassValue {
|
||||
CipherClass() {
|
||||
ciphers().attr("Cipher") = this
|
||||
}
|
||||
CipherClass() { ciphers().attr("Cipher") = this }
|
||||
}
|
||||
|
||||
class AlgorithmClass extends ClassValue {
|
||||
AlgorithmClass() { ciphers().attr("algorithms").attr(_) = this }
|
||||
|
||||
AlgorithmClass() {
|
||||
ciphers().attr("algorithms").attr(_) = this
|
||||
}
|
||||
|
||||
string getAlgorithmName() {
|
||||
result = this.declaredAttribute("name").(StringValue).getText()
|
||||
}
|
||||
string getAlgorithmName() { result = this.declaredAttribute("name").(StringValue).getText() }
|
||||
|
||||
predicate isWeak() {
|
||||
exists(CryptoLib::CryptographicAlgorithm algo |
|
||||
@@ -117,61 +82,39 @@ module Cryptography {
|
||||
}
|
||||
|
||||
class CipherInstance extends TaintKind {
|
||||
|
||||
AlgorithmClass cls;
|
||||
|
||||
CipherInstance() {
|
||||
this = "cryptography.Cipher." + cls.getAlgorithmName()
|
||||
}
|
||||
CipherInstance() { this = "cryptography.Cipher." + cls.getAlgorithmName() }
|
||||
|
||||
AlgorithmClass getAlgorithm() {
|
||||
result = cls
|
||||
}
|
||||
AlgorithmClass getAlgorithm() { result = cls }
|
||||
|
||||
predicate isWeak() {
|
||||
cls.isWeak()
|
||||
}
|
||||
predicate isWeak() { cls.isWeak() }
|
||||
|
||||
override TaintKind getTaintOfMethodResult(string name) {
|
||||
name = "encryptor" and
|
||||
result.(Encryptor).getAlgorithm() = this.getAlgorithm()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class CipherSource extends TaintSource {
|
||||
|
||||
CipherSource() {
|
||||
this.(CallNode).getFunction().pointsTo(any(CipherClass cls))
|
||||
}
|
||||
CipherSource() { this.(CallNode).getFunction().pointsTo(any(CipherClass cls)) }
|
||||
|
||||
override predicate isSourceOf(TaintKind kind) {
|
||||
this.(CallNode).getArg(0).pointsTo().getClass() = kind.(CipherInstance).getAlgorithm()
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "cryptography.Cipher.source"
|
||||
}
|
||||
|
||||
override string toString() { result = "cryptography.Cipher.source" }
|
||||
}
|
||||
|
||||
class Encryptor extends TaintKind {
|
||||
|
||||
AlgorithmClass cls;
|
||||
|
||||
Encryptor() {
|
||||
this = "cryptography.encryptor." + cls.getAlgorithmName()
|
||||
|
||||
}
|
||||
|
||||
AlgorithmClass getAlgorithm() {
|
||||
result = cls
|
||||
}
|
||||
Encryptor() { this = "cryptography.encryptor." + cls.getAlgorithmName() }
|
||||
|
||||
AlgorithmClass getAlgorithm() { result = cls }
|
||||
}
|
||||
|
||||
class CryptographyWeakCryptoSink extends WeakCryptoSink {
|
||||
|
||||
CryptographyWeakCryptoSink() {
|
||||
exists(CallNode call, AttrNode method, Encryptor encryptor |
|
||||
call.getAnArg() = this and
|
||||
@@ -181,17 +124,11 @@ module Cryptography {
|
||||
)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "Use of weak crypto algorithm"
|
||||
}
|
||||
|
||||
override string toString() { result = "Use of weak crypto algorithm" }
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private class CipherConfig extends TaintTracking::Configuration {
|
||||
|
||||
CipherConfig() { this = "Crypto cipher config" }
|
||||
|
||||
override predicate isSource(TaintTracking::Source source) {
|
||||
@@ -199,5 +136,4 @@ private class CipherConfig extends TaintTracking::Configuration {
|
||||
or
|
||||
source instanceof Cryptography::CipherSource
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -7,43 +7,31 @@ import python
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.security.strings.Basic
|
||||
|
||||
private Value traceback_function(string name) {
|
||||
result = Module::named("traceback").attr(name)
|
||||
}
|
||||
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 {
|
||||
ExceptionInfo() { this = "exception.info" }
|
||||
|
||||
ExceptionInfo() {
|
||||
this = "exception.info"
|
||||
}
|
||||
|
||||
override string repr() {
|
||||
result = "exception info"
|
||||
}
|
||||
|
||||
override string repr() { result = "exception info" }
|
||||
}
|
||||
|
||||
/** A class representing sources of information about
|
||||
/**
|
||||
* A class representing sources of information about
|
||||
* execution state exposed in tracebacks and the like.
|
||||
*/
|
||||
abstract class ErrorInfoSource extends TaintSource {}
|
||||
abstract class ErrorInfoSource extends TaintSource { }
|
||||
|
||||
/**
|
||||
* This kind represents exceptions themselves.
|
||||
*/
|
||||
class ExceptionKind extends TaintKind {
|
||||
ExceptionKind() { this = "exception.kind" }
|
||||
|
||||
ExceptionKind() {
|
||||
this = "exception.kind"
|
||||
}
|
||||
|
||||
override string repr() {
|
||||
result = "exception"
|
||||
}
|
||||
override string repr() { result = "exception" }
|
||||
|
||||
override TaintKind getTaintOfAttribute(string name) {
|
||||
name = "args" and result instanceof ExceptionInfoSequence
|
||||
@@ -57,7 +45,6 @@ class ExceptionKind extends TaintKind {
|
||||
* `except` statement.
|
||||
*/
|
||||
class ExceptionSource extends ErrorInfoSource {
|
||||
|
||||
ExceptionSource() {
|
||||
exists(ClassValue cls |
|
||||
cls.getASuperType() = ClassValue::baseException() and
|
||||
@@ -67,13 +54,9 @@ class ExceptionSource extends ErrorInfoSource {
|
||||
this = any(ExceptStmt s).getName().getAFlowNode()
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "exception.source"
|
||||
}
|
||||
override string toString() { result = "exception.source" }
|
||||
|
||||
override predicate isSourceOf(TaintKind kind) {
|
||||
kind instanceof ExceptionKind
|
||||
}
|
||||
override predicate isSourceOf(TaintKind kind) { kind instanceof ExceptionKind }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -81,18 +64,14 @@ class ExceptionSource extends ErrorInfoSource {
|
||||
* for instance the contents of the `args` attribute, or the stack trace.
|
||||
*/
|
||||
class ExceptionInfoSequence extends SequenceKind {
|
||||
ExceptionInfoSequence() {
|
||||
this.getItem() instanceof ExceptionInfo
|
||||
}
|
||||
ExceptionInfoSequence() { this.getItem() instanceof ExceptionInfo }
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Represents calls to functions in the `traceback` module that return
|
||||
* sequences of exception information.
|
||||
*/
|
||||
class CallToTracebackFunction extends ErrorInfoSource {
|
||||
|
||||
CallToTracebackFunction() {
|
||||
exists(string name |
|
||||
name = "extract_tb" or
|
||||
@@ -107,13 +86,9 @@ class CallToTracebackFunction extends ErrorInfoSource {
|
||||
)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "exception.info.sequence.source"
|
||||
}
|
||||
override string toString() { result = "exception.info.sequence.source" }
|
||||
|
||||
override predicate isSourceOf(TaintKind kind) {
|
||||
kind instanceof ExceptionInfoSequence
|
||||
}
|
||||
override predicate isSourceOf(TaintKind kind) { kind instanceof ExceptionInfoSequence }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -121,16 +96,9 @@ class CallToTracebackFunction extends ErrorInfoSource {
|
||||
* string of information about an exception.
|
||||
*/
|
||||
class FormattedTracebackSource extends ErrorInfoSource {
|
||||
FormattedTracebackSource() { this = traceback_function("format_exc").getACall() }
|
||||
|
||||
FormattedTracebackSource() {
|
||||
this = traceback_function("format_exc").getACall()
|
||||
}
|
||||
override string toString() { result = "exception.info.source" }
|
||||
|
||||
override string toString() {
|
||||
result = "exception.info.source"
|
||||
}
|
||||
|
||||
override predicate isSourceOf(TaintKind kind) {
|
||||
kind instanceof ExceptionInfo
|
||||
}
|
||||
override predicate isSourceOf(TaintKind kind) { kind instanceof ExceptionInfo }
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import semmle.python.dataflow.Implementation
|
||||
|
||||
module TaintTrackingPaths {
|
||||
|
||||
|
||||
predicate edge(TaintTrackingNode src, TaintTrackingNode dest, string label) {
|
||||
exists(TaintTrackingNode source, TaintTrackingNode sink |
|
||||
source.getConfiguration().hasFlowPath(source, sink) and
|
||||
@@ -11,10 +9,8 @@ module TaintTrackingPaths {
|
||||
dest.getASuccessor*() = sink
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
query predicate edges(TaintTrackingNode fromnode, TaintTrackingNode tonode) {
|
||||
TaintTrackingPaths::edge(fromnode, tonode, _)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import python
|
||||
import semmle.python.security.TaintTracking
|
||||
|
||||
abstract class SqlInjectionSink extends TaintSink {}
|
||||
abstract class SqlInjectionSink extends TaintSink { }
|
||||
|
||||
@@ -20,7 +20,6 @@ import semmle.python.web.HttpRequest
|
||||
* This is copied from the javascript library, but should be language independent.
|
||||
*/
|
||||
private module HeuristicNames {
|
||||
|
||||
/**
|
||||
* Gets a regular expression that identifies strings that may indicate the presence of secret
|
||||
* or trusted data.
|
||||
@@ -32,8 +31,8 @@ private module HeuristicNames {
|
||||
* user names or other account information.
|
||||
*/
|
||||
string maybeAccountInfo() {
|
||||
result = "(?is).*acc(ou)?nt.*" or
|
||||
result = "(?is).*(puid|username|userid).*"
|
||||
result = "(?is).*acc(ou)?nt.*" or
|
||||
result = "(?is).*(puid|username|userid).*"
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -41,8 +40,8 @@ private module HeuristicNames {
|
||||
* a password or an authorization key.
|
||||
*/
|
||||
string maybePassword() {
|
||||
result = "(?is).*pass(wd|word|code|phrase)(?!.*question).*" or
|
||||
result = "(?is).*(auth(entication|ori[sz]ation)?)key.*"
|
||||
result = "(?is).*pass(wd|word|code|phrase)(?!.*question).*" or
|
||||
result = "(?is).*(auth(entication|ori[sz]ation)?)key.*"
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -51,7 +50,7 @@ private module HeuristicNames {
|
||||
*/
|
||||
string maybeCertificate() { result = "(?is).*(cert)(?!.*(format|name)).*" }
|
||||
|
||||
/**
|
||||
/**
|
||||
* Gets a regular expression that identifies strings that may indicate the presence
|
||||
* of sensitive data, with `classification` describing the kind of sensitive data involved.
|
||||
*/
|
||||
@@ -78,35 +77,35 @@ private module HeuristicNames {
|
||||
name.regexpMatch(HeuristicNames::maybeSensitive(result)) and
|
||||
not name.regexpMatch(HeuristicNames::notSensitive())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
abstract class SensitiveData extends TaintKind {
|
||||
|
||||
bindingset[this]
|
||||
SensitiveData() { this = this }
|
||||
|
||||
}
|
||||
|
||||
module SensitiveData {
|
||||
|
||||
class Secret extends SensitiveData {
|
||||
Secret() { this = "sensitive.data.secret" }
|
||||
|
||||
override string repr() { result = "a secret" }
|
||||
}
|
||||
|
||||
class Id extends SensitiveData {
|
||||
Id() { this = "sensitive.data.id" }
|
||||
|
||||
override string repr() { result = "an ID" }
|
||||
}
|
||||
|
||||
class Password extends SensitiveData {
|
||||
Password() { this = "sensitive.data.password" }
|
||||
|
||||
override string repr() { result = "a password" }
|
||||
}
|
||||
|
||||
class Certificate extends SensitiveData {
|
||||
Certificate() { this = "sensitive.data.certificate" }
|
||||
|
||||
override string repr() { result = "a certificate or key" }
|
||||
}
|
||||
|
||||
@@ -115,53 +114,35 @@ module SensitiveData {
|
||||
}
|
||||
|
||||
abstract class Source extends TaintSource {
|
||||
|
||||
abstract string repr();
|
||||
|
||||
}
|
||||
|
||||
private class SensitiveCallSource extends Source {
|
||||
|
||||
SensitiveData data;
|
||||
|
||||
SensitiveCallSource() {
|
||||
exists(Value callee |
|
||||
callee.getACall() = this |
|
||||
data = fromFunction(callee)
|
||||
)
|
||||
exists(Value callee | callee.getACall() = this | data = fromFunction(callee))
|
||||
}
|
||||
|
||||
override predicate isSourceOf(TaintKind kind) {
|
||||
kind = data
|
||||
}
|
||||
|
||||
override string repr() {
|
||||
result = "a call returning " + data.repr()
|
||||
}
|
||||
override predicate isSourceOf(TaintKind kind) { kind = data }
|
||||
|
||||
override string repr() { result = "a call returning " + data.repr() }
|
||||
}
|
||||
|
||||
/** An access to a variable or property that might contain sensitive data. */
|
||||
private class SensitiveVariableAccess extends SensitiveData::Source {
|
||||
|
||||
SensitiveData data;
|
||||
|
||||
SensitiveVariableAccess() {
|
||||
data = HeuristicNames::getSensitiveDataForName(this.(AttrNode).getName())
|
||||
}
|
||||
|
||||
override predicate isSourceOf(TaintKind kind) {
|
||||
kind = data
|
||||
}
|
||||
|
||||
override string repr() {
|
||||
result = "an attribute or property containing " + data.repr()
|
||||
}
|
||||
override predicate isSourceOf(TaintKind kind) { kind = data }
|
||||
|
||||
override string repr() { result = "an attribute or property containing " + data.repr() }
|
||||
}
|
||||
|
||||
private class SensitiveRequestParameter extends SensitiveData::Source {
|
||||
|
||||
SensitiveData data;
|
||||
|
||||
SensitiveRequestParameter() {
|
||||
@@ -172,16 +153,10 @@ module SensitiveData {
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSourceOf(TaintKind kind) {
|
||||
kind = data
|
||||
}
|
||||
|
||||
override string repr() {
|
||||
result = "a request parameter containing " + data.repr()
|
||||
}
|
||||
override predicate isSourceOf(TaintKind kind) { kind = data }
|
||||
|
||||
override string repr() { result = "a request parameter containing " + data.repr() }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//Backwards compatibility
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
/** For backwards compatibility */
|
||||
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
|
||||
@@ -3,13 +3,7 @@ import semmle.python.security.strings.Basic
|
||||
|
||||
/** Assume that taint flows from argument to result for *any* call */
|
||||
class AnyCallStringFlow extends DataFlowExtension::DataFlowNode {
|
||||
AnyCallStringFlow() { any(CallNode call).getAnArg() = this }
|
||||
|
||||
AnyCallStringFlow() {
|
||||
any(CallNode call).getAnArg() = this
|
||||
}
|
||||
|
||||
override ControlFlowNode getASuccessorNode() {
|
||||
result.(CallNode).getAnArg() = this
|
||||
}
|
||||
|
||||
override ControlFlowNode getASuccessorNode() { result.(CallNode).getAnArg() = this }
|
||||
}
|
||||
|
||||
@@ -1,26 +1,24 @@
|
||||
/** Provides class and predicates to track external data that
|
||||
/**
|
||||
* Provides class and predicates to track external data that
|
||||
* may represent malicious OS commands.
|
||||
*
|
||||
* This module is intended to be imported into a taint-tracking query
|
||||
* to extend `TaintKind` and `TaintSink`.
|
||||
*
|
||||
*/
|
||||
import python
|
||||
|
||||
import python
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.security.strings.Untrusted
|
||||
|
||||
|
||||
private ModuleObject osOrPopenModule() {
|
||||
result.getName() = "os" or
|
||||
result.getName() = "popen2"
|
||||
}
|
||||
|
||||
private Object makeOsCall() {
|
||||
exists(string name |
|
||||
result = ModuleObject::named("subprocess").attr(name) |
|
||||
exists(string name | result = ModuleObject::named("subprocess").attr(name) |
|
||||
name = "Popen" or
|
||||
name = "call" or
|
||||
name = "call" or
|
||||
name = "check_call" or
|
||||
name = "check_output" or
|
||||
name = "run"
|
||||
@@ -29,40 +27,27 @@ private Object makeOsCall() {
|
||||
|
||||
/**Special case for first element in sequence. */
|
||||
class FirstElementKind extends TaintKind {
|
||||
FirstElementKind() { this = "sequence[" + any(ExternalStringKind key) + "][0]" }
|
||||
|
||||
FirstElementKind() {
|
||||
this = "sequence[" + any(ExternalStringKind key) + "][0]"
|
||||
}
|
||||
|
||||
override string repr() {
|
||||
result = "first item in sequence of " + this.getItem().repr()
|
||||
}
|
||||
override string repr() { result = "first item in sequence of " + this.getItem().repr() }
|
||||
|
||||
/** Gets the taint kind for item in this sequence. */
|
||||
ExternalStringKind getItem() {
|
||||
this = "sequence[" + result + "][0]"
|
||||
}
|
||||
|
||||
ExternalStringKind getItem() { this = "sequence[" + result + "][0]" }
|
||||
}
|
||||
|
||||
class FirstElementFlow extends DataFlowExtension::DataFlowNode {
|
||||
FirstElementFlow() { this = any(SequenceNode s).getElement(0) }
|
||||
|
||||
FirstElementFlow() {
|
||||
this = any(SequenceNode s).getElement(0)
|
||||
}
|
||||
|
||||
override
|
||||
ControlFlowNode getASuccessorNode(TaintKind fromkind, TaintKind tokind) {
|
||||
override ControlFlowNode getASuccessorNode(TaintKind fromkind, TaintKind tokind) {
|
||||
result.(SequenceNode).getElement(0) = this and tokind.(FirstElementKind).getItem() = fromkind
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** A taint sink that is potentially vulnerable to malicious shell commands.
|
||||
/**
|
||||
* A taint sink that is potentially vulnerable to malicious shell commands.
|
||||
* The `vuln` in `subprocess.call(shell=vuln)` and similar calls.
|
||||
*/
|
||||
class ShellCommand extends TaintSink {
|
||||
|
||||
override string toString() { result = "shell command" }
|
||||
|
||||
ShellCommand() {
|
||||
@@ -75,7 +60,8 @@ class ShellCommand extends TaintSink {
|
||||
or
|
||||
exists(CallNode call, string name |
|
||||
call.getAnArg() = this and
|
||||
call.getFunction().refersTo(osOrPopenModule().attr(name)) |
|
||||
call.getFunction().refersTo(osOrPopenModule().attr(name))
|
||||
|
|
||||
name = "system" or
|
||||
name = "popen" or
|
||||
name.matches("popen_")
|
||||
@@ -94,19 +80,18 @@ class ShellCommand extends TaintSink {
|
||||
/* List (or tuple) containing a tainted string command */
|
||||
kind instanceof ExternalStringSequenceKind
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** A taint sink that is potentially vulnerable to malicious shell commands.
|
||||
/**
|
||||
* A taint sink that is potentially vulnerable to malicious shell commands.
|
||||
* The `vuln` in `subprocess.call(vuln, ...)` and similar calls.
|
||||
*/
|
||||
class OsCommandFirstArgument extends TaintSink {
|
||||
|
||||
override string toString() { result = "OS command first argument" }
|
||||
|
||||
OsCommandFirstArgument() {
|
||||
not this instanceof ShellCommand and
|
||||
exists(CallNode call|
|
||||
exists(CallNode call |
|
||||
call.getFunction().refersTo(makeOsCall()) and
|
||||
call.getArg(0) = this
|
||||
)
|
||||
@@ -119,5 +104,4 @@ class OsCommandFirstArgument extends TaintSink {
|
||||
/* List (or tuple) whose first element is tainted */
|
||||
kind instanceof FirstElementKind
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,14 +1,8 @@
|
||||
|
||||
import python
|
||||
import semmle.python.security.TaintTracking
|
||||
|
||||
|
||||
/** `pickle.loads(untrusted)` vulnerability. */
|
||||
abstract class DeserializationSink extends TaintSink {
|
||||
|
||||
bindingset[this]
|
||||
DeserializationSink() {
|
||||
this = this
|
||||
}
|
||||
|
||||
DeserializationSink() { this = this }
|
||||
}
|
||||
|
||||
@@ -1,33 +1,30 @@
|
||||
/** Provides class and predicates to track external data that
|
||||
/**
|
||||
* Provides class and predicates to track external data that
|
||||
* may represent malicious Python code.
|
||||
*
|
||||
* This module is intended to be imported into a taint-tracking query
|
||||
* to extend `TaintKind` and `TaintSink`.
|
||||
*
|
||||
*/
|
||||
import python
|
||||
|
||||
import python
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.security.strings.Untrusted
|
||||
|
||||
|
||||
private FunctionObject exec_or_eval() {
|
||||
result = Object::builtin("exec")
|
||||
or
|
||||
result = Object::builtin("eval")
|
||||
}
|
||||
|
||||
/** A taint sink that represents an argument to exec or eval that is vulnerable to malicious input.
|
||||
/**
|
||||
* 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 {
|
||||
|
||||
override string toString() { result = "exec or eval" }
|
||||
|
||||
StringEvaluationNode() {
|
||||
exists(Exec exec |
|
||||
exec.getASubExpression().getAFlowNode() = this
|
||||
)
|
||||
exists(Exec exec | exec.getASubExpression().getAFlowNode() = this)
|
||||
or
|
||||
exists(CallNode call |
|
||||
exec_or_eval().getACall() = call and
|
||||
@@ -35,8 +32,5 @@ class StringEvaluationNode extends TaintSink {
|
||||
)
|
||||
}
|
||||
|
||||
override predicate sinks(TaintKind kind) {
|
||||
kind instanceof ExternalStringKind
|
||||
}
|
||||
|
||||
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
|
||||
}
|
||||
|
||||
@@ -1,26 +1,23 @@
|
||||
/** Provides class and predicates to track external data that
|
||||
/**
|
||||
* Provides class and predicates to track external data that
|
||||
* may represent malicious marshals.
|
||||
*
|
||||
* This module is intended to be imported into a taint-tracking query
|
||||
* to extend `TaintKind` and `TaintSink`.
|
||||
*
|
||||
*/
|
||||
import python
|
||||
|
||||
import python
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.security.strings.Untrusted
|
||||
import semmle.python.security.injection.Deserialization
|
||||
|
||||
private FunctionObject marshalLoads() { result = ModuleObject::named("marshal").attr("loads") }
|
||||
|
||||
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)`. */
|
||||
/**
|
||||
* A taint sink that is potentially vulnerable to malicious marshaled objects.
|
||||
* The `vuln` in `marshal.loads(vuln)`.
|
||||
*/
|
||||
class UnmarshalingNode extends DeserializationSink {
|
||||
|
||||
override string toString() { result = "unmarshaling vulnerability" }
|
||||
|
||||
UnmarshalingNode() {
|
||||
@@ -30,8 +27,5 @@ class UnmarshalingNode extends DeserializationSink {
|
||||
)
|
||||
}
|
||||
|
||||
override predicate sinks(TaintKind kind) {
|
||||
kind instanceof ExternalStringKind
|
||||
}
|
||||
|
||||
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
|
||||
}
|
||||
|
||||
@@ -1,28 +1,22 @@
|
||||
import python
|
||||
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.security.strings.Untrusted
|
||||
|
||||
/** Prevents taint flowing through ntpath.normpath()
|
||||
/**
|
||||
* Prevents taint flowing through ntpath.normpath()
|
||||
* NormalizedPath below handles that case.
|
||||
*/
|
||||
class PathSanitizer extends Sanitizer {
|
||||
|
||||
PathSanitizer() {
|
||||
this = "path.sanitizer"
|
||||
}
|
||||
PathSanitizer() { this = "path.sanitizer" }
|
||||
|
||||
override predicate sanitizingNode(TaintKind taint, ControlFlowNode node) {
|
||||
taint instanceof ExternalStringKind and
|
||||
abspath_call(node, _)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private FunctionObject abspath() {
|
||||
exists(ModuleObject os_path |
|
||||
ModuleObject::named("os").attr("path") = os_path
|
||||
|
|
||||
exists(ModuleObject os_path | ModuleObject::named("os").attr("path") = os_path |
|
||||
os_path.attr("abspath") = result
|
||||
or
|
||||
os_path.attr("normpath") = result
|
||||
@@ -31,15 +25,9 @@ private FunctionObject abspath() {
|
||||
|
||||
/** A path that has been normalized, but not verified to be safe */
|
||||
class NormalizedPath extends TaintKind {
|
||||
NormalizedPath() { this = "normalized.path.injection" }
|
||||
|
||||
NormalizedPath() {
|
||||
this = "normalized.path.injection"
|
||||
}
|
||||
|
||||
override string repr() {
|
||||
result = "normalized path"
|
||||
}
|
||||
|
||||
override string repr() { result = "normalized path" }
|
||||
}
|
||||
|
||||
private predicate abspath_call(CallNode call, ControlFlowNode arg) {
|
||||
@@ -47,39 +35,31 @@ private predicate abspath_call(CallNode call, ControlFlowNode arg) {
|
||||
arg = call.getArg(0)
|
||||
}
|
||||
|
||||
|
||||
class AbsPath extends DataFlowExtension::DataFlowNode {
|
||||
AbsPath() { abspath_call(_, this) }
|
||||
|
||||
AbsPath() {
|
||||
abspath_call(_, this)
|
||||
override ControlFlowNode getASuccessorNode(TaintKind fromkind, TaintKind tokind) {
|
||||
abspath_call(result, this) and
|
||||
tokind instanceof NormalizedPath and
|
||||
fromkind instanceof ExternalStringKind
|
||||
}
|
||||
|
||||
override
|
||||
ControlFlowNode getASuccessorNode(TaintKind fromkind, TaintKind tokind) {
|
||||
abspath_call(result, this) and tokind instanceof NormalizedPath and fromkind instanceof ExternalStringKind
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class NormalizedPathSanitizer extends Sanitizer {
|
||||
|
||||
NormalizedPathSanitizer() {
|
||||
this = "normalized.path.sanitizer"
|
||||
}
|
||||
NormalizedPathSanitizer() { this = "normalized.path.sanitizer" }
|
||||
|
||||
override predicate sanitizingEdge(TaintKind taint, PyEdgeRefinement test) {
|
||||
taint instanceof NormalizedPath and
|
||||
test.getTest().(CallNode).getFunction().(AttrNode).getName() = "startswith" and
|
||||
test.getSense() = true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** A taint sink that is vulnerable to malicious paths.
|
||||
/**
|
||||
* A taint sink that is vulnerable to malicious paths.
|
||||
* The `vuln` in `open(vuln)` and similar.
|
||||
*/
|
||||
class OpenNode extends TaintSink {
|
||||
|
||||
override string toString() { result = "argument to open()" }
|
||||
|
||||
OpenNode() {
|
||||
@@ -94,10 +74,4 @@ class OpenNode extends TaintSink {
|
||||
or
|
||||
kind instanceof NormalizedPath
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
/** Provides class and predicates to track external data that
|
||||
/**
|
||||
* Provides class and predicates to track external data that
|
||||
* may represent malicious pickles.
|
||||
*
|
||||
* This module is intended to be imported into a taint-tracking query
|
||||
* to extend `TaintKind` and `TaintSink`.
|
||||
*
|
||||
*/
|
||||
import python
|
||||
|
||||
import python
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.security.strings.Untrusted
|
||||
import semmle.python.security.injection.Deserialization
|
||||
|
||||
|
||||
private ModuleObject pickleModule() {
|
||||
result.getName() = "pickle"
|
||||
or
|
||||
@@ -20,13 +19,10 @@ private ModuleObject pickleModule() {
|
||||
result.getName() = "dill"
|
||||
}
|
||||
|
||||
private FunctionObject pickleLoads() {
|
||||
result = pickleModule().attr("loads")
|
||||
}
|
||||
private FunctionObject pickleLoads() { result = pickleModule().attr("loads") }
|
||||
|
||||
/** `pickle.loads(untrusted)` vulnerability. */
|
||||
class UnpicklingNode extends DeserializationSink {
|
||||
|
||||
override string toString() { result = "unpickling untrusted data" }
|
||||
|
||||
UnpicklingNode() {
|
||||
@@ -36,8 +32,5 @@ class UnpicklingNode extends DeserializationSink {
|
||||
)
|
||||
}
|
||||
|
||||
override predicate sinks(TaintKind kind) {
|
||||
kind instanceof ExternalStringKind
|
||||
}
|
||||
|
||||
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
|
||||
}
|
||||
|
||||
@@ -1,29 +1,27 @@
|
||||
/** Provides class and predicates to track external data that
|
||||
/**
|
||||
* Provides class and predicates to track external data that
|
||||
* may represent malicious SQL queries or parts of queries.
|
||||
*
|
||||
* This module is intended to be imported into a taint-tracking query
|
||||
* to extend `TaintKind` and `TaintSink`.
|
||||
*
|
||||
*/
|
||||
import python
|
||||
|
||||
import python
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.security.strings.Untrusted
|
||||
import semmle.python.security.SQL
|
||||
|
||||
|
||||
private StringObject first_part(ControlFlowNode command) {
|
||||
command.(BinaryExprNode).getOp() instanceof Add and
|
||||
command.(BinaryExprNode).getLeft().refersTo(result)
|
||||
or
|
||||
exists(CallNode call, SequenceObject seq |
|
||||
call = command |
|
||||
exists(CallNode call, SequenceObject seq | call = command |
|
||||
call = theStrType().lookupAttribute("join") and
|
||||
call.getArg(0).refersTo(seq) and
|
||||
seq.getInferredElement(0) = result
|
||||
)
|
||||
or
|
||||
command.(BinaryExprNode).getOp() instanceof Mod and
|
||||
command.(BinaryExprNode).getOp() instanceof Mod and
|
||||
command.getNode().(StrConst).getLiteralObject() = result
|
||||
}
|
||||
|
||||
@@ -32,52 +30,45 @@ predicate probable_sql_command(ControlFlowNode command, ControlFlowNode inject)
|
||||
exists(string prefix |
|
||||
inject = command.getAChild*() and
|
||||
first_part(command).getText().regexpMatch(" *" + prefix + ".*")
|
||||
|
|
||||
|
|
||||
prefix = "CREATE" or prefix = "SELECT"
|
||||
)
|
||||
}
|
||||
|
||||
/** A taint kind representing a DB cursor.
|
||||
/**
|
||||
* A taint kind representing a DB cursor.
|
||||
* This will be overridden to provide specific kinds of DB cursor.
|
||||
*/
|
||||
abstract class DbCursor extends TaintKind {
|
||||
|
||||
bindingset[this]
|
||||
DbCursor() { any() }
|
||||
|
||||
string getExecuteMethodName() { result = "execute" }
|
||||
|
||||
}
|
||||
|
||||
/** A part of a string that appears to be a SQL command and is thus
|
||||
/**
|
||||
* A part of a string that appears to be a SQL command and is thus
|
||||
* vulnerable to malicious input.
|
||||
*/
|
||||
class SimpleSqlStringInjection extends SqlInjectionSink {
|
||||
|
||||
override string toString() { result = "simple SQL string injection" }
|
||||
|
||||
SimpleSqlStringInjection() {
|
||||
probable_sql_command(_, this)
|
||||
}
|
||||
|
||||
override predicate sinks(TaintKind kind) {
|
||||
kind instanceof ExternalStringKind
|
||||
}
|
||||
SimpleSqlStringInjection() { probable_sql_command(_, this) }
|
||||
|
||||
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
|
||||
}
|
||||
|
||||
/** A taint source representing sources of DB connections.
|
||||
/**
|
||||
* 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 class DbConnectionSource extends TaintSource { }
|
||||
|
||||
}
|
||||
|
||||
/** A taint sink that is vulnerable to malicious SQL queries.
|
||||
/**
|
||||
* A taint sink that is vulnerable to malicious SQL queries.
|
||||
* The `vuln` in `db.connection.execute(vuln)` and similar.
|
||||
*/
|
||||
class DbConnectionExecuteArgument extends SqlInjectionSink {
|
||||
|
||||
override string toString() { result = "db.connection.execute" }
|
||||
|
||||
DbConnectionExecuteArgument() {
|
||||
@@ -88,9 +79,5 @@ class DbConnectionExecuteArgument extends SqlInjectionSink {
|
||||
)
|
||||
}
|
||||
|
||||
override predicate sinks(TaintKind kind) {
|
||||
kind instanceof ExternalStringKind
|
||||
}
|
||||
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,36 +1,26 @@
|
||||
/** Provides class and predicates to track external data that
|
||||
/**
|
||||
* Provides class and predicates to track external data that
|
||||
* may represent malicious XML objects.
|
||||
*
|
||||
* This module is intended to be imported into a taint-tracking query
|
||||
* to extend `TaintKind` and `TaintSink`.
|
||||
*/
|
||||
import python
|
||||
|
||||
import python
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.security.strings.Untrusted
|
||||
import semmle.python.security.injection.Deserialization
|
||||
|
||||
private ModuleObject xmlElementTreeModule() { result.getName() = "xml.etree.ElementTree" }
|
||||
|
||||
private ModuleObject xmlElementTreeModule() {
|
||||
result.getName() = "xml.etree.ElementTree"
|
||||
}
|
||||
private ModuleObject xmlMiniDomModule() { result.getName() = "xml.dom.minidom" }
|
||||
|
||||
private ModuleObject xmlMiniDomModule() {
|
||||
result.getName() = "xml.dom.minidom"
|
||||
}
|
||||
private ModuleObject xmlPullDomModule() { result.getName() = "xml.dom.pulldom" }
|
||||
|
||||
private ModuleObject xmlPullDomModule() {
|
||||
result.getName() = "xml.dom.pulldom"
|
||||
}
|
||||
|
||||
private ModuleObject xmlSaxModule() {
|
||||
result.getName() = "xml.sax"
|
||||
}
|
||||
private ModuleObject xmlSaxModule() { result.getName() = "xml.sax" }
|
||||
|
||||
private class ExpatParser extends TaintKind {
|
||||
|
||||
ExpatParser() { this = "expat.parser" }
|
||||
|
||||
}
|
||||
|
||||
private FunctionObject expatCreateParseFunction() {
|
||||
@@ -38,18 +28,11 @@ private FunctionObject expatCreateParseFunction() {
|
||||
}
|
||||
|
||||
private class ExpatCreateParser extends TaintSource {
|
||||
ExpatCreateParser() { expatCreateParseFunction().getACall() = this }
|
||||
|
||||
ExpatCreateParser() {
|
||||
expatCreateParseFunction().getACall() = this
|
||||
}
|
||||
override predicate isSourceOf(TaintKind kind) { kind instanceof ExpatParser }
|
||||
|
||||
override predicate isSourceOf(TaintKind kind) {
|
||||
kind instanceof ExpatParser
|
||||
}
|
||||
|
||||
string toString() {
|
||||
result = "expat.create.parser"
|
||||
}
|
||||
string toString() { result = "expat.create.parser" }
|
||||
}
|
||||
|
||||
private FunctionObject xmlFromString() {
|
||||
@@ -64,30 +47,22 @@ private FunctionObject xmlFromString() {
|
||||
|
||||
/** A (potentially) malicious XML string. */
|
||||
class ExternalXmlString extends ExternalStringKind {
|
||||
|
||||
ExternalXmlString() {
|
||||
this = "external xml encoded object"
|
||||
}
|
||||
|
||||
ExternalXmlString() { this = "external xml encoded object" }
|
||||
}
|
||||
|
||||
/** A call to an XML library function that is potentially vulnerable to a
|
||||
/**
|
||||
* A call to an XML library function that is potentially vulnerable to a
|
||||
* specially crafted XML string.
|
||||
*/
|
||||
class XmlLoadNode extends DeserializationSink {
|
||||
|
||||
override string toString() { result = "xml.load vulnerability" }
|
||||
|
||||
XmlLoadNode() {
|
||||
exists(CallNode call |
|
||||
call.getAnArg() = this |
|
||||
exists(CallNode call | call.getAnArg() = this |
|
||||
xmlFromString().getACall() = call or
|
||||
any(ExpatParser parser).taints(call.getFunction().(AttrNode).getObject("Parse"))
|
||||
)
|
||||
}
|
||||
|
||||
override predicate sinks(TaintKind kind) {
|
||||
kind instanceof ExternalXmlString
|
||||
}
|
||||
|
||||
override predicate sinks(TaintKind kind) { kind instanceof ExternalXmlString }
|
||||
}
|
||||
|
||||
@@ -1,25 +1,20 @@
|
||||
/** Provides class and predicates to track external data that
|
||||
/**
|
||||
* Provides class and predicates to track external data that
|
||||
* may represent malicious yaml-encoded objects.
|
||||
*
|
||||
* This module is intended to be imported into a taint-tracking query
|
||||
* to extend `TaintKind` and `TaintSink`.
|
||||
*
|
||||
*/
|
||||
|
||||
import python
|
||||
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.security.strings.Untrusted
|
||||
import semmle.python.security.injection.Deserialization
|
||||
|
||||
|
||||
private FunctionObject yamlLoad() {
|
||||
result = ModuleObject::named("yaml").attr("load")
|
||||
}
|
||||
private FunctionObject yamlLoad() { result = ModuleObject::named("yaml").attr("load") }
|
||||
|
||||
/** `yaml.load(untrusted)` vulnerability. */
|
||||
class YamlLoadNode extends DeserializationSink {
|
||||
|
||||
override string toString() { result = "yaml.load vulnerability" }
|
||||
|
||||
YamlLoadNode() {
|
||||
@@ -29,8 +24,5 @@ class YamlLoadNode extends DeserializationSink {
|
||||
)
|
||||
}
|
||||
|
||||
override predicate sinks(TaintKind kind) {
|
||||
kind instanceof ExternalStringKind
|
||||
}
|
||||
|
||||
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
|
||||
}
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
import python
|
||||
private import Common
|
||||
|
||||
import semmle.python.security.TaintTracking
|
||||
|
||||
/** An extensible kind of taint representing any kind of string. */
|
||||
abstract class StringKind extends TaintKind {
|
||||
|
||||
bindingset[this]
|
||||
StringKind() {
|
||||
this = this
|
||||
}
|
||||
StringKind() { this = this }
|
||||
|
||||
override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) {
|
||||
result = this and
|
||||
@@ -27,43 +23,44 @@ abstract class StringKind extends TaintKind {
|
||||
}
|
||||
|
||||
override ClassValue getType() {
|
||||
result = Value::named("bytes") or result = Value::named("str") or result = Value::named("unicode")
|
||||
result = Value::named("bytes") or
|
||||
result = Value::named("str") or
|
||||
result = Value::named("unicode")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class StringEqualitySanitizer extends Sanitizer {
|
||||
|
||||
StringEqualitySanitizer() { this = "string equality sanitizer" }
|
||||
|
||||
/** The test `if untrusted == "KNOWN_VALUE":` sanitizes `untrusted` on its `true` edge. */
|
||||
override predicate sanitizingEdge(TaintKind taint, PyEdgeRefinement test) {
|
||||
taint instanceof StringKind and
|
||||
exists(ControlFlowNode const, Cmpop op |
|
||||
const.getNode() instanceof StrConst |
|
||||
exists(ControlFlowNode const, Cmpop op | const.getNode() instanceof StrConst |
|
||||
(
|
||||
test.getTest().(CompareNode).operands(const, op, _)
|
||||
or
|
||||
test.getTest().(CompareNode).operands(_, op, const)
|
||||
) and (
|
||||
) and
|
||||
(
|
||||
op instanceof Eq and test.getSense() = true
|
||||
or
|
||||
op instanceof NotEq and test.getSense() = false
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* tonode = fromnode.xxx() where the call to xxx returns an identical or similar string */
|
||||
private predicate str_method_call(ControlFlowNode fromnode, CallNode tonode) {
|
||||
exists(string method_name |
|
||||
tonode.getFunction().(AttrNode).getObject(method_name) = fromnode
|
||||
|
|
||||
method_name = "strip" or method_name = "format" or
|
||||
method_name = "lstrip" or method_name = "rstrip" or
|
||||
method_name = "ljust" or method_name = "rjust" or
|
||||
method_name = "title" or method_name = "capitalize"
|
||||
exists(string method_name | tonode.getFunction().(AttrNode).getObject(method_name) = fromnode |
|
||||
method_name = "strip" or
|
||||
method_name = "format" or
|
||||
method_name = "lstrip" or
|
||||
method_name = "rstrip" or
|
||||
method_name = "ljust" or
|
||||
method_name = "rjust" or
|
||||
method_name = "title" or
|
||||
method_name = "capitalize"
|
||||
)
|
||||
}
|
||||
|
||||
@@ -79,8 +76,10 @@ private predicate encode_decode(ControlFlowNode fromnode, CallNode tonode) {
|
||||
not func.getFunction().isMethod() and
|
||||
func.getACall() = tonode and
|
||||
tonode.getAnArg() = fromnode and
|
||||
func.getName() = name |
|
||||
name = "encode" or name = "decode" or
|
||||
func.getName() = name
|
||||
|
|
||||
name = "encode" or
|
||||
name = "decode" or
|
||||
name = "decodestring"
|
||||
)
|
||||
}
|
||||
@@ -99,22 +98,19 @@ private predicate to_str(ControlFlowNode fromnode, CallNode tonode) {
|
||||
private predicate slice(ControlFlowNode fromnode, SubscriptNode tonode) {
|
||||
exists(Slice all |
|
||||
all = tonode.getIndex().getNode() and
|
||||
not exists(all.getStart()) and not exists(all.getStop()) and
|
||||
not exists(all.getStart()) and
|
||||
not exists(all.getStop()) and
|
||||
tonode.getObject() = fromnode
|
||||
)
|
||||
}
|
||||
|
||||
/* tonode = os.path.join(..., fromnode, ...) */
|
||||
private predicate os_path_join(ControlFlowNode fromnode, CallNode tonode) {
|
||||
tonode = Value::named("os.path.join").getACall()
|
||||
and tonode.getAnArg() = fromnode
|
||||
tonode = Value::named("os.path.join").getACall() and
|
||||
tonode.getAnArg() = fromnode
|
||||
}
|
||||
|
||||
/** A kind of "taint", representing a dictionary mapping str->"taint" */
|
||||
class StringDictKind extends DictKind {
|
||||
|
||||
StringDictKind() {
|
||||
this.getValue() instanceof StringKind
|
||||
}
|
||||
|
||||
StringDictKind() { this.getValue() instanceof StringKind }
|
||||
}
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
import python
|
||||
|
||||
|
||||
/* A call that returns a copy (or similar) of the argument */
|
||||
predicate copy_call(ControlFlowNode fromnode, CallNode tonode) {
|
||||
tonode.getFunction().(AttrNode).getObject("copy") = fromnode
|
||||
or
|
||||
exists(ModuleValue copy, string name |
|
||||
name = "copy" or name = "deepcopy" |
|
||||
exists(ModuleValue copy, string name | name = "copy" or name = "deepcopy" |
|
||||
copy.attr(name).(FunctionValue).getACall() = tonode and
|
||||
tonode.getArg(0) = fromnode
|
||||
)
|
||||
|
||||
@@ -206,7 +206,6 @@ class ExternalFileObject extends TaintKind {
|
||||
*/
|
||||
class UrlsplitUrlparseTempSanitizer extends Sanitizer {
|
||||
// TODO: remove this once we have better support for named tuples
|
||||
|
||||
UrlsplitUrlparseTempSanitizer() { this = "UrlsplitUrlparseTempSanitizer" }
|
||||
|
||||
override predicate sanitizingEdge(TaintKind taint, PyEdgeRefinement test) {
|
||||
@@ -238,9 +237,7 @@ class UrlsplitUrlparseTempSanitizer extends Sanitizer {
|
||||
|
||||
/** holds for `== "KNOWN_VALUE"` on `true` edge, and `!= "KNOWN_VALUE"` on `false` edge */
|
||||
private predicate test_equality_with_const(CompareNode cmp, ControlFlowNode tainted, boolean sense) {
|
||||
exists(ControlFlowNode const, Cmpop op |
|
||||
const.getNode() instanceof StrConst
|
||||
|
|
||||
exists(ControlFlowNode const, Cmpop op | const.getNode() instanceof StrConst |
|
||||
(
|
||||
cmp.operands(const, op, tainted)
|
||||
or
|
||||
@@ -257,7 +254,9 @@ class UrlsplitUrlparseTempSanitizer extends Sanitizer {
|
||||
/** holds for `in ["KNOWN_VALUE", ...]` on `true` edge, and `not in ["KNOWN_VALUE", ...]` on `false` edge */
|
||||
private predicate test_in_const_seq(CompareNode cmp, ControlFlowNode tainted, boolean sense) {
|
||||
exists(SequenceNode const_seq, Cmpop op |
|
||||
forall(ControlFlowNode elem | elem = const_seq.getAnElement() | elem.getNode() instanceof StrConst)
|
||||
forall(ControlFlowNode elem | elem = const_seq.getAnElement() |
|
||||
elem.getNode() instanceof StrConst
|
||||
)
|
||||
|
|
||||
cmp.operands(tainted, op, const_seq) and
|
||||
(
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
import python
|
||||
import External
|
||||
|
||||
|
||||
/** A kind of taint representing an externally controlled string.
|
||||
/**
|
||||
* A kind of taint representing an externally controlled string.
|
||||
* This class is a simple sub-class of `ExternalStringKind`.
|
||||
*/
|
||||
class UntrustedStringKind extends ExternalStringKind {
|
||||
|
||||
UntrustedStringKind() {
|
||||
this = "externally controlled string"
|
||||
}
|
||||
|
||||
UntrustedStringKind() { this = "externally controlled string" }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user