1
1
import java
2
2
import semmle.code.xml.MyBatisMapperXML
3
3
import semmle.code.java.dataflow.FlowSources
4
+ import semmle.code.java.frameworks.MyBatis
5
+ import semmle.code.java.frameworks.Properties
6
+
7
+ private predicate propertiesKey ( DataFlow:: Node prop , string key ) {
8
+ exists ( MethodAccess m |
9
+ m .getMethod ( ) instanceof PropertiesSetPropertyMethod and
10
+ key = m .getArgument ( 0 ) .( CompileTimeConstantExpr ) .getStringValue ( ) and
11
+ prop .asExpr ( ) = m .getQualifier ( )
12
+ )
13
+ }
14
+
15
+ private class PropertiesFlowConfig extends DataFlow2:: Configuration {
16
+ PropertiesFlowConfig ( ) { this = "PropertiesFlowConfig" }
17
+
18
+ override predicate isSource ( DataFlow:: Node src ) {
19
+ exists ( MethodAccess ma | ma .getMethod ( ) instanceof IbatisConfigurationGetVariablesMethod |
20
+ src .asExpr ( ) = ma
21
+ )
22
+ }
23
+
24
+ override predicate isSink ( DataFlow:: Node sink ) { propertiesKey ( sink , _) }
25
+ }
26
+
27
+ /** Get the key value of Mybatis Configuration Variable. */
28
+ private string getAnMybatisConfigurationVariableKey ( ) {
29
+ exists ( PropertiesFlowConfig conf , DataFlow:: Node n |
30
+ propertiesKey ( n , result ) and
31
+ conf .hasFlow ( _, n )
32
+ )
33
+ }
4
34
5
35
/** The interface `org.apache.ibatis.annotations.Param`. */
6
36
private class TypeParam extends Interface {
@@ -25,6 +55,11 @@ class MyBatisMapperMethodCallAnArgument extends DataFlow::Node {
25
55
}
26
56
}
27
57
58
+ /** Get the #{...} or ${...} parameters in the Mybatis mapper xml file */
59
+ private string getAnMybatiXmlSetValue ( XMLElement xmle ) {
60
+ result = xmle .getTextValue ( ) .trim ( ) .regexpFind ( "(#|\\$)(\\{([^\\}]*\\}))" , _, _)
61
+ }
62
+
28
63
predicate isSqlInjection ( DataFlow:: Node node , XMLElement xmle ) {
29
64
// MyBatis Mapper method parameter name sql injection vulnerabilities.
30
65
// e.g. MyBatis Mapper method: `void test(String name);` and MyBatis Mapper XML file:`select id,name from test where name like '%${name}%'`
@@ -38,7 +73,7 @@ predicate isSqlInjection(DataFlow::Node node, XMLElement xmle) {
38
73
mbms .getAChild * ( ) = xmle
39
74
) and
40
75
not mc .getMethod ( ) .getParameter ( i ) .hasAnnotation ( ) and
41
- xmle . getTextValue ( ) . trim ( ) . matches ( "% ${" + mc .getMethod ( ) .getParameter ( i ) .getName ( ) + "%" ) and
76
+ getAnMybatiXmlSetValue ( xmle ) . matches ( "${" + mc .getMethod ( ) .getParameter ( i ) .getName ( ) + "%} " ) and
42
77
mc .getArgument ( i ) = node .asExpr ( )
43
78
)
44
79
or
@@ -59,10 +94,9 @@ predicate isSqlInjection(DataFlow::Node node, XMLElement xmle) {
59
94
mc .getMethod ( ) .getParameter ( i ) .hasAnnotation ( ) and
60
95
mc .getMethod ( ) .getParameter ( i ) .getAnAnnotation ( ) = annotation and
61
96
annotation .getType ( ) instanceof TypeParam and
62
- xmle .getTextValue ( )
63
- .trim ( )
97
+ getAnMybatiXmlSetValue ( xmle )
64
98
.matches ( "%${" + annotation .getValue ( "value" ) .( CompileTimeConstantExpr ) .getStringValue ( ) +
65
- "%" ) and
99
+ "%} " ) and
66
100
mc .getArgument ( i ) = node .asExpr ( )
67
101
)
68
102
or
@@ -79,13 +113,15 @@ predicate isSqlInjection(DataFlow::Node node, XMLElement xmle) {
79
113
) and
80
114
not mc .getMethod ( ) .getParameter ( i ) .hasAnnotation ( ) and
81
115
mc .getMethod ( ) .getParameterType ( i ) .getName ( ) = c .getName ( ) and
82
- xmle . getTextValue ( ) . trim ( ) . matches ( "%${" + c .getAField ( ) .getName ( ) + "%" ) and
116
+ getAnMybatiXmlSetValue ( xmle ) . matches ( "%${" + c .getAField ( ) .getName ( ) + "%} " ) and
83
117
mc .getArgument ( i ) = node .asExpr ( )
84
118
)
85
119
or
86
120
// The parameter type of MyBatis Mapper method is Map or List or Array, which may cause SQL injection vulnerability.
87
121
// e.g. MyBatis Mapper method: `void test(Map<String, String> params);` and MyBatis Mapper XML file:`select id,name from test where name like '%${name}%'`
88
- exists ( MyBatisMapperSqlOperation mbmxe , MyBatisMapperSql mbms , MethodAccess mc , int i |
122
+ exists (
123
+ MyBatisMapperSqlOperation mbmxe , MyBatisMapperSql mbms , MethodAccess mc , int i , string res
124
+ |
89
125
mbmxe .getMapperMethod ( ) = mc .getMethod ( )
90
126
|
91
127
(
@@ -100,13 +136,15 @@ predicate isSqlInjection(DataFlow::Node node, XMLElement xmle) {
100
136
mc .getMethod ( ) .getParameterType ( i ) instanceof ListType or
101
137
mc .getMethod ( ) .getParameterType ( i ) instanceof Array
102
138
) and
103
- xmle .getTextValue ( ) .trim ( ) .matches ( "%${%" ) and
139
+ res = getAnMybatiXmlSetValue ( xmle ) and
140
+ res .matches ( "%${%}" ) and
141
+ not res .matches ( "${" + getAnMybatisConfigurationVariableKey ( ) + "}" ) and
104
142
mc .getArgument ( i ) = node .asExpr ( )
105
143
)
106
144
or
107
145
// MyBatis Mapper method string type sql injection vulnerabilities.
108
146
// e.g. MyBatis Mapper method: `void test(String name);` and MyBatis Mapper XML file:`select id,name from test where name like '%${value}%'`
109
- exists ( MyBatisMapperSqlOperation mbmxe , MyBatisMapperSql mbms , MethodAccess mc |
147
+ exists ( MyBatisMapperSqlOperation mbmxe , MyBatisMapperSql mbms , MethodAccess mc , string res |
110
148
mbmxe .getMapperMethod ( ) = mc .getMethod ( )
111
149
|
112
150
(
@@ -115,10 +153,12 @@ predicate isSqlInjection(DataFlow::Node node, XMLElement xmle) {
115
153
mbmxe .getInclude ( ) .getRefid ( ) = mbms .getId ( ) and
116
154
mbms .getAChild * ( ) = xmle
117
155
) and
156
+ res = getAnMybatiXmlSetValue ( xmle ) and
118
157
mc .getMethod ( ) .getAParamType ( ) instanceof TypeString and
119
158
mc .getMethod ( ) .getNumberOfParameters ( ) = 1 and
120
159
not mc .getMethod ( ) .getAParameter ( ) .hasAnnotation ( ) and
121
- xmle .getTextValue ( ) .trim ( ) .matches ( "%${%" ) and
160
+ res .matches ( "%${%}" ) and
161
+ not res .matches ( "${" + getAnMybatisConfigurationVariableKey ( ) + "}" ) and
122
162
mc .getAnArgument ( ) = node .asExpr ( )
123
163
)
124
164
}
0 commit comments