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

Skip to content

Commit 4bd56fd

Browse files
committed
Python: Implement framework sinks
1 parent 0d8bd01 commit 4bd56fd

6 files changed

Lines changed: 165 additions & 4 deletions

File tree

python/ql/src/experimental/semmle/python/Frameworks.qll

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,7 @@
44

55
private import experimental.semmle.python.frameworks.Flask
66
private import experimental.semmle.python.frameworks.Django
7+
private import experimental.semmle.python.frameworks.Marshal
8+
private import experimental.semmle.python.frameworks.Pickle
79
private import experimental.semmle.python.frameworks.Stdlib
10+
private import experimental.semmle.python.frameworks.Yaml
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/**
2+
* Provides classes modeling security-relevant aspects of the `marshal` package.
3+
*/
4+
5+
private import python
6+
private import experimental.dataflow.DataFlow
7+
private import experimental.dataflow.RemoteFlowSources
8+
private import experimental.semmle.python.Concepts
9+
10+
private module Marshal {
11+
/** Gets a reference to the `marshal` module. */
12+
DataFlow::Node marshal(DataFlow::TypeTracker t) {
13+
t.start() and
14+
result = DataFlow::importModule("marshal")
15+
or
16+
exists(DataFlow::TypeTracker t2 | result = marshal(t2).track(t2, t))
17+
}
18+
19+
/** Gets a reference to the `marshal` module. */
20+
DataFlow::Node marshal() { result = marshal(DataFlow::TypeTracker::end()) }
21+
22+
module marshal {
23+
/** Gets a reference to the `marshal.loads` function. */
24+
DataFlow::Node loads(DataFlow::TypeTracker t) {
25+
t.start() and
26+
result = DataFlow::importMember("marshal", "loads")
27+
or
28+
t.startInAttr("loads") and
29+
result = marshal()
30+
or
31+
exists(DataFlow::TypeTracker t2 | result = marshal::loads(t2).track(t2, t))
32+
}
33+
34+
/** Gets a reference to the `marshal.loads` function. */
35+
DataFlow::Node loads() { result = marshal::loads(DataFlow::TypeTracker::end()) }
36+
}
37+
}
38+
39+
/**
40+
* A call to `marshal.loads`
41+
* See https://docs.python.org/2/library/marshal.html#marshal.load
42+
*/
43+
private class MarshalDeserialization extends DeserializationSink::Range {
44+
MarshalDeserialization() {
45+
this.asCfgNode().(CallNode).getFunction() = Marshal::marshal::loads().asCfgNode()
46+
}
47+
48+
override DataFlow::Node getData() { result.asCfgNode() = this.asCfgNode().(CallNode).getArg(0) }
49+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/**
2+
* Provides classes modeling security-relevant aspects of the `pickle` package.
3+
*/
4+
5+
private import python
6+
private import experimental.dataflow.DataFlow
7+
private import experimental.dataflow.RemoteFlowSources
8+
private import experimental.semmle.python.Concepts
9+
10+
private module Pickle {
11+
private string pickleModuleName() { result in ["pickle", "cPickle", "dill"] }
12+
13+
/** Gets a reference to the `pickle` module. */
14+
DataFlow::Node pickle(DataFlow::TypeTracker t) {
15+
t.start() and
16+
result = DataFlow::importModule(pickleModuleName())
17+
or
18+
exists(DataFlow::TypeTracker t2 | result = pickle(t2).track(t2, t))
19+
}
20+
21+
/** Gets a reference to the `pickle` module. */
22+
DataFlow::Node pickle() { result = pickle(DataFlow::TypeTracker::end()) }
23+
24+
module pickle {
25+
/** Gets a reference to the `pickle.loads` function. */
26+
DataFlow::Node loads(DataFlow::TypeTracker t) {
27+
t.start() and
28+
result = DataFlow::importMember(pickleModuleName(), "loads")
29+
or
30+
t.startInAttr("loads") and
31+
result = pickle()
32+
or
33+
exists(DataFlow::TypeTracker t2 | result = pickle::loads(t2).track(t2, t))
34+
}
35+
36+
/** Gets a reference to the `pickle.loads` function. */
37+
DataFlow::Node loads() { result = pickle::loads(DataFlow::TypeTracker::end()) }
38+
}
39+
}
40+
41+
/**
42+
* A call to `pickle.loads`
43+
* See https://docs.python.org/3/library/pickle.html#pickle.loads
44+
*/
45+
private class PickleDeserialization extends DeserializationSink::Range {
46+
PickleDeserialization() {
47+
this.asCfgNode().(CallNode).getFunction() = Pickle::pickle::loads().asCfgNode()
48+
}
49+
50+
override DataFlow::Node getData() { result.asCfgNode() = this.asCfgNode().(CallNode).getArg(0) }
51+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/**
2+
* Provides classes modeling security-relevant aspects of the `yaml` package.
3+
*/
4+
5+
private import python
6+
private import experimental.dataflow.DataFlow
7+
private import experimental.dataflow.RemoteFlowSources
8+
private import experimental.semmle.python.Concepts
9+
10+
private module Yaml {
11+
/** Gets a reference to the `yaml` module. */
12+
DataFlow::Node yaml(DataFlow::TypeTracker t) {
13+
t.start() and
14+
result = DataFlow::importModule("yaml")
15+
or
16+
exists(DataFlow::TypeTracker t2 | result = yaml(t2).track(t2, t))
17+
}
18+
19+
/** Gets a reference to the `yaml` module. */
20+
DataFlow::Node yaml() { result = yaml(DataFlow::TypeTracker::end()) }
21+
22+
module yaml {
23+
/** Gets a reference to the `yaml.load` function. */
24+
DataFlow::Node load(DataFlow::TypeTracker t) {
25+
t.start() and
26+
result = DataFlow::importMember("yaml", "load")
27+
or
28+
t.startInAttr("load") and
29+
result = yaml()
30+
or
31+
exists(DataFlow::TypeTracker t2 | result = yaml::load(t2).track(t2, t))
32+
}
33+
34+
/** Gets a reference to the `yaml.load` function. */
35+
DataFlow::Node load() { result = yaml::load(DataFlow::TypeTracker::end()) }
36+
}
37+
}
38+
39+
/**
40+
* A call to `yaml.load`
41+
* See https://pyyaml.org/wiki/PyYAMLDocumentation
42+
*/
43+
private class YamlDeserialization extends DeserializationSink::Range {
44+
YamlDeserialization() {
45+
this.asCfgNode().(CallNode).getFunction() = Yaml::yaml::load().asCfgNode()
46+
}
47+
48+
override DataFlow::Node getData() { result.asCfgNode() = this.asCfgNode().(CallNode).getArg(0) }
49+
}
Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +0,0 @@
1-
| unsafe_deserialization.py:12:28:12:45 | Comment # $getData=payload | Missing result:getData=payload |
2-
| unsafe_deserialization.py:13:25:13:42 | Comment # $getData=payload | Missing result:getData=payload |
3-
| unsafe_deserialization.py:14:29:14:46 | Comment # $getData=payload | Missing result:getData=payload |
4-
| unsafe_deserialization.py:16:26:16:43 | Comment # $getData=payload | Missing result:getData=payload |
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
11
edges
2+
| unsafe_deserialization.py:11:15:11:26 | ControlFlowNode for Attribute | unsafe_deserialization.py:12:18:12:24 | ControlFlowNode for payload |
3+
| unsafe_deserialization.py:11:15:11:26 | ControlFlowNode for Attribute | unsafe_deserialization.py:13:15:13:21 | ControlFlowNode for payload |
4+
| unsafe_deserialization.py:11:15:11:26 | ControlFlowNode for Attribute | unsafe_deserialization.py:14:19:14:25 | ControlFlowNode for payload |
5+
| unsafe_deserialization.py:11:15:11:26 | ControlFlowNode for Attribute | unsafe_deserialization.py:16:16:16:22 | ControlFlowNode for payload |
26
nodes
7+
| unsafe_deserialization.py:11:15:11:26 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
8+
| unsafe_deserialization.py:12:18:12:24 | ControlFlowNode for payload | semmle.label | ControlFlowNode for payload |
9+
| unsafe_deserialization.py:13:15:13:21 | ControlFlowNode for payload | semmle.label | ControlFlowNode for payload |
10+
| unsafe_deserialization.py:14:19:14:25 | ControlFlowNode for payload | semmle.label | ControlFlowNode for payload |
11+
| unsafe_deserialization.py:16:16:16:22 | ControlFlowNode for payload | semmle.label | ControlFlowNode for payload |
312
#select
13+
| unsafe_deserialization.py:12:18:12:24 | ControlFlowNode for payload | unsafe_deserialization.py:11:15:11:26 | ControlFlowNode for Attribute | unsafe_deserialization.py:12:18:12:24 | ControlFlowNode for payload | Deserializing of $@. | unsafe_deserialization.py:11:15:11:26 | ControlFlowNode for Attribute | untrusted input |
14+
| unsafe_deserialization.py:13:15:13:21 | ControlFlowNode for payload | unsafe_deserialization.py:11:15:11:26 | ControlFlowNode for Attribute | unsafe_deserialization.py:13:15:13:21 | ControlFlowNode for payload | Deserializing of $@. | unsafe_deserialization.py:11:15:11:26 | ControlFlowNode for Attribute | untrusted input |
15+
| unsafe_deserialization.py:14:19:14:25 | ControlFlowNode for payload | unsafe_deserialization.py:11:15:11:26 | ControlFlowNode for Attribute | unsafe_deserialization.py:14:19:14:25 | ControlFlowNode for payload | Deserializing of $@. | unsafe_deserialization.py:11:15:11:26 | ControlFlowNode for Attribute | untrusted input |
16+
| unsafe_deserialization.py:16:16:16:22 | ControlFlowNode for payload | unsafe_deserialization.py:11:15:11:26 | ControlFlowNode for Attribute | unsafe_deserialization.py:16:16:16:22 | ControlFlowNode for payload | Deserializing of $@. | unsafe_deserialization.py:11:15:11:26 | ControlFlowNode for Attribute | untrusted input |

0 commit comments

Comments
 (0)