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

Skip to content

Commit 06835a8

Browse files
committed
JS: Port SecondOrderCommandInjection
1 parent 4af7694 commit 06835a8

4 files changed

Lines changed: 93 additions & 49 deletions

File tree

javascript/ql/lib/semmle/javascript/security/dataflow/SecondOrderCommandInjectionCustomizations.qll

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,30 @@ module SecondOrderCommandInjection {
8383
abstract string getVulnerableArgumentExample();
8484
}
8585

86+
/**
87+
* A barrier guard for second order command-injection vulnerabilities.
88+
*/
89+
abstract class BarrierGuard extends DataFlow::Node {
90+
/**
91+
* Holds if this node acts as a barrier for data flow, blocking further flow from `e` if `this` evaluates to `outcome`.
92+
*/
93+
predicate blocksExpr(boolean outcome, Expr e) { none() }
94+
95+
/**
96+
* Holds if this node acts as a barrier for `label`, blocking further flow from `e` if `this` evaluates to `outcome`.
97+
*/
98+
predicate blocksExpr(boolean outcome, Expr e, DataFlow::FlowLabel label) { none() }
99+
}
100+
101+
/** A subclass of `BarrierGuard` that is used for backward compatibility with the old data flow library. */
102+
abstract class BarrierGuardLegacy extends BarrierGuard, TaintTracking::SanitizerGuardNode {
103+
override predicate sanitizes(boolean outcome, Expr e) { this.blocksExpr(outcome, e) }
104+
105+
override predicate sanitizes(boolean outcome, Expr e, DataFlow::FlowLabel label) {
106+
this.blocksExpr(outcome, e, label)
107+
}
108+
}
109+
86110
/**
87111
* A sink that invokes a command described by the `VulnerableCommand` class.
88112
*/
@@ -190,9 +214,8 @@ module SecondOrderCommandInjection {
190214
/**
191215
* A sanitizer that blocks flow when a string is tested to start with a certain prefix.
192216
*/
193-
class PrefixStringSanitizer extends TaintTracking::SanitizerGuardNode instanceof StringOps::StartsWith
194-
{
195-
override predicate sanitizes(boolean outcome, Expr e) {
217+
class PrefixStringSanitizer extends BarrierGuardLegacy instanceof StringOps::StartsWith {
218+
override predicate blocksExpr(boolean outcome, Expr e) {
196219
e = super.getBaseString().asExpr() and
197220
outcome = super.getPolarity()
198221
}
@@ -201,11 +224,10 @@ module SecondOrderCommandInjection {
201224
/**
202225
* A sanitizer that blocks flow when a string does not start with "--"
203226
*/
204-
class DoubleDashSanitizer extends TaintTracking::SanitizerGuardNode instanceof StringOps::StartsWith
205-
{
227+
class DoubleDashSanitizer extends BarrierGuardLegacy instanceof StringOps::StartsWith {
206228
DoubleDashSanitizer() { super.getSubstring().mayHaveStringValue("--") }
207229

208-
override predicate sanitizes(boolean outcome, Expr e) {
230+
override predicate blocksExpr(boolean outcome, Expr e) {
209231
e = super.getBaseString().asExpr() and
210232
outcome = super.getPolarity().booleanNot()
211233
}

javascript/ql/lib/semmle/javascript/security/dataflow/SecondOrderCommandInjectionQuery.qll

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,51 @@ private import semmle.javascript.security.TaintedObject
1414
/**
1515
* A taint-tracking configuration for reasoning about second order command-injection vulnerabilities.
1616
*/
17-
class Configuration extends TaintTracking::Configuration {
17+
module SecondOrderCommandInjectionConfig implements DataFlow::StateConfigSig {
18+
class FlowState = DataFlow::FlowLabel;
19+
20+
predicate isSource(DataFlow::Node source, DataFlow::FlowLabel label) {
21+
source.(Source).getALabel() = label
22+
}
23+
24+
predicate isSink(DataFlow::Node sink, DataFlow::FlowLabel label) {
25+
sink.(Sink).getALabel() = label
26+
}
27+
28+
predicate isBarrier(DataFlow::Node node) {
29+
node instanceof Sanitizer or node = DataFlow::MakeBarrierGuard<BarrierGuard>::getABarrierNode()
30+
}
31+
32+
predicate isBarrier(DataFlow::Node node, DataFlow::FlowLabel label) {
33+
TaintTracking::defaultSanitizer(node) and
34+
label.isTaint()
35+
or
36+
node = DataFlow::MakeLabeledBarrierGuard<BarrierGuard>::getABarrierNode(label)
37+
or
38+
node = TaintedObject::SanitizerGuard::getABarrierNode(label)
39+
}
40+
41+
predicate isAdditionalFlowStep(
42+
DataFlow::Node src, DataFlow::FlowLabel inlbl, DataFlow::Node trg, DataFlow::FlowLabel outlbl
43+
) {
44+
TaintedObject::step(src, trg, inlbl, outlbl)
45+
or
46+
inlbl.isTaint() and
47+
TaintTracking::defaultTaintStep(src, trg) and
48+
inlbl = outlbl
49+
}
50+
}
51+
52+
/**
53+
* Taint-tracking for reasoning about second order command-injection vulnerabilities.
54+
*/
55+
module SecondOrderCommandInjectionFlow =
56+
DataFlow::GlobalWithState<SecondOrderCommandInjectionConfig>;
57+
58+
/**
59+
* DEPRECATED. Use the `SecondOrderCommandInjectionFlow` module instead.
60+
*/
61+
deprecated class Configuration extends TaintTracking::Configuration {
1862
Configuration() { this = "SecondOrderCommandInjection" }
1963

2064
override predicate isSource(DataFlow::Node source, DataFlow::FlowLabel label) {

javascript/ql/src/Security/CWE-078/SecondOrderCommandInjection.ql

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,14 @@
1414
*/
1515

1616
import javascript
17-
import DataFlow::PathGraph
1817
import semmle.javascript.security.dataflow.SecondOrderCommandInjectionQuery
18+
import DataFlow::DeduplicatePathGraph<SecondOrderCommandInjectionFlow::PathNode, SecondOrderCommandInjectionFlow::PathGraph>
1919

20-
from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink, Sink sinkNode
21-
where cfg.hasFlowPath(source, sink) and sinkNode = sink.getNode()
20+
from PathNode source, PathNode sink, Sink sinkNode
21+
where
22+
SecondOrderCommandInjectionFlow::flowPath(source.getAnOriginalPathNode(),
23+
sink.getAnOriginalPathNode()) and
24+
sinkNode = sink.getNode()
2225
select sink.getNode(), source, sink,
2326
"Command line argument that depends on $@ can execute an arbitrary command if " +
2427
sinkNode.getVulnerableArgumentExample() + " is used with " + sinkNode.getCommand() + ".",

javascript/ql/test/query-tests/Security/CWE-078/SecondOrderCommandInjection/SecondOrderCommandInjection.expected

Lines changed: 14 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,26 @@
11
nodes
2-
| second-order.js:6:9:6:33 | remote |
3-
| second-order.js:6:18:6:33 | req.query.remote |
4-
| second-order.js:6:18:6:33 | req.query.remote |
5-
| second-order.js:7:33:7:38 | remote |
6-
| second-order.js:7:33:7:38 | remote |
7-
| second-order.js:9:29:9:34 | remote |
8-
| second-order.js:9:29:9:34 | remote |
9-
| second-order.js:11:33:11:38 | remote |
10-
| second-order.js:11:33:11:38 | remote |
11-
| second-order.js:13:9:13:31 | myArgs |
12-
| second-order.js:13:18:13:31 | req.query.args |
13-
| second-order.js:13:18:13:31 | req.query.args |
14-
| second-order.js:15:19:15:24 | myArgs |
15-
| second-order.js:15:19:15:24 | myArgs |
16-
| second-order.js:26:35:26:40 | remote |
17-
| second-order.js:26:35:26:40 | remote |
18-
| second-order.js:29:19:29:32 | req.query.args |
19-
| second-order.js:29:19:29:32 | req.query.args |
20-
| second-order.js:29:19:29:32 | req.query.args |
21-
| second-order.js:40:28:40:43 | req.query.remote |
22-
| second-order.js:40:28:40:43 | req.query.remote |
23-
| second-order.js:40:28:40:43 | req.query.remote |
24-
| second-order.js:42:31:42:46 | req.query.remote |
25-
| second-order.js:42:31:42:46 | req.query.remote |
26-
| second-order.js:42:31:42:46 | req.query.remote |
27-
| second-order.js:44:18:44:31 | req.query.args |
28-
| second-order.js:44:18:44:31 | req.query.args |
29-
| second-order.js:44:18:44:31 | req.query.args |
2+
| second-order.js:6:9:6:33 | remote | semmle.label | remote |
3+
| second-order.js:6:18:6:33 | req.query.remote | semmle.label | req.query.remote |
4+
| second-order.js:7:33:7:38 | remote | semmle.label | remote |
5+
| second-order.js:9:29:9:34 | remote | semmle.label | remote |
6+
| second-order.js:11:33:11:38 | remote | semmle.label | remote |
7+
| second-order.js:13:9:13:31 | myArgs | semmle.label | myArgs |
8+
| second-order.js:13:18:13:31 | req.query.args | semmle.label | req.query.args |
9+
| second-order.js:15:19:15:24 | myArgs | semmle.label | myArgs |
10+
| second-order.js:26:35:26:40 | remote | semmle.label | remote |
11+
| second-order.js:29:19:29:32 | req.query.args | semmle.label | req.query.args |
12+
| second-order.js:40:28:40:43 | req.query.remote | semmle.label | req.query.remote |
13+
| second-order.js:42:31:42:46 | req.query.remote | semmle.label | req.query.remote |
14+
| second-order.js:44:18:44:31 | req.query.args | semmle.label | req.query.args |
3015
edges
3116
| second-order.js:6:9:6:33 | remote | second-order.js:7:33:7:38 | remote |
32-
| second-order.js:6:9:6:33 | remote | second-order.js:7:33:7:38 | remote |
33-
| second-order.js:6:9:6:33 | remote | second-order.js:9:29:9:34 | remote |
3417
| second-order.js:6:9:6:33 | remote | second-order.js:9:29:9:34 | remote |
3518
| second-order.js:6:9:6:33 | remote | second-order.js:11:33:11:38 | remote |
36-
| second-order.js:6:9:6:33 | remote | second-order.js:11:33:11:38 | remote |
37-
| second-order.js:6:9:6:33 | remote | second-order.js:26:35:26:40 | remote |
3819
| second-order.js:6:9:6:33 | remote | second-order.js:26:35:26:40 | remote |
3920
| second-order.js:6:18:6:33 | req.query.remote | second-order.js:6:9:6:33 | remote |
40-
| second-order.js:6:18:6:33 | req.query.remote | second-order.js:6:9:6:33 | remote |
41-
| second-order.js:13:9:13:31 | myArgs | second-order.js:15:19:15:24 | myArgs |
4221
| second-order.js:13:9:13:31 | myArgs | second-order.js:15:19:15:24 | myArgs |
4322
| second-order.js:13:18:13:31 | req.query.args | second-order.js:13:9:13:31 | myArgs |
44-
| second-order.js:13:18:13:31 | req.query.args | second-order.js:13:9:13:31 | myArgs |
45-
| second-order.js:29:19:29:32 | req.query.args | second-order.js:29:19:29:32 | req.query.args |
46-
| second-order.js:40:28:40:43 | req.query.remote | second-order.js:40:28:40:43 | req.query.remote |
47-
| second-order.js:42:31:42:46 | req.query.remote | second-order.js:42:31:42:46 | req.query.remote |
48-
| second-order.js:44:18:44:31 | req.query.args | second-order.js:44:18:44:31 | req.query.args |
23+
subpaths
4924
#select
5025
| second-order.js:7:33:7:38 | remote | second-order.js:6:18:6:33 | req.query.remote | second-order.js:7:33:7:38 | remote | Command line argument that depends on $@ can execute an arbitrary command if --upload-pack is used with git. | second-order.js:6:18:6:33 | req.query.remote | a user-provided value |
5126
| second-order.js:9:29:9:34 | remote | second-order.js:6:18:6:33 | req.query.remote | second-order.js:9:29:9:34 | remote | Command line argument that depends on $@ can execute an arbitrary command if --upload-pack is used with git. | second-order.js:6:18:6:33 | req.query.remote | a user-provided value |

0 commit comments

Comments
 (0)