1
1
import javascript
2
-
3
2
import semmle.javascript.security.dataflow.RequestForgeryCustomizations
4
3
import semmle.javascript.security.dataflow.UrlConcatenation
5
4
6
5
class Configuration extends TaintTracking:: Configuration {
7
- Configuration ( ) { this = "SSRF" }
6
+ Configuration ( ) { this = "SSRF" }
7
+
8
+ override predicate isSource ( DataFlow:: Node source ) { source instanceof RequestForgery:: Source }
8
9
9
- override predicate isSource ( DataFlow:: Node source ) { source instanceof RequestForgery:: Source }
10
+ override predicate isSink ( DataFlow:: Node sink ) { sink instanceof RequestForgery:: Sink }
10
11
11
- override predicate isSink ( DataFlow:: Node sink ) { sink instanceof RequestForgery:: Sink }
12
+ override predicate isSanitizer ( DataFlow:: Node node ) {
13
+ super .isSanitizer ( node ) or
14
+ node instanceof RequestForgery:: Sanitizer
15
+ }
12
16
13
- override predicate isSanitizer ( DataFlow:: Node node ) {
14
- super .isSanitizer ( node ) or
15
- node instanceof RequestForgery:: Sanitizer
16
- }
17
+ override predicate isSanitizerEdge ( DataFlow:: Node source , DataFlow:: Node sink ) {
18
+ sanitizingPrefixEdge ( source , sink )
19
+ }
17
20
18
- override predicate isSanitizerEdge ( DataFlow:: Node source , DataFlow:: Node sink ) {
19
- sanitizingPrefixEdge ( source , sink )
20
- }
21
- override predicate isSanitizerGuard ( TaintTracking:: SanitizerGuardNode nd ) {
22
- nd instanceof IntegerCheck or
23
- nd instanceof ValidatorCheck or
24
- nd instanceof TernaryOperatorSanitizerGuard
25
- }
21
+ override predicate isSanitizerGuard ( TaintTracking:: SanitizerGuardNode nd ) {
22
+ nd instanceof IntegerCheck or
23
+ nd instanceof ValidatorCheck or
24
+ nd instanceof TernaryOperatorSanitizerGuard
25
+ }
26
26
}
27
27
28
28
/** TODO add comment */
29
29
class TernaryOperatorSanitizerGuard extends TaintTracking:: SanitizerGuardNode {
30
- TaintTracking:: SanitizerGuardNode originalGuard ;
30
+ TaintTracking:: SanitizerGuardNode originalGuard ;
31
31
32
- TernaryOperatorSanitizerGuard ( ) {
32
+ TernaryOperatorSanitizerGuard ( ) {
33
33
exists ( DataFlow:: Node falseNode |
34
- this .getAPredecessor + ( ) = falseNode and
35
- falseNode .asExpr ( ) .( BooleanLiteral ) .mayHaveBooleanValue ( false )
34
+ this .getAPredecessor + ( ) = falseNode and
35
+ falseNode .asExpr ( ) .( BooleanLiteral ) .mayHaveBooleanValue ( false )
36
36
) and
37
- this .getAPredecessor + ( ) = originalGuard and
37
+ this .getAPredecessor + ( ) = originalGuard and
38
38
not this .asExpr ( ) instanceof LogicalBinaryExpr
39
- }
39
+ }
40
40
41
- override predicate sanitizes ( boolean outcome , Expr e ) {
42
- not this .asExpr ( ) instanceof LogNotExpr and
43
- originalGuard .sanitizes ( outcome , e )
41
+ override predicate sanitizes ( boolean outcome , Expr e ) {
42
+ not this .asExpr ( ) instanceof LogNotExpr and
43
+ originalGuard .sanitizes ( outcome , e )
44
44
or
45
45
exists ( boolean originalOutcome |
46
- this .asExpr ( ) instanceof LogNotExpr and
47
- originalGuard .sanitizes ( originalOutcome , e ) and
48
- (
49
- originalOutcome = true and outcome = false
46
+ this .asExpr ( ) instanceof LogNotExpr and
47
+ originalGuard .sanitizes ( originalOutcome , e ) and
48
+ (
49
+ originalOutcome = true and outcome = false
50
50
or
51
51
originalOutcome = false and outcome = true
52
- )
52
+ )
53
53
)
54
- }
54
+ }
55
55
}
56
56
57
57
/** TODO add comment */
58
58
class TernaryOperatorSanitizer extends RequestForgery:: Sanitizer {
59
- TernaryOperatorSanitizer ( ) {
59
+ TernaryOperatorSanitizer ( ) {
60
60
exists (
61
- TaintTracking:: SanitizerGuardNode guard , IfStmt ifStmt , DataFlow:: Node taintedInput , boolean outcome ,
62
- Stmt r , DataFlow:: Node falseNode
61
+ TaintTracking:: SanitizerGuardNode guard , IfStmt ifStmt , DataFlow:: Node taintedInput ,
62
+ boolean outcome , Stmt r , DataFlow:: Node falseNode
63
63
|
64
- ifStmt .getCondition ( ) .flow ( ) .getAPredecessor + ( ) = guard and
65
- ifStmt .getCondition ( ) .flow ( ) .getAPredecessor + ( ) = falseNode and
66
- falseNode .asExpr ( ) .( BooleanLiteral ) .mayHaveBooleanValue ( false ) and
67
- not ifStmt .getCondition ( ) instanceof LogicalBinaryExpr and
68
- guard .sanitizes ( outcome , taintedInput .asExpr ( ) ) and
69
- (
64
+ ifStmt .getCondition ( ) .flow ( ) .getAPredecessor + ( ) = guard and
65
+ ifStmt .getCondition ( ) .flow ( ) .getAPredecessor + ( ) = falseNode and
66
+ falseNode .asExpr ( ) .( BooleanLiteral ) .mayHaveBooleanValue ( false ) and
67
+ not ifStmt .getCondition ( ) instanceof LogicalBinaryExpr and
68
+ guard .sanitizes ( outcome , taintedInput .asExpr ( ) ) and
69
+ (
70
70
outcome = true and r = ifStmt .getThen ( ) and not ifStmt .getCondition ( ) instanceof LogNotExpr
71
71
or
72
72
outcome = false and r = ifStmt .getElse ( ) and not ifStmt .getCondition ( ) instanceof LogNotExpr
73
73
or
74
74
outcome = false and r = ifStmt .getThen ( ) and ifStmt .getCondition ( ) instanceof LogNotExpr
75
75
or
76
76
outcome = true and r = ifStmt .getElse ( ) and ifStmt .getCondition ( ) instanceof LogNotExpr
77
- ) and
78
- r .getFirstControlFlowNode ( )
79
- .getBasicBlock ( )
80
- .( ReachableBasicBlock )
81
- .dominates ( this .getBasicBlock ( ) )
77
+ ) and
78
+ r .getFirstControlFlowNode ( )
79
+ .getBasicBlock ( )
80
+ .( ReachableBasicBlock )
81
+ .dominates ( this .getBasicBlock ( ) )
82
82
)
83
- }
83
+ }
84
84
}
85
85
86
86
/**
87
87
* Number.isInteger is a sanitizer guard because a number can't be used to exploit a SSRF.
88
88
*/
89
- class IntegerCheck extends TaintTracking:: SanitizerGuardNode , DataFlow:: CallNode {
90
- IntegerCheck ( ) {
91
- this = DataFlow:: globalVarRef ( "Number" ) .getAMemberCall ( "isInteger" )
92
- }
89
+ class IntegerCheck extends TaintTracking:: SanitizerGuardNode , DataFlow:: CallNode {
90
+ IntegerCheck ( ) { this = DataFlow:: globalVarRef ( "Number" ) .getAMemberCall ( "isInteger" ) }
93
91
94
- override predicate sanitizes ( boolean outcome , Expr e ) {
95
- outcome = true and
96
- e = getArgument ( 0 ) .asExpr ( )
97
- }
92
+ override predicate sanitizes ( boolean outcome , Expr e ) {
93
+ outcome = true and
94
+ e = getArgument ( 0 ) .asExpr ( )
95
+ }
98
96
}
99
97
100
98
/**
@@ -103,17 +101,19 @@ class IntegerCheck extends TaintTracking::SanitizerGuardNode, DataFlow::CallNode
103
101
* checking that source is a number (any type of number) or an alphanumeric value.
104
102
*/
105
103
class ValidatorCheck extends TaintTracking:: SanitizerGuardNode , DataFlow:: CallNode {
106
- ValidatorCheck ( ) {
107
- exists (
108
- DataFlow:: SourceNode mod , string method |
109
- mod = DataFlow:: moduleImport ( "validator" ) and
110
- this = mod .getAChainedMethodCall ( method )
111
- and method in [ "isAlphanumeric" , "isAlpha" , "isDecimal" , "isFloat" ,
112
- "isHexadecimal" , "isHexColor" , "isInt" , "isNumeric" , "isOctal" , "isUUID" ]
113
- )
114
- }
115
- override predicate sanitizes ( boolean outcome , Expr e ) {
116
- outcome = true and
117
- e = getArgument ( 0 ) .asExpr ( )
118
- }
104
+ ValidatorCheck ( ) {
105
+ exists ( DataFlow:: SourceNode mod , string method |
106
+ mod = DataFlow:: moduleImport ( "validator" ) and
107
+ this = mod .getAChainedMethodCall ( method ) and
108
+ method in [
109
+ "isAlphanumeric" , "isAlpha" , "isDecimal" , "isFloat" , "isHexadecimal" , "isHexColor" ,
110
+ "isInt" , "isNumeric" , "isOctal" , "isUUID"
111
+ ]
112
+ )
113
+ }
114
+
115
+ override predicate sanitizes ( boolean outcome , Expr e ) {
116
+ outcome = true and
117
+ e = getArgument ( 0 ) .asExpr ( )
118
+ }
119
119
}
0 commit comments