Modify sinks

This commit is contained in:
haby0
2021-07-31 19:10:21 +08:00
parent 4438f8c58c
commit 69690a2509
9 changed files with 179 additions and 66 deletions

View File

@@ -16,15 +16,14 @@ import DataFlow::PathGraph
import MyBatisMapperXmlSqlInjectionLib import MyBatisMapperXmlSqlInjectionLib
import semmle.code.java.dataflow.FlowSources import semmle.code.java.dataflow.FlowSources
/**
* A taint-tracking configuration for tracking untrusted user input used by the Mybatis mapper xml file dynamic splicing sql use.
*/
private class MyBatisMapperXmlSqlInjectionConfiguration extends TaintTracking::Configuration { private class MyBatisMapperXmlSqlInjectionConfiguration extends TaintTracking::Configuration {
MyBatisMapperXmlSqlInjectionConfiguration() { this = "MyBatis mapper xml sql injection" } MyBatisMapperXmlSqlInjectionConfiguration() { this = "MyBatis mapper xml sql injection" }
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
override predicate isSink(DataFlow::Node sink) { sink instanceof MyBatisMapperXmlSqlInjectionSink } override predicate isSink(DataFlow::Node sink) {
sink instanceof MyBatisMapperXmlSqlInjectionSink
}
override predicate isSanitizer(DataFlow::Node node) { override predicate isSanitizer(DataFlow::Node node) {
node.getType() instanceof PrimitiveType or node.getType() instanceof PrimitiveType or
@@ -33,7 +32,8 @@ private class MyBatisMapperXmlSqlInjectionConfiguration extends TaintTracking::C
} }
} }
from MyBatisMapperXmlSqlInjectionConfiguration cfg, DataFlow::PathNode source, DataFlow::PathNode sink from
MyBatisMapperXmlSqlInjectionConfiguration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
where cfg.hasFlowPath(source, sink) where cfg.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "MyBatis Mapper XML sql injection might include code from $@.", source.getNode(), select sink.getNode(), source, sink, "MyBatis Mapper XML sql injection might include code from $@.",
"this user input" source.getNode(), "this user input"

View File

