mirror of
https://github.com/github/codeql.git
synced 2025-12-18 01:33:15 +01:00
Python : Add query to detect Server Side Template Injection
This commit is contained in:
32
python/ql/src/experimental/CWE-074/TemplateInjection.ql
Normal file
32
python/ql/src/experimental/CWE-074/TemplateInjection.ql
Normal file
@@ -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"
|
||||
@@ -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 }
|
||||
}
|
||||
@@ -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 }
|
||||
}
|
||||
@@ -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 }
|
||||
}
|
||||
@@ -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 }
|
||||
}
|
||||
@@ -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 }
|
||||
}
|
||||
@@ -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`)
|
||||
*/
|
||||
@@ -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 }
|
||||
}
|
||||
@@ -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
python/ql/src/experimental/semmle/python/templates/Jinja.qll
Normal file
49
python/ql/src/experimental/semmle/python/templates/Jinja.qll
Normal file
@@ -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 }
|
||||
}
|
||||
27
python/ql/src/experimental/semmle/python/templates/Mako.qll
Normal file
27
python/ql/src/experimental/semmle/python/templates/Mako.qll
Normal file
@@ -0,0 +1,27 @@
|
||||
/** Provides classes which model the `Mako` package. */
|
||||
|
||||
import python
|
||||
import semmle.python.web.HttpRequest
|
||||
import experimental.semmle.python.templates.SSTISink
|
||||
|
||||
/** returns the ClassValue representing `mako.template.Template` */
|
||||
ClassValue theMakoTemplateClass() { result = Value::named("mako.template.Template") }
|
||||
|
||||
/**
|
||||
* Sink representing the `mako.template.Template` class instantiation argument.
|
||||
*
|
||||
* from mako.template import Template
|
||||
* mytemplate = Template("hello world!")
|
||||
*/
|
||||
class MakoTemplateSink extends SSTISink {
|
||||
override string toString() { result = "argument to mako.template.Template()" }
|
||||
|
||||
MakoTemplateSink() {
|
||||
exists(CallNode call |
|
||||
call.getFunction().pointsTo(theMakoTemplateClass()) and
|
||||
call.getArg(0) = this
|
||||
)
|
||||
}
|
||||
|
||||
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
|
||||
/**
|
||||
* A generic taint sink that is vulnerable to template inclusions.
|
||||
* The `temp` in `Jinja2.Template(temp)` and similar.
|
||||
*/
|
||||
abstract class SSTISink extends TaintSink { }
|
||||
13
python/ql/src/experimental/semmle/python/templates/Ssti.qll
Normal file
13
python/ql/src/experimental/semmle/python/templates/Ssti.qll
Normal file
@@ -0,0 +1,13 @@
|
||||
/** Imports all files which model potential SSTI sinks */
|
||||
|
||||
import experimental.semmle.python.templates.Airspeed
|
||||
import experimental.semmle.python.templates.Bottle
|
||||
import experimental.semmle.python.templates.Chameleon
|
||||
import experimental.semmle.python.templates.Cheetah
|
||||
import experimental.semmle.python.templates.Chevron
|
||||
import experimental.semmle.python.templates.DjangoTemplate
|
||||
import experimental.semmle.python.templates.FlaskTemplate
|
||||
import experimental.semmle.python.templates.Genshi
|
||||
import experimental.semmle.python.templates.Jinja
|
||||
import experimental.semmle.python.templates.Mako
|
||||
import experimental.semmle.python.templates.TRender
|
||||
@@ -0,0 +1,27 @@
|
||||
/** Provides classes which model the `TRender` package. */
|
||||
|
||||
import python
|
||||
import semmle.python.web.HttpRequest
|
||||
import experimental.semmle.python.templates.SSTISink
|
||||
|
||||
/** returns the ClassValue representing `trender.TRender` */
|
||||
ClassValue theTRenderTemplateClass() { result = Value::named("trender.TRender") }
|
||||
|
||||
/**
|
||||
* Sink representing the `trender.TRender` class instantiation argument.
|
||||
*
|
||||
* from trender import TRender
|
||||
* template = TRender(`sink`)
|
||||
*/
|
||||
class TRenderTemplateSink extends SSTISink {
|
||||
override string toString() { result = "argument to trender.TRender()" }
|
||||
|
||||
TRenderTemplateSink() {
|
||||
exists(CallNode call |
|
||||
call.getFunction().pointsTo(theTRenderTemplateClass()) and
|
||||
call.getArg(0) = this
|
||||
)
|
||||
}
|
||||
|
||||
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import python
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
|
||||
abstract class Template extends Module { }
|
||||
|
||||
|
||||
14
python/ql/test/experimental/CWE-074/AirspeedSsti.py
Normal file
14
python/ql/test/experimental/CWE-074/AirspeedSsti.py
Normal file
@@ -0,0 +1,14 @@
|
||||
import airspeed
|
||||
from flask import Flask, request
|
||||
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
|
||||
@app.route("/")
|
||||
|
||||
|
||||
@route('/other')
|
||||
def a():
|
||||
template = request.args.get('template')
|
||||
return airspeed.Template(template)
|
||||
20
python/ql/test/experimental/CWE-074/BottleSsti.py
Normal file
20
python/ql/test/experimental/CWE-074/BottleSsti.py
Normal file
@@ -0,0 +1,20 @@
|
||||
from bottle import Bottle, route, request, redirect, response, SimpleTemplate
|
||||
from bottle import template as temp
|
||||
|
||||
|
||||
app = Bottle()
|
||||
|
||||
|
||||
@route('/other')
|
||||
def a():
|
||||
template = request.query.template
|
||||
tpl = SimpleTemplate(template)
|
||||
tpl.render(name='World')
|
||||
return tmp
|
||||
|
||||
|
||||
@route('/other2')
|
||||
def b():
|
||||
template = request.query.template
|
||||
temp(template, name='World')
|
||||
return tmp
|
||||
10
python/ql/test/experimental/CWE-074/Chameleon.py
Normal file
10
python/ql/test/experimental/CWE-074/Chameleon.py
Normal file
@@ -0,0 +1,10 @@
|
||||
from chameleon import PageTemplate
|
||||
from django.urls import path
|
||||
from django.http import HttpResponse
|
||||
|
||||
|
||||
def chameleon(request):
|
||||
template = request.GET['template']
|
||||
tmpl = PageTemplate(template)
|
||||
return HttpResponse(tmpl)
|
||||
|
||||
24
python/ql/test/experimental/CWE-074/ChevronSsti.py
Normal file
24
python/ql/test/experimental/CWE-074/ChevronSsti.py
Normal file
@@ -0,0 +1,24 @@
|
||||
from flask import Flask, request
|
||||
import chevron
|
||||
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
|
||||
@route('/other')
|
||||
def a():
|
||||
template = request.args.get('template')
|
||||
return chevron.render(template, {"key": "value"})
|
||||
|
||||
|
||||
@route('/other2')
|
||||
def b():
|
||||
template = request.args.get('template')
|
||||
args = {
|
||||
'template': template,
|
||||
|
||||
'data': {
|
||||
'key': 'value'
|
||||
}
|
||||
}
|
||||
return chevron.render(**args)
|
||||
41
python/ql/test/experimental/CWE-074/DjangoTemplates.py
Normal file
41
python/ql/test/experimental/CWE-074/DjangoTemplates.py
Normal file
@@ -0,0 +1,41 @@
|
||||
from django.urls import path
|
||||
from django.http import HttpResponse
|
||||
from django.template import Template, Context, Engine, engines
|
||||
|
||||
|
||||
def dj(request):
|
||||
# Load the template
|
||||
template = request.GET['template']
|
||||
t = Template(template)
|
||||
ctx = Context(locals())
|
||||
html = t.render(ctx)
|
||||
return HttpResponse(html)
|
||||
|
||||
|
||||
def djEngine(request):
|
||||
# Load the template
|
||||
template = request.GET['template']
|
||||
|
||||
django_engine = engines['django']
|
||||
t = django_engine.from_string(template)
|
||||
ctx = Context(locals())
|
||||
html = t.render(ctx)
|
||||
return HttpResponse(html)
|
||||
|
||||
|
||||
def djEngineJinja(request):
|
||||
# Load the template
|
||||
template = request.GET['template']
|
||||
|
||||
django_engine = engines['jinja']
|
||||
t = django_engine.from_string(template)
|
||||
ctx = Context(locals())
|
||||
html = t.render(ctx)
|
||||
return HttpResponse(html)
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
path('', dj),
|
||||
path('', djEngine),
|
||||
path('', djEngineJinja),
|
||||
]
|
||||
22
python/ql/test/experimental/CWE-074/FlaskTemplate.py
Normal file
22
python/ql/test/experimental/CWE-074/FlaskTemplate.py
Normal file
@@ -0,0 +1,22 @@
|
||||
from flask import Flask, request
|
||||
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
|
||||
@app.route("/")
|
||||
def home():
|
||||
from flask import render_template_string
|
||||
if request.args.get('template'):
|
||||
return render_template_string(request.args.get('template'))
|
||||
|
||||
|
||||
@app.route("/a")
|
||||
def home():
|
||||
import flask
|
||||
return flask.render_template_string(request.args.get('template'))
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(debug=True)
|
||||
18
python/ql/test/experimental/CWE-074/Genshi.py
Normal file
18
python/ql/test/experimental/CWE-074/Genshi.py
Normal file
@@ -0,0 +1,18 @@
|
||||
from django.urls import path
|
||||
from django.http import HttpResponse
|
||||
from genshi.template import TextTemplate,MarkupTemplate
|
||||
|
||||
def genshi1():
|
||||
template = request.GET['template']
|
||||
tmpl = MarkupTemplate(template)
|
||||
return HttpResponse(tmpl)
|
||||
|
||||
def genshi2():
|
||||
template = request.GET['template']
|
||||
tmpl = TextTemplate(template)
|
||||
return HttpResponse(tmpl)
|
||||
|
||||
urlpatterns = [
|
||||
path('', genshi1),
|
||||
path('', genshi2)
|
||||
]
|
||||
30
python/ql/test/experimental/CWE-074/JinjaSsti.py
Normal file
30
python/ql/test/experimental/CWE-074/JinjaSsti.py
Normal file
@@ -0,0 +1,30 @@
|
||||
from django.urls import path
|
||||
from django.http import HttpResponse
|
||||
from jinja2 import Template as Jinja2_Template
|
||||
from jinja2 import Environment, DictLoader, escape
|
||||
|
||||
|
||||
def j(request):
|
||||
# Load the template
|
||||
template = request.GET['template']
|
||||
t = Jinja2_Template(template)
|
||||
name = request.GET['name']
|
||||
# Render the template with the context data
|
||||
html = t.render(name=escape(name))
|
||||
return HttpResponse(html)
|
||||
|
||||
def j2(request):
|
||||
import jinja2
|
||||
# Load the template
|
||||
template = request.GET['template']
|
||||
t = jinja2.from_string(template)
|
||||
name = request.GET['name']
|
||||
# Render the template with the context data
|
||||
html = t.render(name=escape(name))
|
||||
return HttpResponse(html)
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
path('', jinja),
|
||||
path('', jinja2)
|
||||
]
|
||||
15
python/ql/test/experimental/CWE-074/MakoSsti.py
Normal file
15
python/ql/test/experimental/CWE-074/MakoSsti.py
Normal file
@@ -0,0 +1,15 @@
|
||||
from django.urls import path
|
||||
from django.http import HttpResponse
|
||||
from mako.template import Template
|
||||
|
||||
|
||||
def mako(request):
|
||||
# Load the template
|
||||
template = request.GET['template']
|
||||
mytemplate = Template(template)
|
||||
return HttpResponse(mytemplate)
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
path('', mako)
|
||||
]
|
||||
13
python/ql/test/experimental/CWE-074/TRender.py
Normal file
13
python/ql/test/experimental/CWE-074/TRender.py
Normal file
@@ -0,0 +1,13 @@
|
||||
from django.urls import path
|
||||
from django.http import HttpResponse
|
||||
from trender import TRender
|
||||
|
||||
urlpatterns = [
|
||||
path('', trender)
|
||||
]
|
||||
|
||||
|
||||
def trender(request):
|
||||
template = request.GET['template']
|
||||
compiled = TRender(template)
|
||||
return HttpResponse(compiled])
|
||||
@@ -0,0 +1,33 @@
|
||||
edges
|
||||
| AirspeedSsti.py:13:16:13:27 | dict of externally controlled string | AirspeedSsti.py:13:16:13:43 | externally controlled string |
|
||||
| AirspeedSsti.py:13:16:13:27 | dict of externally controlled string | AirspeedSsti.py:13:16:13:43 | externally controlled string |
|
||||
| AirspeedSsti.py:13:16:13:43 | externally controlled string | AirspeedSsti.py:14:30:14:37 | externally controlled string |
|
||||
| AirspeedSsti.py:13:16:13:43 | externally controlled string | AirspeedSsti.py:14:30:14:37 | externally controlled string |
|
||||
| ChevronSsti.py:10:16:10:27 | dict of externally controlled string | ChevronSsti.py:10:16:10:43 | externally controlled string |
|
||||
| ChevronSsti.py:10:16:10:27 | dict of externally controlled string | ChevronSsti.py:10:16:10:43 | externally controlled string |
|
||||
| ChevronSsti.py:10:16:10:43 | externally controlled string | ChevronSsti.py:11:27:11:34 | externally controlled string |
|
||||
| ChevronSsti.py:10:16:10:43 | externally controlled string | ChevronSsti.py:11:27:11:34 | externally controlled string |
|
||||
| DjangoTemplates.py:6:8:6:14 | django.request.HttpRequest | DjangoTemplates.py:8:16:8:22 | django.request.HttpRequest |
|
||||
| DjangoTemplates.py:6:8:6:14 | django.request.HttpRequest | DjangoTemplates.py:8:16:8:22 | django.request.HttpRequest |
|
||||
| DjangoTemplates.py:8:16:8:22 | django.request.HttpRequest | DjangoTemplates.py:8:16:8:26 | django.http.request.QueryDict |
|
||||
| DjangoTemplates.py:8:16:8:22 | django.request.HttpRequest | DjangoTemplates.py:8:16:8:26 | django.http.request.QueryDict |
|
||||
| DjangoTemplates.py:8:16:8:26 | django.http.request.QueryDict | DjangoTemplates.py:8:16:8:38 | externally controlled string |
|
||||
| DjangoTemplates.py:8:16:8:26 | django.http.request.QueryDict | DjangoTemplates.py:8:16:8:38 | externally controlled string |
|
||||
| DjangoTemplates.py:8:16:8:38 | externally controlled string | DjangoTemplates.py:9:18:9:25 | externally controlled string |
|
||||
| DjangoTemplates.py:8:16:8:38 | externally controlled string | DjangoTemplates.py:9:18:9:25 | externally controlled string |
|
||||
| FlaskTemplate.py:17:41:17:52 | dict of externally controlled string | FlaskTemplate.py:17:41:17:68 | externally controlled string |
|
||||
| FlaskTemplate.py:17:41:17:52 | dict of externally controlled string | FlaskTemplate.py:17:41:17:68 | externally controlled string |
|
||||
| MakoSsti.py:6:10:6:16 | django.request.HttpRequest | MakoSsti.py:8:16:8:22 | django.request.HttpRequest |
|
||||
| MakoSsti.py:6:10:6:16 | django.request.HttpRequest | MakoSsti.py:8:16:8:22 | django.request.HttpRequest |
|
||||
| MakoSsti.py:8:16:8:22 | django.request.HttpRequest | MakoSsti.py:8:16:8:26 | django.http.request.QueryDict |
|
||||
| MakoSsti.py:8:16:8:22 | django.request.HttpRequest | MakoSsti.py:8:16:8:26 | django.http.request.QueryDict |
|
||||
| MakoSsti.py:8:16:8:26 | django.http.request.QueryDict | MakoSsti.py:8:16:8:38 | externally controlled string |
|
||||
| MakoSsti.py:8:16:8:26 | django.http.request.QueryDict | MakoSsti.py:8:16:8:38 | externally controlled string |
|
||||
| MakoSsti.py:8:16:8:38 | externally controlled string | MakoSsti.py:9:27:9:34 | externally controlled string |
|
||||
| MakoSsti.py:8:16:8:38 | externally controlled string | MakoSsti.py:9:27:9:34 | externally controlled string |
|
||||
#select
|
||||
| AirspeedSsti.py:14:30:14:37 | template | AirspeedSsti.py:13:16:13:27 | dict of externally controlled string | AirspeedSsti.py:14:30:14:37 | externally controlled string | This Template depends on $@. | AirspeedSsti.py:13:16:13:27 | Attribute | a user-provided value |
|
||||
| ChevronSsti.py:11:27:11:34 | template | ChevronSsti.py:10:16:10:27 | dict of externally controlled string | ChevronSsti.py:11:27:11:34 | externally controlled string | This Template depends on $@. | ChevronSsti.py:10:16:10:27 | Attribute | a user-provided value |
|
||||
| DjangoTemplates.py:9:18:9:25 | template | DjangoTemplates.py:6:8:6:14 | django.request.HttpRequest | DjangoTemplates.py:9:18:9:25 | externally controlled string | This Template depends on $@. | DjangoTemplates.py:6:8:6:14 | request | a user-provided value |
|
||||
| FlaskTemplate.py:17:41:17:68 | Attribute() | FlaskTemplate.py:17:41:17:52 | dict of externally controlled string | FlaskTemplate.py:17:41:17:68 | externally controlled string | This Template depends on $@. | FlaskTemplate.py:17:41:17:52 | Attribute | a user-provided value |
|
||||
| MakoSsti.py:9:27:9:34 | template | MakoSsti.py:6:10:6:16 | django.request.HttpRequest | MakoSsti.py:9:27:9:34 | externally controlled string | This Template depends on $@. | MakoSsti.py:6:10:6:16 | request | a user-provided value |
|
||||
@@ -0,0 +1 @@
|
||||
experimental/CWE-074/TemplateInjection.ql
|
||||
1
python/ql/test/experimental/CWE-074/options
Normal file
1
python/ql/test/experimental/CWE-074/options
Normal file
@@ -0,0 +1 @@
|
||||
semmle-extractor-options: --max-import-depth=3 -p ../../query-tests/Security/lib/
|
||||
@@ -0,0 +1,10 @@
|
||||
from bottle import Bottle, route, request, redirect, response
|
||||
import airspeed
|
||||
|
||||
|
||||
app = Bottle()
|
||||
|
||||
|
||||
@route('/other')
|
||||
def a():
|
||||
return airspeed.Template("sink")
|
||||
@@ -0,0 +1 @@
|
||||
| Airspeed.py:10:30:10:35 | argument to airspeed.Template() |
|
||||
@@ -0,0 +1,5 @@
|
||||
import python
|
||||
import experimental.semmle.python.templates.Airspeed
|
||||
|
||||
from SSTISink s
|
||||
select s
|
||||
@@ -0,0 +1,17 @@
|
||||
from bottle import Bottle, route, request, redirect, response, SimpleTemplate
|
||||
from bottle import template as temp
|
||||
|
||||
|
||||
app = Bottle()
|
||||
|
||||
|
||||
@route('/other')
|
||||
def a():
|
||||
template = "test"
|
||||
tpl = SimpleTemplate(template)
|
||||
|
||||
|
||||
@route('/other2')
|
||||
def b():
|
||||
template = "test"
|
||||
return temp(template, name='World')
|
||||
@@ -0,0 +1,2 @@
|
||||
| Bottle.py:11:26:11:33 | argument to bottle.SimpleTemplate() |
|
||||
| Bottle.py:17:17:17:24 | argument to bottle.template() |
|
||||
@@ -0,0 +1,5 @@
|
||||
import python
|
||||
import experimental.semmle.python.templates.Bottle
|
||||
|
||||
from SSTISink s
|
||||
select s
|
||||
@@ -0,0 +1,5 @@
|
||||
from chameleon import PageTemplate
|
||||
|
||||
|
||||
def chameleon():
|
||||
template = PageTemplate("sink")
|
||||
@@ -0,0 +1 @@
|
||||
| Chameleon.py:5:29:5:34 | argument to Chameleon.PageTemplate() |
|
||||
@@ -0,0 +1,5 @@
|
||||
import python
|
||||
import experimental.semmle.python.templates.Chameleon
|
||||
|
||||
from SSTISink s
|
||||
select s
|
||||
@@ -0,0 +1,2 @@
|
||||
| CheetahSinks.py:10:21:10:26 | argument to Cheetah.Template.Template() |
|
||||
| CheetahSinks.py:20:20:20:25 | argument to Cheetah.Template.Template() |
|
||||
@@ -0,0 +1,5 @@
|
||||
import python
|
||||
import experimental.semmle.python.templates.Cheetah
|
||||
|
||||
from SSTISink s
|
||||
select s
|
||||
@@ -0,0 +1,20 @@
|
||||
from bottle import Bottle, route, request, redirect, response, SimpleTemplate
|
||||
from Cheetah.Template import Template
|
||||
|
||||
|
||||
app = Bottle()
|
||||
|
||||
|
||||
@route('/other')
|
||||
def a():
|
||||
return Template("sink")
|
||||
|
||||
|
||||
class Template3(Template):
|
||||
title = 'Hello World Example!'
|
||||
contents = 'Hello World!'
|
||||
|
||||
|
||||
@route('/other2')
|
||||
def b():
|
||||
t3 = Template3("sink")
|
||||
@@ -0,0 +1 @@
|
||||
| ChevronSinks.py:10:27:10:32 | argument to chevron.render() |
|
||||
@@ -0,0 +1,5 @@
|
||||
import python
|
||||
import experimental.semmle.python.templates.Chevron
|
||||
|
||||
from SSTISink s
|
||||
select s
|
||||
@@ -0,0 +1,22 @@
|
||||
from bottle import Bottle, route, request, redirect, response, SimpleTemplate
|
||||
import chevron
|
||||
|
||||
|
||||
app = Bottle()
|
||||
|
||||
|
||||
@route('/other')
|
||||
def a():
|
||||
return chevron.render("sink", {"key": "value"})
|
||||
|
||||
|
||||
@route('/other2')
|
||||
def b():
|
||||
sink = {
|
||||
'template': "template",
|
||||
|
||||
'data': {
|
||||
'key': 'value'
|
||||
}
|
||||
}
|
||||
return chevron.render(**sink)
|
||||
@@ -0,0 +1 @@
|
||||
| DjangoTemplates.py:9:18:9:25 | argument to Django.template() |
|
||||
@@ -0,0 +1,5 @@
|
||||
import python
|
||||
import experimental.semmle.python.templates.DjangoTemplate
|
||||
|
||||
from SSTISink s
|
||||
select s
|
||||
@@ -0,0 +1,39 @@
|
||||
from django.urls import path
|
||||
from django.http import HttpResponse
|
||||
from django.template import Template, Context, Engine, engines
|
||||
|
||||
|
||||
def dj(request):
|
||||
# Load the template
|
||||
template = request.GET['template']
|
||||
t = Template(template)
|
||||
ctx = Context(locals())
|
||||
html = t.render(ctx)
|
||||
return HttpResponse(html)
|
||||
|
||||
|
||||
def djEngine(request):
|
||||
# Load the template
|
||||
template = request.GET['template']
|
||||
|
||||
django_engine = engines['django']
|
||||
t = django_engine.from_string(template)
|
||||
ctx = Context(locals())
|
||||
html = t.render(ctx)
|
||||
return HttpResponse(html)
|
||||
|
||||
|
||||
def djEngineJinja(request):
|
||||
# Load the template
|
||||
template = request.GET['template']
|
||||
|
||||
django_engine = engines['jinja']
|
||||
t = django_engine.from_string(template)
|
||||
ctx = Context(locals())
|
||||
html = t.render(ctx)
|
||||
return HttpResponse(html)
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
path('', dj)
|
||||
]
|
||||
@@ -0,0 +1,10 @@
|
||||
|
||||
|
||||
def genshi1():
|
||||
from genshi.template import MarkupTemplate
|
||||
tmpl = MarkupTemplate('sink')
|
||||
|
||||
|
||||
def genshi2():
|
||||
from genshi.template import TextTemplate
|
||||
tmpl = TextTemplate('sink')
|
||||
@@ -0,0 +1,2 @@
|
||||
| Genshi.py:5:27:5:32 | argument to genshi.template.MarkupTemplate() |
|
||||
| Genshi.py:10:25:10:30 | argument to genshi.template.TextTemplate() |
|
||||
@@ -0,0 +1,5 @@
|
||||
import python
|
||||
import experimental.semmle.python.templates.Genshi
|
||||
|
||||
from SSTISink s
|
||||
select s
|
||||
@@ -0,0 +1,17 @@
|
||||
from jinja2 import Template as Jinja2_Template
|
||||
from jinja2 import Environment, DictLoader, escape
|
||||
|
||||
|
||||
def jinja():
|
||||
t = Jinja2_Template("sink")
|
||||
|
||||
|
||||
def jinja2():
|
||||
random = "esdad" + "asdad"
|
||||
t = Jinja2_Template(random)
|
||||
|
||||
|
||||
def jinja3():
|
||||
random = 1234
|
||||
t = Jinja2_Template("sink"+random)
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
| Jinja2Templates.py:6:25:6:30 | argument to Jinja2.template() |
|
||||
| Jinja2Templates.py:11:25:11:30 | argument to Jinja2.template() |
|
||||
| Jinja2Templates.py:16:25:16:37 | argument to Jinja2.template() |
|
||||
@@ -0,0 +1,5 @@
|
||||
import python
|
||||
import experimental.semmle.python.templates.Jinja
|
||||
|
||||
from SSTISink s
|
||||
select s
|
||||
@@ -0,0 +1,5 @@
|
||||
|
||||
|
||||
def mako():
|
||||
from mako.template import Template
|
||||
mytemplate = Template("sink")
|
||||
@@ -0,0 +1 @@
|
||||
| Mako.py:5:27:5:32 | argument to mako.template.Template() |
|
||||
@@ -0,0 +1,5 @@
|
||||
import python
|
||||
import experimental.semmle.python.templates.Mako
|
||||
|
||||
from SSTISink s
|
||||
select s
|
||||
@@ -0,0 +1,6 @@
|
||||
|
||||
|
||||
def trender():
|
||||
from trender import TRender
|
||||
template = '@greet world!'
|
||||
compiled = TRender(template)
|
||||
@@ -0,0 +1 @@
|
||||
| TRender.py:6:24:6:31 | argument to trender.TRender() |
|
||||
@@ -0,0 +1,5 @@
|
||||
import python
|
||||
import experimental.semmle.python.templates.TRender
|
||||
|
||||
from SSTISink s
|
||||
select s
|
||||
@@ -0,0 +1 @@
|
||||
semmle-extractor-options: --lang=3 --max-import-depth=3 -p ../../../../../query-tests/Security/lib/
|
||||
3
python/ql/test/query-tests/Security/lib/airspeed.py
Normal file
3
python/ql/test/query-tests/Security/lib/airspeed.py
Normal file
@@ -0,0 +1,3 @@
|
||||
class Template:
|
||||
def __init__(self, content, filename="<string>"):
|
||||
pass
|
||||
@@ -0,0 +1,2 @@
|
||||
class Template(object):
|
||||
pass
|
||||
6
python/ql/test/query-tests/Security/lib/chevron.py
Normal file
6
python/ql/test/query-tests/Security/lib/chevron.py
Normal file
@@ -0,0 +1,6 @@
|
||||
|
||||
|
||||
def render(template='', data={}, partials_path='.', partials_ext='mustache',
|
||||
partials_dict={}, padding='', def_ldel='{{', def_rdel='}}',
|
||||
scopes=None):
|
||||
pass
|
||||
@@ -28,3 +28,6 @@ def make_response(rv):
|
||||
|
||||
def escape(txt):
|
||||
return Markup.escape(txt)
|
||||
|
||||
def render_template_string(source, **context):
|
||||
pass
|
||||
@@ -18,3 +18,6 @@ class FileSystemLoader(object):
|
||||
|
||||
def __init__(self, searchpath):
|
||||
pass
|
||||
|
||||
def from_string(source, globals=None, template_class=None):
|
||||
pass
|
||||
Reference in New Issue
Block a user