11import javascript
2-
32import semmle.javascript.security.dataflow.RequestForgeryCustomizations
43import semmle.javascript.security.dataflow.UrlConcatenation
54
65class Configuration extends TaintTracking:: Configuration {
7- Configuration ( ) { this = "SSRF" }
6+ Configuration ( ) { this = "SSRF" }
7+
8+ override predicate isSource ( DataFlow:: Node source ) { source instanceof RequestForgery:: Source }
89
9- override predicate isSource ( DataFlow:: Node source ) { source instanceof RequestForgery:: Source }
10+ override predicate isSink ( DataFlow:: Node sink ) { sink instanceof RequestForgery:: Sink }
1011
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+ }
1216
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+ }
1720
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+ }
2626}
2727
2828/** TODO add comment */
2929class TernaryOperatorSanitizerGuard extends TaintTracking:: SanitizerGuardNode {
30- TaintTracking:: SanitizerGuardNode originalGuard ;
30+ TaintTracking:: SanitizerGuardNode originalGuard ;
3131
32- TernaryOperatorSanitizerGuard ( ) {
32+ TernaryOperatorSanitizerGuard ( ) {
3333 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 )
3636 ) and
37- this .getAPredecessor + ( ) = originalGuard and
37+ this .getAPredecessor + ( ) = originalGuard and
3838 not this .asExpr ( ) instanceof LogicalBinaryExpr
39- }
39+ }
4040
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 )
4444 or
4545 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
5050 or
5151 originalOutcome = false and outcome = true
52- )
52+ )
5353 )
54- }
54+ }
5555}
5656
5757/** TODO add comment */
5858class TernaryOperatorSanitizer extends RequestForgery:: Sanitizer {
59- TernaryOperatorSanitizer ( ) {
59+ TernaryOperatorSanitizer ( ) {
6060 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
6363 |
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+ (
7070 outcome = true and r = ifStmt .getThen ( ) and not ifStmt .getCondition ( ) instanceof LogNotExpr
7171 or
7272 outcome = false and r = ifStmt .getElse ( ) and not ifStmt .getCondition ( ) instanceof LogNotExpr
7373 or
7474 outcome = false and r = ifStmt .getThen ( ) and ifStmt .getCondition ( ) instanceof LogNotExpr
7575 or
7676 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 ( ) )
8282 )
83- }
83+ }
8484}
8585
8686/**
8787 * Number.isInteger is a sanitizer guard because a number can't be used to exploit a SSRF.
8888 */
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" ) }
9391
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+ }
9896}
9997
10098/**
@@ -103,17 +101,19 @@ class IntegerCheck extends TaintTracking::SanitizerGuardNode, DataFlow::CallNode
103101 * checking that source is a number (any type of number) or an alphanumeric value.
104102 */
105103class 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+ }
119119}
0 commit comments