1
+ /** Provides classes to reason about XSLT injection vulnerabilities. */
2
+
1
3
import java
2
- import semmle.code.java.dataflow.FlowSources
4
+ import semmle.code.java.dataflow.ExternalFlow
3
5
import semmle.code.java.security.XmlParsers
4
- import DataFlow
6
+ import semmle.code.java.dataflow. DataFlow
5
7
6
8
/**
7
- * A taint-tracking configuration for unvalidated user input that is used in XSLT transformation.
9
+ * A data flow sink for unvalidated user input that is used in XSLT transformation.
10
+ * Extend this class to add your own XSLT Injection sinks.
8
11
*/
9
- class XsltInjectionFlowConfig extends TaintTracking:: Configuration {
10
- XsltInjectionFlowConfig ( ) { this = "XsltInjectionFlowConfig" }
11
-
12
- override predicate isSource ( DataFlow:: Node source ) { source instanceof RemoteFlowSource }
12
+ abstract class XsltInjectionSink extends DataFlow:: Node { }
13
+
14
+ private class DefaultXsltInjectionSinkModel extends SinkModelCsv {
15
+ override predicate row ( string row ) {
16
+ row =
17
+ [
18
+ "javax.xml.transform;Transformer;false;transform;;;Argument[-1];xslt" ,
19
+ "net.sf.saxon.s9api;XsltTransformer;false;transform;;;Argument[-1];xslt" ,
20
+ "net.sf.saxon.s9api;Xslt30Transformer;false;transform;;;Argument[-1];xslt" ,
21
+ "net.sf.saxon.s9api;Xslt30Transformer;false;applyTemplates;;;Argument[-1];xslt" ,
22
+ "net.sf.saxon.s9api;Xslt30Transformer;false;callFunction;;;Argument[-1];xslt" ,
23
+ "net.sf.saxon.s9api;Xslt30Transformer;false;callTemplate;;;Argument[-1];xslt"
24
+ ]
25
+ }
26
+ }
13
27
14
- override predicate isSink ( DataFlow:: Node sink ) { sink instanceof XsltInjectionSink }
28
+ /** A default sink representing methods susceptible to XSLT Injection attacks. */
29
+ private class DefaultXsltInjectionSink extends XsltInjectionSink {
30
+ DefaultXsltInjectionSink ( ) { sinkNode ( this , "xslt" ) }
31
+ }
15
32
16
- override predicate isSanitizer ( DataFlow:: Node node ) {
17
- node .getType ( ) instanceof PrimitiveType or node .getType ( ) instanceof BoxedType
18
- }
33
+ /**
34
+ * A unit class for adding additional taint steps.
35
+ *
36
+ * Extend this class to add additional taint steps that should apply to the `XsltInjectionFlowConfig`.
37
+ */
38
+ class XsltInjectionAdditionalTaintStep extends Unit {
39
+ /**
40
+ * Holds if the step from `node1` to `node2` should be considered a taint
41
+ * step for the `XsltInjectionFlowConfig` configuration.
42
+ */
43
+ abstract predicate step ( DataFlow:: Node node1 , DataFlow:: Node node2 ) ;
44
+ }
19
45
20
- override predicate isAdditionalTaintStep ( DataFlow:: Node node1 , DataFlow:: Node node2 ) {
46
+ /** A set of additional taint steps to consider when taint tracking XSLT related data flows. */
47
+ private class DefaultXsltInjectionAdditionalTaintStep extends XsltInjectionAdditionalTaintStep {
48
+ override predicate step ( DataFlow:: Node node1 , DataFlow:: Node node2 ) {
21
49
xmlStreamReaderStep ( node1 , node2 ) or
22
50
xmlEventReaderStep ( node1 , node2 ) or
23
51
staxSourceStep ( node1 , node2 ) or
@@ -31,95 +59,11 @@ class XsltInjectionFlowConfig extends TaintTracking::Configuration {
31
59
}
32
60
}
33
61
34
- /** The class `javax.xml.transform.stax.StAXSource`. */
35
- class TypeStAXSource extends Class {
36
- TypeStAXSource ( ) { this .hasQualifiedName ( "javax.xml.transform.stax" , "StAXSource" ) }
37
- }
38
-
39
- /** The class `javax.xml.transform.dom.DOMSource`. */
40
- class TypeDOMSource extends Class {
41
- TypeDOMSource ( ) { this .hasQualifiedName ( "javax.xml.transform.dom" , "DOMSource" ) }
42
- }
43
-
44
- /** The interface `javax.xml.transform.Templates`. */
45
- class TypeTemplates extends Interface {
46
- TypeTemplates ( ) { this .hasQualifiedName ( "javax.xml.transform" , "Templates" ) }
47
- }
48
-
49
- /** The method `net.sf.saxon.s9api.XsltTransformer.transform`. */
50
- class XsltTransformerTransformMethod extends Method {
51
- XsltTransformerTransformMethod ( ) {
52
- this .getDeclaringType ( ) .hasQualifiedName ( "net.sf.saxon.s9api" , "XsltTransformer" ) and
53
- this .hasName ( "transform" )
54
- }
55
- }
56
-
57
- /** The method `net.sf.saxon.s9api.Xslt30Transformer.transform`. */
58
- class Xslt30TransformerTransformMethod extends Method {
59
- Xslt30TransformerTransformMethod ( ) {
60
- this .getDeclaringType ( ) .hasQualifiedName ( "net.sf.saxon.s9api" , "Xslt30Transformer" ) and
61
- this .hasName ( "transform" )
62
- }
63
- }
64
-
65
- /** The method `net.sf.saxon.s9api.Xslt30Transformer.applyTemplates`. */
66
- class Xslt30TransformerApplyTemplatesMethod extends Method {
67
- Xslt30TransformerApplyTemplatesMethod ( ) {
68
- this .getDeclaringType ( ) .hasQualifiedName ( "net.sf.saxon.s9api" , "Xslt30Transformer" ) and
69
- this .hasName ( "applyTemplates" )
70
- }
71
- }
72
-
73
- /** The method `net.sf.saxon.s9api.Xslt30Transformer.callFunction`. */
74
- class Xslt30TransformerCallFunctionMethod extends Method {
75
- Xslt30TransformerCallFunctionMethod ( ) {
76
- this .getDeclaringType ( ) .hasQualifiedName ( "net.sf.saxon.s9api" , "Xslt30Transformer" ) and
77
- this .hasName ( "callFunction" )
78
- }
79
- }
80
-
81
- /** The method `net.sf.saxon.s9api.Xslt30Transformer.callTemplate`. */
82
- class Xslt30TransformerCallTemplateMethod extends Method {
83
- Xslt30TransformerCallTemplateMethod ( ) {
84
- this .getDeclaringType ( ) .hasQualifiedName ( "net.sf.saxon.s9api" , "Xslt30Transformer" ) and
85
- this .hasName ( "callTemplate" )
86
- }
87
- }
88
-
89
- /** The class `net.sf.saxon.s9api.XsltCompiler`. */
90
- class TypeXsltCompiler extends Class {
91
- TypeXsltCompiler ( ) { this .hasQualifiedName ( "net.sf.saxon.s9api" , "XsltCompiler" ) }
92
- }
93
-
94
- /** The class `net.sf.saxon.s9api.XsltExecutable`. */
95
- class TypeXsltExecutable extends Class {
96
- TypeXsltExecutable ( ) { this .hasQualifiedName ( "net.sf.saxon.s9api" , "XsltExecutable" ) }
97
- }
98
-
99
- /** The class `net.sf.saxon.s9api.XsltPackage`. */
100
- class TypeXsltPackage extends Class {
101
- TypeXsltPackage ( ) { this .hasQualifiedName ( "net.sf.saxon.s9api" , "XsltPackage" ) }
102
- }
103
-
104
- /** A data flow sink for unvalidated user input that is used in XSLT transformation. */
105
- class XsltInjectionSink extends DataFlow:: ExprNode {
106
- XsltInjectionSink ( ) {
107
- exists ( MethodAccess ma , Method m | m = ma .getMethod ( ) and ma .getQualifier ( ) = this .getExpr ( ) |
108
- ma instanceof TransformerTransform or
109
- m instanceof XsltTransformerTransformMethod or
110
- m instanceof Xslt30TransformerTransformMethod or
111
- m instanceof Xslt30TransformerApplyTemplatesMethod or
112
- m instanceof Xslt30TransformerCallFunctionMethod or
113
- m instanceof Xslt30TransformerCallTemplateMethod
114
- )
115
- }
116
- }
117
-
118
62
/**
119
63
* Holds if `n1` to `n2` is a dataflow step that converts between `InputStream` or `Reader` and
120
64
* `XMLStreamReader`, i.e. `XMLInputFactory.createXMLStreamReader(tainted)`.
121
65
*/
122
- predicate xmlStreamReaderStep ( ExprNode n1 , ExprNode n2 ) {
66
+ private predicate xmlStreamReaderStep ( DataFlow :: Node n1 , DataFlow :: Node n2 ) {
123
67
exists ( XmlInputFactoryStreamReader xmlStreamReader |
124
68
n1 .asExpr ( ) = xmlStreamReader .getSink ( ) and
125
69
n2 .asExpr ( ) = xmlStreamReader
@@ -130,7 +74,7 @@ predicate xmlStreamReaderStep(ExprNode n1, ExprNode n2) {
130
74
* Holds if `n1` to `n2` is a dataflow step that converts between `InputStream` or `Reader` and
131
75
* `XMLEventReader`, i.e. `XMLInputFactory.createXMLEventReader(tainted)`.
132
76
*/
133
- predicate xmlEventReaderStep ( ExprNode n1 , ExprNode n2 ) {
77
+ private predicate xmlEventReaderStep ( DataFlow :: Node n1 , DataFlow :: Node n2 ) {
134
78
exists ( XmlInputFactoryEventReader xmlEventReader |
135
79
n1 .asExpr ( ) = xmlEventReader .getSink ( ) and
136
80
n2 .asExpr ( ) = xmlEventReader
@@ -141,7 +85,7 @@ predicate xmlEventReaderStep(ExprNode n1, ExprNode n2) {
141
85
* Holds if `n1` to `n2` is a dataflow step that converts between `XMLStreamReader` or
142
86
* `XMLEventReader` and `StAXSource`, i.e. `new StAXSource(tainted)`.
143
87
*/
144
- predicate staxSourceStep ( ExprNode n1 , ExprNode n2 ) {
88
+ private predicate staxSourceStep ( DataFlow :: Node n1 , DataFlow :: Node n2 ) {
145
89
exists ( ConstructorCall cc | cc .getConstructedType ( ) instanceof TypeStAXSource |
146
90
n1 .asExpr ( ) = cc .getAnArgument ( ) and
147
91
n2 .asExpr ( ) = cc
@@ -152,7 +96,7 @@ predicate staxSourceStep(ExprNode n1, ExprNode n2) {
152
96
* Holds if `n1` to `n2` is a dataflow step that converts between `InputStream` and `Document`,
153
97
* i.e. `DocumentBuilder.parse(tainted)`.
154
98
*/
155
- predicate documentBuilderStep ( ExprNode n1 , ExprNode n2 ) {
99
+ private predicate documentBuilderStep ( DataFlow :: Node n1 , DataFlow :: Node n2 ) {
156
100
exists ( DocumentBuilderParse documentBuilder |
157
101
n1 .asExpr ( ) = documentBuilder .getSink ( ) and
158
102
n2 .asExpr ( ) = documentBuilder
@@ -163,13 +107,30 @@ predicate documentBuilderStep(ExprNode n1, ExprNode n2) {
163
107
* Holds if `n1` to `n2` is a dataflow step that converts between `Document` and `DOMSource`, i.e.
164
108
* `new DOMSource(tainted)`.
165
109
*/
166
- predicate domSourceStep ( ExprNode n1 , ExprNode n2 ) {
110
+ private predicate domSourceStep ( DataFlow :: Node n1 , DataFlow :: Node n2 ) {
167
111
exists ( ConstructorCall cc | cc .getConstructedType ( ) instanceof TypeDOMSource |
168
112
n1 .asExpr ( ) = cc .getAnArgument ( ) and
169
113
n2 .asExpr ( ) = cc
170
114
)
171
115
}
172
116
117
+ /**
118
+ * Holds if `n1` to `n2` is a dataflow step that converts between `Source` and `Transformer` or
119
+ * `Templates`, i.e. `TransformerFactory.newTransformer(tainted)` or
120
+ * `TransformerFactory.newTemplates(tainted)`.
121
+ */
122
+ private predicate newTransformerOrTemplatesStep ( DataFlow:: Node n1 , DataFlow:: Node n2 ) {
123
+ exists ( MethodAccess ma , Method m | ma .getMethod ( ) = m |
124
+ n1 .asExpr ( ) = ma .getAnArgument ( ) and
125
+ n2 .asExpr ( ) = ma and
126
+ m .getDeclaringType ( ) instanceof TransformerFactory and
127
+ m .hasName ( [ "newTransformer" , "newTemplates" ] ) and
128
+ not exists ( TransformerFactoryWithSecureProcessingFeatureFlowConfig conf |
129
+ conf .hasFlowToExpr ( ma .getQualifier ( ) )
130
+ )
131
+ )
132
+ }
133
+
173
134
/**
174
135
* A data flow configuration for secure processing feature that is enabled on `TransformerFactory`.
175
136
*/
@@ -207,31 +168,11 @@ private class TransformerFactoryFeatureConfig extends ParserConfig {
207
168
}
208
169
}
209
170
210
- /**
211
- * Holds if `n1` to `n2` is a dataflow step that converts between `Source` and `Transformer` or
212
- * `Templates`, i.e. `TransformerFactory.newTransformer(tainted)` or
213
- * `TransformerFactory.newTemplates(tainted)`.
214
- */
215
- predicate newTransformerOrTemplatesStep ( ExprNode n1 , ExprNode n2 ) {
216
- exists ( MethodAccess ma , Method m | ma .getMethod ( ) = m |
217
- n1 .asExpr ( ) = ma .getAnArgument ( ) and
218
- n2 .asExpr ( ) = ma and
219
- (
220
- m .getDeclaringType ( ) instanceof TransformerFactory and m .hasName ( "newTransformer" )
221
- or
222
- m .getDeclaringType ( ) instanceof TransformerFactory and m .hasName ( "newTemplates" )
223
- ) and
224
- not exists ( TransformerFactoryWithSecureProcessingFeatureFlowConfig conf |
225
- conf .hasFlowToExpr ( ma .getQualifier ( ) )
226
- )
227
- )
228
- }
229
-
230
171
/**
231
172
* Holds if `n1` to `n2` is a dataflow step that converts between `Templates` and `Transformer`,
232
173
* i.e. `tainted.newTransformer()`.
233
174
*/
234
- predicate newTransformerFromTemplatesStep ( ExprNode n1 , ExprNode n2 ) {
175
+ private predicate newTransformerFromTemplatesStep ( DataFlow :: Node n1 , DataFlow :: Node n2 ) {
235
176
exists ( MethodAccess ma , Method m | ma .getMethod ( ) = m |
236
177
n1 .asExpr ( ) = ma .getQualifier ( ) and
237
178
n2 .asExpr ( ) = ma and
@@ -246,17 +187,12 @@ predicate newTransformerFromTemplatesStep(ExprNode n1, ExprNode n2) {
246
187
* `XsltCompiler.loadExecutablePackage(tainted)` or `XsltCompiler.compilePackage(tainted)` or
247
188
* `XsltCompiler.loadLibraryPackage(tainted)`.
248
189
*/
249
- predicate xsltCompilerStep ( ExprNode n1 , ExprNode n2 ) {
190
+ private predicate xsltCompilerStep ( DataFlow :: Node n1 , DataFlow :: Node n2 ) {
250
191
exists ( MethodAccess ma , Method m | ma .getMethod ( ) = m |
251
192
n1 .asExpr ( ) = ma .getArgument ( 0 ) and
252
193
n2 .asExpr ( ) = ma and
253
194
m .getDeclaringType ( ) instanceof TypeXsltCompiler and
254
- (
255
- m .hasName ( "compile" ) or
256
- m .hasName ( "loadExecutablePackage" ) or
257
- m .hasName ( "compilePackage" ) or
258
- m .hasName ( "loadLibraryPackage" )
259
- )
195
+ m .hasName ( [ "compile" , "loadExecutablePackage" , "compilePackage" , "loadLibraryPackage" ] )
260
196
)
261
197
}
262
198
@@ -265,24 +201,54 @@ predicate xsltCompilerStep(ExprNode n1, ExprNode n2) {
265
201
* `XsltTransformer` or `Xslt30Transformer`, i.e. `XsltExecutable.load()` or
266
202
* `XsltExecutable.load30()`.
267
203
*/
268
- predicate xsltExecutableStep ( ExprNode n1 , ExprNode n2 ) {
204
+ private predicate xsltExecutableStep ( DataFlow :: Node n1 , DataFlow :: Node n2 ) {
269
205
exists ( MethodAccess ma , Method m | ma .getMethod ( ) = m |
270
206
n1 .asExpr ( ) = ma .getQualifier ( ) and
271
207
n2 .asExpr ( ) = ma and
272
208
m .getDeclaringType ( ) instanceof TypeXsltExecutable and
273
- ( m .hasName ( "load" ) or m . hasName ( "load30" ) )
209
+ m .hasName ( [ "load" , "load30" ] )
274
210
)
275
211
}
276
212
277
213
/**
278
214
* Holds if `n1` to `n2` is a dataflow step that converts between `XsltPackage` and
279
215
* `XsltExecutable`, i.e. `XsltPackage.link()`.
280
216
*/
281
- predicate xsltPackageStep ( ExprNode n1 , ExprNode n2 ) {
217
+ private predicate xsltPackageStep ( DataFlow :: Node n1 , DataFlow :: Node n2 ) {
282
218
exists ( MethodAccess ma , Method m | ma .getMethod ( ) = m |
283
219
n1 .asExpr ( ) = ma .getQualifier ( ) and
284
220
n2 .asExpr ( ) = ma and
285
221
m .getDeclaringType ( ) instanceof TypeXsltPackage and
286
222
m .hasName ( "link" )
287
223
)
288
224
}
225
+
226
+ /** The class `javax.xml.transform.stax.StAXSource`. */
227
+ private class TypeStAXSource extends Class {
228
+ TypeStAXSource ( ) { this .hasQualifiedName ( "javax.xml.transform.stax" , "StAXSource" ) }
229
+ }
230
+
231
+ /** The class `javax.xml.transform.dom.DOMSource`. */
232
+ private class TypeDOMSource extends Class {
233
+ TypeDOMSource ( ) { this .hasQualifiedName ( "javax.xml.transform.dom" , "DOMSource" ) }
234
+ }
235
+
236
+ /** The interface `javax.xml.transform.Templates`. */
237
+ private class TypeTemplates extends Interface {
238
+ TypeTemplates ( ) { this .hasQualifiedName ( "javax.xml.transform" , "Templates" ) }
239
+ }
240
+
241
+ /** The class `net.sf.saxon.s9api.XsltCompiler`. */
242
+ private class TypeXsltCompiler extends Class {
243
+ TypeXsltCompiler ( ) { this .hasQualifiedName ( "net.sf.saxon.s9api" , "XsltCompiler" ) }
244
+ }
245
+
246
+ /** The class `net.sf.saxon.s9api.XsltExecutable`. */
247
+ private class TypeXsltExecutable extends Class {
248
+ TypeXsltExecutable ( ) { this .hasQualifiedName ( "net.sf.saxon.s9api" , "XsltExecutable" ) }
249
+ }
250
+
251
+ /** The class `net.sf.saxon.s9api.XsltPackage`. */
252
+ private class TypeXsltPackage extends Class {
253
+ TypeXsltPackage ( ) { this .hasQualifiedName ( "net.sf.saxon.s9api" , "XsltPackage" ) }
254
+ }
0 commit comments