@@ -4,6 +4,7 @@ import semmle.code.java.dataflow.FlowSources
4
4
import semmle.code.java.frameworks.Servlets
5
5
import semmle.code.java.frameworks.spring.SpringWeb
6
6
import semmle.code.java.security.RequestForgery
7
+ private import semmle.code.java.dataflow.StringPrefixes
7
8
8
9
/** A sanitizer for unsafe url forward vulnerabilities. */
9
10
abstract class UnsafeUrlForwardSanitizer extends DataFlow:: Node { }
@@ -16,76 +17,22 @@ private class PrimitiveSanitizer extends UnsafeUrlForwardSanitizer {
16
17
}
17
18
}
18
19
19
- private class UnsafeUrlForwardSantizer extends UnsafeUrlForwardSanitizer {
20
- UnsafeUrlForwardSantizer ( ) { this .asExpr ( ) instanceof UnsafeUrlForwardSanitizedExpr }
21
- }
22
-
23
- private class UnsafeUrlForwardSanitizingConstantPrefix extends CompileTimeConstantExpr {
24
- UnsafeUrlForwardSanitizingConstantPrefix ( ) {
20
+ private class SanitizingPrefix extends InterestingPrefix {
21
+ SanitizingPrefix ( ) {
25
22
not this .getStringValue ( ) .matches ( "/WEB-INF/%" ) and
26
23
not this .getStringValue ( ) = "forward:"
27
24
}
28
- }
29
25
30
- private Expr getAUnsafeUrlForwardSanitizingPrefix ( ) {
31
- result instanceof UnsafeUrlForwardSanitizingConstantPrefix
32
- or
33
- result .( AddExpr ) .getAnOperand ( ) = getAUnsafeUrlForwardSanitizingPrefix ( )
26
+ override int getOffset ( ) { result = 0 }
34
27
}
35
28
36
- private class UnsafeUrlForwardSanitizedExpr extends Expr {
37
- UnsafeUrlForwardSanitizedExpr ( ) {
38
- // Sanitize expressions that come after a sanitizing prefix in a tree of string additions:
39
- this =
40
- any ( AddExpr add | add .getLeftOperand ( ) = getAUnsafeUrlForwardSanitizingPrefix ( ) )
41
- .getRightOperand ( )
42
- or
43
- // Sanitize expressions that come after a sanitizing prefix in a sequence of StringBuilder operations:
44
- exists (
45
- StringBuilderConstructorOrAppend appendSanitizingConstant ,
46
- StringBuilderAppend subsequentAppend , StringBuilderVarExt v
47
- |
48
- appendSanitizingConstant = v .getAConstructorOrAppend ( ) and
49
- appendSanitizingConstant .getArgument ( 0 ) = getAUnsafeUrlForwardSanitizingPrefix ( ) and
50
- v .getSubsequentAppendIncludingAssignmentChains ( appendSanitizingConstant ) = subsequentAppend and
51
- this = subsequentAppend .getArgument ( 0 )
52
- )
53
- or
54
- exists ( MethodAccess ma , int i |
55
- ma .getMethod ( ) .hasName ( "format" ) and
56
- ma .getMethod ( ) .getDeclaringType ( ) instanceof TypeString and
57
- ma .getArgument ( 0 ) instanceof UnsafeUrlForwardSanitizingConstantPrefix and
58
- ma .getArgument ( i ) = this and
59
- i != 0
60
- )
61
- }
62
- }
63
-
64
- /**
65
- * A concatenate expression using the string `forward:` on the left.
66
- *
67
- * For example, `"forward:" + url`.
68
- */
69
- private class ForwardBuilderExpr extends AddExpr {
70
- ForwardBuilderExpr ( ) {
71
- this .getLeftOperand ( ) .( CompileTimeConstantExpr ) .getStringValue ( ) = "forward:"
72
- }
73
- }
74
-
75
- /**
76
- * A call to `StringBuilder.append` or `StringBuffer.append` method, and the parameter value is `"forward:"`.
77
- *
78
- * For example, `StringBuilder.append("forward:")`.
79
- */
80
- private class ForwardAppendCall extends StringBuilderAppend {
81
- ForwardAppendCall ( ) {
82
- this .getArgument ( 0 ) .( CompileTimeConstantExpr ) .getStringValue ( ) = "forward:"
83
- }
29
+ private class FollowsSanitizingPrefix extends UnsafeUrlForwardSanitizer {
30
+ FollowsSanitizingPrefix ( ) { this .asExpr ( ) = any ( SanitizingPrefix fp ) .getAnAppendedExpression ( ) }
84
31
}
85
32
86
33
abstract class UnsafeUrlForwardSink extends DataFlow:: Node { }
87
34
88
- /** A Unsafe url forward sink from getRequestDispatcher method . */
35
+ /** An argument to `ServletRequest. getRequestDispatcher` . */
89
36
private class RequestDispatcherSink extends UnsafeUrlForwardSink {
90
37
RequestDispatcherSink ( ) {
91
38
exists ( MethodAccess ma |
@@ -95,32 +42,31 @@ private class RequestDispatcherSink extends UnsafeUrlForwardSink {
95
42
}
96
43
}
97
44
98
- /** A Unsafe url forward sink from spring controller method. */
99
- private class SpringUrlForwardSink extends UnsafeUrlForwardSink {
100
- SpringUrlForwardSink ( ) {
101
- exists ( ForwardBuilderExpr rbe |
102
- rbe .getRightOperand ( ) = this .asExpr ( ) and
103
- any ( SpringRequestMappingMethod sqmm ) .polyCalls * ( this .getEnclosingCallable ( ) )
104
- )
105
- or
106
- exists ( MethodAccess ma , ForwardAppendCall rac |
107
- DataFlow2:: localExprFlow ( rac .getQualifier ( ) , ma .getQualifier ( ) ) and
108
- ma .getMethod ( ) .hasName ( "append" ) and
109
- ma .getArgument ( 0 ) = this .asExpr ( ) and
110
- any ( SpringRequestMappingMethod sqmm ) .polyCalls * ( this .getEnclosingCallable ( ) )
111
- )
112
- or
45
+ /** An argument to `new ModelAndView` or `ModelAndView.setViewName`. */
46
+ private class SpringModelAndViewSink extends UnsafeUrlForwardSink {
47
+ SpringModelAndViewSink ( ) {
113
48
exists ( ClassInstanceExpr cie |
114
49
cie .getConstructedType ( ) instanceof ModelAndView and
115
- (
116
- exists ( ForwardBuilderExpr rbe |
117
- rbe = cie .getArgument ( 0 ) and rbe .getRightOperand ( ) = this .asExpr ( )
118
- )
119
- or
120
- cie .getArgument ( 0 ) = this .asExpr ( )
121
- )
50
+ cie .getArgument ( 0 ) = this .asExpr ( )
122
51
)
123
52
or
124
53
exists ( SpringModelAndViewSetViewNameCall smavsvnc | smavsvnc .getArgument ( 0 ) = this .asExpr ( ) )
125
54
}
126
55
}
56
+
57
+ private class ForwardPrefix extends InterestingPrefix {
58
+ ForwardPrefix ( ) { this .getStringValue ( ) = "forward:" }
59
+
60
+ override int getOffset ( ) { result = 0 }
61
+ }
62
+
63
+ /**
64
+ * An expression appended (perhaps indirectly) to `"forward:"`, and which
65
+ * is reachable from a Spring entry point.
66
+ */
67
+ private class SpringUrlForwardSink extends UnsafeUrlForwardSink {
68
+ SpringUrlForwardSink ( ) {
69
+ any ( SpringRequestMappingMethod sqmm ) .polyCalls * ( this .getEnclosingCallable ( ) ) and
70
+ this .asExpr ( ) = any ( ForwardPrefix fp ) .getAnAppendedExpression ( )
71
+ }
72
+ }
0 commit comments