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

Skip to content

Commit 1444b39

Browse files
committed
Python: Add wsgi.environment as a kind of taint, and add suuport for env attribute of falcon request objects.
1 parent 9170d85 commit 1444b39

8 files changed

Lines changed: 69 additions & 19 deletions

File tree

python/ql/src/semmle/python/security/TaintTracking.qll

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ abstract class CollectionKind extends TaintKind {
167167
/* Prevent any collection kinds more than 2 deep */
168168
not this.charAt(2) = "[" and not this.charAt(2) = "{"
169169
}
170+
170171
}
171172

172173
/** A taint kind representing a flat collections of kinds.
@@ -193,7 +194,7 @@ class SequenceKind extends CollectionKind {
193194
tonode.(BinaryExprNode).getAnOperand() = fromnode
194195
)
195196
or
196-
result = this and copy_call(fromnode, tonode)
197+
result = this and TaintFlowImplementation::copyCall(fromnode, tonode)
197198
or
198199
exists(BinaryExprNode mod |
199200
mod = tonode and
@@ -236,20 +237,6 @@ private predicate slice(ControlFlowNode fromnode, SubscriptNode tonode) {
236237
)
237238
}
238239

239-
/* A call that returns a copy (or similar) of the argument */
240-
private predicate copy_call(ControlFlowNode fromnode, CallNode tonode) {
241-
tonode.getFunction().(AttrNode).getObject("copy") = fromnode
242-
or
243-
exists(ModuleObject copy, string name |
244-
name = "copy" or name = "deepcopy" |
245-
copy.attr(name).(FunctionObject).getACall() = tonode and
246-
tonode.getArg(0) = fromnode
247-
)
248-
or
249-
tonode.getFunction().refersTo(Object::builtin("reversed")) and
250-
tonode.getArg(0) = fromnode
251-
}
252-
253240
/** A taint kind representing a mapping of objects to kinds.
254241
* Typically a dict, but can include other mappings.
255242
*/
@@ -272,7 +259,7 @@ class DictKind extends CollectionKind {
272259
result = valueKind and
273260
tonode.(CallNode).getFunction().(AttrNode).getObject("get") = fromnode
274261
or
275-
result = this and copy_call(fromnode, tonode)
262+
result = this and TaintFlowImplementation::copyCall(fromnode, tonode)
276263
or
277264
result = this and
278265
tonode.(CallNode).getFunction().refersTo(theDictType()) and
@@ -1263,6 +1250,20 @@ library module TaintFlowImplementation {
12631250
context = fromnode.getContext()
12641251
}
12651252

1253+
/* A call that returns a copy (or similar) of the argument */
1254+
predicate copyCall(ControlFlowNode fromnode, CallNode tonode) {
1255+
tonode.getFunction().(AttrNode).getObject("copy") = fromnode
1256+
or
1257+
exists(ModuleObject copy, string name |
1258+
name = "copy" or name = "deepcopy" |
1259+
copy.attr(name).(FunctionObject).getACall() = tonode and
1260+
tonode.getArg(0) = fromnode
1261+
)
1262+
or
1263+
tonode.getFunction().refersTo(Object::builtin("reversed")) and
1264+
tonode.getArg(0) = fromnode
1265+
}
1266+
12661267
}
12671268

12681269
/* Helper predicate for tainted_with */

python/ql/src/semmle/python/security/strings/External.qll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,15 +96,15 @@ private predicate json_load(ControlFlowNode fromnode, CallNode tonode) {
9696
)
9797
}
9898

99-
/** A kind of "taint", representing am open file-like object from an external source. */
99+
/** A kind of "taint", representing an open file-like object from an external source. */
100100
class ExternalFileObject extends TaintKind {
101101

102102
ExternalFileObject() {
103103
this = "file[" + any(ExternalStringKind key) + "]"
104104
}
105105

106106

107-
/** Gets the taint kind for item in this sequence */
107+
/** Gets the taint kind for the contents of this file */
108108
TaintKind getValue() {
109109
this = "file[" + result + "]"
110110
}

python/ql/src/semmle/python/web/Http.qll

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,37 @@ string httpVerb() {
2323
string httpVerbLower() {
2424
result = httpVerb().toLowerCase()
2525
}
26+
27+
/** Taint kind representing the WSGI environment.
28+
* As specified in PEP 3333. https://www.python.org/dev/peps/pep-3333/#environ-variables
29+
*/
30+
class WsgiEnvironment extends TaintKind {
31+
32+
WsgiEnvironment() { this = "wsgi.environment" }
33+
34+
override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) {
35+
result = this and TaintFlowImplementation::copyCall(fromnode, tonode)
36+
or
37+
result = this and
38+
tonode.(CallNode).getFunction().refersTo(theDictType()) and
39+
tonode.(CallNode).getArg(0) = fromnode
40+
or
41+
exists(StringObject key, string text |
42+
tonode.(CallNode).getFunction().(AttrNode).getObject("get") = fromnode and
43+
tonode.(CallNode).getArg(0).refersTo(key)
44+
or
45+
tonode.(SubscriptNode).getValue() = fromnode and tonode.isLoad() and
46+
tonode.(SubscriptNode).getIndex().refersTo(key)
47+
|
48+
text = key.getText() and result instanceof ExternalStringKind and
49+
(
50+
text = "QUERY_STRING" or
51+
text = "PATH_INFO" or
52+
text.prefix(5) = "HTTP_"
53+
)
54+
)
55+
}
56+
57+
}
58+
59+

python/ql/src/semmle/python/web/falcon/Request.qll

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ class FalconRequest extends TaintKind {
1313
}
1414

1515
override TaintKind getTaintOfAttribute(string name) {
16-
// name = "env" and result instanceof WsgiEnvironment
16+
name = "env" and result instanceof WsgiEnvironment
17+
or
1718
result instanceof ExternalStringKind and
1819
(
1920
name = "uri" or name = "url" or
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1+
| /hello | delete | test.py:22:5:22:35 | Function on_delete |
12
| /hello | get | test.py:9:5:9:32 | Function on_get |
23
| /hello | post | test.py:19:5:19:33 | Function on_post |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
| test.py:9 | req | falcon.request |
22
| test.py:19 | req | falcon.request |
3+
| test.py:22 | req | falcon.request |

python/ql/test/library-tests/web/falcon/Taint.expected

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,10 @@
1616
| test.py:17 | result | {json[externally controlled string]} |
1717
| test.py:19 | req | falcon.request |
1818
| test.py:19 | resp | falcon.response |
19+
| test.py:22 | req | falcon.request |
20+
| test.py:22 | resp | falcon.response |
21+
| test.py:23 | Attribute | wsgi.environment |
22+
| test.py:23 | req | falcon.request |
23+
| test.py:24 | Subscript | externally controlled string |
24+
| test.py:24 | env | wsgi.environment |
25+
| test.py:25 | qs | externally controlled string |

python/ql/test/library-tests/web/falcon/test.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,10 @@ def on_get(self, req, resp):
1919
def on_post(self, req, resp):
2020
pass
2121

22+
def on_delete(self, req, resp):
23+
env = req.env
24+
qs = env["QUERY_STRING"]
25+
return qs
26+
2227
app.add_route('/hello', Handler())
2328

0 commit comments

Comments
 (0)