-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Python : Add query to detect Server Side Template Injection
- Loading branch information
1 parent
499e349
commit 2513950
Showing
64 changed files
with
924 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
/** | ||
* @name Server Side Template Injection | ||
* @description Using user-controlled data to create a template can cause security issues. | ||
* @kind path-problem | ||
* @problem.severity error | ||
* @precision high | ||
* @id py/template-injection | ||
* @tags security | ||
* external/cwe/cwe-074 | ||
*/ | ||
|
||
import python | ||
import semmle.python.security.Paths | ||
/* Sources */ | ||
import semmle.python.web.HttpRequest | ||
/* Sinks */ | ||
import experimental.semmle.python.templates.Ssti | ||
|
||
class TemplateInjectionConfiguration extends TaintTracking::Configuration { | ||
TemplateInjectionConfiguration() { this = "Template injection configuration" } | ||
|
||
override predicate isSource(TaintTracking::Source source) { | ||
source instanceof HttpRequestTaintSource | ||
} | ||
|
||
override predicate isSink(TaintTracking::Sink sink) { sink instanceof SSTISink } | ||
} | ||
|
||
from TemplateInjectionConfiguration config, TaintedPathSource src, TaintedPathSink sink | ||
where config.hasFlowPath(src, sink) | ||
select sink.getSink(), src, sink, "This Template depends on $@.", src.getSource(), | ||
"a user-provided value" |
27 changes: 27 additions & 0 deletions
27
python/ql/src/experimental/semmle/python/templates/Airspeed.qll
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
/** Provides classes which model the `airspeed` package. */ | ||
|
||
import python | ||
import semmle.python.web.HttpRequest | ||
import experimental.semmle.python.templates.SSTISink | ||
|
||
/** returns the ClassValue representing `airspeed.Template` */ | ||
ClassValue theAirspeedTemplateClass() { result = Value::named("airspeed.Template") } | ||
|
||
/** | ||
* Sink representing the `airspeed.Template` class instantiation argument. | ||
* | ||
* import airspeed | ||
* temp = airspeed.Template(`"sink"`) | ||
*/ | ||
class AirspeedTemplateSink extends SSTISink { | ||
override string toString() { result = "argument to airspeed.Template()" } | ||
|
||
AirspeedTemplateSink() { | ||
exists(CallNode call | | ||
call.getFunction().pointsTo(theAirspeedTemplateClass()) and | ||
call.getArg(0) = this | ||
) | ||
} | ||
|
||
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } | ||
} |
46 changes: 46 additions & 0 deletions
46
python/ql/src/experimental/semmle/python/templates/Bottle.qll
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
/** Provides classes which model the `bottle` package. */ | ||
|
||
import python | ||
import semmle.python.web.HttpRequest | ||
import experimental.semmle.python.templates.SSTISink | ||
|
||
/** returns the ClassValue representing `bottle.SimpleTemplate` */ | ||
ClassValue theBottleSimpleTemplateClass() { result = Value::named("bottle.SimpleTemplate") } | ||
|
||
/** | ||
* Sink representing the `bottle.SimpleTemplate` class instantiation argument. | ||
* | ||
* from bottle import SimpleTemplate | ||
* template = SimpleTemplate(`sink`) | ||
*/ | ||
class BottleSimpleTemplateSink extends SSTISink { | ||
override string toString() { result = "argument to bottle.SimpleTemplate()" } | ||
|
||
BottleSimpleTemplateSink() { | ||
exists(CallNode call | | ||
call.getFunction().pointsTo(theBottleSimpleTemplateClass()) and | ||
call.getArg(0) = this | ||
) | ||
} | ||
|
||
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } | ||
} | ||
|
||
/** | ||
* Sink representing the `bottle.template` function call argument. | ||
* | ||
* from bottle import template | ||
* tmp = template(`sink`) | ||
*/ | ||
class BottleTemplateSink extends SSTISink { | ||
override string toString() { result = "argument to bottle.template()" } | ||
|
||
BottleTemplateSink() { | ||
exists(CallNode call | | ||
call.getFunction() = theBottleModule().attr("template").getAReference() and | ||
call.getArg(0) = this | ||
) | ||
} | ||
|
||
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } | ||
} |
27 changes: 27 additions & 0 deletions
27
python/ql/src/experimental/semmle/python/templates/Chameleon.qll
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
/** Provides classes which model the `Chameleon` package. */ | ||
|
||
import python | ||
import semmle.python.web.HttpRequest | ||
import experimental.semmle.python.templates.SSTISink | ||
|
||
/** returns the ClassValue representing `chameleon.PageTemplate` */ | ||
ClassValue theChameleonPageTemplateClass() { result = Value::named("chameleon.PageTemplate") } | ||
|
||
/** | ||
* Sink representing the `chameleon.PageTemplate` class instantiation argument. | ||
* | ||
* from chameleon import PageTemplate | ||
* template = PageTemplate(`sink`) | ||
*/ | ||
class ChameleonTemplateSink extends SSTISink { | ||
override string toString() { result = "argument to Chameleon.PageTemplate()" } | ||
|
||
ChameleonTemplateSink() { | ||
exists(CallNode call | | ||
call.getFunction().pointsTo(theChameleonPageTemplateClass()) and | ||
call.getArg(0) = this | ||
) | ||
} | ||
|
||
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } | ||
} |
37 changes: 37 additions & 0 deletions
37
python/ql/src/experimental/semmle/python/templates/Cheetah.qll
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
/** Provides classes which model the `Cheetah3` package. */ | ||
|
||
import python | ||
import semmle.python.web.HttpRequest | ||
import experimental.semmle.python.templates.SSTISink | ||
|
||
/** returns the ClassValue representing `Cheetah.Template.Template` */ | ||
ClassValue theCheetahTemplateClass() { result = Value::named("Cheetah.Template.Template") } | ||
|
||
/** | ||
* Sink representing the instantiation argument of any class which derives from | ||
* the `Cheetah.Template.Template` class . | ||
* | ||
* from Cheetah.Template import Template | ||
* class Template3(Template): | ||
* title = 'Hello World Example!' | ||
* contents = 'Hello World!' | ||
* t3 = Template3("sink") | ||
* | ||
* This should also detect cases of the following type : | ||
* | ||
* from Cheetah.Template import Template | ||
* t3 = Template("sink") | ||
*/ | ||
class CheetahTemplateInstantiationSink extends SSTISink { | ||
override string toString() { result = "argument to Cheetah.Template.Template()" } | ||
|
||
CheetahTemplateInstantiationSink() { | ||
exists(CallNode call, ClassValue cv | | ||
cv.getASuperType() = theCheetahTemplateClass() and | ||
call.getFunction().pointsTo(cv) and | ||
call.getArg(0) = this | ||
) | ||
} | ||
|
||
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } | ||
} |
36 changes: 36 additions & 0 deletions
36
python/ql/src/experimental/semmle/python/templates/Chevron.qll
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
/** Provides classes which model the `chevron` package. */ | ||
|
||
import python | ||
import semmle.python.web.HttpRequest | ||
import experimental.semmle.python.templates.SSTISink | ||
|
||
/** returns the Value representing `chevron.render` function */ | ||
Value theChevronRenderFunc() { result = Value::named("chevron.render") } | ||
|
||
/** | ||
* Sink representing the `chevron.render` function call argument. | ||
* | ||
* import chevron | ||
* tmp = chevron.render(`sink`,{ 'key' : 'value' }) | ||
*/ | ||
class ChevronRenderSink extends SSTISink { | ||
override string toString() { result = "argument to chevron.render()" } | ||
|
||
ChevronRenderSink() { | ||
exists(CallNode call | | ||
call.getFunction() = theChevronRenderFunc().getAReference() and | ||
call.getArg(0) = this | ||
) | ||
// TODO: this should also detect : | ||
// import chevron | ||
// args = { | ||
// 'template': 'sink', | ||
// 'data': { | ||
// 'mustache': 'World' | ||
// } | ||
// } | ||
// chevron.render(**args) | ||
} | ||
|
||
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } | ||
} |
36 changes: 36 additions & 0 deletions
36
python/ql/src/experimental/semmle/python/templates/DjangoTemplate.qll
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
/** Provides classes which model the `DjangoTemplate` package. */ | ||
|
||
import python | ||
import semmle.python.web.HttpRequest | ||
import experimental.semmle.python.templates.SSTISink | ||
|
||
ClassValue theDjangoTemplateClass() { result = Value::named("django.template.Template") } | ||
|
||
/** | ||
* Sink representng `django.template.Template` class instantiation argument. | ||
* | ||
* from django.template import Template | ||
* template = Template(`sink`) | ||
*/ | ||
class DjangoTemplateTemplateSink extends SSTISink { | ||
override string toString() { result = "argument to Django.template()" } | ||
|
||
DjangoTemplateTemplateSink() { | ||
exists(CallNode call | | ||
call.getFunction().pointsTo(theDjangoTemplateClass()) and | ||
call.getArg(0) = this | ||
) | ||
} | ||
|
||
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } | ||
} | ||
|
||
// TODO | ||
/** | ||
* Sinks representng the django.template.Template class instantiation. | ||
* | ||
* from django.template import engines | ||
* | ||
* django_engine = engines["django"] | ||
* template = django_engine.from_string(`sink`) | ||
*/ |
26 changes: 26 additions & 0 deletions
26
python/ql/src/experimental/semmle/python/templates/FlaskTemplate.qll
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
/** Provides classes which model templates in the`flask` package. */ | ||
|
||
import python | ||
import semmle.python.web.HttpRequest | ||
import experimental.semmle.python.templates.SSTISink | ||
|
||
Value theFlaskRenderTemplateClass() { result = Value::named("flask.render_template_string") } | ||
|
||
/** | ||
* Sink representng `flask.render_template_string` function call argument. | ||
* | ||
* from flask import render_template_string | ||
* render_template_string(`sink`) | ||
*/ | ||
class FlaskTemplateSink extends SSTISink { | ||
override string toString() { result = "argument to flask.render_template_string()" } | ||
|
||
FlaskTemplateSink() { | ||
exists(CallNode call | | ||
call.getFunction().pointsTo(theFlaskRenderTemplateClass()) and | ||
call.getArg(0) = this | ||
) | ||
} | ||
|
||
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } | ||
} |
51 changes: 51 additions & 0 deletions
51
python/ql/src/experimental/semmle/python/templates/Genshi.qll
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
/** Provides classes which model the `Genshi` package. */ | ||
|
||
import python | ||
import semmle.python.web.HttpRequest | ||
import experimental.semmle.python.templates.SSTISink | ||
|
||
/** returns the ClassValue representing `Genshi.template.TextTemplate` */ | ||
ClassValue theGenshiTextTemplateClass() { result = Value::named("genshi.template.TextTemplate") } | ||
|
||
/** returns the ClassValue representing `Genshi.template.MarkupTemplate` */ | ||
ClassValue theGenshiMarkupTemplateClass() { | ||
result = Value::named("genshi.template.MarkupTemplate") | ||
} | ||
|
||
/** | ||
* Sink representing the `genshi.template.TextTemplate` class instantiation argument. | ||
* | ||
* from genshi.template import TextTemplate | ||
* tmpl = TextTemplate('sink') | ||
*/ | ||
class GenshiTextTemplateSink extends SSTISink { | ||
override string toString() { result = "argument to genshi.template.TextTemplate()" } | ||
|
||
GenshiTextTemplateSink() { | ||
exists(CallNode call | | ||
call.getFunction().pointsTo(theGenshiTextTemplateClass()) and | ||
call.getArg(0) = this | ||
) | ||
} | ||
|
||
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } | ||
} | ||
|
||
/** | ||
* Sink representing the `genshi.template.MarkupTemplate` class instantiation argument. | ||
* | ||
* from genshi.template import MarkupTemplate | ||
* tmpl = MarkupTemplate('sink') | ||
*/ | ||
class GenshiMarkupTemplateSink extends SSTISink { | ||
override string toString() { result = "argument to genshi.template.MarkupTemplate()" } | ||
|
||
GenshiMarkupTemplateSink() { | ||
exists(CallNode call | | ||
call.getFunction().pointsTo(theGenshiMarkupTemplateClass()) and | ||
call.getArg(0) = this | ||
) | ||
} | ||
|
||
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } | ||
} |
49 changes: 49 additions & 0 deletions
49
python/ql/src/experimental/semmle/python/templates/Jinja.qll
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
/** Provides classes which model the `Jinja2` package. */ | ||
|
||
import python | ||
import semmle.python.web.HttpRequest | ||
import experimental.semmle.python.templates.SSTISink | ||
|
||
/** returns the ClassValue representing `jinja2.Template` */ | ||
ClassValue theJinja2TemplateClass() { result = Value::named("jinja2.Template") } | ||
|
||
/** returns the ClassValue representing `jinja2.Template` */ | ||
Value theJinja2FromStringValue() { result = Value::named("jinja2.from_string") } | ||
|
||
/** | ||
* Sink representing the `jinja2.Template` class instantiation argument. | ||
* | ||
* from jinja2 import Template | ||
* template = Template(`sink`) | ||
*/ | ||
class Jinja2TemplateSink extends SSTISink { | ||
override string toString() { result = "argument to Jinja2.template()" } | ||
|
||
Jinja2TemplateSink() { | ||
exists(CallNode call | | ||
call.getFunction().pointsTo(theJinja2TemplateClass()) and | ||
call.getArg(0) = this | ||
) | ||
} | ||
|
||
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } | ||
} | ||
|
||
/** | ||
* Sink representing the `jinja2.Template` class instantiation argument. | ||
* | ||
* from jinja2 import Template | ||
* template = Template(`sink`) | ||
*/ | ||
class Jinja2FromStringSink extends SSTISink { | ||
override string toString() { result = "argument to Jinja2.from_string()" } | ||
|
||
Jinja2FromStringSink() { | ||
exists(CallNode call | | ||
call.getFunction().pointsTo(theJinja2FromStringValue()) and | ||
call.getArg(0) = this | ||
) | ||
} | ||
|
||
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } | ||
} |
Oops, something went wrong.