This commit is contained in:
haby0
2021-12-08 21:03:17 +08:00
parent 1d321c692b
commit a18aad8536
3 changed files with 87 additions and 41 deletions

View File

@@ -44,12 +44,17 @@ private class MyBatisAnnotationSqlInjectionConfiguration extends TaintTracking::
from
MyBatisAnnotationSqlInjectionConfiguration cfg, DataFlow::PathNode source,
DataFlow::PathNode sink, IbatisSqlOperationAnnotation isoa, MethodAccess ma
DataFlow::PathNode sink, IbatisSqlOperationAnnotation isoa, MethodAccess ma,
string unsafeExpression
where
cfg.hasFlowPath(source, sink) and
ma.getAnArgument() = sink.getNode().asExpr() and
myBatisSqlOperationAnnotationFromMethod(ma.getMethod(), isoa) and
isMybatisXmlOrAnnotationSqlInjection(sink.getNode(), ma, getAMybatisAnnotationSqlValue(isoa), _)
unsafeExpression = getAMybatisAnnotationSqlValue(isoa) and
(
isMybatisXmlOrAnnotationSqlInjection(sink.getNode(), ma, unsafeExpression) or
isMybatisAnnotationCollectionTypeSqlInjection(sink.getNode(), ma, unsafeExpression)
)
select sink.getNode(), source, sink,
"MyBatis annotation SQL injection might include code from $@ to $@.", source.getNode(),
"this user input", isoa, "this SQL operation"

View File

