Skip to content

Commit 3573f0b

Browse files
committed
JS: Migrate SecondOrderCommandInjection
1 parent 355f7cd commit 3573f0b

File tree

2 files changed

+30
-24
lines changed

2 files changed

+30
-24
lines changed

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

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ private import semmle.javascript.security.TaintedObjectCustomizations
1010

1111
/** Classes and predicates for reasoning about second order command injection. */
1212
module SecondOrderCommandInjection {
13+
import semmle.javascript.security.CommonFlowState
14+
1315
/** A shell command that allows for second order command injection. */
1416
private class VulnerableCommand extends string {
1517
VulnerableCommand() { this = ["git", "hg"] }
@@ -39,8 +41,11 @@ module SecondOrderCommandInjection {
3941
/** Gets a string that describes the source. For use in the alert message. */
4042
abstract string describe();
4143

42-
/** Gets a label for which this is a source. */
43-
abstract DataFlow::FlowLabel getALabel();
44+
/** Gets a flow state for which this is a source. */
45+
FlowState getAFlowState() { result.isTaint() }
46+
47+
/** DEPRECATED. Use `getAFlowState()` instead */
48+
deprecated DataFlow::FlowLabel getALabel() { result = this.getAFlowState().toFlowLabel() }
4449
}
4550

4651
/** A parameter of an exported function, seen as a source for second order command injection. */
@@ -49,18 +54,18 @@ module SecondOrderCommandInjection {
4954

5055
override string describe() { result = "library input" }
5156

52-
override DataFlow::FlowLabel getALabel() { result = TaintedObject::label() or result.isTaint() }
57+
override FlowState getAFlowState() { result.isTaintedObject() or result.isTaint() }
5358
}
5459

5560
/** A source of remote flow, seen as a source for second order command injection. */
5661
class RemoteFlowAsSource extends Source instanceof RemoteFlowSource {
5762
override string describe() { result = "a user-provided value" }
5863

59-
override DataFlow::FlowLabel getALabel() { result.isTaint() }
64+
override FlowState getAFlowState() { result.isTaint() }
6065
}
6166

6267
private class TaintedObjectSourceAsSource extends Source instanceof TaintedObject::Source {
63-
override DataFlow::FlowLabel getALabel() { result = TaintedObject::label() }
68+
override FlowState getAFlowState() { result.isTaintedObject() }
6469

6570
override string describe() { result = "a user-provided value" }
6671
}
@@ -70,8 +75,11 @@ module SecondOrderCommandInjection {
7075

7176
/** A sink for second order command injection. */
7277
abstract class Sink extends DataFlow::Node {
73-
/** Gets a label for which this is a sink. */
74-
abstract DataFlow::FlowLabel getALabel();
78+
/** Gets a flow state for which this is a sink. */
79+
FlowState getAFlowState() { result.isTaint() or result.isTaintedObject() }
80+
81+
/** DERECATED. Use `getAFlowState()` instead. */
82+
deprecated DataFlow::FlowLabel getALabel() { result = this.getAFlowState().toFlowLabel() }
7583

7684
/** Gets the command getting invoked. I.e. `git` or `hg`. */
7785
abstract string getCommand();
@@ -93,16 +101,16 @@ module SecondOrderCommandInjection {
93101
predicate blocksExpr(boolean outcome, Expr e) { none() }
94102

95103
/**
96-
* Holds if this node acts as a barrier for `label`, blocking further flow from `e` if `this` evaluates to `outcome`.
104+
* Holds if this node acts as a barrier for `state`, blocking further flow from `e` if `this` evaluates to `outcome`.
97105
*/
98-
predicate blocksExpr(boolean outcome, Expr e, DataFlow::FlowLabel label) { none() }
106+
predicate blocksExpr(boolean outcome, Expr e, FlowState state) { none() }
99107

100108
/** DEPRECATED. Use `blocksExpr` instead. */
101109
deprecated predicate sanitizes(boolean outcome, Expr e) { this.blocksExpr(outcome, e) }
102110

103111
/** DEPRECATED. Use `blocksExpr` instead. */
104112
deprecated predicate sanitizes(boolean outcome, Expr e, DataFlow::FlowLabel label) {
105-
this.blocksExpr(outcome, e, label)
113+
this.blocksExpr(outcome, e, FlowState::fromFlowLabel(label))
106114
}
107115
}
108116

@@ -205,7 +213,7 @@ module SecondOrderCommandInjection {
205213
)
206214
}
207215

208-
override DataFlow::FlowLabel getALabel() { result.isTaint() }
216+
override FlowState getAFlowState() { result.isTaint() }
209217
}
210218

211219
/**
@@ -219,7 +227,7 @@ module SecondOrderCommandInjection {
219227
}
220228

221229
// only vulnerable if an attacker controls the entire array
222-
override DataFlow::FlowLabel getALabel() { result = TaintedObject::label() }
230+
override FlowState getAFlowState() { result.isTaintedObject() }
223231
}
224232

225233
/**

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

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,33 +15,31 @@ private import semmle.javascript.security.TaintedObject
1515
* A taint-tracking configuration for reasoning about second order command-injection vulnerabilities.
1616
*/
1717
module SecondOrderCommandInjectionConfig implements DataFlow::StateConfigSig {
18-
class FlowState = DataFlow::FlowLabel;
18+
import semmle.javascript.security.CommonFlowState
1919

20-
predicate isSource(DataFlow::Node source, DataFlow::FlowLabel label) {
21-
source.(Source).getALabel() = label
20+
predicate isSource(DataFlow::Node source, FlowState state) {
21+
source.(Source).getAFlowState() = state
2222
}
2323

24-
predicate isSink(DataFlow::Node sink, DataFlow::FlowLabel label) {
25-
sink.(Sink).getALabel() = label
26-
}
24+
predicate isSink(DataFlow::Node sink, FlowState state) { sink.(Sink).getAFlowState() = state }
2725

2826
predicate isBarrier(DataFlow::Node node) {
2927
node instanceof Sanitizer or node = DataFlow::MakeBarrierGuard<BarrierGuard>::getABarrierNode()
3028
}
3129

32-
predicate isBarrier(DataFlow::Node node, DataFlow::FlowLabel label) {
30+
predicate isBarrier(DataFlow::Node node, FlowState state) {
3331
TaintTracking::defaultSanitizer(node) and
34-
label.isTaint()
32+
state.isTaint()
3533
or
36-
node = DataFlow::MakeLabeledBarrierGuard<BarrierGuard>::getABarrierNode(label)
34+
node = DataFlow::MakeStateBarrierGuard<FlowState, BarrierGuard>::getABarrierNode(state)
3735
or
38-
node = TaintedObject::SanitizerGuard::getABarrierNode(label)
36+
node = TaintedObject::SanitizerGuard::getABarrierNode(state)
3937
}
4038

4139
predicate isAdditionalFlowStep(
42-
DataFlow::Node src, DataFlow::FlowLabel inlbl, DataFlow::Node trg, DataFlow::FlowLabel outlbl
40+
DataFlow::Node src, FlowState inlbl, DataFlow::Node trg, FlowState outlbl
4341
) {
44-
TaintedObject::step(src, trg, inlbl, outlbl)
42+
TaintedObject::isAdditionalFlowStep(src, inlbl, trg, outlbl)
4543
or
4644
// We're not using a taint-tracking config because taint steps would then apply to all flow states.
4745
// So we use a plain data flow config and manually add the default taint steps.

0 commit comments

Comments
 (0)