Python: CherryPy web framework support -- requests.

This commit is contained in:
Mark Shannon
2019-02-27 15:14:42 +00:00
parent e933ba28d5
commit 6c82be8bda
10 changed files with 220 additions and 0 deletions

View File

@@ -6,3 +6,4 @@ 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

View File

@@ -0,0 +1,54 @@
import python
import semmle.python.web.Http
module CherryPy {
FunctionObject expose() {
result = ModuleObject::named("cherrypy").attr("expose")
}
}
class CherryPyExposedFunction extends Function {
CherryPyExposedFunction() {
this.getADecorator().refersTo(CherryPy::expose())
}
}
class CherryPyRoute extends CallNode {
CherryPyRoute() {
/* cherrypy.quickstart(root, script_name, config) */
ModuleObject::named("cherrypy").attr("quickstart").(FunctionObject).getACall() = this
or
/* cherrypy.tree.mount(root, script_name, config) */
this.getFunction().(AttrNode).getObject("mount").refersTo(ModuleObject::named("cherrypy").attr("tree"))
}
ClassObject getAppClass() {
this.getArg(0).refersTo(_, result, _)
or
this.getArgByName("root").refersTo(_, result, _)
}
string getPath() {
exists(StringObject path |
result = path.getText()
|
this.getArg(1).refersTo(path)
or
this.getArgByName("script_name").refersTo(path)
)
}
Object getConfig() {
this.getArg(2).refersTo(_, result, _)
or
this.getArgByName("config").refersTo(_, result, _)
}
}

View File

@@ -0,0 +1,69 @@
import python
import semmle.python.security.TaintTracking
import semmle.python.security.strings.Basic
import semmle.python.web.Http
import semmle.python.web.cherrypy.General
/** A twisted.web.http.Request object */
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 = "getHeader" or
name = "getCookie" or
name = "getUser" or
name = "getPassword"
) and
result instanceof ExternalStringKind
}
}
class CherryPyExposedFunctionParameter extends TaintSource {
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
}
}
class CherryPyRequestSource extends TaintSource {
CherryPyRequestSource() {
this.(ControlFlowNode).refersTo(ModuleObject::named("cherrypy").attr("request"))
}
override predicate isSourceOf(TaintKind kind) {
kind instanceof CherryPyRequest
}
}

View File

@@ -0,0 +1,4 @@
| ../../../query-tests/Security/lib/cherrypy/__init__.py:10 | _ThreadLocalProxy() | cherrypy.request |
| ../../../query-tests/Security/lib/cherrypy/__init__.py:10 | request | cherrypy.request |
| test.py:10 | arg | externally controlled string |
| test.py:16 | arg | externally controlled string |

View File

@@ -0,0 +1,10 @@
import python
import semmle.python.web.HttpRequest
import semmle.python.security.strings.Untrusted
from TaintSource src, TaintKind kind
where src.isSourceOf(kind) and not kind.matches("tornado%")
select src.getLocation().toString(), src.(ControlFlowNode).getNode().toString(), kind

View File

@@ -0,0 +1,2 @@
semmle-extractor-options: --max-import-depth=3 --lang=3 -p ../../../query-tests/Security/lib/
optimize: true

View File

@@ -0,0 +1,11 @@
import cherrypy
class MultiPath(object):
@cherrypy.expose(['color', 'colour'])
def red(self):
return "RED"
if __name__ == '__main__':
cherrypy.quickstart(MultiPath())

View File

@@ -0,0 +1,23 @@
import random
import string
import cherrypy
class A(object):
@cherrypy.expose
def a(self, arg):
return "hello " + arg
class B(object):
@cherrypy.expose
def b(self, arg):
return "bye " + arg
cherrypy.tree.mount(A(), '/a', a_conf)
cherrypy.tree.mount(B(), '/b', b_conf)
cherrypy.engine.start()
cherrypy.engine.block()

View File

@@ -0,0 +1,15 @@
from ._helper import expose, popargs, url
class _ThreadLocalProxy(object):
def __getattr__(self, name):
pass
request = _ThreadLocalProxy('request')
response = _ThreadLocalProxy('response')
def quickstart(root=None, script_name='', config=None):
"""Mount the given root, start the builtin server (and engine), then block."""
pass

View File

@@ -0,0 +1,31 @@
def expose(func=None, alias=None):
"""Expose the function or class.
Optionally provide an alias or set of aliases.
"""
def expose_(func):
func.exposed = True
return func
return expose_
def popargs(*args, **kwargs):
"""Decorate _cp_dispatch."""
def decorated(cls_or_self=None, vpath=None):
if inspect.isclass(cls_or_self):
# cherrypy.popargs is a class decorator
return cls
# We're in the actual function
self = cls_or_self
if vpath:
return getattr(self, vpath.pop(0), None)
else:
return self
return decorated
def url(path='', qs='', script_name=None, base=None, relative=None):
#Do some opaque stuff here...
return new_url