Skip to content

Commit 9573048

Browse files
committed
Python: Port py/clear-text-logging-sensitive-data
1 parent 68cfeb0 commit 9573048

File tree

5 files changed

+141
-27
lines changed

5 files changed

+141
-27
lines changed

python/ql/src/Security/CWE-312/CleartextLogging.ql

Lines changed: 9 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -14,25 +14,13 @@
1414
*/
1515

1616
import python
17-
import semmle.python.security.Paths
18-
import semmle.python.dataflow.TaintTracking
19-
import semmle.python.security.SensitiveData
20-
import semmle.python.security.ClearText
17+
private import semmle.python.dataflow.new.DataFlow
18+
import DataFlow::PathGraph
19+
import semmle.python.security.dataflow.CleartextLogging::CleartextLogging
2120

22-
class CleartextLoggingConfiguration extends TaintTracking::Configuration {
23-
CleartextLoggingConfiguration() { this = "ClearTextLogging" }
24-
25-
override predicate isSource(DataFlow::Node src, TaintKind kind) {
26-
src.asCfgNode().(SensitiveData::Source).isSourceOf(kind)
27-
}
28-
29-
override predicate isSink(DataFlow::Node sink, TaintKind kind) {
30-
sink.asCfgNode() instanceof ClearTextLogging::Sink and
31-
kind instanceof SensitiveData
32-
}
33-
}
34-
35-
from CleartextLoggingConfiguration config, TaintedPathSource source, TaintedPathSink sink
36-
where config.hasFlowPath(source, sink)
37-
select sink.getSink(), source, sink, "Sensitive data returned by $@ is logged here.",
38-
source.getSource(), source.getCfgNode().(SensitiveData::Source).repr()
21+
from Configuration config, DataFlow::PathNode source, DataFlow::PathNode sink, string classification
22+
where
23+
config.hasFlowPath(source, sink) and
24+
classification = source.getNode().(Source).getClassification()
25+
select sink.getNode(), source, sink, "$@ is logged here.", source.getNode(),
26+
"Sensitive data (" + classification + ")"
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/**
2+
* Provides a taint-tracking configuration for "Clear-text logging of sensitive information".
3+
*
4+
* Note, for performance reasons: only import this file if
5+
* `CleartextLogging::Configuration` is needed, otherwise
6+
* `CleartextLoggingCustomizations` should be imported instead.
7+
*/
8+
9+
private import python
10+
private import semmle.python.dataflow.new.DataFlow
11+
private import semmle.python.dataflow.new.TaintTracking
12+
private import semmle.python.Concepts
13+
private import semmle.python.dataflow.new.RemoteFlowSources
14+
private import semmle.python.dataflow.new.BarrierGuards
15+
private import semmle.python.dataflow.new.SensitiveDataSources
16+
17+
/**
18+
* Provides a taint-tracking configuration for detecting "Clear-text logging of sensitive information".
19+
*/
20+
module CleartextLogging {
21+
import CleartextLoggingCustomizations::CleartextLogging
22+
23+
/**
24+
* A taint-tracking configuration for detecting "Clear-text logging of sensitive information".
25+
*/
26+
class Configuration extends TaintTracking::Configuration {
27+
Configuration() { this = "CleartextLogging" }
28+
29+
override predicate isSource(DataFlow::Node source) { source instanceof Source }
30+
31+
override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
32+
33+
override predicate isSanitizer(DataFlow::Node node) {
34+
super.isSanitizer(node)
35+
or
36+
node instanceof Sanitizer
37+
}
38+
}
39+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/**
2+
* Provides default sources, sinks and sanitizers for detecting
3+
* "Clear-text logging of sensitive information"
4+
* vulnerabilities, as well as extension points for adding your own.
5+
*/
6+
7+
private import python
8+
private import semmle.python.dataflow.new.DataFlow
9+
private import semmle.python.dataflow.new.TaintTracking
10+
private import semmle.python.Concepts
11+
private import semmle.python.ApiGraphs
12+
private import semmle.python.dataflow.new.SensitiveDataSources
13+
private import semmle.python.dataflow.new.BarrierGuards
14+
15+
/**
16+
* Provides default sources, sinks and sanitizers for detecting
17+
* "Clear-text logging of sensitive information"
18+
* vulnerabilities, as well as extension points for adding your own.
19+
*/
20+
module CleartextLogging {
21+
/**
22+
* A data flow source for "Clear-text logging of sensitive information" vulnerabilities.
23+
*/
24+
abstract class Source extends DataFlow::Node {
25+
/** Gets the classification of the sensitive data. */
26+
abstract string getClassification();
27+
}
28+
29+
/**
30+
* A data flow sink for "Clear-text logging of sensitive information" vulnerabilities.
31+
*/
32+
abstract class Sink extends DataFlow::Node { }
33+
34+
/**
35+
* A sanitizer for "Clear-text logging of sensitive information" vulnerabilities.
36+
*/
37+
abstract class Sanitizer extends DataFlow::Node { }
38+
39+
/**
40+
* A source of sensitive data, considered as a flow source.
41+
*/
42+
class SensitiveDataSourceAsSource extends Source, SensitiveDataSource {
43+
override SensitiveDataClassification getClassification() {
44+
result = SensitiveDataSource.super.getClassification()
45+
}
46+
}
47+
48+
/** A piece of data logged, considered as a flow sink. */
49+
class LoggingAsSink extends Sink {
50+
LoggingAsSink() { this = any(Logging write).getAnInput() }
51+
}
52+
53+
/** A piece of data printed, considered as a flow sink. */
54+
class PrintedDataAsSink extends Sink, DataFlow::CallCfgNode {
55+
PrintedDataAsSink() {
56+
this = API::builtin("print").getACall().getArg(_)
57+
or
58+
// special handling of writing to `sys.stdout` and `sys.stderr`, which is
59+
// essentially the same as printing
60+
this =
61+
API::moduleImport("sys")
62+
.getMember(["stdout", "stderr"])
63+
.getMember("write")
64+
.getACall()
65+
.getArg(0)
66+
}
67+
}
68+
}
Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,27 @@
11
edges
2-
| test.py:19:16:19:29 | a password | test.py:20:48:20:55 | a password |
3-
| test.py:19:16:19:29 | a password | test.py:20:48:20:55 | a password |
2+
| test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:20:48:20:55 | ControlFlowNode for password |
3+
| test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:22:58:22:65 | ControlFlowNode for password |
4+
| test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:23:58:23:65 | ControlFlowNode for password |
5+
| test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:27:40:27:47 | ControlFlowNode for password |
6+
| test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:30:58:30:65 | ControlFlowNode for password |
7+
nodes
8+
| test.py:19:16:19:29 | ControlFlowNode for get_password() | semmle.label | ControlFlowNode for get_password() |
9+
| test.py:20:48:20:55 | ControlFlowNode for password | semmle.label | ControlFlowNode for password |
10+
| test.py:22:58:22:65 | ControlFlowNode for password | semmle.label | ControlFlowNode for password |
11+
| test.py:23:58:23:65 | ControlFlowNode for password | semmle.label | ControlFlowNode for password |
12+
| test.py:27:40:27:47 | ControlFlowNode for password | semmle.label | ControlFlowNode for password |
13+
| test.py:30:58:30:65 | ControlFlowNode for password | semmle.label | ControlFlowNode for password |
14+
| test.py:34:30:34:39 | ControlFlowNode for get_cert() | semmle.label | ControlFlowNode for get_cert() |
15+
| test.py:37:11:37:24 | ControlFlowNode for get_password() | semmle.label | ControlFlowNode for get_password() |
16+
| test.py:39:22:39:35 | ControlFlowNode for get_password() | semmle.label | ControlFlowNode for get_password() |
17+
| test.py:40:22:40:35 | ControlFlowNode for get_password() | semmle.label | ControlFlowNode for get_password() |
418
#select
5-
| test.py:20:48:20:55 | password | test.py:19:16:19:29 | a password | test.py:20:48:20:55 | a password | Sensitive data returned by $@ is logged here. | test.py:19:16:19:29 | get_password() | a call returning a password |
6-
| test.py:34:30:34:39 | get_cert() | test.py:34:30:34:39 | a certificate or key | test.py:34:30:34:39 | a certificate or key | Sensitive data returned by $@ is logged here. | test.py:34:30:34:39 | get_cert() | a call returning a certificate or key |
7-
| test.py:37:11:37:24 | get_password() | test.py:37:11:37:24 | a password | test.py:37:11:37:24 | a password | Sensitive data returned by $@ is logged here. | test.py:37:11:37:24 | get_password() | a call returning a password |
19+
| test.py:20:48:20:55 | ControlFlowNode for password | test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:20:48:20:55 | ControlFlowNode for password | $@ is logged here. | test.py:19:16:19:29 | ControlFlowNode for get_password() | Sensitive data (password) |
20+
| test.py:22:58:22:65 | ControlFlowNode for password | test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:22:58:22:65 | ControlFlowNode for password | $@ is logged here. | test.py:19:16:19:29 | ControlFlowNode for get_password() | Sensitive data (password) |
21+
| test.py:23:58:23:65 | ControlFlowNode for password | test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:23:58:23:65 | ControlFlowNode for password | $@ is logged here. | test.py:19:16:19:29 | ControlFlowNode for get_password() | Sensitive data (password) |
22+
| test.py:27:40:27:47 | ControlFlowNode for password | test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:27:40:27:47 | ControlFlowNode for password | $@ is logged here. | test.py:19:16:19:29 | ControlFlowNode for get_password() | Sensitive data (password) |
23+
| test.py:30:58:30:65 | ControlFlowNode for password | test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:30:58:30:65 | ControlFlowNode for password | $@ is logged here. | test.py:19:16:19:29 | ControlFlowNode for get_password() | Sensitive data (password) |
24+
| test.py:34:30:34:39 | ControlFlowNode for get_cert() | test.py:34:30:34:39 | ControlFlowNode for get_cert() | test.py:34:30:34:39 | ControlFlowNode for get_cert() | $@ is logged here. | test.py:34:30:34:39 | ControlFlowNode for get_cert() | Sensitive data (certificate) |
25+
| test.py:37:11:37:24 | ControlFlowNode for get_password() | test.py:37:11:37:24 | ControlFlowNode for get_password() | test.py:37:11:37:24 | ControlFlowNode for get_password() | $@ is logged here. | test.py:37:11:37:24 | ControlFlowNode for get_password() | Sensitive data (password) |
26+
| test.py:39:22:39:35 | ControlFlowNode for get_password() | test.py:39:22:39:35 | ControlFlowNode for get_password() | test.py:39:22:39:35 | ControlFlowNode for get_password() | $@ is logged here. | test.py:39:22:39:35 | ControlFlowNode for get_password() | Sensitive data (password) |
27+
| test.py:40:22:40:35 | ControlFlowNode for get_password() | test.py:40:22:40:35 | ControlFlowNode for get_password() | test.py:40:22:40:35 | ControlFlowNode for get_password() | $@ is logged here. | test.py:40:22:40:35 | ControlFlowNode for get_password() | Sensitive data (password) |

python/ql/test/query-tests/Security/CWE-312-CleartextLogging/options

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)