@@ -44,7 +44,7 @@ class ListType extends RefType {
}
}
/** Holds if the specified method uses MyBatis Mapper XMLElement. */
/** Holds if the specified `method` uses MyBatis Mapper XMLElement `mmxx`. */
predicate myBatisMapperXMLElementFromMethod(Method method, MyBatisMapperXMLElement mmxx) {
exists(MyBatisMapperSqlOperation mbmxe | mbmxe.getMapperMethod() = method |
mbmxe.getAChild*() = mmxx
@@ -56,7 +56,7 @@ predicate myBatisMapperXMLElementFromMethod(Method method, MyBatisMapperXMLEleme
)
}
/** Holds if the specified method uses Ibatis Sql Operation Annotation. */
/** Holds if the specified `method` has Ibatis Sql operation annotation `isoa`. */
predicate myBatisSqlOperationAnnotationFromMethod(Method method, IbatisSqlOperationAnnotation isoa) {
exists(MyBatisSqlOperationAnnotationMethod msoam |
msoam = method and
@@ -64,23 +64,80 @@ predicate myBatisSqlOperationAnnotationFromMethod(Method method, IbatisSqlOperat
)
}
/** Get the #{...} or ${...} parameters in the Mybatis mapper xml file. */
/** Gets a `#{...}` or `${...}` expression argument in XML element `xmle`. */
string getAMybatisXmlSetValue(XMLElement xmle) {
result = xmle.getTextValue().regexpFind("(#|\\$)\\{[^\\}]*\\}", _, _)
}
/** Get the #{...} or ${...} parameters in the Mybatis sql operation annotation value. */
/** Gets a `#{...}` or `${...}` expression argument in annotation `isoa`. */
string getAMybatisAnnotationSqlValue(IbatisSqlOperationAnnotation isoa) {
result = isoa.getSqlValue().regexpFind("(#|\\$)\\{[^\\}]*\\}", _, _)
}
/** Holds if it is SQL injection of MyBatis xml or MyBatis annotation. */
bindingset[setValue]
predicate isMybatisXmlOrAnnotationSqlInjection(
//DataFlow::Node node, MyBatisMapperXMLElement xmle, IbatisSqlOperationAnnotation isoa
DataFlow::Node node, MethodAccess ma, string setValue, MyBatisMapperXMLElement mmxe
/** Holds if `node` is an argument to `ma` that is vulnerable to SQL injection attacks if `unsafeExpression` occurs in a MyBatis SQL expression. */
bindingset[unsafeExpression]
predicate isMybatisAnnotationCollectionTypeSqlInjection(
DataFlow::Node node, MethodAccess ma, string unsafeExpression
) {
not setValue.regexpMatch("\\$\\{" + getAMybatisConfigurationVariableKey() + "\\}") and
not unsafeExpression.regexpMatch("\\$\\{" + getAMybatisConfigurationVariableKey() + "\\}") and
// The parameter type of the MyBatis method parameter is Map or List or Array.
// SQL injection vulnerability caused by improper use of this parameter.
// e.g.
//
// ```java
// @Select(select id,name from test where name like '%${value}%')
// Test test(Map map);
// ```
exists(int i |
not ma.getMethod().getParameter(i).getAnAnnotation().getType() instanceof TypeParam and
(
ma.getMethod().getParameterType(i) instanceof MapType or
ma.getMethod().getParameterType(i) instanceof ListType or
ma.getMethod().getParameterType(i) instanceof Array
) and
unsafeExpression.matches("${%}") and
ma.getArgument(i) = node.asExpr()
)
}
/** Holds if `node` is an argument to `ma` that is vulnerable to SQL injection attacks if `unsafeExpression` occurs in a MyBatis SQL expression. */
bindingset[unsafeExpression]
predicate isMybatisXmlCollectionTypeSqlInjection(
DataFlow::Node node, MethodAccess ma, string unsafeExpression, MyBatisMapperXMLElement mmxe
) {
not unsafeExpression.regexpMatch("\\$\\{" + getAMybatisConfigurationVariableKey() + "\\}") and
// The parameter type of the MyBatis method parameter is Map or List or Array.
// SQL injection vulnerability caused by improper use of this parameter.
// e.g.
//
// ```java
// Test test(Map map);
// <select id="test" resultMap="BaseResultMap">
// select id,name from test where name in
// <foreach collection="list" item="value" open="(" close=")" separator=",">
// ${value}
// </foreach>
// </select>
// ```
exists(int i, MyBatisMapperForeach mbmf |
mbmf = mmxe and
not ma.getMethod().getParameter(i).getAnAnnotation().getType() instanceof TypeParam and
(
ma.getMethod().getParameterType(i) instanceof MapType or
ma.getMethod().getParameterType(i) instanceof ListType or
ma.getMethod().getParameterType(i) instanceof Array
) and
unsafeExpression.matches("${%}") and
ma.getArgument(i) = node.asExpr()
)
}
/** Holds if `node` is an argument to `ma` that is vulnerable to SQL injection attacks if `unsafeExpression` occurs in a MyBatis SQL expression. */
bindingset[unsafeExpression]
predicate isMybatisXmlOrAnnotationSqlInjection(
DataFlow::Node node, MethodAccess ma, string unsafeExpression
) {
not unsafeExpression.regexpMatch("\\$\\{" + getAMybatisConfigurationVariableKey() + "\\}") and
(
// The method parameters use `@Param` annotation. Due to improper use of this parameter, SQL injection vulnerabilities are caused.
// e.g.
@@ -89,12 +146,12 @@ predicate isMybatisXmlOrAnnotationSqlInjection(
// @Select(select id,name from test order by ${orderby,jdbcType=VARCHAR})
// void test(@Param("orderby") String name);
// ```
exists(int i, Annotation annotation |
setValue
exists(Annotation annotation |
unsafeExpression
.matches("${" + annotation.getValue("value").(CompileTimeConstantExpr).getStringValue() +
"%}") and
annotation.getType() instanceof TypeParam and
ma.getArgument(i) = node.asExpr()
ma.getAnArgument() = node.asExpr()
)
or
// MyBatis default parameter sql injection vulnerabilities.the default parameter form of the method is arg[0...n] or param[1...n].
@@ -107,9 +164,9 @@ predicate isMybatisXmlOrAnnotationSqlInjection(
exists(int i |
not ma.getMethod().getParameter(i).getAnAnnotation().getType() instanceof TypeParam and
(
setValue.matches("${param" + (i + 1) + "%}")
unsafeExpression.matches("${param" + (i + 1) + "%}")
or
setValue.matches("${arg" + i + "%}")
unsafeExpression.matches("${arg" + i + "%}")
) and
ma.getArgument(i) = node.asExpr()
)
@@ -124,27 +181,7 @@ predicate isMybatisXmlOrAnnotationSqlInjection(
exists(int i, RefType t |
not ma.getMethod().getParameter(i).getAnAnnotation().getType() instanceof TypeParam and
ma.getMethod().getParameterType(i).getName() = t.getName() and
setValue.matches("${" + t.getAField().getName() + "%}") and
ma.getArgument(i) = node.asExpr()
)
or
// The parameter type of the MyBatis method parameter is Map or List or Array.
// SQL injection vulnerability caused by improper use of this parameter.
// e.g.
//
// ```java
// @Select(select id,name from test where name like '%${value}%')
// Test test(Map map);
// ```
exists(int i, MyBatisMapperForeach mbmf |
mbmf = mmxe and
not ma.getMethod().getParameter(i).getAnAnnotation().getType() instanceof TypeParam and
(
ma.getMethod().getParameterType(i) instanceof MapType or
ma.getMethod().getParameterType(i) instanceof ListType or
ma.getMethod().getParameterType(i) instanceof Array
) and
setValue.matches("${%}") and
unsafeExpression.matches("${" + t.getAField().getName() + "%}") and
ma.getArgument(i) = node.asExpr()
)
or
@@ -160,7 +197,7 @@ predicate isMybatisXmlOrAnnotationSqlInjection(
exists(int i | i = 1 |
ma.getMethod().getNumberOfParameters() = i and
not ma.getMethod().getAParameter().getAnAnnotation().getType() instanceof TypeParam and
setValue.matches("${%}") and
unsafeExpression.matches("${%}") and
ma.getAnArgument() = node.asExpr()
)
)

View File

@@ -45,12 +45,16 @@ private class MyBatisMapperXmlSqlInjectionConfiguration extends TaintTracking::C
from
MyBatisMapperXmlSqlInjectionConfiguration cfg, DataFlow::PathNode source, DataFlow::PathNode sink,
MyBatisMapperXMLElement mmxe, MethodAccess ma
MyBatisMapperXMLElement mmxe, MethodAccess ma, string unsafeExpression
where
cfg.hasFlowPath(source, sink) and
ma.getAnArgument() = sink.getNode().asExpr() and
myBatisMapperXMLElementFromMethod(ma.getMethod(), mmxe) and
isMybatisXmlOrAnnotationSqlInjection(sink.getNode(), ma, getAMybatisXmlSetValue(mmxe), mmxe)
unsafeExpression = getAMybatisXmlSetValue(mmxe) and
(
isMybatisXmlOrAnnotationSqlInjection(sink.getNode(), ma, unsafeExpression) or
isMybatisXmlCollectionTypeSqlInjection(sink.getNode(), ma, unsafeExpression, mmxe)
)
select sink.getNode(), source, sink,
"MyBatis Mapper XML SQL injection might include code from $@ to $@.", source.getNode(),
"this user input", mmxe, "this SQL operation"