|
15 | 15 | */ |
16 | 16 |
|
17 | 17 | import python |
18 | | -import semmle.python.dataflow.new.DataFlow |
19 | | -import semmle.python.dataflow.new.TaintTracking |
20 | | -import semmle.python.Concepts |
21 | | -import semmle.python.dataflow.new.RemoteFlowSources |
| 18 | +import semmle.python.security.dataflow.CommandInjection |
22 | 19 | import DataFlow::PathGraph |
23 | 20 |
|
24 | | -class CommandInjectionConfiguration extends TaintTracking::Configuration { |
25 | | - CommandInjectionConfiguration() { this = "CommandInjectionConfiguration" } |
26 | | - |
27 | | - override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } |
28 | | - |
29 | | - override predicate isSink(DataFlow::Node sink) { |
30 | | - sink = any(SystemCommandExecution e).getCommand() and |
31 | | - // Since the implementation of standard library functions such `os.popen` looks like |
32 | | - // ```py |
33 | | - // def popen(cmd, mode="r", buffering=-1): |
34 | | - // ... |
35 | | - // proc = subprocess.Popen(cmd, ...) |
36 | | - // ``` |
37 | | - // any time we would report flow to the `os.popen` sink, we can ALSO report the flow |
38 | | - // from the `cmd` parameter to the `subprocess.Popen` sink -- obviously we don't |
39 | | - // want that. |
40 | | - // |
41 | | - // However, simply removing taint edges out of a sink is not a good enough solution, |
42 | | - // since we would only flag one of the `os.system` calls in the following example |
43 | | - // due to use-use flow |
44 | | - // ```py |
45 | | - // os.system(cmd) |
46 | | - // os.system(cmd) |
47 | | - // ``` |
48 | | - // |
49 | | - // Best solution I could come up with is to exclude all sinks inside the modules of |
50 | | - // known sinks. This does have a downside: If we have overlooked a function in any |
51 | | - // of these, that internally runs a command, we no longer give an alert :| -- and we |
52 | | - // need to keep them updated (which is hard to remember) |
53 | | - // |
54 | | - // This does not only affect `os.popen`, but also the helper functions in |
55 | | - // `subprocess`. See: |
56 | | - // https://github.com/python/cpython/blob/fa7ce080175f65d678a7d5756c94f82887fc9803/Lib/os.py#L974 |
57 | | - // https://github.com/python/cpython/blob/fa7ce080175f65d678a7d5756c94f82887fc9803/Lib/subprocess.py#L341 |
58 | | - not sink.getScope().getEnclosingModule().getName() in ["os", "subprocess", "platform", "popen2"] |
59 | | - } |
60 | | -} |
61 | | - |
62 | 21 | from CommandInjectionConfiguration config, DataFlow::PathNode source, DataFlow::PathNode sink |
63 | 22 | where config.hasFlowPath(source, sink) |
64 | 23 | select sink.getNode(), source, sink, "This command depends on $@.", source.getNode(), |
|
0 commit comments