mirror of
https://github.com/github/codeql.git
synced 2026-04-21 23:14:03 +02:00
delete old deprecations
This commit is contained in:
@@ -1,103 +0,0 @@
|
||||
/**
|
||||
* Provides classes and predicates for tracking exceptions and information
|
||||
* associated with exceptions.
|
||||
*/
|
||||
|
||||
import python
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.security.strings.Basic
|
||||
|
||||
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.
|
||||
*/
|
||||
deprecated class ExceptionInfo extends StringKind {
|
||||
ExceptionInfo() { this = "exception.info" }
|
||||
|
||||
override string repr() { result = "exception info" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A class representing sources of information about
|
||||
* execution state exposed in tracebacks and the like.
|
||||
*/
|
||||
abstract deprecated class ErrorInfoSource extends TaintSource { }
|
||||
|
||||
/**
|
||||
* This kind represents exceptions themselves.
|
||||
*/
|
||||
deprecated class ExceptionKind extends TaintKind {
|
||||
ExceptionKind() { this = "exception.kind" }
|
||||
|
||||
override string repr() { result = "exception" }
|
||||
|
||||
override TaintKind getTaintOfAttribute(string name) {
|
||||
name = "args" and result instanceof ExceptionInfoSequence
|
||||
or
|
||||
name = "message" and result instanceof ExceptionInfo
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A source of exception objects, either explicitly created, or captured by an
|
||||
* `except` statement.
|
||||
*/
|
||||
deprecated class ExceptionSource extends ErrorInfoSource {
|
||||
ExceptionSource() {
|
||||
exists(ClassValue cls |
|
||||
cls.getASuperType() = ClassValue::baseException() and
|
||||
this.(ControlFlowNode).pointsTo().getClass() = cls
|
||||
)
|
||||
or
|
||||
this = any(ExceptStmt s).getName().getAFlowNode()
|
||||
}
|
||||
|
||||
override string toString() { result = "exception.source" }
|
||||
|
||||
override predicate isSourceOf(TaintKind kind) { kind instanceof ExceptionKind }
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a sequence of pieces of information relating to an exception,
|
||||
* for instance the contents of the `args` attribute, or the stack trace.
|
||||
*/
|
||||
deprecated class ExceptionInfoSequence extends SequenceKind {
|
||||
ExceptionInfoSequence() { this.getItem() instanceof ExceptionInfo }
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents calls to functions in the `traceback` module that return
|
||||
* sequences of exception information.
|
||||
*/
|
||||
deprecated class CallToTracebackFunction extends ErrorInfoSource {
|
||||
CallToTracebackFunction() {
|
||||
exists(string name |
|
||||
name in [
|
||||
"extract_tb", "extract_stack", "format_list", "format_exception_only", "format_exception",
|
||||
"format_tb", "format_stack"
|
||||
]
|
||||
|
|
||||
this = traceback_function(name).getACall()
|
||||
)
|
||||
}
|
||||
|
||||
override string toString() { result = "exception.info.sequence.source" }
|
||||
|
||||
override predicate isSourceOf(TaintKind kind) { kind instanceof ExceptionInfoSequence }
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents calls to functions in the `traceback` module that return a single
|
||||
* string of information about an exception.
|
||||
*/
|
||||
deprecated class FormattedTracebackSource extends ErrorInfoSource {
|
||||
FormattedTracebackSource() { this = traceback_function("format_exc").getACall() }
|
||||
|
||||
override string toString() { result = "exception.info.source" }
|
||||
|
||||
override predicate isSourceOf(TaintKind kind) { kind instanceof ExceptionInfo }
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import semmle.python.dataflow.Implementation
|
||||
|
||||
deprecated module TaintTrackingPaths {
|
||||
predicate edge(TaintTrackingNode src, TaintTrackingNode dest, string label) {
|
||||
exists(TaintTrackingNode source, TaintTrackingNode sink |
|
||||
source.getConfiguration().hasFlowPath(source, sink) and
|
||||
source.getASuccessor*() = src and
|
||||
src.getASuccessor(label) = dest and
|
||||
dest.getASuccessor*() = sink
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
deprecated query predicate edges(TaintTrackingNode fromnode, TaintTrackingNode tonode) {
|
||||
TaintTrackingPaths::edge(fromnode, tonode, _)
|
||||
}
|
||||
@@ -1,263 +0,0 @@
|
||||
/**
|
||||
* 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 semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.security.strings.Untrusted
|
||||
|
||||
/** Abstract taint sink that is potentially vulnerable to malicious shell commands. */
|
||||
abstract deprecated class CommandSink extends TaintSink { }
|
||||
|
||||
deprecated private ModuleObject osOrPopenModule() { result.getName() = ["os", "popen2"] }
|
||||
|
||||
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. */
|
||||
deprecated class FirstElementKind extends TaintKind {
|
||||
FirstElementKind() { this = "sequence[" + any(ExternalStringKind key) + "][0]" }
|
||||
|
||||
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]" }
|
||||
}
|
||||
|
||||
deprecated class FirstElementFlow extends DataFlowExtension::DataFlowNode {
|
||||
FirstElementFlow() { this = any(SequenceNode s).getElement(0) }
|
||||
|
||||
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.
|
||||
* The `vuln` in `subprocess.call(shell=vuln)` and similar calls.
|
||||
*/
|
||||
deprecated class ShellCommand extends CommandSink {
|
||||
override string toString() { result = "shell command" }
|
||||
|
||||
ShellCommand() {
|
||||
exists(CallNode call, Object istrue |
|
||||
call.getFunction().refersTo(makeOsCall()) and
|
||||
call.getAnArg() = this and
|
||||
call.getArgByName("shell").refersTo(istrue) and
|
||||
istrue.booleanValue() = true
|
||||
)
|
||||
or
|
||||
exists(CallNode call, string name |
|
||||
call.getAnArg() = this and
|
||||
call.getFunction().refersTo(osOrPopenModule().attr(name))
|
||||
|
|
||||
name = ["system", "popen"] or
|
||||
name.matches("popen_")
|
||||
)
|
||||
or
|
||||
exists(CallNode call |
|
||||
call.getAnArg() = this and
|
||||
call.getFunction().refersTo(ModuleObject::named("commands"))
|
||||
)
|
||||
}
|
||||
|
||||
override predicate sinks(TaintKind kind) {
|
||||
/* Tainted string command */
|
||||
kind instanceof ExternalStringKind
|
||||
or
|
||||
/* List (or tuple) containing a tainted string command */
|
||||
kind instanceof ExternalStringSequenceKind
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint sink that is potentially vulnerable to malicious shell commands.
|
||||
* The `vuln` in `subprocess.call(vuln, ...)` and similar calls.
|
||||
*/
|
||||
deprecated class OsCommandFirstArgument extends CommandSink {
|
||||
override string toString() { result = "OS command first argument" }
|
||||
|
||||
OsCommandFirstArgument() {
|
||||
not this instanceof ShellCommand and
|
||||
exists(CallNode call |
|
||||
call.getFunction().refersTo(makeOsCall()) and
|
||||
call.getArg(0) = this
|
||||
)
|
||||
}
|
||||
|
||||
override predicate sinks(TaintKind kind) {
|
||||
/* Tainted string command */
|
||||
kind instanceof ExternalStringKind
|
||||
or
|
||||
/* List (or tuple) whose first element is tainted */
|
||||
kind instanceof FirstElementKind
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------- //
|
||||
// Modeling of the 'invoke' package and 'fabric' package (v 2.x)
|
||||
//
|
||||
// Since fabric build so closely upon invoke, we model them together to avoid
|
||||
// duplication
|
||||
// -------------------------------------------------------------------------- //
|
||||
/**
|
||||
* A taint sink that is potentially vulnerable to malicious shell commands.
|
||||
* The `vuln` in `invoke.run(vuln, ...)` and similar calls.
|
||||
*/
|
||||
deprecated class InvokeRun extends CommandSink {
|
||||
InvokeRun() {
|
||||
this = Value::named("invoke.run").(FunctionValue).getArgumentForCall(_, 0)
|
||||
or
|
||||
this = Value::named("invoke.sudo").(FunctionValue).getArgumentForCall(_, 0)
|
||||
}
|
||||
|
||||
override string toString() { result = "InvokeRun" }
|
||||
|
||||
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal TaintKind to track the invoke.Context instance passed to functions
|
||||
* marked with @invoke.task
|
||||
*/
|
||||
deprecated private class InvokeContextArg extends TaintKind {
|
||||
InvokeContextArg() { this = "InvokeContextArg" }
|
||||
}
|
||||
|
||||
/** Internal TaintSource to track the context passed to functions marked with @invoke.task */
|
||||
deprecated private class InvokeContextArgSource extends TaintSource {
|
||||
InvokeContextArgSource() {
|
||||
exists(Function f, Expr decorator |
|
||||
count(f.getADecorator()) = 1 and
|
||||
(
|
||||
decorator = f.getADecorator() and not decorator instanceof Call
|
||||
or
|
||||
decorator = f.getADecorator().(Call).getFunc()
|
||||
) and
|
||||
(
|
||||
decorator.pointsTo(Value::named("invoke.task"))
|
||||
or
|
||||
decorator.pointsTo(Value::named("fabric.task"))
|
||||
)
|
||||
|
|
||||
this.(ControlFlowNode).getNode() = f.getArg(0)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSourceOf(TaintKind kind) { kind instanceof InvokeContextArg }
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint sink that is potentially vulnerable to malicious shell commands.
|
||||
* The `vuln` in `invoke.Context().run(vuln, ...)` and similar calls.
|
||||
*/
|
||||
deprecated class InvokeContextRun extends CommandSink {
|
||||
InvokeContextRun() {
|
||||
exists(CallNode call |
|
||||
any(InvokeContextArg k).taints(call.getFunction().(AttrNode).getObject("run"))
|
||||
or
|
||||
call = Value::named("invoke.Context").(ClassValue).lookup("run").getACall()
|
||||
or
|
||||
// fabric.connection.Connection is a subtype of invoke.context.Context
|
||||
// since fabric.Connection.run has a decorator, it doesn't work with FunctionValue :|
|
||||
// and `Value::named("fabric.Connection").(ClassValue).lookup("run").getACall()` returned no results,
|
||||
// so here is the hacky solution that works :\
|
||||
call.getFunction().(AttrNode).getObject("run").pointsTo().getClass() =
|
||||
Value::named("fabric.Connection")
|
||||
|
|
||||
this = call.getArg(0)
|
||||
or
|
||||
this = call.getArgByName("command")
|
||||
)
|
||||
}
|
||||
|
||||
override string toString() { result = "InvokeContextRun" }
|
||||
|
||||
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint sink that is potentially vulnerable to malicious shell commands.
|
||||
* The `vuln` in `fabric.Group().run(vuln, ...)` and similar calls.
|
||||
*/
|
||||
deprecated class FabricGroupRun extends CommandSink {
|
||||
FabricGroupRun() {
|
||||
exists(ClassValue cls |
|
||||
cls.getASuperType() = Value::named("fabric.Group") and
|
||||
this = cls.lookup("run").(FunctionValue).getArgumentForCall(_, 1)
|
||||
)
|
||||
}
|
||||
|
||||
override string toString() { result = "FabricGroupRun" }
|
||||
|
||||
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------- //
|
||||
// Modeling of the 'invoke' package and 'fabric' package (v 1.x)
|
||||
// -------------------------------------------------------------------------- //
|
||||
deprecated class FabricV1Commands extends CommandSink {
|
||||
FabricV1Commands() {
|
||||
// since `run` and `sudo` are decorated, we can't use FunctionValue's :(
|
||||
exists(CallNode call |
|
||||
call = Value::named("fabric.api.local").getACall()
|
||||
or
|
||||
call = Value::named("fabric.api.run").getACall()
|
||||
or
|
||||
call = Value::named("fabric.api.sudo").getACall()
|
||||
|
|
||||
this = call.getArg(0)
|
||||
or
|
||||
this = call.getArgByName("command")
|
||||
)
|
||||
}
|
||||
|
||||
override string toString() { result = "FabricV1Commands" }
|
||||
|
||||
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
|
||||
}
|
||||
|
||||
/**
|
||||
* 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, ...)`.
|
||||
*/
|
||||
deprecated class FabricExecuteExtension extends DataFlowExtension::DataFlowNode {
|
||||
CallNode call;
|
||||
|
||||
FabricExecuteExtension() {
|
||||
call = Value::named("fabric.api.execute").getACall() and
|
||||
(
|
||||
this = call.getArg(any(int i | i > 0))
|
||||
or
|
||||
this = call.getArgByName(any(string s | not s = "task"))
|
||||
)
|
||||
}
|
||||
|
||||
override ControlFlowNode getASuccessorNode(TaintKind fromkind, TaintKind tokind) {
|
||||
tokind = fromkind and
|
||||
exists(CallableValue func |
|
||||
(
|
||||
call.getArg(0).pointsTo(func)
|
||||
or
|
||||
call.getArgByName("task").pointsTo(func)
|
||||
) and
|
||||
exists(int i |
|
||||
// execute(func, arg0, arg1) => func(arg0, arg1)
|
||||
this = call.getArg(i) and
|
||||
result = func.getParameter(i - 1)
|
||||
)
|
||||
or
|
||||
exists(string name |
|
||||
this = call.getArgByName(name) and
|
||||
result = func.getParameterByName(name)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
/**
|
||||
* 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 semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.security.strings.Untrusted
|
||||
import semmle.python.security.SQL
|
||||
|
||||
deprecated 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 |
|
||||
call = theStrType().lookupAttribute("join") and
|
||||
call.getArg(0).refersTo(seq) and
|
||||
seq.getInferredElement(0) = result
|
||||
)
|
||||
or
|
||||
command.(BinaryExprNode).getOp() instanceof Mod and
|
||||
command.getNode().(StrConst).getLiteralObject() = result
|
||||
}
|
||||
|
||||
/** Holds if `command` appears to be a SQL command string of which `inject` is a part. */
|
||||
deprecated 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.
|
||||
* This will be overridden to provide specific kinds of DB cursor.
|
||||
*/
|
||||
abstract deprecated 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
|
||||
* vulnerable to malicious input.
|
||||
*/
|
||||
deprecated 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 }
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint source representing sources of DB connections.
|
||||
* This will be overridden to provide specific kinds of DB connection sources.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
deprecated class DbConnectionExecuteArgument extends SqlInjectionSink {
|
||||
override string toString() { result = "db.connection.execute" }
|
||||
|
||||
DbConnectionExecuteArgument() {
|
||||
exists(CallNode call, DbCursor cursor, string name |
|
||||
cursor.taints(call.getFunction().(AttrNode).getObject(name)) and
|
||||
cursor.getExecuteMethodName() = name and
|
||||
call.getArg(0) = this
|
||||
)
|
||||
}
|
||||
|
||||
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
|
||||
}
|
||||
@@ -1,124 +0,0 @@
|
||||
import python
|
||||
private import Common
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
|
||||
/** An extensible kind of taint representing any kind of string. */
|
||||
abstract deprecated class StringKind extends TaintKind {
|
||||
bindingset[this]
|
||||
StringKind() { this = this }
|
||||
|
||||
override TaintKind getTaintOfMethodResult(string name) {
|
||||
name in [
|
||||
"capitalize", "casefold", "center", "expandtabs", "format", "format_map", "ljust", "lstrip",
|
||||
"lower", "replace", "rjust", "rstrip", "strip", "swapcase", "title", "upper", "zfill",
|
||||
/* encode/decode is technically not correct, but close enough */
|
||||
"encode", "decode"
|
||||
] and
|
||||
result = this
|
||||
or
|
||||
name in ["partition", "rpartition", "rsplit", "split", "splitlines"] and
|
||||
result.(SequenceKind).getItem() = this
|
||||
}
|
||||
|
||||
override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) {
|
||||
result = this and
|
||||
(
|
||||
slice(fromnode, tonode) or
|
||||
tonode.(BinaryExprNode).getAnOperand() = fromnode or
|
||||
os_path_join(fromnode, tonode) or
|
||||
str_format(fromnode, tonode) or
|
||||
encode_decode(fromnode, tonode) or
|
||||
to_str(fromnode, tonode) or
|
||||
f_string(fromnode, tonode)
|
||||
)
|
||||
or
|
||||
result = this and copy_call(fromnode, tonode)
|
||||
}
|
||||
|
||||
override ClassValue getType() {
|
||||
result = Value::named("bytes") or
|
||||
result = Value::named("str") or
|
||||
result = Value::named("unicode")
|
||||
}
|
||||
}
|
||||
|
||||
deprecated 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 |
|
||||
(
|
||||
test.getTest().(CompareNode).operands(const, op, _)
|
||||
or
|
||||
test.getTest().(CompareNode).operands(_, op, const)
|
||||
) and
|
||||
(
|
||||
op instanceof Eq and test.getSense() = true
|
||||
or
|
||||
op instanceof NotEq and test.getSense() = false
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** tonode = ....format(fromnode) */
|
||||
deprecated private predicate str_format(ControlFlowNode fromnode, CallNode tonode) {
|
||||
tonode.getFunction().(AttrNode).getName() = "format" and
|
||||
tonode.getAnArg() = fromnode
|
||||
}
|
||||
|
||||
/** tonode = codec.[en|de]code(fromnode) */
|
||||
deprecated private predicate encode_decode(ControlFlowNode fromnode, CallNode tonode) {
|
||||
exists(FunctionObject func, string name |
|
||||
not func.getFunction().isMethod() and
|
||||
func.getACall() = tonode and
|
||||
tonode.getAnArg() = fromnode and
|
||||
func.getName() = name
|
||||
|
|
||||
name = "encode" or
|
||||
name = "decode" or
|
||||
name = "decodestring"
|
||||
)
|
||||
}
|
||||
|
||||
/** tonode = str(fromnode) */
|
||||
deprecated private predicate to_str(ControlFlowNode fromnode, CallNode tonode) {
|
||||
tonode.getAnArg() = fromnode and
|
||||
(
|
||||
tonode = ClassValue::bytes().getACall()
|
||||
or
|
||||
tonode = ClassValue::unicode().getACall()
|
||||
)
|
||||
}
|
||||
|
||||
/** tonode = fromnode[:] */
|
||||
deprecated 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
|
||||
tonode.getObject() = fromnode
|
||||
)
|
||||
}
|
||||
|
||||
/** tonode = os.path.join(..., fromnode, ...) */
|
||||
deprecated private predicate os_path_join(ControlFlowNode fromnode, CallNode tonode) {
|
||||
tonode = Value::named("os.path.join").getACall() and
|
||||
tonode.getAnArg() = fromnode
|
||||
}
|
||||
|
||||
/** tonode = f"... {fromnode} ..." */
|
||||
deprecated private predicate f_string(ControlFlowNode fromnode, ControlFlowNode tonode) {
|
||||
tonode.getNode().(Fstring).getAValue() = fromnode.getNode()
|
||||
}
|
||||
|
||||
/**
|
||||
* A kind of "taint", representing a dictionary mapping str->"taint"
|
||||
*
|
||||
* DEPRECATED: Use `ExternalStringDictKind` instead.
|
||||
*/
|
||||
deprecated class StringDictKind extends DictKind {
|
||||
StringDictKind() { this.getValue() instanceof StringKind }
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
import python
|
||||
|
||||
/** A call that returns a copy (or similar) of the argument */
|
||||
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" |
|
||||
copy.attr(name).(FunctionValue).getACall() = tonode and
|
||||
tonode.getArg(0) = fromnode
|
||||
)
|
||||
or
|
||||
tonode.getFunction().pointsTo(Value::named("reversed")) and
|
||||
tonode.getArg(0) = fromnode
|
||||
}
|
||||
@@ -1,318 +0,0 @@
|
||||
import python
|
||||
import Basic
|
||||
private import Common
|
||||
|
||||
/**
|
||||
* An extensible kind of taint representing an externally controlled string.
|
||||
*/
|
||||
abstract deprecated class ExternalStringKind extends StringKind {
|
||||
bindingset[this]
|
||||
ExternalStringKind() { this = this }
|
||||
|
||||
override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) {
|
||||
result = StringKind.super.getTaintForFlowStep(fromnode, tonode)
|
||||
or
|
||||
tonode.(SequenceNode).getElement(_) = fromnode and
|
||||
result.(ExternalStringSequenceKind).getItem() = this
|
||||
or
|
||||
json_load(fromnode, tonode) and result.(ExternalJsonKind).getValue() = this
|
||||
or
|
||||
tonode.(DictNode).getAValue() = fromnode and result.(ExternalStringDictKind).getValue() = this
|
||||
or
|
||||
urlsplit(fromnode, tonode) and result.(ExternalUrlSplitResult).getItem() = this
|
||||
or
|
||||
urlparse(fromnode, tonode) and result.(ExternalUrlParseResult).getItem() = this
|
||||
or
|
||||
parse_qs(fromnode, tonode) and result.(ExternalStringDictKind).getValue() = this
|
||||
or
|
||||
parse_qsl(fromnode, tonode) and result.(SequenceKind).getItem().(SequenceKind).getItem() = this
|
||||
}
|
||||
}
|
||||
|
||||
/** A kind of "taint", representing a sequence, with a "taint" member */
|
||||
deprecated class ExternalStringSequenceKind extends SequenceKind {
|
||||
ExternalStringSequenceKind() { this.getItem() instanceof ExternalStringKind }
|
||||
}
|
||||
|
||||
/**
|
||||
* An hierarchical dictionary or list where the entire structure is externally controlled
|
||||
* This is typically a parsed JSON object.
|
||||
*/
|
||||
deprecated class ExternalJsonKind extends TaintKind {
|
||||
ExternalJsonKind() { this = "json[" + any(ExternalStringKind key) + "]" }
|
||||
|
||||
/** Gets the taint kind for item in this sequence */
|
||||
TaintKind getValue() {
|
||||
this = "json[" + result + "]"
|
||||
or
|
||||
result = this
|
||||
}
|
||||
|
||||
override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) {
|
||||
this.taints(fromnode) and
|
||||
json_subscript_taint(tonode, fromnode, this, result)
|
||||
or
|
||||
result = this and copy_call(fromnode, tonode)
|
||||
}
|
||||
|
||||
override TaintKind getTaintOfMethodResult(string name) {
|
||||
name = "get" and result = this.getValue()
|
||||
}
|
||||
}
|
||||
|
||||
/** A kind of "taint", representing a dictionary mapping keys to tainted strings. */
|
||||
deprecated class ExternalStringDictKind extends DictKind {
|
||||
ExternalStringDictKind() { this.getValue() instanceof ExternalStringKind }
|
||||
}
|
||||
|
||||
/**
|
||||
* A kind of "taint", representing a dictionary mapping keys to sequences of
|
||||
* tainted strings.
|
||||
*/
|
||||
deprecated class ExternalStringSequenceDictKind extends DictKind {
|
||||
ExternalStringSequenceDictKind() { this.getValue() instanceof ExternalStringSequenceKind }
|
||||
}
|
||||
|
||||
/** TaintKind for the result of `urlsplit(tainted_string)` */
|
||||
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)
|
||||
or
|
||||
name in [
|
||||
// namedtuple field names
|
||||
"scheme", "netloc", "path", "query", "fragment",
|
||||
// class methods
|
||||
"password", "username", "hostname",
|
||||
] and
|
||||
result instanceof ExternalStringKind
|
||||
}
|
||||
|
||||
override TaintKind getTaintOfMethodResult(string name) {
|
||||
result = super.getTaintOfMethodResult(name)
|
||||
or
|
||||
name = "geturl" and
|
||||
result instanceof ExternalStringKind
|
||||
}
|
||||
}
|
||||
|
||||
/** TaintKind for the result of `urlparse(tainted_string)` */
|
||||
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)
|
||||
or
|
||||
name in [
|
||||
// namedtuple field names
|
||||
"scheme", "netloc", "path", "params", "query", "fragment",
|
||||
// class methods
|
||||
"username", "password", "hostname",
|
||||
] and
|
||||
result instanceof ExternalStringKind
|
||||
}
|
||||
|
||||
override TaintKind getTaintOfMethodResult(string name) {
|
||||
result = super.getTaintOfMethodResult(name)
|
||||
or
|
||||
name = "geturl" and
|
||||
result instanceof ExternalStringKind
|
||||
}
|
||||
}
|
||||
|
||||
/* Helper for getTaintForStep() */
|
||||
pragma[noinline]
|
||||
deprecated private predicate json_subscript_taint(
|
||||
SubscriptNode sub, ControlFlowNode obj, ExternalJsonKind seq, TaintKind key
|
||||
) {
|
||||
sub.isLoad() and
|
||||
sub.getObject() = obj and
|
||||
key = seq.getValue()
|
||||
}
|
||||
|
||||
deprecated private predicate json_load(ControlFlowNode fromnode, CallNode tonode) {
|
||||
tonode = Value::named("json.loads").getACall() and
|
||||
tonode.getArg(0) = fromnode
|
||||
}
|
||||
|
||||
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.
|
||||
exists(Value urlsplit |
|
||||
(
|
||||
urlsplit = Value::named("six.moves.urllib.parse.urlsplit")
|
||||
or
|
||||
// Python 2
|
||||
urlsplit = Value::named("urlparse.urlsplit")
|
||||
or
|
||||
// Python 3
|
||||
urlsplit = Value::named("urllib.parse.urlsplit")
|
||||
) and
|
||||
tonode = urlsplit.getACall() and
|
||||
tonode.getArg(0) = fromnode
|
||||
)
|
||||
}
|
||||
|
||||
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.
|
||||
exists(Value urlparse |
|
||||
(
|
||||
urlparse = Value::named("six.moves.urllib.parse.urlparse")
|
||||
or
|
||||
// Python 2
|
||||
urlparse = Value::named("urlparse.urlparse")
|
||||
or
|
||||
// Python 3
|
||||
urlparse = Value::named("urllib.parse.urlparse")
|
||||
) and
|
||||
tonode = urlparse.getACall() and
|
||||
tonode.getArg(0) = fromnode
|
||||
)
|
||||
}
|
||||
|
||||
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.
|
||||
exists(Value parse_qs |
|
||||
(
|
||||
parse_qs = Value::named("six.moves.urllib.parse.parse_qs")
|
||||
or
|
||||
// Python 2
|
||||
parse_qs = Value::named("urlparse.parse_qs")
|
||||
or
|
||||
// Python 2 deprecated version of `urlparse.parse_qs`
|
||||
parse_qs = Value::named("cgi.parse_qs")
|
||||
or
|
||||
// Python 3
|
||||
parse_qs = Value::named("urllib.parse.parse_qs")
|
||||
) and
|
||||
tonode = parse_qs.getACall() and
|
||||
(
|
||||
tonode.getArg(0) = fromnode
|
||||
or
|
||||
tonode.getArgByName("qs") = fromnode
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
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.
|
||||
exists(Value parse_qsl |
|
||||
(
|
||||
parse_qsl = Value::named("six.moves.urllib.parse.parse_qsl")
|
||||
or
|
||||
// Python 2
|
||||
parse_qsl = Value::named("urlparse.parse_qsl")
|
||||
or
|
||||
// Python 2 deprecated version of `urlparse.parse_qsl`
|
||||
parse_qsl = Value::named("cgi.parse_qsl")
|
||||
or
|
||||
// Python 3
|
||||
parse_qsl = Value::named("urllib.parse.parse_qsl")
|
||||
) and
|
||||
tonode = parse_qsl.getACall() and
|
||||
(
|
||||
tonode.getArg(0) = fromnode
|
||||
or
|
||||
tonode.getArgByName("qs") = fromnode
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/** A kind of "taint", representing an open file-like object from an external source. */
|
||||
deprecated class ExternalFileObject extends TaintKind {
|
||||
ExternalStringKind valueKind;
|
||||
|
||||
ExternalFileObject() { this = "file[" + valueKind + "]" }
|
||||
|
||||
/** Gets the taint kind for the contents of this file */
|
||||
TaintKind getValue() { result = valueKind }
|
||||
|
||||
override TaintKind getTaintOfMethodResult(string name) {
|
||||
name in ["read", "readline"] and result = this.getValue()
|
||||
or
|
||||
name = "readlines" and result.(SequenceKind).getItem() = this.getValue()
|
||||
}
|
||||
|
||||
override TaintKind getTaintForIteration() { result = this.getValue() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Temporary sanitizer for the tainted result from `urlsplit` and `urlparse`. Can be used to reduce FPs until
|
||||
* we have better support for namedtuples.
|
||||
*
|
||||
* Will clear **all** taint on a test of the kind. That is, on the true edge of any matching test,
|
||||
* all fields/indexes will be cleared of taint.
|
||||
*
|
||||
* Handles:
|
||||
* - `if splitres.netloc == "KNOWN_VALUE"`
|
||||
* - `if splitres[0] == "KNOWN_VALUE"`
|
||||
*/
|
||||
deprecated 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) {
|
||||
(
|
||||
taint instanceof ExternalUrlSplitResult
|
||||
or
|
||||
taint instanceof ExternalUrlParseResult
|
||||
) and
|
||||
exists(ControlFlowNode full_use |
|
||||
full_use.(SubscriptNode).getObject() = test.getInput().getAUse()
|
||||
or
|
||||
full_use.(AttrNode).getObject() = test.getInput().getAUse()
|
||||
|
|
||||
this.clears_taint(full_use, test.getTest(), test.getSense())
|
||||
)
|
||||
}
|
||||
|
||||
private predicate clears_taint(ControlFlowNode tainted, ControlFlowNode test, boolean sense) {
|
||||
this.test_equality_with_const(test, tainted, sense)
|
||||
or
|
||||
this.test_in_const_seq(test, tainted, sense)
|
||||
or
|
||||
test.(UnaryExprNode).getNode().getOp() instanceof Not and
|
||||
exists(ControlFlowNode nested_test |
|
||||
nested_test = test.(UnaryExprNode).getOperand() and
|
||||
this.clears_taint(tainted, nested_test, sense.booleanNot())
|
||||
)
|
||||
}
|
||||
|
||||
/** 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 |
|
||||
(
|
||||
cmp.operands(const, op, tainted)
|
||||
or
|
||||
cmp.operands(tainted, op, const)
|
||||
) and
|
||||
(
|
||||
op instanceof Eq and sense = true
|
||||
or
|
||||
op instanceof NotEq and sense = false
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/** 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
|
||||
)
|
||||
|
|
||||
cmp.operands(tainted, op, const_seq) and
|
||||
(
|
||||
op instanceof In and sense = true
|
||||
or
|
||||
op instanceof NotIn and sense = false
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
import python
|
||||
import External
|
||||
|
||||
/**
|
||||
* A kind of taint representing an externally controlled string.
|
||||
* This class is a simple sub-class of `ExternalStringKind`.
|
||||
*/
|
||||
deprecated class UntrustedStringKind extends ExternalStringKind {
|
||||
UntrustedStringKind() { this = "externally controlled string" }
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
import semmle.python.web.client.StdLib
|
||||
import semmle.python.web.client.Requests
|
||||
@@ -1,119 +0,0 @@
|
||||
import python
|
||||
import semmle.python.dataflow.Implementation
|
||||
import semmle.python.security.strings.External
|
||||
import HttpConstants
|
||||
|
||||
/** Generic taint source from a http request */
|
||||
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
|
||||
*/
|
||||
deprecated class WsgiEnvironment extends TaintKind {
|
||||
WsgiEnvironment() { this = "wsgi.environment" }
|
||||
|
||||
override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) {
|
||||
result = this and Implementation::copyCall(fromnode, tonode)
|
||||
or
|
||||
result = this and
|
||||
tonode.(CallNode).getFunction().pointsTo(ClassValue::dict()) and
|
||||
tonode.(CallNode).getArg(0) = fromnode
|
||||
or
|
||||
exists(Value key, string text |
|
||||
tonode.(CallNode).getFunction().(AttrNode).getObject("get") = fromnode and
|
||||
tonode.(CallNode).getArg(0).pointsTo(key)
|
||||
or
|
||||
tonode.(SubscriptNode).getObject() = fromnode and
|
||||
tonode.isLoad() and
|
||||
tonode.(SubscriptNode).getIndex().pointsTo(key)
|
||||
|
|
||||
key = Value::forString(text) and
|
||||
result instanceof ExternalStringKind and
|
||||
(
|
||||
text = "QUERY_STRING" or
|
||||
text = "PATH_INFO" or
|
||||
text.matches("HTTP\\_%")
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A standard morsel object from a HTTP request, a value in a cookie,
|
||||
* typically an instance of `http.cookies.Morsel`
|
||||
*/
|
||||
deprecated class UntrustedMorsel extends TaintKind {
|
||||
UntrustedMorsel() { this = "http.Morsel" }
|
||||
|
||||
override TaintKind getTaintOfAttribute(string name) {
|
||||
result instanceof ExternalStringKind and
|
||||
name = "value"
|
||||
}
|
||||
}
|
||||
|
||||
/** A standard cookie object from a HTTP request, typically an instance of `http.cookies.SimpleCookie` */
|
||||
deprecated class UntrustedCookie extends TaintKind {
|
||||
UntrustedCookie() { this = "http.Cookie" }
|
||||
|
||||
override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) {
|
||||
tonode.(SubscriptNode).getObject() = fromnode and
|
||||
result instanceof UntrustedMorsel
|
||||
}
|
||||
}
|
||||
|
||||
abstract deprecated class CookieOperation extends @py_flow_node {
|
||||
/** Gets a textual representation of this element. */
|
||||
abstract string toString();
|
||||
|
||||
abstract ControlFlowNode getKey();
|
||||
|
||||
abstract ControlFlowNode getValue();
|
||||
}
|
||||
|
||||
abstract deprecated class CookieGet extends CookieOperation { }
|
||||
|
||||
abstract deprecated class CookieSet extends CookieOperation { }
|
||||
|
||||
/** Generic taint sink in a http response */
|
||||
abstract deprecated class HttpResponseTaintSink extends TaintSink {
|
||||
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
|
||||
}
|
||||
|
||||
abstract deprecated class HttpRedirectTaintSink extends TaintSink {
|
||||
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
|
||||
}
|
||||
|
||||
deprecated module Client {
|
||||
// TODO: user-input in other than URL:
|
||||
// - `data`, `json` for `requests.post`
|
||||
// - `body` for `HTTPConnection.request`
|
||||
// - headers?
|
||||
// TODO: Add more library support
|
||||
// - urllib3 https://github.com/urllib3/urllib3
|
||||
// - httpx https://github.com/encode/httpx
|
||||
/**
|
||||
* An outgoing http request
|
||||
*
|
||||
* For example:
|
||||
* conn = HTTPConnection('example.com')
|
||||
* conn.request('GET', '/path')
|
||||
*/
|
||||
abstract class HttpRequest extends ControlFlowNode {
|
||||
/**
|
||||
* Get any ControlFlowNode that is used to construct the final URL.
|
||||
*
|
||||
* In the HTTPConnection example, there is a result for both `'example.com'` and for `'/path'`.
|
||||
*/
|
||||
abstract ControlFlowNode getAUrlPart();
|
||||
|
||||
abstract string getMethodUpper();
|
||||
}
|
||||
|
||||
/** Taint sink for the URL-part of an outgoing http request */
|
||||
class HttpRequestUrlTaintSink extends TaintSink {
|
||||
HttpRequestUrlTaintSink() { this = any(HttpRequest r).getAUrlPart() }
|
||||
|
||||
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
/** Gets an HTTP verb, in upper case */
|
||||
deprecated string httpVerb() {
|
||||
result in ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", "HEAD"]
|
||||
}
|
||||
|
||||
/** Gets an HTTP verb, in lower case */
|
||||
deprecated string httpVerbLower() { result = httpVerb().toLowerCase() }
|
||||
@@ -1,7 +0,0 @@
|
||||
import python
|
||||
import semmle.python.security.strings.Basic
|
||||
import semmle.python.web.django.Redirect
|
||||
import semmle.python.web.flask.Redirect
|
||||
import semmle.python.web.tornado.Redirect
|
||||
import semmle.python.web.pyramid.Redirect
|
||||
import semmle.python.web.bottle.Redirect
|
||||
@@ -1,10 +0,0 @@
|
||||
import semmle.python.web.django.Request
|
||||
import semmle.python.web.flask.Request
|
||||
import semmle.python.web.tornado.Request
|
||||
import semmle.python.web.pyramid.Request
|
||||
import semmle.python.web.twisted.Request
|
||||
import semmle.python.web.bottle.Request
|
||||
import semmle.python.web.turbogears.Request
|
||||
import semmle.python.web.falcon.Request
|
||||
import semmle.python.web.cherrypy.Request
|
||||
import semmle.python.web.stdlib.Request
|
||||
@@ -1,10 +0,0 @@
|
||||
import semmle.python.web.django.Response
|
||||
import semmle.python.web.flask.Response
|
||||
import semmle.python.web.pyramid.Response
|
||||
import semmle.python.web.tornado.Response
|
||||
import semmle.python.web.twisted.Response
|
||||
import semmle.python.web.bottle.Response
|
||||
import semmle.python.web.turbogears.Response
|
||||
import semmle.python.web.falcon.Response
|
||||
import semmle.python.web.cherrypy.Response
|
||||
import semmle.python.web.stdlib.Response
|
||||
@@ -1,46 +0,0 @@
|
||||
import python
|
||||
import semmle.python.web.Http
|
||||
import semmle.python.types.Extensions
|
||||
|
||||
/** Gets the bottle module */
|
||||
deprecated ModuleValue theBottleModule() { result = Module::named("bottle") }
|
||||
|
||||
/** Gets the bottle.Bottle class */
|
||||
deprecated ClassValue theBottleClass() { result = theBottleModule().attr("Bottle") }
|
||||
|
||||
/**
|
||||
* Holds if `route` is routed to `func`
|
||||
* by decorating `func` with `app.route(route)` or `route(route)`
|
||||
*/
|
||||
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))
|
||||
|
|
||||
(name = "route" or name = httpVerbLower()) and
|
||||
decorator_call.getFunction() = route_call and
|
||||
route_call.getArg(0) = route and
|
||||
decorator_call.getArg(0).getNode().(FunctionExpr).getInnerScope() = func
|
||||
)
|
||||
}
|
||||
|
||||
deprecated class BottleRoute extends ControlFlowNode {
|
||||
BottleRoute() { bottle_route(this, _, _) }
|
||||
|
||||
string getUrl() {
|
||||
exists(StrConst url |
|
||||
bottle_route(this, url.getAFlowNode(), _) and
|
||||
result = url.getText()
|
||||
)
|
||||
}
|
||||
|
||||
Function getFunction() { bottle_route(this, _, result) }
|
||||
|
||||
Parameter getANamedArgument() {
|
||||
exists(string name, Function func |
|
||||
func = this.getFunction() and
|
||||
func.getArgByName(name) = result and
|
||||
this.getUrl().matches("%<" + name + ">%")
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
/**
|
||||
* Provides class representing the `bottle.redirect` function.
|
||||
* This module is intended to be imported into a taint-tracking query
|
||||
* to extend `TaintSink`.
|
||||
*/
|
||||
|
||||
import python
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.security.strings.Basic
|
||||
import semmle.python.web.bottle.General
|
||||
|
||||
deprecated FunctionValue bottle_redirect() { result = theBottleModule().attr("redirect") }
|
||||
|
||||
/**
|
||||
* An argument to the `bottle.redirect` function.
|
||||
*/
|
||||
deprecated class BottleRedirect extends TaintSink {
|
||||
override string toString() { result = "bottle.redirect" }
|
||||
|
||||
BottleRedirect() {
|
||||
exists(CallNode call |
|
||||
bottle_redirect().getACall() = call and
|
||||
this = call.getAnArg()
|
||||
)
|
||||
}
|
||||
|
||||
override predicate sinks(TaintKind kind) { kind instanceof StringKind }
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
import python
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.security.strings.External
|
||||
import semmle.python.web.Http
|
||||
import semmle.python.web.bottle.General
|
||||
|
||||
deprecated private Value theBottleRequestObject() { result = theBottleModule().attr("request") }
|
||||
|
||||
deprecated class BottleRequestKind extends TaintKind {
|
||||
BottleRequestKind() { this = "bottle.request" }
|
||||
|
||||
override TaintKind getTaintOfAttribute(string name) {
|
||||
result instanceof BottleFormsDict and
|
||||
(name = "cookies" or name = "query" or name = "form")
|
||||
or
|
||||
result instanceof ExternalStringKind and
|
||||
(name = "query_string" or name = "url_args")
|
||||
or
|
||||
result.(DictKind).getValue() instanceof FileUpload and
|
||||
name = "files"
|
||||
}
|
||||
}
|
||||
|
||||
deprecated private class RequestSource extends HttpRequestTaintSource {
|
||||
RequestSource() { this.(ControlFlowNode).pointsTo(theBottleRequestObject()) }
|
||||
|
||||
override predicate isSourceOf(TaintKind kind) { kind instanceof BottleRequestKind }
|
||||
}
|
||||
|
||||
deprecated class BottleFormsDict extends TaintKind {
|
||||
BottleFormsDict() { this = "bottle.FormsDict" }
|
||||
|
||||
override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) {
|
||||
/* Cannot use `getTaintOfAttribute(name)` as it wouldn't bind `name` */
|
||||
exists(string name |
|
||||
fromnode = tonode.(AttrNode).getObject(name) and
|
||||
result instanceof ExternalStringKind
|
||||
|
|
||||
name != "get" and name != "getunicode" and name != "getall"
|
||||
)
|
||||
}
|
||||
|
||||
override TaintKind getTaintOfMethodResult(string name) {
|
||||
(name = "get" or name = "getunicode") and
|
||||
result instanceof ExternalStringKind
|
||||
or
|
||||
name = "getall" and result.(SequenceKind).getItem() instanceof ExternalStringKind
|
||||
}
|
||||
}
|
||||
|
||||
deprecated class FileUpload extends TaintKind {
|
||||
FileUpload() { this = "bottle.FileUpload" }
|
||||
|
||||
override TaintKind getTaintOfAttribute(string name) {
|
||||
name = "filename" and result instanceof ExternalStringKind
|
||||
or
|
||||
name = "raw_filename" and result instanceof ExternalStringKind
|
||||
or
|
||||
name = "file" and result instanceof UntrustedFile
|
||||
}
|
||||
}
|
||||
|
||||
deprecated class UntrustedFile extends TaintKind {
|
||||
UntrustedFile() { this = "Untrusted file" }
|
||||
}
|
||||
|
||||
//
|
||||
// TO DO.. File uploads -- Should check about file uploads for other frameworks as well.
|
||||
// Move UntrustedFile to shared location
|
||||
//
|
||||
/** A parameter to a bottle request handler function */
|
||||
deprecated class BottleRequestParameter extends HttpRequestTaintSource {
|
||||
BottleRequestParameter() {
|
||||
exists(BottleRoute route | route.getANamedArgument() = this.(ControlFlowNode).getNode())
|
||||
}
|
||||
|
||||
override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind }
|
||||
|
||||
override string toString() { result = "bottle handler function argument" }
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
import python
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.security.strings.Untrusted
|
||||
import semmle.python.web.Http
|
||||
import semmle.python.web.bottle.General
|
||||
|
||||
/**
|
||||
* A bottle.Response object
|
||||
* This isn't really a "taint", but we use the value tracking machinery to
|
||||
* track the flow of response objects.
|
||||
*/
|
||||
deprecated class BottleResponse extends TaintKind {
|
||||
BottleResponse() { this = "bottle.response" }
|
||||
}
|
||||
|
||||
deprecated private Value theBottleResponseObject() { result = theBottleModule().attr("response") }
|
||||
|
||||
deprecated class BottleResponseBodyAssignment extends HttpResponseTaintSink {
|
||||
BottleResponseBodyAssignment() {
|
||||
exists(DefinitionNode lhs |
|
||||
lhs.getValue() = this and
|
||||
lhs.(AttrNode).getObject("body").pointsTo(theBottleResponseObject())
|
||||
)
|
||||
}
|
||||
|
||||
override predicate sinks(TaintKind kind) { kind instanceof StringKind }
|
||||
}
|
||||
|
||||
deprecated class BottleHandlerFunctionResult extends HttpResponseTaintSink {
|
||||
BottleHandlerFunctionResult() {
|
||||
exists(BottleRoute route, Return ret |
|
||||
ret.getScope() = route.getFunction() and
|
||||
ret.getValue().getAFlowNode() = this
|
||||
)
|
||||
}
|
||||
|
||||
override predicate sinks(TaintKind kind) { kind instanceof StringKind }
|
||||
|
||||
override string toString() { result = "bottle handler function result" }
|
||||
}
|
||||
|
||||
deprecated class BottleCookieSet extends CookieSet, CallNode {
|
||||
BottleCookieSet() {
|
||||
any(BottleResponse r).taints(this.getFunction().(AttrNode).getObject("set_cookie"))
|
||||
}
|
||||
|
||||
override string toString() { result = CallNode.super.toString() }
|
||||
|
||||
override ControlFlowNode getKey() { result = this.getArg(0) }
|
||||
|
||||
override ControlFlowNode getValue() { result = this.getArg(1) }
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
import python
|
||||
import semmle.python.web.Http
|
||||
|
||||
deprecated module CherryPy {
|
||||
FunctionValue expose() { result = Value::named("cherrypy.expose") }
|
||||
}
|
||||
|
||||
deprecated class CherryPyExposedFunction extends Function {
|
||||
CherryPyExposedFunction() {
|
||||
this.getADecorator().pointsTo(CherryPy::expose())
|
||||
or
|
||||
this.getADecorator().(Call).getFunc().pointsTo(CherryPy::expose())
|
||||
}
|
||||
}
|
||||
|
||||
deprecated class CherryPyRoute extends CallNode {
|
||||
CherryPyRoute() {
|
||||
/* cherrypy.quickstart(root, script_name, config) */
|
||||
Value::named("cherrypy.quickstart").(FunctionValue).getACall() = this
|
||||
or
|
||||
/* cherrypy.tree.mount(root, script_name, config) */
|
||||
this.getFunction().(AttrNode).getObject("mount").pointsTo(Value::named("cherrypy.tree"))
|
||||
}
|
||||
|
||||
ClassValue getAppClass() {
|
||||
this.getArg(0).pointsTo().getClass() = result
|
||||
or
|
||||
this.getArgByName("root").pointsTo().getClass() = result
|
||||
}
|
||||
|
||||
string getPath() {
|
||||
exists(Value path | path = Value::forString(result) |
|
||||
this.getArg(1).pointsTo(path)
|
||||
or
|
||||
this.getArgByName("script_name").pointsTo(path)
|
||||
)
|
||||
}
|
||||
|
||||
ClassValue getConfig() {
|
||||
this.getArg(2).pointsTo().getClass() = result
|
||||
or
|
||||
this.getArgByName("config").pointsTo().getClass() = result
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
import python
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.security.strings.Basic
|
||||
import semmle.python.web.Http
|
||||
import semmle.python.web.cherrypy.General
|
||||
|
||||
/** The cherrypy.request local-proxy object */
|
||||
deprecated class CherryPyRequest extends TaintKind {
|
||||
CherryPyRequest() { this = "cherrypy.request" }
|
||||
|
||||
override TaintKind getTaintOfAttribute(string name) {
|
||||
name = "params" and result instanceof ExternalStringDictKind
|
||||
or
|
||||
name = "cookie" and result instanceof UntrustedCookie
|
||||
}
|
||||
|
||||
override TaintKind getTaintOfMethodResult(string name) {
|
||||
name in ["getHeader", "getCookie", "getUser", "getPassword"] and
|
||||
result instanceof ExternalStringKind
|
||||
}
|
||||
}
|
||||
|
||||
deprecated class CherryPyExposedFunctionParameter extends HttpRequestTaintSource {
|
||||
CherryPyExposedFunctionParameter() {
|
||||
exists(Parameter p |
|
||||
p = any(CherryPyExposedFunction f).getAnArg() and
|
||||
not p.isSelf() and
|
||||
p.asName().getAFlowNode() = this
|
||||
)
|
||||
}
|
||||
|
||||
override string toString() { result = "CherryPy handler function parameter" }
|
||||
|
||||
override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind }
|
||||
}
|
||||
|
||||
deprecated class CherryPyRequestSource extends HttpRequestTaintSource {
|
||||
CherryPyRequestSource() { this.(ControlFlowNode).pointsTo(Value::named("cherrypy.request")) }
|
||||
|
||||
override predicate isSourceOf(TaintKind kind) { kind instanceof CherryPyRequest }
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
import python
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.security.strings.Untrusted
|
||||
import semmle.python.web.Http
|
||||
import semmle.python.web.cherrypy.General
|
||||
|
||||
deprecated class CherryPyExposedFunctionResult extends HttpResponseTaintSink {
|
||||
CherryPyExposedFunctionResult() {
|
||||
exists(Return ret |
|
||||
ret.getScope() instanceof CherryPyExposedFunction and
|
||||
ret.getValue().getAFlowNode() = this
|
||||
)
|
||||
}
|
||||
|
||||
override predicate sinks(TaintKind kind) { kind instanceof StringKind }
|
||||
|
||||
override string toString() { result = "cherrypy handler function result" }
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
/**
|
||||
* Modeling outgoing HTTP requests using the `requests` package
|
||||
* https://pypi.org/project/requests/
|
||||
*/
|
||||
|
||||
import python
|
||||
private import semmle.python.web.Http
|
||||
|
||||
deprecated class RequestsHttpRequest extends Client::HttpRequest, CallNode {
|
||||
CallableValue func;
|
||||
string method;
|
||||
|
||||
RequestsHttpRequest() {
|
||||
method = httpVerbLower() and
|
||||
func = Module::named("requests").attr(method) and
|
||||
this = func.getACall()
|
||||
}
|
||||
|
||||
override ControlFlowNode getAUrlPart() { result = func.getNamedArgumentForCall(this, "url") }
|
||||
|
||||
override string getMethodUpper() { result = method.toUpperCase() }
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
import python
|
||||
private import semmle.python.web.Http
|
||||
|
||||
deprecated ClassValue httpConnectionClass() {
|
||||
// Python 2
|
||||
result = Value::named("httplib.HTTPConnection")
|
||||
or
|
||||
result = Value::named("httplib.HTTPSConnection")
|
||||
or
|
||||
// Python 3
|
||||
result = Value::named("http.client.HTTPConnection")
|
||||
or
|
||||
result = Value::named("http.client.HTTPSConnection")
|
||||
or
|
||||
// six
|
||||
result = Value::named("six.moves.http_client.HTTPConnection")
|
||||
or
|
||||
result = Value::named("six.moves.http_client.HTTPSConnection")
|
||||
}
|
||||
|
||||
deprecated class HttpConnectionHttpRequest extends Client::HttpRequest, CallNode {
|
||||
CallNode constructor_call;
|
||||
CallableValue func;
|
||||
|
||||
HttpConnectionHttpRequest() {
|
||||
exists(ClassValue cls, AttrNode call_origin, Value constructor_call_value |
|
||||
cls = httpConnectionClass() and
|
||||
func = cls.lookup("request") and
|
||||
this = func.getACall() and
|
||||
// since you can do `r = conn.request; r('GET', path)`, we need to find the origin
|
||||
this.getFunction().pointsTo(_, _, call_origin) and
|
||||
// Since HTTPSConnection is a subtype of HTTPConnection, up until this point, `cls` could be either class,
|
||||
// because `HTTPSConnection.request == HTTPConnection.request`. To avoid generating 2 results, we filter
|
||||
// on the actual class used as the constructor
|
||||
call_origin.getObject().pointsTo(_, constructor_call_value, constructor_call) and
|
||||
cls = constructor_call_value.getClass() and
|
||||
constructor_call = cls.getACall()
|
||||
)
|
||||
}
|
||||
|
||||
override ControlFlowNode getAUrlPart() {
|
||||
result = func.getNamedArgumentForCall(this, "url")
|
||||
or
|
||||
result = constructor_call.getArg(0)
|
||||
or
|
||||
result = constructor_call.getArgByName("host")
|
||||
}
|
||||
|
||||
override string getMethodUpper() {
|
||||
exists(string method |
|
||||
result = method.toUpperCase() and
|
||||
func.getNamedArgumentForCall(this, "method").pointsTo(Value::forString(method))
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
import python
|
||||
import semmle.python.security.injection.Sql
|
||||
|
||||
/**
|
||||
* A taint kind representing a django cursor object.
|
||||
*/
|
||||
deprecated class DjangoDbCursor extends DbCursor {
|
||||
DjangoDbCursor() { this = "django.db.connection.cursor" }
|
||||
}
|
||||
|
||||
deprecated private Value theDjangoConnectionObject() {
|
||||
result = Value::named("django.db.connection")
|
||||
}
|
||||
|
||||
/**
|
||||
* A kind of taint source representing sources of django cursor objects.
|
||||
*/
|
||||
deprecated class DjangoDbCursorSource extends DbConnectionSource {
|
||||
DjangoDbCursorSource() {
|
||||
exists(AttrNode cursor |
|
||||
this.(CallNode).getFunction() = cursor and
|
||||
cursor.getObject("cursor").pointsTo(theDjangoConnectionObject())
|
||||
)
|
||||
}
|
||||
|
||||
override string toString() { result = "django.db.connection.cursor" }
|
||||
|
||||
override predicate isSourceOf(TaintKind kind) { kind instanceof DjangoDbCursor }
|
||||
}
|
||||
|
||||
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.
|
||||
*/
|
||||
deprecated class DjangoRawSqlSink extends SqlInjectionSink {
|
||||
DjangoRawSqlSink() {
|
||||
exists(CallNode call |
|
||||
call = theDjangoRawSqlClass().getACall() and
|
||||
this = call.getArg(0)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
|
||||
|
||||
override string toString() { result = "django.db.models.expressions.RawSQL(sink,...)" }
|
||||
}
|
||||
@@ -1,136 +0,0 @@
|
||||
import python
|
||||
import semmle.python.regex
|
||||
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 deprecated class DjangoRoute extends CallNode {
|
||||
DjangoViewHandler getViewHandler() {
|
||||
result = view_handler_from_view_arg(this.getArg(1))
|
||||
or
|
||||
result = view_handler_from_view_arg(this.getArgByName("view"))
|
||||
}
|
||||
|
||||
abstract string getANamedArgument();
|
||||
|
||||
/**
|
||||
* Get the number of positional arguments that will be passed to the view.
|
||||
* Will only return a result if there are no named arguments.
|
||||
*/
|
||||
abstract int getNumPositionalArguments();
|
||||
}
|
||||
|
||||
/**
|
||||
* For function based views -- also see `DjangoClassBasedViewHandler`
|
||||
* https://docs.djangoproject.com/en/1.11/topics/http/views/
|
||||
* https://docs.djangoproject.com/en/3.0/topics/http/views/
|
||||
*/
|
||||
deprecated class DjangoViewHandler extends PythonFunctionValue {
|
||||
/** Gets the index of the 'request' argument */
|
||||
int getRequestArgIndex() { result = 0 }
|
||||
}
|
||||
|
||||
/**
|
||||
* Class based views
|
||||
* https://docs.djangoproject.com/en/1.11/topics/class-based-views/
|
||||
* https://docs.djangoproject.com/en/3.0/topics/class-based-views/
|
||||
*/
|
||||
deprecated private class DjangoViewClass extends ClassValue {
|
||||
DjangoViewClass() {
|
||||
Value::named("django.views.generic.View") = this.getASuperType()
|
||||
or
|
||||
Value::named("django.views.View") = this.getASuperType()
|
||||
}
|
||||
}
|
||||
|
||||
deprecated class DjangoClassBasedViewHandler extends DjangoViewHandler {
|
||||
DjangoClassBasedViewHandler() { exists(DjangoViewClass cls | cls.lookup(httpVerbLower()) = this) }
|
||||
|
||||
override int getRequestArgIndex() {
|
||||
// due to `self` being the first parameter
|
||||
result = 1
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
deprecated private DjangoViewHandler view_handler_from_view_arg(ControlFlowNode view_arg) {
|
||||
// Function-based view
|
||||
result = view_arg.pointsTo()
|
||||
or
|
||||
// Class-based view
|
||||
exists(ClassValue cls |
|
||||
cls = view_arg.(CallNode).getFunction().(AttrNode).getObject("as_view").pointsTo() and
|
||||
result = cls.lookup(httpVerbLower())
|
||||
)
|
||||
}
|
||||
|
||||
// We need this "dummy" class, since otherwise the regex argument would not be considered
|
||||
// a regex (RegexString is abstract)
|
||||
deprecated class DjangoRouteRegex extends RegexString {
|
||||
DjangoRouteRegex() { exists(DjangoRegexRoute route | route.getRouteArg() = this.getAFlowNode()) }
|
||||
}
|
||||
|
||||
deprecated class DjangoRegexRoute extends DjangoRoute {
|
||||
ControlFlowNode route;
|
||||
|
||||
DjangoRegexRoute() {
|
||||
exists(FunctionValue route_maker |
|
||||
// Django 1.x: https://docs.djangoproject.com/en/1.11/ref/urls/#django.conf.urls.url
|
||||
Value::named("django.conf.urls.url") = route_maker and
|
||||
route_maker.getArgumentForCall(this, 0) = route
|
||||
)
|
||||
or
|
||||
// Django 2.x and 3.x: https://docs.djangoproject.com/en/3.0/ref/urls/#re-path
|
||||
this = Value::named("django.urls.re_path").getACall() and
|
||||
(
|
||||
route = this.getArg(0)
|
||||
or
|
||||
route = this.getArgByName("route")
|
||||
)
|
||||
}
|
||||
|
||||
ControlFlowNode getRouteArg() { result = route }
|
||||
|
||||
override string getANamedArgument() {
|
||||
exists(DjangoRouteRegex regex | regex.getAFlowNode() = route |
|
||||
result = regex.getGroupName(_, _)
|
||||
)
|
||||
}
|
||||
|
||||
override int getNumPositionalArguments() {
|
||||
not exists(this.getANamedArgument()) and
|
||||
exists(DjangoRouteRegex regex | regex.getAFlowNode() = route |
|
||||
result = count(regex.getGroupNumber(_, _))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
deprecated class DjangoPathRoute extends DjangoRoute {
|
||||
ControlFlowNode route;
|
||||
|
||||
DjangoPathRoute() {
|
||||
// Django 2.x and 3.x: https://docs.djangoproject.com/en/3.0/ref/urls/#path
|
||||
this = Value::named("django.urls.path").getACall() and
|
||||
(
|
||||
route = this.getArg(0)
|
||||
or
|
||||
route = this.getArgByName("route")
|
||||
)
|
||||
}
|
||||
|
||||
override string getANamedArgument() {
|
||||
// regexp taken from django:
|
||||
// https://github.com/django/django/blob/7d1bf29977bb368d7c28e7c6eb146db3b3009ae7/django/urls/resolvers.py#L199
|
||||
exists(StrConst route_str, string match |
|
||||
route_str = route.getNode() and
|
||||
match = route_str.getText().regexpFind("<(?:(?<converter>[^>:]+):)?(?<parameter>\\w+)>", _, _) and
|
||||
result = match.regexpCapture("<(?:(?<converter>[^>:]+):)?(?<parameter>\\w+)>", 2)
|
||||
)
|
||||
}
|
||||
|
||||
override int getNumPositionalArguments() { none() }
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
import python
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.security.strings.Basic
|
||||
import semmle.python.web.Http
|
||||
import semmle.python.security.injection.Sql
|
||||
|
||||
/** A django model class */
|
||||
deprecated class DjangoModel extends ClassValue {
|
||||
DjangoModel() { Value::named("django.db.models.Model") = this.getASuperType() }
|
||||
}
|
||||
|
||||
/** A "taint" for django database tables */
|
||||
deprecated class DjangoDbTableObjects extends TaintKind {
|
||||
DjangoDbTableObjects() { this = "django.db.models.Model.objects" }
|
||||
|
||||
override TaintKind getTaintOfMethodResult(string name) {
|
||||
result = this and
|
||||
name in [
|
||||
"filter", "exclude", "none", "all", "union", "intersection", "difference", "select_related",
|
||||
"prefetch_related", "extra", "defer", "only", "annotate", "using", "select_for_update",
|
||||
"raw", "order_by", "reverse", "distinct", "values", "values_list", "dates", "datetimes"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
/** Django model objects, which are sources of django database table "taint" */
|
||||
deprecated class DjangoModelObjects extends TaintSource {
|
||||
DjangoModelObjects() {
|
||||
this.(AttrNode).isLoad() and this.(AttrNode).getObject("objects").pointsTo(any(DjangoModel m))
|
||||
}
|
||||
|
||||
override predicate isSourceOf(TaintKind kind) { kind instanceof DjangoDbTableObjects }
|
||||
|
||||
override string toString() { result = "django.db.models.Model.objects" }
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
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
|
||||
any(DjangoDbTableObjects objs).taints(queryset)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
|
||||
|
||||
override string toString() { result = "django.models.QuerySet.raw(sink,...)" }
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
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
|
||||
any(DjangoDbTableObjects objs).taints(queryset)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
|
||||
|
||||
override string toString() { result = "django.models.QuerySet.extra(sink,...)" }
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
/**
|
||||
* Provides class representing the `django.redirect` function.
|
||||
* This module is intended to be imported into a taint-tracking query
|
||||
* to extend `TaintSink`.
|
||||
*/
|
||||
|
||||
import python
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.security.strings.Basic
|
||||
private import semmle.python.web.django.Shared
|
||||
private import semmle.python.web.Http
|
||||
|
||||
/**
|
||||
* The URL argument for a call to the `django.shortcuts.redirect` function.
|
||||
*/
|
||||
deprecated class DjangoShortcutsRedirectSink extends HttpRedirectTaintSink {
|
||||
override string toString() { result = "DjangoShortcutsRedirectSink" }
|
||||
|
||||
DjangoShortcutsRedirectSink() {
|
||||
this = Value::named("django.shortcuts.redirect").(FunctionValue).getArgumentForCall(_, 0)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The URL argument when instantiating a Django Redirect Response.
|
||||
*/
|
||||
deprecated class DjangoRedirectResponseSink extends HttpRedirectTaintSink {
|
||||
DjangoRedirectResponseSink() {
|
||||
exists(CallNode call | call = any(DjangoRedirectResponseClass cls).getACall() |
|
||||
this = call.getArg(0)
|
||||
or
|
||||
this = call.getArgByName("redirect_to")
|
||||
)
|
||||
}
|
||||
|
||||
override string toString() { result = "DjangoRedirectResponseSink" }
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
import python
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.web.Http
|
||||
import semmle.python.web.django.General
|
||||
|
||||
/** A django.request.HttpRequest object */
|
||||
deprecated class DjangoRequest extends TaintKind {
|
||||
DjangoRequest() { this = "django.request.HttpRequest" }
|
||||
|
||||
override TaintKind getTaintOfAttribute(string name) {
|
||||
(name = "GET" or name = "POST") and
|
||||
result instanceof DjangoQueryDict
|
||||
}
|
||||
|
||||
override TaintKind getTaintOfMethodResult(string name) {
|
||||
(name = "body" or name = "path") and
|
||||
result instanceof ExternalStringKind
|
||||
}
|
||||
}
|
||||
|
||||
/* Helper for getTaintForStep() */
|
||||
pragma[noinline]
|
||||
deprecated private predicate subscript_taint(SubscriptNode sub, ControlFlowNode obj, TaintKind kind) {
|
||||
sub.getObject() = obj and
|
||||
kind instanceof ExternalStringKind
|
||||
}
|
||||
|
||||
/** A django.request.QueryDict object */
|
||||
deprecated class DjangoQueryDict extends TaintKind {
|
||||
DjangoQueryDict() { this = "django.http.request.QueryDict" }
|
||||
|
||||
override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) {
|
||||
this.taints(fromnode) and
|
||||
subscript_taint(tonode, fromnode, result)
|
||||
}
|
||||
|
||||
override TaintKind getTaintOfMethodResult(string name) {
|
||||
name = "get" and result instanceof ExternalStringKind
|
||||
}
|
||||
}
|
||||
|
||||
/** A Django request parameter */
|
||||
deprecated class DjangoRequestSource extends HttpRequestTaintSource {
|
||||
DjangoRequestSource() {
|
||||
exists(DjangoRoute route, DjangoViewHandler view, int request_arg_index |
|
||||
route.getViewHandler() = view and
|
||||
request_arg_index = view.getRequestArgIndex() and
|
||||
this = view.getScope().getArg(request_arg_index).asName().getAFlowNode()
|
||||
)
|
||||
}
|
||||
|
||||
override string toString() { result = "Django request source" }
|
||||
|
||||
override predicate isSourceOf(TaintKind kind) { kind instanceof DjangoRequest }
|
||||
}
|
||||
|
||||
/** An argument specified in a url routing table */
|
||||
deprecated class DjangoRequestParameter extends HttpRequestTaintSource {
|
||||
DjangoRequestParameter() {
|
||||
exists(DjangoRoute route, Function f, DjangoViewHandler view, int request_arg_index |
|
||||
route.getViewHandler() = view and
|
||||
request_arg_index = view.getRequestArgIndex() and
|
||||
f = view.getScope()
|
||||
|
|
||||
this.(ControlFlowNode).getNode() = f.getArgByName(route.getANamedArgument())
|
||||
or
|
||||
exists(int i | i >= 0 |
|
||||
i < route.getNumPositionalArguments() and
|
||||
// +1 because first argument is always the request
|
||||
this.(ControlFlowNode).getNode() = f.getArg(request_arg_index + 1 + i)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind }
|
||||
|
||||
override string toString() { result = "django.http.request.parameter" }
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
import python
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.security.strings.Basic
|
||||
private import semmle.python.web.django.Shared
|
||||
private import semmle.python.web.Http
|
||||
|
||||
/** INTERNAL class used for tracking a django response object. */
|
||||
deprecated private class DjangoResponseKind extends TaintKind {
|
||||
DjangoResponseKind() { this = "django.response.HttpResponse" }
|
||||
}
|
||||
|
||||
/** INTERNAL taint-source used for tracking a django response object. */
|
||||
deprecated private class DjangoResponseSource extends TaintSource {
|
||||
DjangoResponseSource() { exists(DjangoContentResponseClass cls | cls.getACall() = this) }
|
||||
|
||||
override predicate isSourceOf(TaintKind kind) { kind instanceof DjangoResponseKind }
|
||||
|
||||
override string toString() { result = "django.http.response.HttpResponse" }
|
||||
}
|
||||
|
||||
/** A write to a django response, which is vulnerable to external data (xss) */
|
||||
deprecated class DjangoResponseWrite extends HttpResponseTaintSink {
|
||||
DjangoResponseWrite() {
|
||||
exists(AttrNode meth, CallNode call |
|
||||
call.getFunction() = meth and
|
||||
any(DjangoResponseKind response).taints(meth.getObject("write")) and
|
||||
this = call.getArg(0)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate sinks(TaintKind kind) { kind instanceof StringKind }
|
||||
|
||||
override string toString() { result = "django.Response.write(...)" }
|
||||
}
|
||||
|
||||
/**
|
||||
* An argument to initialization of a django response.
|
||||
*/
|
||||
deprecated class DjangoResponseContent extends HttpResponseTaintSink {
|
||||
DjangoContentResponseClass cls;
|
||||
CallNode call;
|
||||
|
||||
DjangoResponseContent() {
|
||||
call = cls.getACall() and
|
||||
this = cls.getContentArg(call)
|
||||
}
|
||||
|
||||
override predicate sinks(TaintKind kind) { kind instanceof StringKind }
|
||||
|
||||
override string toString() { result = "django.Response(...)" }
|
||||
}
|
||||
|
||||
/**
|
||||
* An argument to initialization of a django response, which is vulnerable to external data (XSS).
|
||||
*/
|
||||
deprecated class DjangoResponseContentXSSVulnerable extends DjangoResponseContent {
|
||||
override DjangoXSSVulnerableResponseClass cls;
|
||||
|
||||
DjangoResponseContentXSSVulnerable() {
|
||||
not exists(cls.getContentTypeArg(call))
|
||||
or
|
||||
exists(StringValue s |
|
||||
cls.getContentTypeArg(call).pointsTo(s) and
|
||||
s.getText().matches("text/html%")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
deprecated class DjangoCookieSet extends CookieSet, CallNode {
|
||||
DjangoCookieSet() {
|
||||
any(DjangoResponseKind r).taints(this.getFunction().(AttrNode).getObject("set_cookie"))
|
||||
}
|
||||
|
||||
override string toString() { result = CallNode.super.toString() }
|
||||
|
||||
override ControlFlowNode getKey() { result = this.getArg(0) }
|
||||
|
||||
override ControlFlowNode getValue() { result = this.getArg(1) }
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
import python
|
||||
/*
|
||||
* Sanitizers
|
||||
* No django sanitizers implemented yet.
|
||||
*/
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
import python
|
||||
|
||||
/** A class that is a Django Redirect Response (subclass of `django.http.HttpResponseRedirectBase`). */
|
||||
deprecated class DjangoRedirectResponseClass extends ClassValue {
|
||||
DjangoRedirectResponseClass() {
|
||||
exists(ClassValue redirect_base |
|
||||
// version 1.x
|
||||
redirect_base = Value::named("django.http.response.HttpResponseRedirectBase")
|
||||
or
|
||||
// version 2.x and 3.x
|
||||
redirect_base = Value::named("django.http.HttpResponseRedirectBase")
|
||||
|
|
||||
this.getASuperType() = redirect_base
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A class that is a Django Response, which can contain content.
|
||||
* A subclass of `django.http.HttpResponse` that is not a `DjangoRedirectResponseClass`.
|
||||
*/
|
||||
deprecated class DjangoContentResponseClass extends ClassValue {
|
||||
ClassValue base;
|
||||
|
||||
DjangoContentResponseClass() {
|
||||
(
|
||||
// version 1.x
|
||||
base = Value::named("django.http.response.HttpResponse")
|
||||
or
|
||||
// version 2.x and 3.x
|
||||
// https://docs.djangoproject.com/en/2.2/ref/request-response/#httpresponse-objects
|
||||
base = Value::named("django.http.HttpResponse")
|
||||
) and
|
||||
this.getASuperType() = base
|
||||
}
|
||||
|
||||
// The reason these two methods are defined in this class (and not in the Sink
|
||||
// definition that uses this class), is that if we were to add support for
|
||||
// `django.http.response.HttpResponseNotAllowed` it would make much more sense to add
|
||||
// the custom logic in this class (or subclass), than to handle all of it in the sink
|
||||
// definition.
|
||||
/** Gets the `content` argument of a `call` to the constructor */
|
||||
ControlFlowNode getContentArg(CallNode call) { none() }
|
||||
|
||||
/** Gets the `content_type` argument of a `call` to the constructor */
|
||||
ControlFlowNode getContentTypeArg(CallNode call) { none() }
|
||||
}
|
||||
|
||||
/** A class that is a Django Response, and is vulnerable to XSS. */
|
||||
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.
|
||||
// It's not guaranteed to remove all FPs, or not to generate FNs, but compared to our
|
||||
// previous implementation that would treat 0-th argument to _any_ subclass as a sink,
|
||||
// this gets us much closer to reality.
|
||||
this.lookup("__init__") = base.lookup("__init__") and
|
||||
not this instanceof DjangoRedirectResponseClass
|
||||
}
|
||||
|
||||
override ControlFlowNode getContentArg(CallNode call) {
|
||||
result = call.getArg(0)
|
||||
or
|
||||
result = call.getArgByName("content")
|
||||
}
|
||||
|
||||
override ControlFlowNode getContentTypeArg(CallNode call) {
|
||||
result = call.getArg(1)
|
||||
or
|
||||
result = call.getArgByName("content_type")
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
import python
|
||||
import semmle.python.web.Http
|
||||
|
||||
/** Gets the falcon API class */
|
||||
deprecated ClassValue theFalconAPIClass() { result = Value::named("falcon.API") }
|
||||
|
||||
/** Holds if `route` is routed to `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
|
||||
}
|
||||
|
||||
deprecated private predicate route(FalconRoute route, Function target, string funcname) {
|
||||
route.getResourceClass().lookup("on_" + funcname).(FunctionValue).getScope() = target
|
||||
}
|
||||
|
||||
deprecated class FalconRoute extends ControlFlowNode {
|
||||
FalconRoute() { api_route(this, _, _) }
|
||||
|
||||
string getUrl() {
|
||||
exists(StrConst url |
|
||||
api_route(this, url.getAFlowNode(), _) and
|
||||
result = url.getText()
|
||||
)
|
||||
}
|
||||
|
||||
ClassValue getResourceClass() { api_route(this, _, result) }
|
||||
|
||||
FalconHandlerFunction getHandlerFunction(string method) { route(this, result, method) }
|
||||
}
|
||||
|
||||
deprecated class FalconHandlerFunction extends Function {
|
||||
FalconHandlerFunction() { route(_, this, _) }
|
||||
|
||||
private string methodName() { route(_, this, result) }
|
||||
|
||||
string getMethod() { result = this.methodName().toUpperCase() }
|
||||
|
||||
Parameter getRequest() { result = this.getArg(1) }
|
||||
|
||||
Parameter getResponse() { result = this.getArg(2) }
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
import python
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.web.Http
|
||||
import semmle.python.web.falcon.General
|
||||
|
||||
/** https://falcon.readthedocs.io/en/stable/api/request_and_response.html */
|
||||
deprecated class FalconRequest extends TaintKind {
|
||||
FalconRequest() { this = "falcon.request" }
|
||||
|
||||
override TaintKind getTaintOfAttribute(string name) {
|
||||
name = "env" and result instanceof WsgiEnvironment
|
||||
or
|
||||
result instanceof ExternalStringKind and
|
||||
name in ["uri", "url", "forwarded_uri", "relative_uri", "query_string"]
|
||||
or
|
||||
result instanceof ExternalStringDictKind and
|
||||
(name = "cookies" or name = "params")
|
||||
or
|
||||
name = "stream" and result instanceof ExternalFileObject
|
||||
}
|
||||
|
||||
override TaintKind getTaintOfMethodResult(string name) {
|
||||
name = "get_param" and result instanceof ExternalStringKind
|
||||
or
|
||||
name = "get_param_as_json" and result instanceof ExternalJsonKind
|
||||
or
|
||||
name = "get_param_as_list" and result instanceof ExternalStringSequenceKind
|
||||
}
|
||||
}
|
||||
|
||||
deprecated class FalconRequestParameter extends HttpRequestTaintSource {
|
||||
FalconRequestParameter() {
|
||||
exists(FalconHandlerFunction f | f.getRequest() = this.(ControlFlowNode).getNode())
|
||||
}
|
||||
|
||||
override predicate isSourceOf(TaintKind k) { k instanceof FalconRequest }
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
import python
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.web.Http
|
||||
import semmle.python.web.falcon.General
|
||||
|
||||
/** https://falcon.readthedocs.io/en/stable/api/request_and_response.html */
|
||||
deprecated class FalconResponse extends TaintKind {
|
||||
FalconResponse() { this = "falcon.response" }
|
||||
}
|
||||
|
||||
/** Only used internally to track the response parameter */
|
||||
deprecated private class FalconResponseParameter extends TaintSource {
|
||||
FalconResponseParameter() {
|
||||
exists(FalconHandlerFunction f | f.getResponse() = this.(ControlFlowNode).getNode())
|
||||
}
|
||||
|
||||
override predicate isSourceOf(TaintKind k) { k instanceof FalconResponse }
|
||||
}
|
||||
|
||||
deprecated class FalconResponseBodySink extends HttpResponseTaintSink {
|
||||
FalconResponseBodySink() {
|
||||
exists(AttrNode attr | any(FalconResponse f).taints(attr.getObject("body")) |
|
||||
attr.(DefinitionNode).getValue() = this
|
||||
)
|
||||
}
|
||||
|
||||
override predicate sinks(TaintKind kind) { kind instanceof StringKind }
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
import python
|
||||
import semmle.python.web.Http
|
||||
import semmle.python.web.flask.Response
|
||||
|
||||
/** Gets the flask app class */
|
||||
deprecated ClassValue theFlaskClass() { result = Value::named("flask.Flask") }
|
||||
|
||||
/** Gets the flask MethodView class */
|
||||
deprecated ClassValue theFlaskMethodViewClass() { result = Value::named("flask.views.MethodView") }
|
||||
|
||||
deprecated ClassValue theFlaskReponseClass() { result = Value::named("flask.Response") }
|
||||
|
||||
/**
|
||||
* Holds if `route` is routed to `func`
|
||||
* by decorating `func` with `app.route(route)`
|
||||
*/
|
||||
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
|
||||
route_call.getArg(0) = route and
|
||||
decorator_call.getArg(0).getNode().(FunctionExpr).getInnerScope() = func
|
||||
)
|
||||
}
|
||||
|
||||
/* Helper for add_url_rule */
|
||||
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)
|
||||
|
|
||||
callable = call.getArg(2) or
|
||||
callable = call.getArgByName("view_func")
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if urls matching `regex` are routed to `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
|
||||
/* MethodView.as_view() */
|
||||
exists(MethodViewClass view_cls | view_cls.asTaint().taints(callable) |
|
||||
func = view_cls.lookup(httpVerbLower()).(FunctionValue).getScope()
|
||||
)
|
||||
/* TODO: -- Handle Views that aren't MethodViews */
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if urls matching `regex` are routed to `func` using
|
||||
* any of flask's routing mechanisms.
|
||||
*/
|
||||
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 */
|
||||
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. */
|
||||
string taintString() { result = "flask/" + this.getQualifiedName() + ".as.view" }
|
||||
|
||||
/* As we are restricted to strings for taint kinds, we need to map these classes to strings. */
|
||||
TaintKind asTaint() { result = this.taintString() }
|
||||
}
|
||||
|
||||
deprecated private class MethodViewTaint extends TaintKind {
|
||||
MethodViewTaint() { any(MethodViewClass cls).taintString() = this }
|
||||
}
|
||||
|
||||
/** A source of method view "taint"s. */
|
||||
deprecated private class AsView extends TaintSource {
|
||||
AsView() {
|
||||
exists(ClassValue view_class |
|
||||
view_class.getASuperType() = theFlaskMethodViewClass() and
|
||||
this.(CallNode).getFunction().(AttrNode).getObject("as_view").pointsTo(view_class)
|
||||
)
|
||||
}
|
||||
|
||||
override string toString() { result = "flask.MethodView.as_view()" }
|
||||
|
||||
override predicate isSourceOf(TaintKind kind) {
|
||||
exists(MethodViewClass view_class |
|
||||
kind = view_class.asTaint() and
|
||||
this.(CallNode).getFunction().(AttrNode).getObject("as_view").pointsTo(view_class)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
deprecated class FlaskCookieSet extends CookieSet, CallNode {
|
||||
FlaskCookieSet() {
|
||||
any(FlaskResponseTaintKind t).taints(this.getFunction().(AttrNode).getObject("set_cookie"))
|
||||
}
|
||||
|
||||
override string toString() { result = CallNode.super.toString() }
|
||||
|
||||
override ControlFlowNode getKey() { result = this.getArg(0) }
|
||||
|
||||
override ControlFlowNode getValue() { result = this.getArg(1) }
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
/**
|
||||
* Provides class representing the `flask.redirect` function.
|
||||
* This module is intended to be imported into a taint-tracking query
|
||||
* to extend `TaintSink`.
|
||||
*/
|
||||
|
||||
import python
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.security.strings.Basic
|
||||
import semmle.python.web.flask.General
|
||||
|
||||
deprecated FunctionValue flask_redirect() { result = Value::named("flask.redirect") }
|
||||
|
||||
/**
|
||||
* Represents an argument to the `flask.redirect` function.
|
||||
*/
|
||||
deprecated class FlaskRedirect extends HttpRedirectTaintSink {
|
||||
override string toString() { result = "flask.redirect" }
|
||||
|
||||
FlaskRedirect() {
|
||||
exists(CallNode call |
|
||||
flask_redirect().getACall() = call and
|
||||
this = call.getAnArg()
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
import python
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.web.Http
|
||||
import semmle.python.web.flask.General
|
||||
|
||||
deprecated private Value theFlaskRequestObject() { result = Value::named("flask.request") }
|
||||
|
||||
/** Holds if `attr` is an access of attribute `name` of the flask request object */
|
||||
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 */
|
||||
deprecated class FlaskRequestData extends HttpRequestTaintSource {
|
||||
FlaskRequestData() {
|
||||
not this instanceof FlaskRequestArgs and
|
||||
exists(string name | flask_request_attr(this, name) |
|
||||
name in ["path", "full_path", "base_url", "url"]
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind }
|
||||
|
||||
override string toString() { result = "flask.request" }
|
||||
}
|
||||
|
||||
/** Source of dictionary whose values are externally controlled */
|
||||
deprecated class FlaskRequestArgs extends HttpRequestTaintSource {
|
||||
FlaskRequestArgs() {
|
||||
exists(string attr | flask_request_attr(this, attr) |
|
||||
attr in ["args", "form", "values", "files", "headers", "json"]
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringDictKind }
|
||||
|
||||
override string toString() { result = "flask.request.args" }
|
||||
}
|
||||
|
||||
/** Source of dictionary whose values are externally controlled */
|
||||
deprecated class FlaskRequestJson extends HttpRequestTaintSource {
|
||||
FlaskRequestJson() { flask_request_attr(this, "json") }
|
||||
|
||||
override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalJsonKind }
|
||||
|
||||
override string toString() { result = "flask.request.json" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A parameter to a flask request handler, that can capture a part of the URL (as specified in
|
||||
* the url-pattern of a route).
|
||||
*
|
||||
* For example, the `name` parameter in:
|
||||
* ```
|
||||
* @app.route('/hello/<name>')
|
||||
* def hello(name):
|
||||
* ```
|
||||
*/
|
||||
deprecated class FlaskRoutedParameter extends HttpRequestTaintSource {
|
||||
FlaskRoutedParameter() {
|
||||
exists(string name, Function func, StrConst url_pattern |
|
||||
this.(ControlFlowNode).getNode() = func.getArgByName(name) and
|
||||
flask_routing(url_pattern.getAFlowNode(), func) and
|
||||
exists(string match |
|
||||
match = url_pattern.getS().regexpFind(werkzeug_rule_re(), _, _) and
|
||||
name = match.regexpCapture(werkzeug_rule_re(), 4)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind }
|
||||
}
|
||||
|
||||
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 =
|
||||
"(?<static>[^<]*)<(?:(?<converter>[a-zA-Z_][a-zA-Z0-9_]*)(?:\\((?<args>.*?)\\))?\\:)?(?<variable>[a-zA-Z_][a-zA-Z0-9_]*)>"
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
import python
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.security.strings.Basic
|
||||
import semmle.python.web.flask.General
|
||||
|
||||
/**
|
||||
* A flask response, which is vulnerable to any sort of
|
||||
* http response malice.
|
||||
*/
|
||||
deprecated class FlaskRoutedResponse extends HttpResponseTaintSink {
|
||||
FlaskRoutedResponse() {
|
||||
exists(PythonFunctionValue response |
|
||||
flask_routing(_, response.getScope()) and
|
||||
this = response.getAReturnedNode()
|
||||
)
|
||||
}
|
||||
|
||||
override predicate sinks(TaintKind kind) { kind instanceof StringKind }
|
||||
|
||||
override string toString() { result = "flask.routed.response" }
|
||||
}
|
||||
|
||||
deprecated class FlaskResponseArgument extends HttpResponseTaintSink {
|
||||
FlaskResponseArgument() {
|
||||
exists(CallNode call |
|
||||
(
|
||||
call.getFunction().pointsTo(theFlaskReponseClass())
|
||||
or
|
||||
call.getFunction().pointsTo(Value::named("flask.make_response"))
|
||||
) and
|
||||
call.getArg(0) = this
|
||||
)
|
||||
}
|
||||
|
||||
override predicate sinks(TaintKind kind) { kind instanceof StringKind }
|
||||
|
||||
override string toString() { result = "flask.response.argument" }
|
||||
}
|
||||
|
||||
deprecated class FlaskResponseTaintKind extends TaintKind {
|
||||
FlaskResponseTaintKind() { this = "flask.Response" }
|
||||
}
|
||||
|
||||
deprecated class FlaskResponseConfiguration extends TaintTracking::Configuration {
|
||||
FlaskResponseConfiguration() { this = "Flask response configuration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node node, TaintKind kind) {
|
||||
kind instanceof FlaskResponseTaintKind and
|
||||
(
|
||||
node.asCfgNode().(CallNode).getFunction().pointsTo(theFlaskReponseClass())
|
||||
or
|
||||
node.asCfgNode().(CallNode).getFunction().pointsTo(Value::named("flask.make_response"))
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
/**
|
||||
* Provides class representing the `pyramid.redirect` function.
|
||||
* This module is intended to be imported into a taint-tracking query
|
||||
* to extend `TaintSink`.
|
||||
*/
|
||||
|
||||
import python
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.security.strings.Basic
|
||||
import semmle.python.web.Http
|
||||
|
||||
deprecated private ClassValue redirectClass() {
|
||||
exists(ModuleValue ex | ex.getName() = "pyramid.httpexceptions" |
|
||||
ex.attr("HTTPFound") = result
|
||||
or
|
||||
ex.attr("HTTPTemporaryRedirect") = result
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an argument to the `tornado.redirect` function.
|
||||
*/
|
||||
deprecated class PyramidRedirect extends HttpRedirectTaintSink {
|
||||
override string toString() { result = "pyramid.redirect" }
|
||||
|
||||
PyramidRedirect() {
|
||||
exists(CallNode call | call.getFunction().pointsTo(redirectClass()) |
|
||||
call.getArg(0) = this
|
||||
or
|
||||
call.getArgByName("location") = this
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
import python
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.web.Http
|
||||
private import semmle.python.web.webob.Request
|
||||
private import semmle.python.web.pyramid.View
|
||||
|
||||
deprecated class PyramidRequest extends BaseWebobRequest {
|
||||
PyramidRequest() { this = "pyramid.request" }
|
||||
|
||||
override ClassValue getType() { result = Value::named("pyramid.request.Request") }
|
||||
}
|
||||
|
||||
/** Source of pyramid request objects */
|
||||
deprecated class PyramidViewArgument extends HttpRequestTaintSource {
|
||||
PyramidViewArgument() {
|
||||
exists(Function view_func |
|
||||
is_pyramid_view_function(view_func) and
|
||||
this.(ControlFlowNode).getNode() = view_func.getArg(0)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSourceOf(TaintKind kind) { kind instanceof PyramidRequest }
|
||||
|
||||
override string toString() { result = "pyramid.view.argument" }
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
import python
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.security.strings.Basic
|
||||
import semmle.python.web.Http
|
||||
private import semmle.python.web.pyramid.View
|
||||
|
||||
/**
|
||||
* A pyramid response, which is vulnerable to any sort of
|
||||
* http response malice.
|
||||
*/
|
||||
deprecated class PyramidRoutedResponse extends HttpResponseTaintSink {
|
||||
PyramidRoutedResponse() {
|
||||
exists(PythonFunctionValue view |
|
||||
is_pyramid_view_function(view.getScope()) and
|
||||
this = view.getAReturnedNode()
|
||||
)
|
||||
}
|
||||
|
||||
override predicate sinks(TaintKind kind) { kind instanceof StringKind }
|
||||
|
||||
override string toString() { result = "pyramid.routed.response" }
|
||||
}
|
||||
|
||||
deprecated class PyramidCookieSet extends CookieSet, CallNode {
|
||||
PyramidCookieSet() {
|
||||
exists(ControlFlowNode f |
|
||||
f = this.getFunction().(AttrNode).getObject("set_cookie") and
|
||||
f.pointsTo().getClass() = Value::named("pyramid.response.Response")
|
||||
)
|
||||
}
|
||||
|
||||
override string toString() { result = CallNode.super.toString() }
|
||||
|
||||
override ControlFlowNode getKey() { result = this.getArg(0) }
|
||||
|
||||
override ControlFlowNode getValue() { result = this.getArg(1) }
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
import python
|
||||
|
||||
deprecated ModuleValue thePyramidViewModule() { result.getName() = "pyramid.view" }
|
||||
|
||||
deprecated Value thePyramidViewConfig() { result = thePyramidViewModule().attr("view_config") }
|
||||
|
||||
deprecated predicate is_pyramid_view_function(Function func) {
|
||||
func.getADecorator().pointsTo().getClass() = thePyramidViewConfig()
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
/**
|
||||
* Provides the sources and taint-flow for HTTP servers defined using the standard library (stdlib).
|
||||
* Specifically, we model `HttpRequestTaintSource`s from instances of `BaseHTTPRequestHandler`
|
||||
* (or subclasses) and form parsing using `cgi.FieldStorage`.
|
||||
*/
|
||||
|
||||
import python
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.web.Http
|
||||
|
||||
/** Source of BaseHttpRequestHandler instances. */
|
||||
deprecated class StdLibRequestSource extends HttpRequestTaintSource {
|
||||
StdLibRequestSource() {
|
||||
exists(ClassValue cls |
|
||||
cls.getABaseType+() = Value::named("BaseHTTPServer.BaseHTTPRequestHandler")
|
||||
or
|
||||
cls.getABaseType+() = Value::named("http.server.BaseHTTPRequestHandler")
|
||||
|
|
||||
this.(ControlFlowNode).pointsTo().getClass() = cls
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSourceOf(TaintKind kind) { kind instanceof BaseHTTPRequestHandlerKind }
|
||||
}
|
||||
|
||||
/** TaintKind for an instance of BaseHttpRequestHandler. */
|
||||
deprecated class BaseHTTPRequestHandlerKind extends TaintKind {
|
||||
BaseHTTPRequestHandlerKind() { this = "BaseHTTPRequestHandlerKind" }
|
||||
|
||||
override TaintKind getTaintOfAttribute(string name) {
|
||||
name in ["requestline", "path"] and
|
||||
result instanceof ExternalStringKind
|
||||
or
|
||||
name = "headers" and
|
||||
result instanceof HTTPMessageKind
|
||||
or
|
||||
name = "rfile" and
|
||||
result instanceof ExternalFileObject
|
||||
}
|
||||
}
|
||||
|
||||
/** TaintKind for headers (instance of HttpMessage). */
|
||||
deprecated class HTTPMessageKind extends ExternalStringDictKind {
|
||||
override TaintKind getTaintOfMethodResult(string name) {
|
||||
result = super.getTaintOfMethodResult(name)
|
||||
or
|
||||
name = "get_all" and
|
||||
result.(SequenceKind).getItem() = this.getValue()
|
||||
or
|
||||
name in ["as_bytes", "as_string"] and
|
||||
result instanceof ExternalStringKind
|
||||
}
|
||||
|
||||
override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) {
|
||||
result = super.getTaintForFlowStep(fromnode, tonode)
|
||||
or
|
||||
exists(ClassValue cls | cls = ClassValue::unicode() or cls = ClassValue::bytes() |
|
||||
tonode = cls.getACall() and
|
||||
tonode.(CallNode).getArg(0) = fromnode and
|
||||
result instanceof ExternalStringKind
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** Source of parsed HTTP forms (by using the `cgi` module). */
|
||||
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. */
|
||||
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
|
||||
* ```
|
||||
* form = cgi.FieldStorage()
|
||||
* field = form['myfield']
|
||||
* ```
|
||||
* both `form` and `field` have the type `cgi.FieldStorage`. This allows the code to represent
|
||||
* nested forms as `form['nested_form']['myfield']`. However, since HTML forms can't be nested
|
||||
* we ignore that detail since it allows for a more clean modeling.
|
||||
*/
|
||||
|
||||
CgiFieldStorageFormKind() { this = "CgiFieldStorageFormKind" }
|
||||
|
||||
override TaintKind getTaintOfAttribute(string name) {
|
||||
name = "value" and result.(SequenceKind).getItem() instanceof CgiFieldStorageFieldKind
|
||||
}
|
||||
|
||||
override TaintKind getTaintOfMethodResult(string name) {
|
||||
name = "getvalue" and
|
||||
(
|
||||
result instanceof ExternalStringKind
|
||||
or
|
||||
result.(SequenceKind).getItem() instanceof ExternalStringKind
|
||||
)
|
||||
or
|
||||
name = "getfirst" and
|
||||
result instanceof ExternalStringKind
|
||||
or
|
||||
name = "getlist" and
|
||||
result.(SequenceKind).getItem() instanceof ExternalStringKind
|
||||
}
|
||||
|
||||
override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) {
|
||||
tonode.(SubscriptNode).getObject() = fromnode and
|
||||
(
|
||||
result instanceof CgiFieldStorageFieldKind
|
||||
or
|
||||
result.(SequenceKind).getItem() instanceof CgiFieldStorageFieldKind
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** TaintKind for the field of a parsed HTTP form. */
|
||||
deprecated class CgiFieldStorageFieldKind extends TaintKind {
|
||||
CgiFieldStorageFieldKind() { this = "CgiFieldStorageFieldKind" }
|
||||
|
||||
override TaintKind getTaintOfAttribute(string name) {
|
||||
name in ["filename", "value"] and result instanceof ExternalStringKind
|
||||
or
|
||||
name = "file" and result instanceof ExternalFileObject
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
/**
|
||||
* Provides the sinks for HTTP servers defined with standard library (stdlib).
|
||||
*/
|
||||
|
||||
import python
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.web.Http
|
||||
|
||||
deprecated private predicate is_wfile(AttrNode wfile) {
|
||||
exists(ClassValue cls |
|
||||
// Python 2
|
||||
cls.getABaseType+() = Value::named("BaseHTTPServer.BaseHTTPRequestHandler")
|
||||
or
|
||||
// Python 3
|
||||
cls.getABaseType+() = Value::named("http.server.BaseHTTPRequestHandler")
|
||||
|
|
||||
wfile.getObject("wfile").pointsTo().getClass() = cls
|
||||
)
|
||||
}
|
||||
|
||||
/** Sink for `h.wfile.write` where `h` is an instance of BaseHttpRequestHandler. */
|
||||
deprecated class StdLibWFileWriteSink extends HttpResponseTaintSink {
|
||||
StdLibWFileWriteSink() {
|
||||
exists(CallNode call |
|
||||
is_wfile(call.getFunction().(AttrNode).getObject("write")) and
|
||||
call.getArg(0) = this
|
||||
)
|
||||
}
|
||||
|
||||
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
|
||||
}
|
||||
|
||||
/** Sink for `h.wfile.writelines` where `h` is an instance of BaseHttpRequestHandler. */
|
||||
deprecated class StdLibWFileWritelinesSink extends HttpResponseTaintSink {
|
||||
StdLibWFileWritelinesSink() {
|
||||
exists(CallNode call |
|
||||
is_wfile(call.getFunction().(AttrNode).getObject("writelines")) and
|
||||
call.getArg(0) = this
|
||||
)
|
||||
}
|
||||
|
||||
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringSequenceKind }
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
/**
|
||||
* Provides class representing the `tornado.redirect` function.
|
||||
* This module is intended to be imported into a taint-tracking query
|
||||
* to extend `TaintSink`.
|
||||
*/
|
||||
|
||||
import python
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.security.strings.Basic
|
||||
import semmle.python.web.Http
|
||||
import Tornado
|
||||
|
||||
/**
|
||||
* Represents an argument to the `tornado.redirect` function.
|
||||
*/
|
||||
deprecated class TornadoHttpRequestHandlerRedirect extends HttpRedirectTaintSink {
|
||||
override string toString() { result = "tornado.HttpRequestHandler.redirect" }
|
||||
|
||||
TornadoHttpRequestHandlerRedirect() {
|
||||
exists(CallNode call, ControlFlowNode node |
|
||||
node = call.getFunction().(AttrNode).getObject("redirect") and
|
||||
isTornadoRequestHandlerInstance(node) and
|
||||
this = call.getArg(0)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate sinks(TaintKind kind) { kind instanceof StringKind }
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
import python
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.web.Http
|
||||
import Tornado
|
||||
|
||||
/** A tornado.request.HttpRequest object */
|
||||
deprecated class TornadoRequest extends TaintKind {
|
||||
TornadoRequest() { this = "tornado.request.HttpRequest" }
|
||||
|
||||
override TaintKind getTaintOfAttribute(string name) {
|
||||
result instanceof ExternalStringDictKind and
|
||||
(
|
||||
name = "headers" or
|
||||
name = "cookies"
|
||||
)
|
||||
or
|
||||
result instanceof ExternalStringKind and
|
||||
(
|
||||
name = "uri" or
|
||||
name = "query" or
|
||||
name = "body"
|
||||
)
|
||||
or
|
||||
result instanceof ExternalStringSequenceDictKind and
|
||||
(
|
||||
name = "arguments" or
|
||||
name = "query_arguments" or
|
||||
name = "body_arguments"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
deprecated class TornadoRequestSource extends HttpRequestTaintSource {
|
||||
TornadoRequestSource() { isTornadoRequestHandlerInstance(this.(AttrNode).getObject("request")) }
|
||||
|
||||
override string toString() { result = "Tornado request source" }
|
||||
|
||||
override predicate isSourceOf(TaintKind kind) { kind instanceof TornadoRequest }
|
||||
}
|
||||
|
||||
deprecated class TornadoExternalInputSource extends HttpRequestTaintSource {
|
||||
TornadoExternalInputSource() {
|
||||
exists(string name |
|
||||
name in ["get_argument", "get_query_argument", "get_body_argument", "decode_argument"]
|
||||
|
|
||||
this = callToNamedTornadoRequestHandlerMethod(name)
|
||||
)
|
||||
}
|
||||
|
||||
override string toString() { result = "Tornado request method" }
|
||||
|
||||
override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind }
|
||||
}
|
||||
|
||||
deprecated class TornadoExternalInputListSource extends HttpRequestTaintSource {
|
||||
TornadoExternalInputListSource() {
|
||||
exists(string name |
|
||||
name = "get_arguments" or
|
||||
name = "get_query_arguments" or
|
||||
name = "get_body_arguments"
|
||||
|
|
||||
this = callToNamedTornadoRequestHandlerMethod(name)
|
||||
)
|
||||
}
|
||||
|
||||
override string toString() { result = "Tornado request method" }
|
||||
|
||||
override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringSequenceKind }
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
import python
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.security.strings.Basic
|
||||
private import semmle.python.web.Http
|
||||
import Tornado
|
||||
|
||||
deprecated class TornadoConnection extends TaintKind {
|
||||
TornadoConnection() { this = "tornado.http.connection" }
|
||||
}
|
||||
|
||||
deprecated class TornadoConnectionSource extends TaintSource {
|
||||
TornadoConnectionSource() {
|
||||
isTornadoRequestHandlerInstance(this.(AttrNode).getObject("connection"))
|
||||
}
|
||||
|
||||
override string toString() { result = "Tornado http connection source" }
|
||||
|
||||
override predicate isSourceOf(TaintKind kind) { kind instanceof TornadoConnection }
|
||||
}
|
||||
|
||||
deprecated class TornadoConnectionWrite extends HttpResponseTaintSink {
|
||||
override string toString() { result = "tornado.connection.write" }
|
||||
|
||||
TornadoConnectionWrite() {
|
||||
exists(CallNode call, ControlFlowNode conn |
|
||||
conn = call.getFunction().(AttrNode).getObject("write") and
|
||||
this = call.getAnArg() and
|
||||
exists(TornadoConnection tc | tc.taints(conn))
|
||||
)
|
||||
}
|
||||
|
||||
override predicate sinks(TaintKind kind) { kind instanceof StringKind }
|
||||
}
|
||||
|
||||
deprecated class TornadoHttpRequestHandlerWrite extends HttpResponseTaintSink {
|
||||
override string toString() { result = "tornado.HttpRequestHandler.write" }
|
||||
|
||||
TornadoHttpRequestHandlerWrite() {
|
||||
exists(CallNode call, ControlFlowNode node |
|
||||
node = call.getFunction().(AttrNode).getObject("write") and
|
||||
this = call.getAnArg() and
|
||||
isTornadoRequestHandlerInstance(node)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate sinks(TaintKind kind) { kind instanceof StringKind }
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
import python
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.web.Http
|
||||
|
||||
deprecated private ClassValue theTornadoRequestHandlerClass() {
|
||||
result = Value::named("tornado.web.RequestHandler")
|
||||
}
|
||||
|
||||
deprecated ClassValue aTornadoRequestHandlerClass() {
|
||||
result.getABaseType+() = theTornadoRequestHandlerClass()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` is likely to refer to an instance of a tornado
|
||||
* `RequestHandler` class.
|
||||
*/
|
||||
deprecated predicate isTornadoRequestHandlerInstance(ControlFlowNode node) {
|
||||
node.pointsTo().getClass() = aTornadoRequestHandlerClass()
|
||||
or
|
||||
/*
|
||||
* In some cases, the points-to analysis won't capture all instances we care
|
||||
* about. For these, we use the following syntactic check. First, that
|
||||
* `node` appears inside a method of a subclass of
|
||||
* `tornado.web.RequestHandler`:
|
||||
*/
|
||||
|
||||
node.getScope().getEnclosingScope() = aTornadoRequestHandlerClass().getScope() and
|
||||
/* Secondly, that `node` refers to the `self` argument: */
|
||||
node.isLoad() and
|
||||
node.(NameNode).isSelf()
|
||||
}
|
||||
|
||||
deprecated CallNode callToNamedTornadoRequestHandlerMethod(string name) {
|
||||
isTornadoRequestHandlerInstance(result.getFunction().(AttrNode).getObject(name))
|
||||
}
|
||||
|
||||
deprecated class TornadoCookieSet extends CookieSet, CallNode {
|
||||
TornadoCookieSet() {
|
||||
exists(ControlFlowNode f |
|
||||
f = this.getFunction().(AttrNode).getObject("set_cookie") and
|
||||
isTornadoRequestHandlerInstance(f)
|
||||
)
|
||||
}
|
||||
|
||||
override string toString() { result = CallNode.super.toString() }
|
||||
|
||||
override ControlFlowNode getKey() { result = this.getArg(0) }
|
||||
|
||||
override ControlFlowNode getValue() { result = this.getArg(1) }
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
import python
|
||||
import semmle.python.security.strings.External
|
||||
import semmle.python.web.Http
|
||||
import TurboGears
|
||||
|
||||
deprecated private class ValidatedMethodParameter extends Parameter {
|
||||
ValidatedMethodParameter() {
|
||||
exists(string name, TurboGearsControllerMethod method |
|
||||
method.getArgByName(name) = this and
|
||||
method.getValidationDict().getItem(_).(KeyValuePair).getKey().(StrConst).getText() = name
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
deprecated class UnvalidatedControllerMethodParameter extends HttpRequestTaintSource {
|
||||
UnvalidatedControllerMethodParameter() {
|
||||
exists(Parameter p |
|
||||
any(TurboGearsControllerMethod m | not m.getName() = "onerror").getAnArg() = p and
|
||||
not p instanceof ValidatedMethodParameter and
|
||||
not p.isSelf() and
|
||||
p.(Name).getAFlowNode() = this
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind }
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
import python
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.security.strings.Basic
|
||||
import semmle.python.web.Http
|
||||
import TurboGears
|
||||
|
||||
deprecated class ControllerMethodReturnValue extends HttpResponseTaintSink {
|
||||
override string toString() { result = "TurboGears ControllerMethodReturnValue" }
|
||||
|
||||
ControllerMethodReturnValue() {
|
||||
exists(TurboGearsControllerMethod m |
|
||||
m.getAReturnValueFlowNode() = this and
|
||||
not m.isTemplated()
|
||||
)
|
||||
}
|
||||
|
||||
override predicate sinks(TaintKind kind) { kind instanceof StringKind }
|
||||
}
|
||||
|
||||
deprecated class ControllerMethodTemplatedReturnValue extends HttpResponseTaintSink {
|
||||
override string toString() { result = "TurboGears ControllerMethodTemplatedReturnValue" }
|
||||
|
||||
ControllerMethodTemplatedReturnValue() {
|
||||
exists(TurboGearsControllerMethod m |
|
||||
m.getAReturnValueFlowNode() = this and
|
||||
m.isTemplated()
|
||||
)
|
||||
}
|
||||
|
||||
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringDictKind }
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
import python
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
|
||||
deprecated private ClassValue theTurboGearsControllerClass() {
|
||||
result = Value::named("tg.TGController")
|
||||
}
|
||||
|
||||
deprecated ClassValue aTurboGearsControllerClass() {
|
||||
result.getABaseType+() = theTurboGearsControllerClass()
|
||||
}
|
||||
|
||||
deprecated class TurboGearsControllerMethod extends Function {
|
||||
ControlFlowNode decorator;
|
||||
|
||||
TurboGearsControllerMethod() {
|
||||
aTurboGearsControllerClass().getScope() = this.getScope() and
|
||||
decorator = this.getADecorator().getAFlowNode() and
|
||||
/* Is decorated with @expose() or @expose(path) */
|
||||
(
|
||||
decorator.(CallNode).getFunction().(NameNode).getId() = "expose"
|
||||
or
|
||||
decorator.pointsTo().getClass() = Value::named("tg.expose")
|
||||
)
|
||||
}
|
||||
|
||||
private ControlFlowNode templateName() { result = decorator.(CallNode).getArg(0) }
|
||||
|
||||
predicate isTemplated() { exists(this.templateName()) }
|
||||
|
||||
Dict getValidationDict() {
|
||||
exists(Call call |
|
||||
call = this.getADecorator() and
|
||||
call.getFunc().(Name).getId() = "validate" and
|
||||
call.getArg(0).pointsTo(_, result)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
import python
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.web.Http
|
||||
import Twisted
|
||||
|
||||
/** A twisted.web.http.Request object */
|
||||
deprecated class TwistedRequest extends TaintKind {
|
||||
TwistedRequest() { this = "twisted.request.http.Request" }
|
||||
|
||||
override TaintKind getTaintOfAttribute(string name) {
|
||||
result instanceof ExternalStringSequenceDictKind and
|
||||
name = "args"
|
||||
or
|
||||
result instanceof ExternalStringKind and
|
||||
name = "uri"
|
||||
}
|
||||
|
||||
override TaintKind getTaintOfMethodResult(string name) {
|
||||
name in ["getHeader", "getCookie", "getUser", "getPassword"] and
|
||||
result instanceof ExternalStringKind
|
||||
}
|
||||
}
|
||||
|
||||
deprecated class TwistedRequestSource extends HttpRequestTaintSource {
|
||||
TwistedRequestSource() { isTwistedRequestInstance(this) }
|
||||
|
||||
override string toString() { result = "Twisted request source" }
|
||||
|
||||
override predicate isSourceOf(TaintKind kind) { kind instanceof TwistedRequest }
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
import python
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.web.Http
|
||||
import semmle.python.security.strings.Basic
|
||||
import Twisted
|
||||
import Request
|
||||
|
||||
deprecated class TwistedResponse extends HttpResponseTaintSink {
|
||||
TwistedResponse() {
|
||||
exists(PythonFunctionValue func, string name |
|
||||
isKnownRequestHandlerMethodName(name) and
|
||||
name = func.getName() and
|
||||
func = getTwistedRequestHandlerMethod(name) and
|
||||
this = func.getAReturnedNode()
|
||||
)
|
||||
}
|
||||
|
||||
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
|
||||
|
||||
override string toString() { result = "Twisted response" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A sink of taint in the form of a "setter" method on a twisted request
|
||||
* object, which affects the properties of the subsequent response sent to this
|
||||
* request.
|
||||
*/
|
||||
deprecated class TwistedRequestSetter extends HttpResponseTaintSink {
|
||||
TwistedRequestSetter() {
|
||||
exists(CallNode call, ControlFlowNode node, string name |
|
||||
(
|
||||
name = "setHeader" or
|
||||
name = "addCookie" or
|
||||
name = "write"
|
||||
) and
|
||||
any(TwistedRequest t).taints(node) and
|
||||
node = call.getFunction().(AttrNode).getObject(name) and
|
||||
this = call.getAnArg()
|
||||
)
|
||||
}
|
||||
|
||||
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
|
||||
|
||||
override string toString() { result = "Twisted request setter" }
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
import python
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
|
||||
deprecated private ClassValue theTwistedHttpRequestClass() {
|
||||
result = Value::named("twisted.web.http.Request")
|
||||
}
|
||||
|
||||
deprecated private ClassValue theTwistedHttpResourceClass() {
|
||||
result = Value::named("twisted.web.resource.Resource")
|
||||
}
|
||||
|
||||
deprecated ClassValue aTwistedRequestHandlerClass() {
|
||||
result.getABaseType+() = theTwistedHttpResourceClass()
|
||||
}
|
||||
|
||||
deprecated FunctionValue getTwistedRequestHandlerMethod(string name) {
|
||||
result = aTwistedRequestHandlerClass().declaredAttribute(name)
|
||||
}
|
||||
|
||||
bindingset[name]
|
||||
deprecated predicate isKnownRequestHandlerMethodName(string name) {
|
||||
name = "render" or
|
||||
name.matches("render_%")
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` is likely to refer to an instance of the twisted
|
||||
* `Request` class.
|
||||
*/
|
||||
deprecated predicate isTwistedRequestInstance(NameNode node) {
|
||||
node.pointsTo().getClass() = theTwistedHttpRequestClass()
|
||||
or
|
||||
/*
|
||||
* In points-to analysis cannot infer that a given object is an instance of
|
||||
* the `twisted.web.http.Request` class, we also include any parameter
|
||||
* called `request` that appears inside a subclass of a request handler
|
||||
* class, and the appropriate arguments of known request handler methods.
|
||||
*/
|
||||
|
||||
exists(Function func |
|
||||
func = node.getScope() and
|
||||
func.getEnclosingScope() = aTwistedRequestHandlerClass().getScope()
|
||||
|
|
||||
/* Any parameter called `request` */
|
||||
node.getId() = "request" and
|
||||
node.isParameter()
|
||||
or
|
||||
/* Any request parameter of a known request handler method */
|
||||
isKnownRequestHandlerMethodName(func.getName()) and
|
||||
node.getNode() = func.getArg(1)
|
||||
)
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
import python
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.web.Http
|
||||
|
||||
abstract deprecated class BaseWebobRequest extends TaintKind {
|
||||
bindingset[this]
|
||||
BaseWebobRequest() { any() }
|
||||
|
||||
override TaintKind getTaintOfAttribute(string name) {
|
||||
result instanceof ExternalStringDictKind and
|
||||
(
|
||||
name = "GET" or
|
||||
name = "POST" or
|
||||
name = "headers"
|
||||
)
|
||||
or
|
||||
result instanceof ExternalStringKind and
|
||||
name = "body"
|
||||
}
|
||||
|
||||
override TaintKind getTaintOfMethodResult(string name) {
|
||||
result = this and
|
||||
(
|
||||
name = "copy" or
|
||||
name = "copy_get" or
|
||||
name = "copy_body"
|
||||
)
|
||||
or
|
||||
result instanceof ExternalStringKind and
|
||||
name = "as_bytes"
|
||||
}
|
||||
}
|
||||
|
||||
deprecated class WebobRequest extends BaseWebobRequest {
|
||||
WebobRequest() { this = "webob.Request" }
|
||||
|
||||
override ClassValue getType() { result = Value::named("webob.request.Request") }
|
||||
}
|
||||
Reference in New Issue
Block a user