@@ -2,24 +2,100 @@ import java
import semmle.code.xml.MyBatisMapperXML import semmle.code.xml.MyBatisMapperXML
import semmle.code.java.dataflow.FlowSources import semmle.code.java.dataflow.FlowSources
/** The interface `org.apache.ibatis.annotations.Param`. */
private class TypeParam extends Interface {
TypeParam() { this.hasQualifiedName("org.apache.ibatis.annotations", "Param") }
}
/** A sink for MyBatis Mapper XML file sql injection vulnerabilities. */ /** A sink for MyBatis Mapper XML file sql injection vulnerabilities. */
class MyBatisMapperXmlSqlInjectionSink extends DataFlow::Node { abstract class MyBatisMapperXmlSqlInjectionSink extends DataFlow::Node { }
MyBatisMapperXmlSqlInjectionSink() {
exists(MyBatisMapperSqlOperation mbmxe, MethodAccess ma | /**
mbmxe.getAChild*().getTextValue().trim().matches("%${%") and * A sink for MyBatis Mapper method parameter name sql injection vulnerabilities.
*
* e.g. MyBatis Mapper method: `void test(String name);` and MyBatis Mapper XML file:`select id,name from test where name like '%${name}%'`
*/
class MyBatisMapperParameterNameSqlInjectionSink extends MyBatisMapperXmlSqlInjectionSink {
MyBatisMapperParameterNameSqlInjectionSink() {
exists(
MyBatisMapperSqlOperation mbmxe, MyBatisMapperSql mbms, MethodAccess ma, int i, Method m,
Expr arg, string sql
|
m = ma.getMethod() and arg = ma.getArgument(i)
|
arg = this.asExpr() and
(
mbmxe.getAChild*().getTextValue().trim() = sql
or
mbmxe.getInclude().getRefid() = mbms.getId() and
mbms.getAChild*().getTextValue().trim() = sql
) and
not m.getParameter(i).hasAnnotation() and
sql.matches("%${" + m.getParameter(i).getName() + "%") and
mbmxe.getId() = ma.getMethod().getName() and mbmxe.getId() = ma.getMethod().getName() and
ma.getMethod().getDeclaringType() = ma.getMethod().getDeclaringType() =
mbmxe.getParent().(MyBatisMapperXMLElement).getNamespaceRefType() and mbmxe.getParent().(MyBatisMapperXMLElement).getNamespaceRefType()
ma.getAnArgument() = this.asExpr() )
) }
or }
exists(MyBatisMapperSqlOperation mbmxe, MyBatisMapperSql mbms, MethodAccess ma |
mbmxe.getInclude().getRefid() = mbms.getId() and /**
mbms.getAChild*().getTextValue().trim().matches("%${%") and * A sink for MyBatis Mapper method Param Annotation sql injection vulnerabilities.
mbmxe.getId() = ma.getMethod().getName() and *
ma.getMethod().getDeclaringType() = * e.g. MyBatis Mapper method: `void test(@Param("orderby") String name);` and MyBatis Mapper XML file:`select id,name from test order by ${orderby,jdbcType=VARCHAR}`
mbmxe.getParent().(MyBatisMapperXMLElement).getNamespaceRefType() and */
ma.getAnArgument() = this.asExpr() class MyBatisMapperParamAnnotationSqlInjectionSink extends MyBatisMapperXmlSqlInjectionSink {
MyBatisMapperParamAnnotationSqlInjectionSink() {
exists(
MyBatisMapperSqlOperation mbmxe, MyBatisMapperSql mbms, MethodAccess ma, int i, Method m,
Expr arg, Annotation a, string sql
|
m = ma.getMethod() and arg = ma.getArgument(i)
|
arg = this.asExpr() and
(
mbmxe.getAChild*().getTextValue().trim() = sql
or
mbmxe.getInclude().getRefid() = mbms.getId() and
mbms.getAChild*().getTextValue().trim() = sql
) and
m.getParameter(i).hasAnnotation() and
m.getParameter(i).getAnAnnotation() = a and
a.getType() instanceof TypeParam and
sql.matches("%${" + a.getValue("value").(CompileTimeConstantExpr).getStringValue() + "%") and
mbmxe.getId() = ma.getMethod().getName() and
ma.getMethod().getDeclaringType() =
mbmxe.getParent().(MyBatisMapperXMLElement).getNamespaceRefType()
)
}
}
/**
* A sink for MyBatis Mapper method Class Field sql injection vulnerabilities.
*
* e.g. MyBatis Mapper method: `void test(Test test);` and MyBatis Mapper XML file:`select id,name from test order by ${name,jdbcType=VARCHAR}`
*/
class MyBatisMapperClassFieldSqlInjectionSink extends MyBatisMapperXmlSqlInjectionSink {
MyBatisMapperClassFieldSqlInjectionSink() {
exists(
MyBatisMapperSqlOperation mbmxe, MyBatisMapperSql mbms, MethodAccess ma, int i, Method m,
Expr arg, string sql, Class c
|
m = ma.getMethod() and arg = ma.getArgument(i)
|
arg = this.asExpr() and
(
mbmxe.getAChild*().getTextValue().trim() = sql
or
mbmxe.getInclude().getRefid() = mbms.getId() and
mbms.getAChild*().getTextValue().trim() = sql
) and
not m.getParameter(i).hasAnnotation() and
m.getParameterType(i).getName() = c.getName() and
sql.matches("%${" + c.getAField().getName() + "%") and
mbmxe.getId() = ma.getMethod().getName() and
ma.getMethod().getDeclaringType() =
mbmxe.getParent().(MyBatisMapperXMLElement).getNamespaceRefType()
) )
} }
} }

View File

