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

Skip to content

Commit 2bdd028

Browse files
committed
Python: Port py-command-line-injection with new dataflow
1 parent 7c205dd commit 2bdd028

4 files changed

Lines changed: 84 additions & 0 deletions

File tree

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/**
2+
* @name Uncontrolled command line
3+
* @description Using externally controlled strings in a command line may allow a malicious
4+
* user to change the meaning of the command.
5+
* @kind path-problem
6+
* @problem.severity error
7+
* @sub-severity high
8+
* @precision high
9+
* @id py/command-line-injection
10+
* @tags correctness
11+
* security
12+
* external/owasp/owasp-a1
13+
* external/cwe/cwe-078
14+
* external/cwe/cwe-088
15+
*/
16+
17+
import python
18+
import experimental.dataflow.DataFlow
19+
import experimental.dataflow.TaintTracking
20+
import experimental.semmle.python.Concepts
21+
import experimental.dataflow.RemoteFlowSources
22+
import DataFlow::PathGraph
23+
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()
31+
}
32+
}
33+
34+
from CommandInjectionConfiguration config, DataFlow::PathNode source, DataFlow::PathNode sink
35+
where config.hasFlowPath(source, sink)
36+
select sink.getNode(), source, sink, "This command depends on $@.", source.getNode(),
37+
"a user-provided value"
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
edges
2+
| command_injection.py:10:13:10:24 | ControlFlowNode for Attribute | command_injection.py:12:15:12:27 | ControlFlowNode for BinaryExpr |
3+
| command_injection.py:30:13:30:24 | ControlFlowNode for Attribute | command_injection.py:32:14:32:26 | ControlFlowNode for BinaryExpr |
4+
nodes
5+
| command_injection.py:10:13:10:24 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
6+
| command_injection.py:12:15:12:27 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr |
7+
| command_injection.py:30:13:30:24 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
8+
| command_injection.py:32:14:32:26 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr |
9+
#select
10+
| command_injection.py:12:15:12:27 | ControlFlowNode for BinaryExpr | command_injection.py:10:13:10:24 | ControlFlowNode for Attribute | command_injection.py:12:15:12:27 | ControlFlowNode for BinaryExpr | This command depends on $@. | command_injection.py:10:13:10:24 | ControlFlowNode for Attribute | a user-provided value |
11+
| command_injection.py:32:14:32:26 | ControlFlowNode for BinaryExpr | command_injection.py:30:13:30:24 | ControlFlowNode for Attribute | command_injection.py:32:14:32:26 | ControlFlowNode for BinaryExpr | This command depends on $@. | command_injection.py:30:13:30:24 | ControlFlowNode for Attribute | a user-provided value |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
experimental/Security-new-dataflow/CWE-078/CommandInjection.ql
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
2+
import os
3+
import subprocess
4+
5+
from flask import Flask, request
6+
app = Flask(__name__)
7+
8+
@app.route("/command1")
9+
def command_injection1():
10+
files = request.args.get('files', '')
11+
# Don't let files be `; rm -rf /`
12+
os.system("ls " + files)
13+
14+
15+
@app.route("/command2")
16+
def command_injection2():
17+
files = request.args.get('files', '')
18+
# Don't let files be `; rm -rf /`
19+
subprocess.Popen(["ls", files], shell = True)
20+
21+
22+
@app.route("/command3")
23+
def first_arg_injection():
24+
cmd = request.args.get('cmd', '')
25+
subprocess.Popen([cmd, "param1"])
26+
27+
28+
@app.route("/other_cases")
29+
def others():
30+
files = request.args.get('files', '')
31+
# Don't let files be `; rm -rf /`
32+
os.popen("ls " + files)
33+
34+
# TODO: popen2 module for Python 2 only https://devdocs.io/python~2.7/library/popen2
35+
# (deprecated since Python 2.6, but still functional in Python 2.7.17)

0 commit comments

Comments
 (0)