@@ -4,45 +4,15 @@ import semmle.javascript.security.dataflow.ZipSlipQuery as ZipSlip
4
4
import semmle.javascript.security.dataflow.TaintedPathCustomizations:: TaintedPath as TaintedPath
5
5
6
6
/**
7
- * An instance of `$.util.Zip`, but the argument to the constructor call is reachable from a remote flow source.
8
- */
9
- class XSJSZipInstanceDependingOnRemoteFlowSource extends XSJSZipInstance {
10
- RemoteFlowSource remoteArgument ;
11
-
12
- XSJSZipInstanceDependingOnRemoteFlowSource ( ) {
13
- this .getAnArgument ( ) .getALocalSource ( ) = remoteArgument
14
- }
15
-
16
- RemoteFlowSource getRemoteArgument ( ) { result = remoteArgument }
17
- }
18
-
19
- class XSJSRemoteFlowSourceToZipInstanceStep extends DataFlow:: SharedFlowStep {
20
- override predicate step ( DataFlow:: Node pred , DataFlow:: Node succ ) {
21
- exists ( XSJSZipInstanceDependingOnRemoteFlowSource dollarUtilZip |
22
- pred = dollarUtilZip .getRemoteArgument ( ) and
23
- succ = dollarUtilZip
24
- )
25
- }
26
- }
27
-
28
- class ForInLoopDomainToVariableStep extends DataFlow:: SharedFlowStep {
29
- override predicate step ( DataFlow:: Node pred , DataFlow:: Node succ ) {
30
- exists ( ForInStmt forLoop |
31
- pred = forLoop .getIterationDomain ( ) .flow ( ) and
32
- succ = forLoop .getAnIterationVariable ( ) .getAnAccess ( ) .flow ( )
33
- )
34
- }
35
- }
36
-
37
- /**
38
- * A node that checks if the path that is being extracted is indeed the prefix of the entry, e.g.
7
+ * A node that checks if the path that is being extracted is indeed the prefix of the entry.
8
+ * e.g.
39
9
* ``` javascript
40
10
* if (entryPath.indexOf("SomePrefix") === 0) {
41
11
* // extract the file with the path.
42
12
* }
43
13
* ```
44
14
*/
45
- class ZipEntryPathIndexOfCallEqualsZeroGuard extends TaintTracking :: SanitizerGuardNode {
15
+ class ZipEntryPathIndexOfCallEqualsZeroGuard extends DataFlow :: Node {
46
16
EqualityTest equalityTest ;
47
17
MethodCallNode indexOfCall ;
48
18
ForInStmt forLoop ;
@@ -55,53 +25,68 @@ class ZipEntryPathIndexOfCallEqualsZeroGuard extends TaintTracking::SanitizerGua
55
25
equalityTest .getRightOperand ( ) .getIntValue ( ) = 0
56
26
}
57
27
58
- override predicate sanitizes ( boolean outcome , Expr receiver ) {
28
+ predicate blocksExpr ( boolean outcome , Expr receiver ) {
59
29
exists ( DataFlow:: Node targetFilePath , DataFlow:: Node forLoopVariable |
60
30
receiver = targetFilePath .asExpr ( ) and
61
31
targetFilePath = indexOfCall .getReceiver ( ) and
62
32
forLoopVariable = forLoop .getAnIterationVariable ( ) .getAnAccess ( ) .flow ( ) and
63
- TaintedPath:: isAdditionalTaintedPathFlowStep ( forLoopVariable ,
64
- targetFilePath .getALocalSource ( ) , _, _) and
33
+ TaintedPath:: isAdditionalFlowStep ( forLoopVariable , _, targetFilePath .getALocalSource ( ) , _) and
65
34
outcome = equalityTest .getPolarity ( )
66
35
)
67
36
}
68
37
}
69
38
70
- /**
71
- * A class wraps `TaintedPath::BarrierGuardNode` by delegating its `sanitizes/0` to the `blocks/0` predicate.
72
- * The characteristic predicate of this class is deliberately left out.
73
- */
74
- class TaintedPathSanitizerGuard extends TaintTracking:: SanitizerGuardNode {
75
- TaintedPathSanitizerGuard ( ) { this = this }
76
-
77
- override predicate sanitizes ( boolean outcome , Expr receiver ) {
78
- exists ( TaintedPath:: BarrierGuard node | node .blocksExpr ( outcome , receiver ) )
39
+ module XSJSZipSlip implements DataFlow:: StateConfigSig {
40
+ class FlowState extends string {
41
+ FlowState ( ) { this in [ "$.util.Zip uninitialized" , "$.util.Zip initialized" ] }
79
42
}
80
- }
81
43
82
- class Configuration extends TaintTracking:: Configuration {
83
- Configuration ( ) { this = "XSJS Zip Slip Query" }
44
+ predicate isSource ( DataFlow:: Node node , FlowState state ) {
45
+ node instanceof RemoteFlowSource and
46
+ state = "$.util.Zip uninitialized"
47
+ }
84
48
85
- override predicate isSource ( DataFlow:: Node start ) {
86
- super .isSource ( start )
87
- or
88
- exists ( XSJSZipInstanceDependingOnRemoteFlowSource dollarUtilZip |
89
- start = dollarUtilZip .getRemoteArgument ( )
90
- )
49
+ predicate isSink ( DataFlow:: Node node , FlowState state ) {
50
+ node instanceof ZipSlip:: Sink and
51
+ state = "$.util.Zip initialized"
91
52
}
92
53
93
- override predicate isAdditionalTaintStep ( DataFlow:: Node src , DataFlow:: Node dst ) {
94
- TaintedPath:: isAdditionalTaintedPathFlowStep ( src , dst , _, _)
54
+ predicate isBarrier ( DataFlow:: Node node , FlowState state ) {
55
+ (
56
+ node = DataFlow:: MakeBarrierGuard< ZipEntryPathIndexOfCallEqualsZeroGuard > :: getABarrierNode ( )
57
+ or
58
+ node = DataFlow:: MakeBarrierGuard< TaintedPath:: BarrierGuard > :: getABarrierNode ( )
59
+ ) and
60
+ state = state
95
61
}
96
62
97
- override predicate isSink ( DataFlow:: Node end ) {
98
- super .isSink ( end )
63
+ predicate isAdditionalFlowStep (
64
+ DataFlow:: Node start , FlowState preState , DataFlow:: Node end , FlowState postState
65
+ ) {
66
+ /* 1. `$.util.Zip` initialized */
67
+ start = start and
68
+ preState = "$.util.Zip uninitialized" and
69
+ end instanceof XSJSZipInstance and
70
+ postState = "$.util.Zip initialized"
99
71
or
100
- end instanceof ZipSlip:: Sink
101
- }
72
+ /*
73
+ * 2. Jump from a domain of a for-in statement to an access of the iteration variable.
74
+ * e.g.
75
+ * ``` javascript
76
+ * for (var x in y) {
77
+ * var z = x;
78
+ * }
79
+ * ```
80
+ * This step jumps from `y` to `x` in the body of the for-in loop.
81
+ */
102
82
103
- override predicate isSanitizerGuard ( TaintTracking:: SanitizerGuardNode node ) {
104
- node instanceof ZipEntryPathIndexOfCallEqualsZeroGuard or
105
- node instanceof TaintedPathSanitizerGuard
83
+ exists ( ForInStmt forLoop |
84
+ start = forLoop .getIterationDomain ( ) .flow ( ) and
85
+ end = forLoop .getAnIterationVariable ( ) .getAnAccess ( ) .flow ( ) and
86
+ preState = postState
87
+ )
88
+ or
89
+ TaintedPath:: isAdditionalFlowStep ( start , _, end , _) and
90
+ preState = postState
106
91
}
107
92
}
0 commit comments