@@ -1,43 +1,43 @@
edges edges
| MybatisSqlInjection.java:16:25:16:35 | name : String | MybatisSqlInjection.java:17:55:17:58 | name : String | | MybatisSqlInjection.java:17:25:17:35 | name : String | MybatisSqlInjection.java:18:55:18:58 | name : String |
| MybatisSqlInjection.java:17:55:17:58 | name : String | MybatisSqlInjectionService.java:11:25:11:35 | name : String | | MybatisSqlInjection.java:18:55:18:58 | name : String | MybatisSqlInjectionService.java:11:25:11:35 | name : String |
| MybatisSqlInjection.java:22:25:22:35 | name : String | MybatisSqlInjection.java:23:55:23:58 | name : String | | MybatisSqlInjection.java:23:25:23:35 | name : String | MybatisSqlInjection.java:24:55:24:58 | name : String |
| MybatisSqlInjection.java:23:55:23:58 | name : String | MybatisSqlInjectionService.java:16:25:16:35 | name : String | | MybatisSqlInjection.java:24:55:24:58 | name : String | MybatisSqlInjectionService.java:16:25:16:35 | name : String |
| MybatisSqlInjection.java:28:25:28:35 | name : String | MybatisSqlInjection.java:29:55:29:58 | name : String | | MybatisSqlInjection.java:29:25:29:49 | test : Test | MybatisSqlInjection.java:30:55:30:58 | test : Test |
| MybatisSqlInjection.java:29:55:29:58 | name : String | MybatisSqlInjectionService.java:21:25:21:35 | name : String | | MybatisSqlInjection.java:30:55:30:58 | test : Test | MybatisSqlInjectionService.java:21:25:21:33 | test : Test |
| MybatisSqlInjection.java:34:19:34:40 | test : Test | MybatisSqlInjection.java:35:35:35:38 | test : Test | | MybatisSqlInjection.java:35:19:35:40 | test : Test | MybatisSqlInjection.java:36:35:36:38 | test : Test |
| MybatisSqlInjection.java:35:35:35:38 | test : Test | MybatisSqlInjectionService.java:26:19:26:27 | test : Test | | MybatisSqlInjection.java:36:35:36:38 | test : Test | MybatisSqlInjectionService.java:26:19:26:27 | test : Test |
| MybatisSqlInjection.java:39:19:39:40 | test : Test | MybatisSqlInjection.java:40:35:40:38 | test : Test | | MybatisSqlInjection.java:40:19:40:40 | test : Test | MybatisSqlInjection.java:41:35:41:38 | test : Test |
| MybatisSqlInjection.java:40:35:40:38 | test : Test | MybatisSqlInjectionService.java:30:19:30:27 | test : Test | | MybatisSqlInjection.java:41:35:41:38 | test : Test | MybatisSqlInjectionService.java:30:19:30:27 | test : Test |
| MybatisSqlInjectionService.java:11:25:11:35 | name : String | MybatisSqlInjectionService.java:12:47:12:50 | name | | MybatisSqlInjectionService.java:11:25:11:35 | name : String | MybatisSqlInjectionService.java:12:47:12:50 | name |
| MybatisSqlInjectionService.java:16:25:16:35 | name : String | MybatisSqlInjectionService.java:17:47:17:50 | name | | MybatisSqlInjectionService.java:16:25:16:35 | name : String | MybatisSqlInjectionService.java:17:47:17:50 | name |
| MybatisSqlInjectionService.java:21:25:21:35 | name : String | MybatisSqlInjectionService.java:22:47:22:50 | name | | MybatisSqlInjectionService.java:21:25:21:33 | test : Test | MybatisSqlInjectionService.java:22:47:22:50 | test |
| MybatisSqlInjectionService.java:26:19:26:27 | test : Test | MybatisSqlInjectionService.java:27:27:27:30 | test | | MybatisSqlInjectionService.java:26:19:26:27 | test : Test | MybatisSqlInjectionService.java:27:27:27:30 | test |
| MybatisSqlInjectionService.java:30:19:30:27 | test : Test | MybatisSqlInjectionService.java:31:27:31:30 | test | | MybatisSqlInjectionService.java:30:19:30:27 | test : Test | MybatisSqlInjectionService.java:31:27:31:30 | test |
nodes nodes
| MybatisSqlInjection.java:16:25:16:35 | name : String | semmle.label | name : String | | MybatisSqlInjection.java:17:25:17:35 | name : String | semmle.label | name : String |
| MybatisSqlInjection.java:17:55:17:58 | name : String | semmle.label | name : String | | MybatisSqlInjection.java:18:55:18:58 | name : String | semmle.label | name : String |
| MybatisSqlInjection.java:22:25:22:35 | name : String | semmle.label | name : String | | MybatisSqlInjection.java:23:25:23:35 | name : String | semmle.label | name : String |
| MybatisSqlInjection.java:23:55:23:58 | name : String | semmle.label | name : String | | MybatisSqlInjection.java:24:55:24:58 | name : String | semmle.label | name : String |
| MybatisSqlInjection.java:28:25:28:35 | name : String | semmle.label | name : String | | MybatisSqlInjection.java:29:25:29:49 | test : Test | semmle.label | test : Test |
| MybatisSqlInjection.java:29:55:29:58 | name : String | semmle.label | name : String | | MybatisSqlInjection.java:30:55:30:58 | test : Test | semmle.label | test : Test |
| MybatisSqlInjection.java:34:19:34:40 | test : Test | semmle.label | test : Test | | MybatisSqlInjection.java:35:19:35:40 | test : Test | semmle.label | test : Test |
| MybatisSqlInjection.java:35:35:35:38 | test : Test | semmle.label | test : Test | | MybatisSqlInjection.java:36:35:36:38 | test : Test | semmle.label | test : Test |
| MybatisSqlInjection.java:39:19:39:40 | test : Test | semmle.label | test : Test | | MybatisSqlInjection.java:40:19:40:40 | test : Test | semmle.label | test : Test |
| MybatisSqlInjection.java:40:35:40:38 | test : Test | semmle.label | test : Test | | MybatisSqlInjection.java:41:35:41:38 | test : Test | semmle.label | test : Test |
| MybatisSqlInjectionService.java:11:25:11:35 | name : String | semmle.label | name : String | | MybatisSqlInjectionService.java:11:25:11:35 | name : String | semmle.label | name : String |
| MybatisSqlInjectionService.java:12:47:12:50 | name | semmle.label | name | | MybatisSqlInjectionService.java:12:47:12:50 | name | semmle.label | name |
| MybatisSqlInjectionService.java:16:25:16:35 | name : String | semmle.label | name : String | | MybatisSqlInjectionService.java:16:25:16:35 | name : String | semmle.label | name : String |
| MybatisSqlInjectionService.java:17:47:17:50 | name | semmle.label | name | | MybatisSqlInjectionService.java:17:47:17:50 | name | semmle.label | name |
| MybatisSqlInjectionService.java:21:25:21:35 | name : String | semmle.label | name : String | | MybatisSqlInjectionService.java:21:25:21:33 | test : Test | semmle.label | test : Test |
| MybatisSqlInjectionService.java:22:47:22:50 | name | semmle.label | name | | MybatisSqlInjectionService.java:22:47:22:50 | test | semmle.label | test |
| MybatisSqlInjectionService.java:26:19:26:27 | test : Test | semmle.label | test : Test | | MybatisSqlInjectionService.java:26:19:26:27 | test : Test | semmle.label | test : Test |
| MybatisSqlInjectionService.java:27:27:27:30 | test | semmle.label | test | | MybatisSqlInjectionService.java:27:27:27:30 | test | semmle.label | test |
| MybatisSqlInjectionService.java:30:19:30:27 | test : Test | semmle.label | test : Test | | MybatisSqlInjectionService.java:30:19:30:27 | test : Test | semmle.label | test : Test |
| MybatisSqlInjectionService.java:31:27:31:30 | test | semmle.label | test | | MybatisSqlInjectionService.java:31:27:31:30 | test | semmle.label | test |
#select #select
| MybatisSqlInjectionService.java:12:47:12:50 | name | MybatisSqlInjection.java:16:25:16:35 | name : String | MybatisSqlInjectionService.java:12:47:12:50 | name | MyBatis Mapper XML sql injection might include code from $@. | MybatisSqlInjection.java:16:25:16:35 | name | this user input | | MybatisSqlInjectionService.java:12:47:12:50 | name | MybatisSqlInjection.java:17:25:17:35 | name : String | MybatisSqlInjectionService.java:12:47:12:50 | name | MyBatis Mapper XML sql injection might include code from $@. | MybatisSqlInjection.java:17:25:17:35 | name | this user input |
| MybatisSqlInjectionService.java:17:47:17:50 | name | MybatisSqlInjection.java:22:25:22:35 | name : String | MybatisSqlInjectionService.java:17:47:17:50 | name | MyBatis Mapper XML sql injection might include code from $@. | MybatisSqlInjection.java:22:25:22:35 | name | this user input | | MybatisSqlInjectionService.java:17:47:17:50 | name | MybatisSqlInjection.java:23:25:23:35 | name : String | MybatisSqlInjectionService.java:17:47:17:50 | name | MyBatis Mapper XML sql injection might include code from $@. | MybatisSqlInjection.java:23:25:23:35 | name | this user input |
| MybatisSqlInjectionService.java:22:47:22:50 | name | MybatisSqlInjection.java:28:25:28:35 | name : String | MybatisSqlInjectionService.java:22:47:22:50 | name | MyBatis Mapper XML sql injection might include code from $@. | MybatisSqlInjection.java:28:25:28:35 | name | this user input | | MybatisSqlInjectionService.java:22:47:22:50 | test | MybatisSqlInjection.java:29:25:29:49 | test : Test | MybatisSqlInjectionService.java:22:47:22:50 | test | MyBatis Mapper XML sql injection might include code from $@. | MybatisSqlInjection.java:29:25:29:49 | test | this user input |
| MybatisSqlInjectionService.java:27:27:27:30 | test | MybatisSqlInjection.java:34:19:34:40 | test : Test | MybatisSqlInjectionService.java:27:27:27:30 | test | MyBatis Mapper XML sql injection might include code from $@. | MybatisSqlInjection.java:34:19:34:40 | test | this user input | | MybatisSqlInjectionService.java:27:27:27:30 | test | MybatisSqlInjection.java:35:19:35:40 | test : Test | MybatisSqlInjectionService.java:27:27:27:30 | test | MyBatis Mapper XML sql injection might include code from $@. | MybatisSqlInjection.java:35:19:35:40 | test | this user input |
| MybatisSqlInjectionService.java:31:27:31:30 | test | MybatisSqlInjection.java:39:19:39:40 | test : Test | MybatisSqlInjectionService.java:31:27:31:30 | test | MyBatis Mapper XML sql injection might include code from $@. | MybatisSqlInjection.java:39:19:39:40 | test | this user input | | MybatisSqlInjectionService.java:31:27:31:30 | test | MybatisSqlInjection.java:40:19:40:40 | test : Test | MybatisSqlInjectionService.java:31:27:31:30 | test | MyBatis Mapper XML sql injection might include code from $@. | MybatisSqlInjection.java:40:19:40:40 | test | this user input |

