Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 49df416

Browse files
author
Porcupiney Hairs
committed
Python : Add query to detect Server Side Template Injection
1 parent 2e5af67 commit 49df416

64 files changed

Lines changed: 918 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/**
2+
* @name Server Side Template Injection
3+
* @description Using user-controlled data to create a template can cause security issues.
4+
* @kind path-problem
5+
* @problem.severity error
6+
* @precision high
7+
* @id py/template-injection
8+
* @tags security
9+
* external/cwe/cwe-074
10+
*/
11+
12+
import python
13+
import semmle.python.security.Paths
14+
/* Sources */
15+
import semmle.python.web.HttpRequest
16+
/* Sinks */
17+
import experimental.semmle.python.templates.Ssti
18+
19+
class TemplateInjectionConfiguration extends TaintTracking::Configuration {
20+
TemplateInjectionConfiguration() { this = "Template injection configuration" }
21+
22+
override predicate isSource(TaintTracking::Source source) {
23+
source instanceof HttpRequestTaintSource
24+
}
25+
26+
override predicate isSink(TaintTracking::Sink sink) { sink instanceof SSTISink }
27+
}
28+
29+
from TemplateInjectionConfiguration config, TaintedPathSource src, TaintedPathSink sink
30+
where config.hasFlowPath(src, sink)
31+
select sink.getSink(), src, sink, "This Template depends on $@.", src.getSource(),
32+
"a user-provided value"
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/** Provides classes which model the `airspeed` package. */
2+
3+
import python
4+
import semmle.python.web.HttpRequest
5+
import experimental.semmle.python.templates.SSTISink
6+
7+
/** returns the ClassValue representing `airspeed.Template` */
8+
ClassValue theAirspeedTemplateClass() { result = Value::named("airspeed.Template") }
9+
10+
/**
11+
* Sink representing the `airspeed.Template` class instantiation argument.
12+
*
13+
* import airspeed
14+
* temp = airspeed.Template(`"sink"`)
15+
*/
16+
class AirspeedTemplateSink extends SSTISink {
17+
override string toString() { result = "argument to airspeed.Template()" }
18+
19+
AirspeedTemplateSink() {
20+
exists(CallNode call |
21+
call.getFunction().pointsTo(theAirspeedTemplateClass()) and
22+
call.getArg(0) = this
23+
)
24+
}
25+
26+
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
27+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/** Provides classes which model the `bottle` package. */
2+
3+
import python
4+
import semmle.python.web.HttpRequest
5+
import experimental.semmle.python.templates.SSTISink
6+
7+
/** returns the ClassValue representing `bottle.SimpleTemplate` */
8+
ClassValue theBottleSimpleTemplateClass() { result = Value::named("bottle.SimpleTemplate") }
9+
10+
/**
11+
* Sink representing the `bottle.SimpleTemplate` class instantiation argument.
12+
*
13+
* from bottle import SimpleTemplate
14+
* template = SimpleTemplate(`sink`)
15+
*/
16+
class BottleSimpleTemplateSink extends SSTISink {
17+
override string toString() { result = "argument to bottle.SimpleTemplate()" }
18+
19+
BottleSimpleTemplateSink() {
20+
exists(CallNode call |
21+
call.getFunction().pointsTo(theBottleSimpleTemplateClass()) and
22+
call.getArg(0) = this
23+
)
24+
}
25+
26+
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
27+
}
28+
29+
/**
30+
* Sink representing the `bottle.template` function call argument.
31+
*
32+
* from bottle import template
33+
* tmp = template(`sink`)
34+
*/
35+
class BottleTemplateSink extends SSTISink {
36+
override string toString() { result = "argument to bottle.template()" }
37+
38+
BottleTemplateSink() {
39+
exists(CallNode call |
40+
call.getFunction() = theBottleModule().attr("template").getAReference() and
41+
call.getArg(0) = this
42+
)
43+
}
44+
45+
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
46+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/** Provides classes which model the `Chameleon` package. */
2+
3+
import python
4+
import semmle.python.web.HttpRequest
5+
import experimental.semmle.python.templates.SSTISink
6+
7+
/** returns the ClassValue representing `chameleon.PageTemplate` */
8+
ClassValue theChameleonPageTemplateClass() { result = Value::named("chameleon.PageTemplate") }
9+
10+
/**
11+
* Sink representing the `chameleon.PageTemplate` class instantiation argument.
12+
*
13+
* from chameleon import PageTemplate
14+
* template = PageTemplate(`sink`)
15+
*/
16+
class ChameleonTemplateSink extends SSTISink {
17+
override string toString() { result = "argument to Chameleon.PageTemplate()" }
18+
19+
ChameleonTemplateSink() {
20+
exists(CallNode call |
21+
call.getFunction().pointsTo(theChameleonPageTemplateClass()) and
22+
call.getArg(0) = this
23+
)
24+
}
25+
26+
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
27+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/** Provides classes which model the `Cheetah3` package. */
2+
3+
import python
4+
import semmle.python.web.HttpRequest
5+
import experimental.semmle.python.templates.SSTISink
6+
7+
/** returns the ClassValue representing `Cheetah.Template.Template` */
8+
ClassValue theCheetahTemplateClass() { result = Value::named("Cheetah.Template.Template") }
9+
10+
/**
11+
* Sink representing the instantiation argument of any class which derives from
12+
* the `Cheetah.Template.Template` class .
13+
*
14+
* from Cheetah.Template import Template
15+
* class Template3(Template):
16+
* title = 'Hello World Example!'
17+
* contents = 'Hello World!'
18+
* t3 = Template3("sink")
19+
*
20+
* This should also detect cases of the following type :
21+
*
22+
* from Cheetah.Template import Template
23+
* t3 = Template("sink")
24+
*/
25+
class CheetahTemplateInstantiationSink extends SSTISink {
26+
override string toString() { result = "argument to Cheetah.Template.Template()" }
27+
28+
CheetahTemplateInstantiationSink() {
29+
exists(CallNode call, ClassValue cv |
30+
cv.getASuperType() = theCheetahTemplateClass() and
31+
call.getFunction().pointsTo(cv) and
32+
call.getArg(0) = this
33+
)
34+
}
35+
36+
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
37+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/** Provides classes which model the `chevron` package. */
2+
3+
import python
4+
import semmle.python.web.HttpRequest
5+
import experimental.semmle.python.templates.SSTISink
6+
7+
/** returns the Value representing `chevron.render` function */
8+
Value theChevronRenderFunc() { result = Value::named("chevron.render") }
9+
10+
/**
11+
* Sink representing the `chevron.render` function call argument.
12+
*
13+
* import chevron
14+
* tmp = chevron.render(`sink`,{ 'key' : 'value' })
15+
*/
16+
class ChevronRenderSink extends SSTISink {
17+
override string toString() { result = "argument to chevron.render()" }
18+
19+
ChevronRenderSink() {
20+
exists(CallNode call |
21+
call.getFunction() = theChevronRenderFunc().getAReference() and
22+
call.getArg(0) = this
23+
)
24+
// TODO: this should also detect :
25+
// import chevron
26+
// args = {
27+
// 'template': 'sink',
28+
// 'data': {
29+
// 'mustache': 'World'
30+
// }
31+
// }
32+
// chevron.render(**args)
33+
}
34+
35+
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
36+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/** Provides classes which model the `DjangoTemplate` package. */
2+
3+
import python
4+
import semmle.python.web.HttpRequest
5+
import experimental.semmle.python.templates.SSTISink
6+
7+
ClassValue theDjangoTemplateClass() { result = Value::named("django.template.Template") }
8+
9+
/**
10+
* Sink representng `django.template.Template` class instantiation argument.
11+
*
12+
* from django.template import Template
13+
* template = Template(`sink`)
14+
*/
15+
class DjangoTemplateTemplateSink extends SSTISink {
16+
override string toString() { result = "argument to Django.template()" }
17+
18+
DjangoTemplateTemplateSink() {
19+
exists(CallNode call |
20+
call.getFunction().pointsTo(theDjangoTemplateClass()) and
21+
call.getArg(0) = this
22+
)
23+
}
24+
25+
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
26+
}
27+
28+
// TODO
29+
/**
30+
* Sinks representng the django.template.Template class instantiation.
31+
*
32+
* from django.template import engines
33+
*
34+
* django_engine = engines["django"]
35+
* template = django_engine.from_string(`sink`)
36+
*/
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/** Provides classes which model templates in the`flask` package. */
2+
3+
import python
4+
import semmle.python.web.HttpRequest
5+
import experimental.semmle.python.templates.SSTISink
6+
7+
Value theFlaskRenderTemplateClass() { result = Value::named("flask.render_template_string") }
8+
9+
/**
10+
* Sink representng `flask.render_template_string` function call argument.
11+
*
12+
* from flask import render_template_string
13+
* render_template_string(`sink`)
14+
*/
15+
class FlaskTemplateSink extends SSTISink {
16+
override string toString() { result = "argument to flask.render_template_string()" }
17+
18+
FlaskTemplateSink() {
19+
exists(CallNode call |
20+
call.getFunction().pointsTo(theFlaskRenderTemplateClass()) and
21+
call.getArg(0) = this
22+
)
23+
}
24+
25+
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
26+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/** Provides classes which model the `Genshi` package. */
2+
3+
import python
4+
import semmle.python.web.HttpRequest
5+
import experimental.semmle.python.templates.SSTISink
6+
7+
/** returns the ClassValue representing `Genshi.template.TextTemplate` */
8+
ClassValue theGenshiTextTemplateClass() { result = Value::named("genshi.template.TextTemplate") }
9+
10+
/** returns the ClassValue representing `Genshi.template.MarkupTemplate` */
11+
ClassValue theGenshiMarkupTemplateClass() {
12+
result = Value::named("genshi.template.MarkupTemplate")
13+
}
14+
15+
/**
16+
* Sink representing the `genshi.template.TextTemplate` class instantiation argument.
17+
*
18+
* from genshi.template import TextTemplate
19+
* tmpl = TextTemplate('sink')
20+
*/
21+
class GenshiTextTemplateSink extends SSTISink {
22+
override string toString() { result = "argument to genshi.template.TextTemplate()" }
23+
24+
GenshiTextTemplateSink() {
25+
exists(CallNode call |
26+
call.getFunction().pointsTo(theGenshiTextTemplateClass()) and
27+
call.getArg(0) = this
28+
)
29+
}
30+
31+
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
32+
}
33+
34+
/**
35+
* Sink representing the `genshi.template.MarkupTemplate` class instantiation argument.
36+
*
37+
* from genshi.template import MarkupTemplate
38+
* tmpl = MarkupTemplate('sink')
39+
*/
40+
class GenshiMarkupTemplateSink extends SSTISink {
41+
override string toString() { result = "argument to genshi.template.MarkupTemplate()" }
42+
43+
GenshiMarkupTemplateSink() {
44+
exists(CallNode call |
45+
call.getFunction().pointsTo(theGenshiMarkupTemplateClass()) and
46+
call.getArg(0) = this
47+
)
48+
}
49+
50+
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
51+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/** Provides classes which model the `Jinja2` package. */
2+
3+
import python
4+
import semmle.python.web.HttpRequest
5+
import experimental.semmle.python.templates.SSTISink
6+
7+
/** returns the ClassValue representing `jinja2.Template` */
8+
ClassValue theJinja2TemplateClass() { result = Value::named("jinja2.Template") }
9+
10+
/** returns the ClassValue representing `jinja2.Template` */
11+
Value theJinja2FromStringValue() { result = Value::named("jinja2.from_string") }
12+
13+
/**
14+
* Sink representing the `jinja2.Template` class instantiation argument.
15+
*
16+
* from jinja2 import Template
17+
* template = Template(`sink`)
18+
*/
19+
class Jinja2TemplateSink extends SSTISink {
20+
override string toString() { result = "argument to Jinja2.template()" }
21+
22+
Jinja2TemplateSink() {
23+
exists(CallNode call |
24+
call.getFunction().pointsTo(theJinja2TemplateClass()) and
25+
call.getArg(0) = this
26+
)
27+
}
28+
29+
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
30+
}
31+
32+
/**
33+
* Sink representing the `jinja2.Template` class instantiation argument.
34+
*
35+
* from jinja2 import Template
36+
* template = Template(`sink`)
37+
*/
38+
class Jinja2FromStringSink extends SSTISink {
39+
override string toString() { result = "argument to Jinja2.from_string()" }
40+
41+
Jinja2FromStringSink() {
42+
exists(CallNode call |
43+
call.getFunction().pointsTo(theJinja2FromStringValue()) and
44+
call.getArg(0) = this
45+
)
46+
}
47+
48+
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
49+
}

0 commit comments

Comments
 (0)