View File

@@ -3,6 +3,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestMethod;
@@ -25,8 +26,8 @@ public class MybatisSqlInjection {
} }
@GetMapping(value = "bad3") @GetMapping(value = "bad3")
public List<Test> bad3(String name) { public List<Test> bad3(@ModelAttribute Test test) {
List<Test> result = mybatisSqlInjectionService.bad3(name); List<Test> result = mybatisSqlInjectionService.bad3(test);
return result; return result;
} }

View File

@@ -18,8 +18,8 @@ public class MybatisSqlInjectionService {
return result; return result;
} }
public List<Test> bad3(String name) { public List<Test> bad3(Test test) {
List<Test> result = sqlInjectionMapper.bad3(name); List<Test> result = sqlInjectionMapper.bad3(test);
return result; return result;
} }

View File

@@ -1,5 +1,6 @@
import java.util.List; import java.util.List;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
@Mapper @Mapper
@@ -8,11 +9,11 @@ public interface SqlInjectionMapper {
List<Test> bad1(String name); List<Test> bad1(String name);
List<Test> bad2(String name); List<Test> bad2(@Param("orderby") String name);
List<Test> bad3(String name); List<Test> bad3(Test test);
void bad4(Test test); void bad4(@Param("test") Test test);
void bad5(Test test); void bad5(Test test);

View File

@@ -11,11 +11,11 @@
<sql id="Update_By_Example_Where_Clause"> <sql id="Update_By_Example_Where_Clause">
<where> <where>
<if test="name != null"> <if test="test.name != null">
and name = ${name} and name = ${test.name,jdbcType=VARCHAR}
</if> </if>
<if test="id != null"> <if test="test.id != null">
and id = #{id} and id = #{test.id}
</if> </if>
</where> </where>
</sql> </sql>
@@ -24,19 +24,19 @@
select id,name from test where name like '%${name}%' select id,name from test where name like '%${name}%'
</select> </select>
<select id="bad2" parameterType="java.lang.String" resultMap="BaseResultMap"> <select id="bad2" resultMap="BaseResultMap">
select id,name from test order by ${name} desc select id,name from test order by ${orderby,jdbcType=VARCHAR} desc
</select> </select>
<select id="bad3" parameterType="java.lang.String" resultMap="BaseResultMap"> <select id="bad3" parameterType="java.lang.String" resultMap="BaseResultMap">
select id,name from test where name in ${name} select id,name from test where name in ${name}
</select> </select>
<update id="bad4" parameterType="Test"> <update id="bad4" parameterType="com.example.demo.entity.Test">
update test update test
<set> <set>
<if test="pass != null"> <if test="test.pass != null">
pass = #{pass}, pass = #{test.pass},
</if> </if>
</set> </set>
<if test="_parameter != null"> <if test="_parameter != null">

View File

@@ -0,0 +1,14 @@
package org.apache.ibatis.annotations;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
public @interface Param {
String value();
}

View File

@@ -0,0 +1,21 @@
package org.springframework.web.bind.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ModelAttribute {
@AliasFor("name")
String value() default "";
@AliasFor("value")
String name() default "";
boolean binding() default true;
}